Skip to content

Commit

Permalink
Move version to cypherQueryOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
angrykoala committed Jan 27, 2025
1 parent 04ed78a commit d8eaecb
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 247 deletions.
11 changes: 5 additions & 6 deletions .changeset/soft-socks-count.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
"@neo4j/graphql": patch
---

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

```js
neoSchema = new Neo4jGraphQL({
typeDefs,
features: {
addCypherVersion: true,
{
cypherQueryOptions: {
version: "5",
},
});
}
```

This prepends all Cypher queries with a `CYPHER [version]` statement:
Expand Down
27 changes: 21 additions & 6 deletions packages/graphql/src/classes/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,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 @@ -174,12 +173,28 @@ export class Executor {
}

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(" ")}`;
if (this.cypherQueryOptions) {
let cypherVersion = "";
// Cypher version should be rendered as a separate statement
if (this.cypherQueryOptions.version) {
cypherVersion = `CYPHER ${this.cypherQueryOptions.version}\n`;
}

let cypherQueryOptions = "";
const cypherQueryOptionsToAddToStatement = Object.entries(this.cypherQueryOptions).filter(
([key, _value]) => {
return key !== "version";
}
);
if (cypherQueryOptionsToAddToStatement.length) {
cypherQueryOptions = `CYPHER ${cypherQueryOptionsToAddToStatement
.map(([key, value]) => {
return `${key}=${value}`;
})
.join(" ")}\n`;
}

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

return query;
Expand Down
5 changes: 1 addition & 4 deletions packages/graphql/src/translate/translate-aggregate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Debug from "debug";
import { DEBUG_TRANSLATE } from "../constants";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { getCypherVersion } from "../utils/get-cypher-version";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

const debug = Debug(DEBUG_TRANSLATE);
Expand All @@ -44,7 +43,5 @@ export function translateAggregate({
const queryAST = queryASTFactory.createQueryAST({ resolveTree, entityAdapter, context });
debug(queryAST.print());
const clause = queryAST.buildNew(context);
return clause.build({
cypherVersion: getCypherVersion(context),
});
return clause.build();
}
3 changes: 1 addition & 2 deletions packages/graphql/src/translate/translate-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { CallbackBucket } from "../classes/CallbackBucket";
import { DEBUG_TRANSLATE } from "../constants";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { compileCypherIfExists } from "../utils/compile-cypher";
import { getCypherVersion } from "../utils/get-cypher-version";
import { asArray, filterTruthy } from "../utils/utils";
import createCreateAndParams from "./create-create-and-params";
import { QueryASTContext, QueryASTEnv } from "./queryAST/ast/QueryASTContext";
Expand Down Expand Up @@ -153,7 +152,7 @@ export default async function translateCreate({
];
});

const createQueryCypher = createQuery.build({ prefix: "create_", cypherVersion: getCypherVersion(context) });
const createQueryCypher = createQuery.build({ prefix: "create_" });
const { cypher, params: resolvedCallbacks } = await callbackBucket.resolveCallbacksAndFilterCypher({
cypher: createQueryCypher.cypher,
});
Expand Down
5 changes: 1 addition & 4 deletions packages/graphql/src/translate/translate-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-tran
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

import type { ResolveTree } from "graphql-parse-resolve-info";
import { getCypherVersion } from "../utils/get-cypher-version";

const debug = Debug(DEBUG_TRANSLATE);

Expand Down Expand Up @@ -53,9 +52,7 @@ function translateUsingQueryAST({
});
debug(operationsTree.print());
const clause = operationsTree.build(context, varName);
return clause.build({
cypherVersion: getCypherVersion(context),
});
return clause.build();
}
export function translateDelete({
context,
Expand Down
5 changes: 1 addition & 4 deletions packages/graphql/src/translate/translate-read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Debug from "debug";
import { DEBUG_TRANSLATE } from "../constants";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { getCypherVersion } from "../utils/get-cypher-version";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

const debug = Debug(DEBUG_TRANSLATE);
Expand All @@ -46,7 +45,5 @@ export function translateRead({
});
debug(operationsTree.print());
const clause = operationsTree.build(context, varName);
return clause.build({
cypherVersion: getCypherVersion(context),
});
return clause.build();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import Debug from "debug";
import { DEBUG_TRANSLATE } from "../constants";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { getCypherVersion } from "../utils/get-cypher-version";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

const debug = Debug(DEBUG_TRANSLATE);
Expand All @@ -47,7 +46,5 @@ export function translateResolveReference({
});
debug(operationsTree.print());
const clause = operationsTree.build(context, "this");
return clause.build({
cypherVersion: getCypherVersion(context),
});
return clause.build();
}
5 changes: 1 addition & 4 deletions packages/graphql/src/translate/translate-top-level-cypher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import type { AuthenticationOperation } from "../schema-model/annotation/Authent
import { getEntityAdapter } from "../schema-model/utils/get-entity-adapter";
import type { CypherField } from "../types";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { getCypherVersion } from "../utils/get-cypher-version";
import { applyAuthentication } from "./authorization/utils/apply-authentication";
import { QueryASTContext, QueryASTEnv } from "./queryAST/ast/QueryASTContext";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";
Expand Down Expand Up @@ -85,7 +84,5 @@ export function translateTopLevelCypher({
const projectionStatements = queryASTResult.clauses.length
? Cypher.utils.concat(...queryASTResult.clauses)
: new Cypher.Return(new Cypher.Literal("Query cannot conclude with CALL"));
return projectionStatements.build({
cypherVersion: getCypherVersion(context),
});
return projectionStatements.build();
}
3 changes: 1 addition & 2 deletions packages/graphql/src/translate/translate-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { DEBUG_TRANSLATE } from "../constants";
import type { GraphQLWhereArg, RelationField } from "../types";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { compileCypher } from "../utils/compile-cypher";
import { getCypherVersion } from "../utils/get-cypher-version";
import createConnectAndParams from "./create-connect-and-params";
import { createConnectOrCreateAndParams } from "./create-connect-or-create-and-params";
import createCreateAndParams from "./create-create-and-params";
Expand Down Expand Up @@ -486,7 +485,7 @@ export default async function translateUpdate({
];
});

const cypherResult = updateQuery.build({ prefix: "update_", cypherVersion: getCypherVersion(context) });
const cypherResult = updateQuery.build({ prefix: "update_" });
const { cypher, params: resolvedCallbacks } = await callbackBucket.resolveCallbacksAndFilterCypher({
cypher: cypherResult.cypher,
});
Expand Down
3 changes: 1 addition & 2 deletions packages/graphql/src/translate/unwind-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import Debug from "debug";
import { DEBUG_TRANSLATE } from "../constants";
import type { EntityAdapter } from "../schema-model/entity/EntityAdapter";
import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context";
import { getCypherVersion } from "../utils/get-cypher-version";
import { QueryASTFactory } from "./queryAST/factory/QueryASTFactory";

const debug = Debug(DEBUG_TRANSLATE);
Expand All @@ -45,5 +44,5 @@ export default function unwindCreate({

const clauses = queryAST.build(context);

return clauses.build({ prefix: "create_", cypherVersion: getCypherVersion(context) });
return clauses.build({ prefix: "create_" });
}
2 changes: 1 addition & 1 deletion 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";
version?: "5";
}

/** Input field for graphql-compose */
Expand Down Expand Up @@ -443,7 +444,6 @@ export type Neo4jFeaturesSettings = {
populatedBy?: Neo4jPopulatedBySettings;
authorization?: Neo4jAuthorizationSettings;
subscriptions?: boolean | Neo4jGraphQLSubscriptionsCDCEngine;
addCypherVersion?: boolean;
/** If set to `true`, removes `@neo4j/graphql` fields that are marked as deprecated to reduce schema size.
*
* NOTE: this will not remove user defined deprecated fields
Expand Down
25 changes: 0 additions & 25 deletions packages/graphql/src/utils/get-cypher-version.ts

This file was deleted.

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", version: "5" } },
});

expect(result.errors).toBeFalsy();

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

0 comments on commit d8eaecb

Please sign in to comment.