Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions src/execution/ResolveInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import type { ObjMap } from '../jsutils/ObjMap';
import type { Path } from '../jsutils/Path';

import type {
FieldNode,
FragmentDefinitionNode,
OperationDefinitionNode,
} from '../language/ast';

import type {
GraphQLField,
GraphQLObjectType,
GraphQLOutputType,
GraphQLResolveInfo,
} from '../type/definition';
import type { GraphQLSchema } from '../type/schema';

interface ExecutionDetails {
schema: GraphQLSchema;
fragments: ObjMap<FragmentDefinitionNode>;
rootValue: unknown;
operation: OperationDefinitionNode;
variableValues: { [key: string]: unknown };
}

/** @internal */
/** @internal */
export class ResolveInfo implements GraphQLResolveInfo {
private _executionDetails: ExecutionDetails;
private _fieldDef: GraphQLField<unknown, unknown>;
private _fieldNodes: ReadonlyArray<FieldNode>;
private _parentType: GraphQLObjectType;
private _path: Path;

private _fieldName: string | undefined;
private _returnType: GraphQLOutputType | undefined;
private _schema: GraphQLSchema | undefined;
private _fragments: ObjMap<FragmentDefinitionNode> | undefined;
private _rootValue: unknown;
private _rootValueDefined?: boolean;
private _operation: OperationDefinitionNode | undefined;
private _variableValues: { [key: string]: unknown } | undefined;

constructor(
executionDetails: ExecutionDetails,
fieldDef: GraphQLField<unknown, unknown>,
fieldNodes: ReadonlyArray<FieldNode>,
parentType: GraphQLObjectType,
path: Path,
) {
this._executionDetails = executionDetails;
this._fieldDef = fieldDef;
this._fieldNodes = fieldNodes;
this._parentType = parentType;
this._path = path;
}

get fieldName(): string {
this._fieldName ??= this._fieldDef.name;
return this._fieldName;
}

get fieldNodes(): ReadonlyArray<FieldNode> {
return this._fieldNodes;
}

get returnType(): GraphQLOutputType {
this._returnType ??= this._fieldDef.type;
return this._returnType;
}

get parentType(): GraphQLObjectType {
return this._parentType;
}

get path(): Path {
return this._path;
}

get schema(): GraphQLSchema {
this._schema ??= this._executionDetails.schema;
return this._schema;
}

get fragments(): ObjMap<FragmentDefinitionNode> {
this._fragments ??= this._executionDetails.fragments;
return this._fragments;
}

get rootValue(): unknown {
if (!this._rootValueDefined) {
this._rootValueDefined = true;
this._rootValue = this._executionDetails.rootValue;
}
return this._rootValue;
}

get operation(): OperationDefinitionNode {
this._operation ??= this._executionDetails.operation;
return this._operation;
}

get variableValues(): { [key: string]: unknown } {
this._variableValues ??= this._executionDetails.variableValues;
return this._variableValues;
}
}
99 changes: 99 additions & 0 deletions src/execution/__tests__/ResolveInfo-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';

import { invariant } from '../../jsutils/invariant';

import { Kind } from '../../language/kinds';
import { parse } from '../../language/parser';

import { GraphQLObjectType } from '../../type/definition';
import { GraphQLString } from '../../type/scalars';
import { GraphQLSchema } from '../../type/schema';

import { collectFields } from '../collectFields';
import { ResolveInfo } from '../ResolveInfo';

describe('ResolveInfo', () => {
const query = new GraphQLObjectType({
name: 'Query',
fields: { test: { type: GraphQLString } },
});

const document = parse('{ test }');

const operation = document.definitions[0];
invariant(operation.kind === Kind.OPERATION_DEFINITION);

const executionDetails = {
schema: new GraphQLSchema({ query }),
operation,
fragments: {},
rootValue: { test: 'root' },
variableValues: {},
};

const { schema, fragments, rootValue, variableValues } = executionDetails;

const groupedFieldSet = collectFields(
schema,
fragments,
variableValues,
query,
operation.selectionSet,
);

const fieldDetailsList = groupedFieldSet.get('test');
invariant(fieldDetailsList != null);

const path = { key: 'test', prev: undefined, typename: 'Query' };

const resolveInfo = new ResolveInfo(
executionDetails,
query.getFields().test,
fieldDetailsList,
query,
path,
);

it('exposes fieldName', () => {
expect(resolveInfo.fieldName).to.equal('test');
});

it('exposes fieldNodes', () => {
const retrievedFieldNodes = resolveInfo.fieldNodes;
expect(retrievedFieldNodes).to.deep.equal(fieldDetailsList);
expect(retrievedFieldNodes).to.equal(resolveInfo.fieldNodes); // ensure same reference
});

it('exposes returnType', () => {
expect(resolveInfo.returnType).to.equal(query.getFields().test.type);
});

it('exposes parentType', () => {
expect(resolveInfo.parentType).to.equal(query);
});

it('exposes path', () => {
expect(resolveInfo.path).to.deep.equal(path);
});

it('exposes schema', () => {
expect(resolveInfo.schema).to.equal(schema);
});

it('exposes fragments', () => {
expect(resolveInfo.fragments).to.equal(fragments);
});

it('exposes rootValue', () => {
expect(resolveInfo.rootValue).to.equal(rootValue);
});

it('exposes operation', () => {
expect(resolveInfo.operation).to.equal(operation);
});

it('exposes variableValues', () => {
expect(resolveInfo.variableValues).to.equal(variableValues);
});
});
1 change: 1 addition & 0 deletions src/execution/execute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ function executeField(
}

/**
* @deprecated will be removed in v17, use ResolveInfo class instead
* @internal
*/
export function buildResolveInfo(
Expand Down
2 changes: 2 additions & 0 deletions src/execution/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
// eslint-disable-next-line import/no-deprecated
assertValidExecutionArguments,
buildExecutionContext,
// eslint-disable-next-line import/no-deprecated
buildResolveInfo,
execute,
getFieldDef,
Expand Down Expand Up @@ -228,6 +229,7 @@ async function executeSubscription(
}

const path = addPath(undefined, responseName, rootType.name);
// eslint-disable-next-line import/no-deprecated
const info = buildResolveInfo(
exeContext,
fieldDef,
Expand Down
Loading