Skip to content

Commit

Permalink
@appendEdge and @prependEdge handlefield generation
Browse files Browse the repository at this point in the history
Reviewed By: josephsavona

Differential Revision: D22346924

fbshipit-source-id: 1619adabede7308c4522946260d311825e3c4929
  • Loading branch information
tyao1 authored and facebook-github-bot committed Jul 6, 2020
1 parent 796950e commit 2719324
Show file tree
Hide file tree
Showing 10 changed files with 363 additions and 4 deletions.
9 changes: 9 additions & 0 deletions packages/relay-compiler/codegen/NormalizationCodeGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,15 @@ function generateLinkedField(
},
};
}
if (handle.handleArgs != null) {
const handleArgs = generateArgs(handle.handleArgs);
if (handleArgs != null) {
handleNode = {
...handleNode,
handleArgs,
};
}
}
return handleNode;
})) ||
[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,184 @@ mutation ChangeNameMutation(
`;

exports[`compileRelayArtifacts matches expected output: append-edge.graphql 1`] = `
~~~~~~~~~~ INPUT ~~~~~~~~~~
mutation CommentCreateMutation(
$connections: [String!]!
$input: CommentCreateInput
) {
commentCreate(input: $input) {
feedbackCommentEdge @appendEdge(connections: $connections) {
cursor
node {
id
}
}
}
}
~~~~~~~~~~ OUTPUT ~~~~~~~~~~
Request {
fragment: Fragment {
argumentDefinitions: [
LocalArgument {
defaultValue: null,
name: "connections",
},
LocalArgument {
defaultValue: null,
name: "input",
},
],
metadata: null,
name: "CommentCreateMutation",
selections: [
LinkedField {
alias: null,
args: [
Variable {
name: "input",
variableName: "input",
},
],
concreteType: "CommentCreateResponsePayload",
name: "commentCreate",
plural: false,
selections: [
LinkedField {
alias: null,
args: null,
concreteType: "CommentsEdge",
name: "feedbackCommentEdge",
plural: false,
selections: [
ScalarField {
alias: null,
args: null,
name: "cursor",
storageKey: null,
},
LinkedField {
alias: null,
args: null,
concreteType: "Comment",
name: "node",
plural: false,
selections: [
ScalarField {
alias: null,
args: null,
name: "id",
storageKey: null,
},
],
storageKey: null,
},
],
storageKey: null,
},
],
storageKey: null,
},
],
type: "Mutation",
abstractKey: null,
},
operation: Operation {
argumentDefinitions: [
LocalArgument {
defaultValue: null,
name: "connections",
},
LocalArgument {
defaultValue: null,
name: "input",
},
],
name: "CommentCreateMutation",
selections: [
LinkedField {
alias: null,
args: [
Variable {
name: "input",
variableName: "input",
},
],
concreteType: "CommentCreateResponsePayload",
name: "commentCreate",
plural: false,
selections: [
LinkedField {
alias: null,
args: null,
concreteType: "CommentsEdge",
name: "feedbackCommentEdge",
plural: false,
selections: [
ScalarField {
alias: null,
args: null,
name: "cursor",
storageKey: null,
},
LinkedField {
alias: null,
args: null,
concreteType: "Comment",
name: "node",
plural: false,
selections: [
ScalarField {
alias: null,
args: null,
name: "id",
storageKey: null,
},
],
storageKey: null,
},
],
storageKey: null,
},
LinkedHandle {
alias: null,
args: null,
filters: null,
handle: "appendEdge",
key: "",
name: "feedbackCommentEdge",
handleArgs: [
Variable {
name: "connections",
variableName: "connections",
},
],
},
],
storageKey: null,
},
],
},
}
QUERY:
mutation CommentCreateMutation(
$input: CommentCreateInput
) {
commentCreate(input: $input) {
feedbackCommentEdge {
cursor
node {
id
}
}
}
}
`;

exports[`compileRelayArtifacts matches expected output: client-conditions.graphql 1`] = `
~~~~~~~~~~ INPUT ~~~~~~~~~~
fragment Foo_user on User {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mutation CommentCreateMutation(
$connections: [String!]!
$input: CommentCreateInput
) {
commentCreate(input: $input) {
feedbackCommentEdge @appendEdge(connections: $connections) {
cursor
node {
id
}
}
}
}
1 change: 1 addition & 0 deletions packages/relay-compiler/core/IR.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export type Handle = {|
// T45504512: new connection model
+dynamicKey: Variable | null,
+filters: ?$ReadOnlyArray<string>,
+handleArgs?: $ReadOnlyArray<Argument>,
|};

export type ClientExtension = {|
Expand Down
6 changes: 5 additions & 1 deletion packages/relay-compiler/core/IRPrinter.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,11 @@ function printHandles(schema: Schema, field: Field): string {
handle.filters == null
? ''
: `, filters: ${JSON.stringify(Array.from(handle.filters).sort())}`;
return `@__clientField(handle: "${handle.name}"${key}${filters})`;
const handleArgs =
handle.handleArgs == null
? ''
: `, handleArgs: ${printArguments(schema, handle.handleArgs)}`;
return `@__clientField(handle: "${handle.name}"${key}${filters}${handleArgs})`;
});
return printed.length ? ' ' + printed.join(' ') : '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,25 @@
const IRTransformer = require('../core/IRTransformer');

const {createUserError} = require('../core/CompilerError');
const {ConnectionInterface} = require('relay-runtime');

const DELETE_RECORD = 'deleteRecord';
const APPEND_EDGE = 'appendEdge';
const PREPEND_EDGE = 'prependEdge';
const LINKED_FIELD_DIRECTIVES = [APPEND_EDGE, PREPEND_EDGE];

const SCHEMA_EXTENSION = `
directive @${DELETE_RECORD} on FIELD
directive @${APPEND_EDGE}(
connections: [String!]!
) on FIELD
directive @${PREPEND_EDGE}(
connections: [String!]!
) on FIELD
`;

import type CompilerContext from '../core/CompilerContext';
import type {ScalarField, Root, Handle, LinkedField} from '../core/IR';
import type {ScalarField, LinkedField, Root, Handle} from '../core/IR';

function transform(context: CompilerContext): CompilerContext {
return IRTransformer.transform(context, {
Expand All @@ -46,6 +57,15 @@ function visitRoot(root: Root): Root {
}

function visitScalarField(field: ScalarField): ScalarField {
const linkedFieldDirective = field.directives.find(
directive => LINKED_FIELD_DIRECTIVES.indexOf(directive.name) > -1,
);
if (linkedFieldDirective != null) {
throw createUserError(
`Invalid use of @${linkedFieldDirective.name} on scalar field '${field.name}'`,
[linkedFieldDirective.loc],
);
}
const deleteDirective = field.directives.find(
directive => directive.name === DELETE_RECORD,
);
Expand Down Expand Up @@ -83,11 +103,60 @@ function visitLinkedField(field: LinkedField): LinkedField {
);
if (deleteDirective != null) {
throw createUserError(
`Invalid use of @${deleteDirective.name} on scalar field '${transformedField.name}'`,
`Invalid use of @${deleteDirective.name} on scalar field '${transformedField.name}'.`,
[deleteDirective.loc],
);
}
return transformedField;
const edgeDirective = transformedField.directives.find(
directive => LINKED_FIELD_DIRECTIVES.indexOf(directive.name) > -1,
);
if (edgeDirective == null) {
return transformedField;
}
const connectionsArg = edgeDirective.args.find(
arg => arg.name === 'connections',
);
if (connectionsArg == null) {
throw createUserError(
`Expected the 'connections' argument to be defined on @${edgeDirective.name}.`,
[edgeDirective.loc],
);
}
const schema = this.getContext().getSchema();
const fields = schema.getFields(transformedField.type);
let cursorFieldID;
let nodeFieldID;
for (const fieldID of fields) {
const fieldName = schema.getFieldName(fieldID);
if (fieldName === ConnectionInterface.get().CURSOR) {
cursorFieldID = fieldID;
} else if (fieldName === ConnectionInterface.get().NODE) {
nodeFieldID = fieldID;
}
}
// Edge
if (cursorFieldID != null && nodeFieldID != null) {
const handle: Handle = {
name: edgeDirective.name,
key: '',
dynamicKey: null,
filters: null,
handleArgs: [connectionsArg],
};
return {
...transformedField,
directives: transformedField.directives.filter(
directive => directive !== edgeDirective,
),
handles: transformedField.handles
? [...transformedField.handles, handle]
: [handle],
};
}
throw createUserError(
`Unsupported use of @${edgeDirective.name} on field '${transformedField.name}', expected an edge field (a field with 'cursor' and 'node' selection).`,
[edgeDirective.loc],
);
}

module.exports = {
Expand Down
Loading

0 comments on commit 2719324

Please sign in to comment.