Skip to content

Commit

Permalink
Merge pull request #5952 from neo4j/addCypherVersion
Browse files Browse the repository at this point in the history
add new flag: addCypherVersion
  • Loading branch information
angrykoala authored Jan 28, 2025
2 parents 4fe3ccd + c1f163b commit 5d9d9d5
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 18 deletions.
22 changes: 22 additions & 0 deletions .changeset/soft-socks-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"@neo4j/graphql": patch
---

Add `version` to `cypherQueryOptions` in context to add a Cypher version with `CYPHER` before each query:

```js
{
cypherQueryOptions: {
addVersionPrefix: true,
},
}
```

This prepends all Cypher queries with a `CYPHER [version]` statement:

```cypher
CYPHER 5
MATCH (this:Movie)
WHERE this.title = $param0
RETURN this { .title } AS this
```
2 changes: 1 addition & 1 deletion packages/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"@graphql-tools/resolvers-composition": "^7.0.0",
"@graphql-tools/schema": "^10.0.0",
"@graphql-tools/utils": "10.6.1",
"@neo4j/cypher-builder": "2.2.1",
"@neo4j/cypher-builder": "2.3.0",
"camelcase": "^6.3.0",
"debug": "^4.3.4",
"dot-prop": "^6.0.1",
Expand Down
38 changes: 29 additions & 9 deletions packages/graphql/src/classes/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
} from "../constants";
import { debugCypherAndParams } from "../debug/debug-cypher-and-params";
import type { CypherQueryOptions } from "../types";
import { isInArray } from "../utils/is-in-array";
import {
Neo4jGraphQLAuthenticationError,
Neo4jGraphQLConstraintValidationError,
Expand All @@ -49,6 +50,8 @@ import {

const debug = Debug(DEBUG_EXECUTE);

const SUPPORTED_CYPHER_VERSION = "5";

interface DriverLike {
session(config);
}
Expand Down Expand Up @@ -107,7 +110,6 @@ export class Executor {
}: ExecutorConstructorParam) {
this.executionContext = executionContext;
this.cypherQueryOptions = cypherQueryOptions;
this.cypherQueryOptions = cypherQueryOptions;
this.sessionConfig = sessionConfig;
this.cypherParams = cypherParams;
this.transactionMetadata = transactionMetadata;
Expand Down Expand Up @@ -173,16 +175,34 @@ export class Executor {
return error;
}

private generateQuery(query: string): string {
if (this.cypherQueryOptions && Object.keys(this.cypherQueryOptions).length) {
const cypherQueryOptions = `CYPHER ${Object.entries(this.cypherQueryOptions)
.map(([key, value]) => `${key}=${value}`)
.join(" ")}`;
private addCypherOptionsToQuery(query: string): string {
const cypherVersion = this.getCypherVersionStatement();

const cypherQueryOptions = this.getCypherQueryOptionsStatement();

return `${cypherVersion}${cypherQueryOptions}${query}`;
}

return `${cypherQueryOptions}\n${query}`;
private getCypherVersionStatement(): string {
if (this.cypherQueryOptions?.addVersionPrefix) {
return `CYPHER ${SUPPORTED_CYPHER_VERSION}\n`;
}
return "";
}

return query;
private getCypherQueryOptionsStatement(): string {
const ignoredCypherQueryOptions: Array<keyof CypherQueryOptions> = ["addVersionPrefix"];
const cypherQueryOptions = Object.entries(this.cypherQueryOptions ?? []).filter(([key, _value]) => {
return !isInArray(ignoredCypherQueryOptions, key);
});
if (cypherQueryOptions.length) {
return `CYPHER ${cypherQueryOptions
.map(([key, value]) => {
return `${key}=${value}`;
})
.join(" ")}\n`;
}
return "";
}

private getTransactionConfig(info?: GraphQLResolveInfo): TransactionConfig {
Expand Down Expand Up @@ -276,7 +296,7 @@ export class Executor {
parameters: Record<string, any>,
transaction: Transaction | ManagedTransaction
): Result {
const queryToRun = this.generateQuery(query);
const queryToRun = this.addCypherOptionsToQuery(query);

debugCypherAndParams(debug, queryToRun, parameters);

Expand Down
6 changes: 3 additions & 3 deletions packages/graphql/src/translate/translate-resolve-reference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
*/

import type Cypher from "@neo4j/cypher-builder";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import Debug from "debug";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import { DEBUG_TRANSLATE } from "../constants";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

const debug = Debug(DEBUG_TRANSLATE);

Expand Down
1 change: 1 addition & 0 deletions packages/graphql/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ export interface CypherQueryOptions {
operatorEngine?: "default" | "interpreted" | "compiled";
interpretedPipesFallback?: "default" | "disabled" | "whitelisted_plans_only" | "all";
replan?: "default" | "force" | "skip";
addVersionPrefix?: boolean;
}

/** Input field for graphql-compose */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,36 @@ describe("query options", () => {

expect(result?.data?.[Movie.plural]).toEqual([{ id }, { id }, { id }]);
});

test("queries should work with version set to Cypher version", async () => {
const id = generate({
charset: "alphabetic",
});

const query = `
query($id: ID){
${Movie.plural}(where: {id_EQ: $id}){
id
}
}
`;

await neoSchema.checkNeo4jCompat();

await testHelper.executeCypher(
`
CREATE (:${Movie} {id: $id}), (:${Movie} {id: $id}), (:${Movie} {id: $id})
`,
{ id }
);

const result = await testHelper.executeGraphQL(query, {
variableValues: { id },
contextValue: { cypherQueryOptions: { runtime: "interpreted", addVersionPrefix: true } },
});

expect(result.errors).toBeFalsy();

expect(result?.data?.[Movie.plural]).toEqual([{ id }, { id }, { id }]);
});
});
10 changes: 5 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2082,10 +2082,10 @@ __metadata:
languageName: node
linkType: hard

"@neo4j/cypher-builder@npm:2.2.1":
version: 2.2.1
resolution: "@neo4j/cypher-builder@npm:2.2.1"
checksum: 10c0/5d3af9a6b9bc7db5dc36ca7cfe6e0ec2d104a65538afca20aa47245cfb87681275e26d99e802f9ac80f2597b3535133c3be97cd3b5db35ba1495e6ef4f230dfb
"@neo4j/cypher-builder@npm:2.3.0":
version: 2.3.0
resolution: "@neo4j/cypher-builder@npm:2.3.0"
checksum: 10c0/bd7d98b8c3a84e9562ff88b9f2ad10a9258aabc2204dba247d4aa83944bce6f5100a3e14199a688dea62de2313910b90e03da7a9b1a423d0a279b022e5909fc3
languageName: node
linkType: hard

Expand All @@ -2106,7 +2106,7 @@ __metadata:
"@graphql-tools/resolvers-composition": "npm:^7.0.0"
"@graphql-tools/schema": "npm:^10.0.0"
"@graphql-tools/utils": "npm:10.6.1"
"@neo4j/cypher-builder": "npm:2.2.1"
"@neo4j/cypher-builder": "npm:2.3.0"
"@types/deep-equal": "npm:1.0.4"
"@types/is-uuid": "npm:1.0.2"
"@types/jest": "npm:29.5.14"
Expand Down

0 comments on commit 5d9d9d5

Please sign in to comment.