Skip to content
This repository was archived by the owner on Sep 3, 2021. It is now read-only.

Interfaced relations fix #374

Merged
merged 2 commits into from
Jan 9, 2020
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
2 changes: 1 addition & 1 deletion example/apollo-server/movies.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { augmentTypeDefs, augmentSchema } from '../../src/index';
import { ApolloServer, gql, makeExecutableSchema } from 'apollo-server';
import { v1 as neo4j } from 'neo4j-driver';
import neo4j from 'neo4j-driver';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this should be in this pull request, but the example server didn't work for on the master branch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a result of upgrading the version of neo4j-driver, which removes the v1 namespace. I was lazy and only updated movies-middleware.js which is why this one was failing. My fault.

import { typeDefs, resolvers } from './movies-schema';

const schema = makeExecutableSchema({
Expand Down
22 changes: 18 additions & 4 deletions src/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,11 @@ export const nodeTypeFieldOnRelationType = ({
return {
selection: relationTypeMutationPayloadField({
...fieldInfo,
parentSelectionInfo
schemaType,
isInlineFragment,
parentSelectionInfo,
innerSchemaType,
resolveInfo
}),
subSelection: fieldInfo.subSelection
};
Expand All @@ -405,17 +409,27 @@ const relationTypeMutationPayloadField = ({
initial,
fieldName,
variableName,
nestedVariable,
subSelection,
skipLimit,
commaIfTail,
tailParams,
parentSelectionInfo
parentSelectionInfo,
isInlineFragment,
resolveInfo,
innerSchemaType
}) => {
const safeVariableName = safeVar(variableName);
const fragmentTypeParams = isInlineFragment
? derivedTypesParams(resolveInfo.schema, innerSchemaType.name)
: {};
subSelection[1] = { ...subSelection[1], ...fragmentTypeParams };
return {
initial: `${initial}${fieldName}: ${safeVariableName} {${
subSelection[0]
}}${skipLimit} ${commaIfTail}`,
isInlineFragment
? `${fragmentType(nestedVariable, innerSchemaType.name)},`
: ''
}${subSelection[0]}}${skipLimit} ${commaIfTail}`,
...tailParams,
variableName:
fieldName === 'from' ? parentSelectionInfo.to : parentSelectionInfo.from
Expand Down
3 changes: 3 additions & 0 deletions test/helpers/cypherTestHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ export function augmentedSchemaCypherTestRunner(
MergeUserFriends: checkCypherMutation,
UpdateUserFriends: checkCypherMutation,
RemoveUserFriends: checkCypherMutation,
AddActorKnows: checkCypherMutation,
MergeActorKnows: checkCypherMutation,
RemoveActorKnows: checkCypherMutation,
currentUserId: checkCypherMutation,
computedObjectWithCypherParams: checkCypherMutation,
computedStringList: checkCypherMutation,
Expand Down
1 change: 1 addition & 0 deletions test/helpers/testSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const testSchema = /* GraphQL */ `
userId: ID!
name: String
movies: [Movie] @relation(name: "ACTED_IN", direction: "OUT")
knows: [Person] @relation(name: "KNOWS", direction: "OUT")
}

type User implements Person {
Expand Down
50 changes: 50 additions & 0 deletions test/unit/augmentSchemaTest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,14 @@ test.cb('Test augmented schema', t => {
movies_none: _MovieFilter
movies_single: _MovieFilter
movies_every: _MovieFilter
knows: _PersonFilter
knows_not: _PersonFilter
knows_in: [_PersonFilter!]
knows_not_in: [_PersonFilter!]
knows_some: _PersonFilter
knows_none: _PersonFilter
knows_single: _PersonFilter
knows_every: _PersonFilter
}

input _StateFilter {
Expand Down Expand Up @@ -866,6 +874,12 @@ test.cb('Test augmented schema', t => {
orderBy: [_MovieOrdering]
filter: _MovieFilter
): [Movie] @relation(name: "ACTED_IN", direction: "OUT")
knows(
first: Int
offset: Int
orderBy: [_PersonOrdering]
filter: _PersonFilter
): [Person] @relation(name: "KNOWS", direction: "OUT")
_id: String
}

Expand Down Expand Up @@ -1503,6 +1517,24 @@ test.cb('Test augmented schema', t => {
): _MergeActorMoviesPayload
@MutationMeta(relationship: "ACTED_IN", from: "Actor", to: "Movie")
@hasScope(scopes: ["Actor: Merge", "Movie: Merge"])
AddActorKnows(
from: _ActorInput!
to: _PersonInput!
): _AddActorKnowsPayload
@MutationMeta(relationship: "KNOWS", from: "Actor", to: "Person")
@hasScope(scopes: ["Actor: Create", "Person: Create"])
RemoveActorKnows(
from: _ActorInput!
to: _PersonInput!
): _RemoveActorKnowsPayload
@MutationMeta(relationship: "KNOWS", from: "Actor", to: "Person")
@hasScope(scopes: ["Actor: Delete", "Person: Delete"])
MergeActorKnows(
from: _ActorInput!
to: _PersonInput!
): _MergeActorKnowsPayload
@MutationMeta(relationship: "KNOWS", from: "Actor", to: "Person")
@hasScope(scopes: ["Actor: Merge", "Person: Merge"])
CreateActor(userId: ID, name: String): Actor
@hasScope(scopes: ["Actor: Create"])
UpdateActor(userId: ID!, name: String): Actor
Expand Down Expand Up @@ -1901,6 +1933,24 @@ test.cb('Test augmented schema', t => {
to: Movie
}

type _AddActorKnowsPayload
@relation(name: "KNOWS", from: "Actor", to: "Person") {
from: Actor
to: Person
}

type _MergeActorKnowsPayload
@relation(name: "KNOWS", from: "Actor", to: "Person") {
from: Actor
to: Person
}

type _RemoveActorKnowsPayload
@relation(name: "KNOWS", from: "Actor", to: "Person") {
from: Actor
to: Person
}

type _AddUserRatedPayload
@relation(name: "RATED", from: "User", to: "Movie") {
from: User
Expand Down
116 changes: 116 additions & 0 deletions test/unit/cypherTest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,122 @@ test('Update reflexive relationship mutation with relationship property', t => {
);
});

test('Add interfaced relationship mutation', t => {
const graphQLQuery = `mutation someMutation {
AddActorKnows(
from: { userId: "123" },
to: { userId: "456" }
) {
from {
userId
name
}
to {
userId
name
}
}
}`,
expectedCypherQuery = `
MATCH (\`actor_from\`:\`Actor\` {userId: $from.userId})
MATCH (\`person_to\`:\`Person\` {userId: $to.userId})
CREATE (\`actor_from\`)-[\`knows_relation\`:\`KNOWS\`]->(\`person_to\`)
RETURN \`knows_relation\` { from: \`actor_from\` { .userId , .name } ,to: \`person_to\` {FRAGMENT_TYPE: head( [ label IN labels(person_to) WHERE label IN $Person_derivedTypes ] ), .userId , .name } } AS \`_AddActorKnowsPayload\`;
`;

t.plan(1);
return augmentedSchemaCypherTestRunner(
t,
graphQLQuery,
{
from: { userId: '123' },
to: { userId: '456' },
first: -1,
offset: 0
},
expectedCypherQuery,
{}
);
});

test('Merge interfaced relationship mutation', t => {
const graphQLQuery = `mutation someMutation {
MergeActorKnows(
from: { userId: "123" },
to: { userId: "456" }
) {
from {
userId
name
}
to {
userId
name
}
}
}`,
expectedCypherQuery = `
MATCH (\`actor_from\`:\`Actor\` {userId: $from.userId})
MATCH (\`person_to\`:\`Person\` {userId: $to.userId})
MERGE (\`actor_from\`)-[\`knows_relation\`:\`KNOWS\`]->(\`person_to\`)
RETURN \`knows_relation\` { from: \`actor_from\` { .userId , .name } ,to: \`person_to\` {FRAGMENT_TYPE: head( [ label IN labels(person_to) WHERE label IN $Person_derivedTypes ] ), .userId , .name } } AS \`_MergeActorKnowsPayload\`;
`;

t.plan(1);
return augmentedSchemaCypherTestRunner(
t,
graphQLQuery,
{
from: { userId: '123' },
to: { userId: '456' },
first: -1,
offset: 0
},
expectedCypherQuery,
{}
);
});

test('Remove interfaced relationship mutation', t => {
const graphQLQuery = `mutation someMutation {
RemoveActorKnows(
from: { userId: "123" },
to: { userId: "456" }
) {
from {
userId
name
}
to {
userId
name
}
}
}`,
expectedCypherQuery = `
MATCH (\`actor_from\`:\`Actor\` {userId: $from.userId})
MATCH (\`person_to\`:\`Person\` {userId: $to.userId})
OPTIONAL MATCH (\`actor_from\`)-[\`actor_fromperson_to\`:\`KNOWS\`]->(\`person_to\`)
DELETE \`actor_fromperson_to\`
WITH COUNT(*) AS scope, \`actor_from\` AS \`_actor_from\`, \`person_to\` AS \`_person_to\`
RETURN {from: \`_actor_from\` { .userId , .name } ,to: \`_person_to\` {FRAGMENT_TYPE: head( [ label IN labels(_person_to) WHERE label IN $Person_derivedTypes ] ), .userId , .name } } AS \`_RemoveActorKnowsPayload\`;
`;

t.plan(1);
return augmentedSchemaCypherTestRunner(
t,
graphQLQuery,
{
from: { userId: '123' },
to: { userId: '456' },
first: -1,
offset: 0
},
expectedCypherQuery,
{}
);
});

test('Remove relationship mutation', t => {
const graphQLQuery = `mutation someMutation {
RemoveMovieGenres(
Expand Down