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

Fix for #218 #485

Merged
merged 2 commits into from
Jul 27, 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
33 changes: 25 additions & 8 deletions src/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,9 @@ export const relationTypeFieldOnNodeType = ({
}) => {
let translation = '';
if (innerSchemaTypeRelation.from === innerSchemaTypeRelation.to) {
translation = `${initial}${fieldName}: {${subSelection[0]}}${skipLimit} ${commaIfTail}`;
translation = `${initial}${fieldName}: {${
subSelection[0]
}}${skipLimit} ${commaIfTail}`;
} else {
const relationshipVariableName = `${nestedVariable}_relation`;

Expand Down Expand Up @@ -481,22 +483,25 @@ export const nodeTypeFieldOnRelationType = ({
fieldArgs,
cypherParams
}) => {
const safeVariableName = safeVar(variableName);
if (
isRootSelection({
selectionInfo: parentSelectionInfo,
rootType: 'relationship'
}) &&
isRelationTypeDirectedField(fieldName)
) {
const nodeFieldVariableName = decideRootRelationshipTypeNodeVariable({
parentSelectionInfo,
fieldName
});
const [mapProjection, labelPredicate] = buildMapProjection({
schemaType: innerSchemaType,
isObjectType: isObjectTypeField,
isInterfaceType: isInterfaceTypeField,
isUnionType: isUnionTypeField,
usesFragments,
safeVariableName,
safeVariableName: nodeFieldVariableName,
subQuery: subSelection[0],
usesFragments,
schemaTypeFields,
derivedTypeMap,
resolveInfo
Expand Down Expand Up @@ -544,6 +549,19 @@ export const nodeTypeFieldOnRelationType = ({
});
};

const decideRootRelationshipTypeNodeVariable = ({
parentSelectionInfo = {},
fieldName
}) => {
const fromVariable = parentSelectionInfo.from;
const toVariable = parentSelectionInfo.to;
// assume incoming
let variableName = safeVar(fromVariable);
// else set as outgoing
if (fieldName === 'to') variableName = safeVar(toVariable);
return variableName;
};

const relationTypeMutationPayloadField = ({
initial,
fieldName,
Expand Down Expand Up @@ -871,7 +889,9 @@ export const neo4jType = ({
return {
initial: `${initial}${fieldName}: ${
fieldIsArray
? `reduce(a = [], INSTANCE IN ${variableName}.${fieldName} | a + {${subSelection[0]}})${commaIfTail}`
? `reduce(a = [], INSTANCE IN ${variableName}.${fieldName} | a + {${
subSelection[0]
}})${commaIfTail}`
: usesTemporalOrdering
? `${safeVariableName}.${fieldName}${commaIfTail}`
: `{${subSelection[0]}}${commaIfTail}`
Expand Down Expand Up @@ -1816,7 +1836,6 @@ const relationshipCreate = ({
to: toVar,
variableName: lowercased
},
variableName: schemaType.name === fromType ? `${toVar}` : `${fromVar}`,
cypherParams: getCypherParams(context)
});
params = { ...preparedParams, ...subParams };
Expand Down Expand Up @@ -1942,7 +1961,6 @@ const relationshipDelete = ({
from: `_${fromVar}`,
to: `_${toVar}`
},
variableName: schemaType.name === fromType ? `_${toVar}` : `_${fromVar}`,
cypherParams: getCypherParams(context)
});
params = { ...params, ...subParams };
Expand Down Expand Up @@ -2068,7 +2086,6 @@ const relationshipMergeOrUpdate = ({
to: toVar,
variableName: lowercased
},
variableName: schemaType.name === fromType ? `${toVar}` : `${fromVar}`,
cypherParams: getCypherParams(context)
});
let cypherOperation = '';
Expand Down
125 changes: 125 additions & 0 deletions test/unit/cypherTest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,39 @@ test('Add relationship mutation', t => {
);
});

test('Add relationship mutation and query only outgoing nodes', t => {
const graphQLQuery = `mutation someMutation {
AddMovieGenres(
from: { movieId: "123" },
to: { name: "Action" }
) {
to {
name
}
}
}`,
expectedCypherQuery = `
MATCH (\`movie_from\`:\`Movie\`${ADDITIONAL_MOVIE_LABELS} {movieId: $from.movieId})
MATCH (\`genre_to\`:\`Genre\` {name: $to.name})
CREATE (\`movie_from\`)-[\`in_genre_relation\`:\`IN_GENRE\`]->(\`genre_to\`)
RETURN \`in_genre_relation\` { to: \`genre_to\` { .name } } AS \`_AddMovieGenresPayload\`;
`;

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

test('Merge relationship mutation', t => {
const graphQLQuery = `mutation someMutation {
MergeMovieGenres(
Expand Down Expand Up @@ -1053,6 +1086,63 @@ test('Update relationship mutation with relationship property', t => {
);
});

test('Update relationship mutation with relationship property and query only outgoing nodes', t => {
const graphQLQuery = `mutation someMutation {
UpdateUserRated(
from: { userId: "123" }
to: { movieId: "2kljghd" }
data: {
rating: 1
location: { longitude: 3.0, latitude: 4.5, height: 12.5 }
}
) {
to {
_id
movieId
title
ratings {
rating
User {
_id
userId
name
}
}
}
rating
}
}
`,
expectedCypherQuery = `
MATCH (\`user_from\`:\`User\` {userId: $from.userId})
MATCH (\`movie_to\`:\`Movie\`${ADDITIONAL_MOVIE_LABELS} {movieId: $to.movieId})
MATCH (\`user_from\`)-[\`rated_relation\`:\`RATED\`]->(\`movie_to\`)
SET \`rated_relation\` += {rating:$data.rating,location: point($data.location)}
RETURN \`rated_relation\` { to: \`movie_to\` {_id: ID(\`movie_to\`), .movieId , .title ,ratings: [(\`movie_to\`)<-[\`movie_to_ratings_relation\`:\`RATED\`]-(:\`User\`) | movie_to_ratings_relation { .rating ,User: head([(:\`Movie\`${ADDITIONAL_MOVIE_LABELS})<-[\`movie_to_ratings_relation\`]-(\`movie_to_ratings_User\`:\`User\`) | movie_to_ratings_User {_id: ID(\`movie_to_ratings_User\`), .userId , .name }]) }] } , .rating } AS \`_UpdateUserRatedPayload\`;
`;

t.plan(1);
return augmentedSchemaCypherTestRunner(
t,
graphQLQuery,
{
from: { userId: '123' },
to: { movieId: '2kljghd' },
data: {
rating: 1,
location: {
longitude: 3.0,
latitude: 4.5,
height: 12.5
}
},
first: -1,
offset: 0
},
expectedCypherQuery
);
});

test('Add reflexive relationship mutation with relationship property', t => {
const graphQLQuery = `mutation {
AddUserFriends(
Expand Down Expand Up @@ -1755,6 +1845,41 @@ test('Remove relationship mutation', t => {
);
});

test('Remove relationship mutation and query only outgoing nodes', t => {
const graphQLQuery = `mutation someMutation {
RemoveMovieGenres(
from: { movieId: "123" },
to: { name: "Action" }
) {
to {
_id
name
}
}
}`,
expectedCypherQuery = `
MATCH (\`movie_from\`:\`Movie\`${ADDITIONAL_MOVIE_LABELS} {movieId: $from.movieId})
MATCH (\`genre_to\`:\`Genre\` {name: $to.name})
OPTIONAL MATCH (\`movie_from\`)-[\`movie_fromgenre_to\`:\`IN_GENRE\`]->(\`genre_to\`)
DELETE \`movie_fromgenre_to\`
WITH COUNT(*) AS scope, \`movie_from\` AS \`_movie_from\`, \`genre_to\` AS \`_genre_to\`
RETURN {to: \`_genre_to\` {_id: ID(\`_genre_to\`), .name } } AS \`_RemoveMovieGenresPayload\`;
`;

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

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