Skip to content

Commit

Permalink
add dynamic label fix for union/interface type (#4212)
Browse files Browse the repository at this point in the history
  • Loading branch information
MacondoExpress authored Oct 27, 2023
1 parent 04c1c34 commit 96e139e
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class AggregationOperation extends Operation {
): Cypher.Clause[] {
if (!context.target) throw new Error("No parent node found!");
const relVar = createRelationshipFromEntity(entity);
const targetNode = createNodeFromEntity(entity.target as ConcreteEntityAdapter, context.neo4jGraphQLContext);
const targetNode = createNodeFromEntity(entity.target, context.neo4jGraphQLContext);
const relDirection = entity.getCypherDirection(this.directed);

const pattern = new Cypher.Pattern(context.target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class ReadOperation extends Operation {
//TODO: dupe from transpile
if (!hasTarget(context)) throw new Error("No parent node found!");
const relVar = createRelationshipFromEntity(entity);
const targetNode = createNodeFromEntity(entity.target as ConcreteEntityAdapter, context.neo4jGraphQLContext);
const targetNode = createNodeFromEntity(entity.target, context.neo4jGraphQLContext);
const relDirection = entity.getCypherDirection(this.directed);

const pattern = new Cypher.Pattern(context.target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class CompositeReadPartial extends ReadOperation {
if (!hasTarget(context)) throw new Error("No parent node found!");
const parentNode = context.target;
const relVar = createRelationshipFromEntity(entity);
const targetNode = createNodeFromEntity(this.target);
const targetNode = createNodeFromEntity(this.target, context.neo4jGraphQLContext);
const relDirection = entity.getCypherDirection(this.directed);

const pattern = new Cypher.Pattern(parentNode)
Expand Down Expand Up @@ -83,7 +83,7 @@ export class CompositeReadPartial extends ReadOperation {

// dupe from transpileNestedCompositeRelationship
private transpileTopLevelCompositeEntity({ context }: OperationTranspileOptions): OperationTranspileResult {
const targetNode = createNodeFromEntity(this.target);
const targetNode = createNodeFromEntity(this.target, context.neo4jGraphQLContext);
const nestedContext = new QueryASTContext({
target: targetNode,
env: context.env,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ describe("context-variable-not-always-resolved-on-cypher-queries", () => {
@limit(default: 100, max: 300) {
iri: ID! @id @alias(property: "uri")
realizationOf: Work @relationship(type: "realizationOf", direction: OUT)
relToUnion: [unionTarget!]! @relationship(type: "relToUnion", direction: OUT)
relToInterface: [interfaceTarget!]! @relationship(type: "relToInterface", direction: OUT)
}
type Work
@node(labels: ["WorkLabel", "$context.tenant", "Resource"])
Expand All @@ -42,6 +44,22 @@ describe("context-variable-not-always-resolved-on-cypher-queries", () => {
type ResourceType @mutation(operations: []) @limit(default: 1, max: 1000) {
iri: ID! @id @alias(property: "uri")
}
type coreFrag implements interfaceTarget
@node(labels: ["coreFrag", "$context.tenant", "Resource"])
@mutation(operations: [])
@limit(default: 100, max: 1000) {
iri: ID! @id @alias(property: "uri")
}
type coreRoot @node(labels: ["coreRoot", "Resource"]) @mutation(operations: []) @limit(default: 100, max: 300) {
iri: ID! @id @alias(property: "uri")
}
union unionTarget = coreRoot | coreFrag
interface interfaceTarget {
iri: ID!
}
`;

beforeAll(() => {
Expand Down Expand Up @@ -92,4 +110,127 @@ describe("context-variable-not-always-resolved-on-cypher-queries", () => {
}"
`);
});

test("should apply dynamic label with filter when queried an union", async () => {
const query = gql`
query {
exprs(
where: { realizationOf: { hasResourceType: { iri: "http://data.somesite.com/crown/test-id" } } }
options: { limit: 1 }
) {
iri
relToUnion {
... on coreFrag {
iri
}
}
}
}
`;

const result = await translateQuery(neoSchema, query, {
contextValues: {
cypherParams: {
tenant: "test",
},
},
});

expect(formatCypher(result.cypher)).toMatchInlineSnapshot(`
"MATCH (this:Exprlabel:test:Resource)
WHERE single(this0 IN [(this)-[:realizationOf]->(this0:WorkLabel:test:Resource) WHERE EXISTS {
MATCH (this0)-[:hasResourceType]->(this1:ResourceType)
WHERE this1.uri = $param0
} | 1] WHERE true)
WITH *
LIMIT $param1
CALL {
WITH this
CALL {
WITH *
MATCH (this)-[this2:relToUnion]->(this3:coreRoot:Resource)
WITH this3 { __resolveType: \\"coreRoot\\", __id: id(this3) } AS this3
RETURN this3 AS var4
UNION
WITH *
MATCH (this)-[this5:relToUnion]->(this6:coreFrag:test:Resource)
WITH this6 { iri: this6.uri, __resolveType: \\"coreFrag\\", __id: id(this6) } AS this6
RETURN this6 AS var4
}
WITH var4
RETURN collect(var4) AS var4
}
RETURN this { iri: this.uri, relToUnion: var4 } AS this"
`);

expect(formatParams(result.params)).toMatchInlineSnapshot(`
"{
\\"param0\\": \\"http://data.somesite.com/crown/test-id\\",
\\"param1\\": {
\\"low\\": 1,
\\"high\\": 0
},
\\"tenant\\": \\"test\\"
}"
`);
});

test("should apply dynamic label with filter when queried an interface", async () => {
const query = gql`
query {
exprs(
where: { realizationOf: { hasResourceType: { iri: "http://data.somesite.com/crown/test-id" } } }
options: { limit: 1 }
) {
iri
relToInterface {
... on coreFrag {
iri
}
}
}
}
`;

const result = await translateQuery(neoSchema, query, {
contextValues: {
cypherParams: {
tenant: "test",
},
},
});

expect(formatCypher(result.cypher)).toMatchInlineSnapshot(`
"MATCH (this:Exprlabel:test:Resource)
WHERE single(this0 IN [(this)-[:realizationOf]->(this0:WorkLabel:test:Resource) WHERE EXISTS {
MATCH (this0)-[:hasResourceType]->(this1:ResourceType)
WHERE this1.uri = $param0
} | 1] WHERE true)
WITH *
LIMIT $param1
CALL {
WITH this
CALL {
WITH *
MATCH (this)-[this2:relToInterface]->(this3:coreFrag:test:Resource)
WITH this3 { iri: this3.uri, __resolveType: \\"coreFrag\\", __id: id(this3) } AS this3
RETURN this3 AS var4
}
WITH var4
RETURN collect(var4) AS var4
}
RETURN this { iri: this.uri, relToInterface: var4 } AS this"
`);

expect(formatParams(result.params)).toMatchInlineSnapshot(`
"{
\\"param0\\": \\"http://data.somesite.com/crown/test-id\\",
\\"param1\\": {
\\"low\\": 1,
\\"high\\": 0
},
\\"tenant\\": \\"test\\"
}"
`);
});
});

0 comments on commit 96e139e

Please sign in to comment.