Skip to content

Commit

Permalink
Simpler configuration of Cypher query options (#3628)
Browse files Browse the repository at this point in the history
  • Loading branch information
darrellwarde authored Jul 11, 2023
1 parent 170a895 commit 2167c9a
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 104 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-ads-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neo4j/graphql": major
---

Specifying Cypher query options to be used is now `cypherQueryOptions` instead of just `queryOptions`, and each option accepts a simple string rather than an enum.
51 changes: 51 additions & 0 deletions docs/modules/ROOT/pages/migration/v4-migration/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -778,3 +778,54 @@ type Actor @query(aggregate: true) {
}
----

=== Cypher query options

If you had a need to pass in Cypher query options for query tuning, this interface has been changed.

The config option `queryOptions` has now become `cypherQueryOptions`, and it now accepts simple strings instead of enums.

The following is an example before the change:

[source, javascript, indent=0]
----
const { Neo4jGraphQL, CypherRuntime } = require("@neo4j/graphql");
const { ApolloServer } = require("apollo-server");
const typeDefs = `
type Movie {
title: String!
}
`;
const neoSchema = new Neo4jGraphQL({
typeDefs,
config: {
queryOptions: {
runtime: CypherRuntime.INTERPRETED,
},
},
});
----

This is what is required after the change:

[source, javascript, indent=0]
----
const { Neo4jGraphQL } = require("@neo4j/graphql");
const { ApolloServer } = require("apollo-server");
const typeDefs = `
type Movie {
title: String!
}
`;
const neoSchema = new Neo4jGraphQL({
typeDefs,
config: {
cypherQueryOptions: {
runtime: "interpreted",
},
},
});
----
47 changes: 44 additions & 3 deletions docs/modules/ROOT/pages/troubleshooting.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ For example, in order to set the Cypher runtime to "interpreted":

[source, javascript, indent=0]
----
const { Neo4jGraphQL, CypherRuntime } = require("@neo4j/graphql");
const { Neo4jGraphQL } = require("@neo4j/graphql");
const neo4j = require("neo4j-driver");
const { ApolloServer } = require("apollo-server");
Expand All @@ -65,8 +65,8 @@ const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
config: {
queryOptions: {
runtime: CypherRuntime.INTERPRETED,
cypherQueryOptions: {
runtime: "interpreted",
},
},
});
Expand All @@ -83,6 +83,47 @@ neoSchema.getSchema().then((schema) => {
});
----

These options can also be set in the context function, which will take precedence:

[source, javascript, indent=0]
----
const { Neo4jGraphQL } = require("@neo4j/graphql");
const neo4j = require("neo4j-driver");
const { ApolloServer } = require("apollo-server");
const typeDefs = `
type Movie {
title: String!
}
`;
const driver = neo4j.driver(
"bolt://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);
const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
});
neoSchema.getSchema().then((schema) => {
const server = new ApolloServer({
schema,
context: ({ req }) => ({
req,
cypherQueryOptions: {
runtime: "interpreted",
},
}),
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
});
----

[[troubleshooting-faqs]]
== FAQs

Expand Down
14 changes: 7 additions & 7 deletions packages/graphql/src/classes/Executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export type ExecutionContext = Driver | Session | Transaction;

export type ExecutorConstructorParam = {
executionContext: ExecutionContext;
queryOptions?: CypherQueryOptions;
cypherQueryOptions?: CypherQueryOptions;
database?: string;
bookmarks?: string | string[];
measureTime?: boolean;
Expand All @@ -94,15 +94,15 @@ export class Executor {

public lastBookmark: string | null;

private queryOptions: CypherQueryOptions | undefined;
private cypherQueryOptions: CypherQueryOptions | undefined;

private database: string | undefined;
private bookmarks: string | string[] | undefined;

constructor({ executionContext, queryOptions, database, bookmarks }: ExecutorConstructorParam) {
constructor({ executionContext, cypherQueryOptions, database, bookmarks }: ExecutorConstructorParam) {
this.executionContext = executionContext;
this.lastBookmark = null;
this.queryOptions = queryOptions;
this.cypherQueryOptions = cypherQueryOptions;
this.database = database;
this.bookmarks = bookmarks;
}
Expand Down Expand Up @@ -157,12 +157,12 @@ export class Executor {
}

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

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

return query;
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql/src/classes/Neo4jGraphQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export interface Neo4jGraphQLConfig {
driverConfig?: DriverConfig;
enableDebug?: boolean;
startupValidation?: StartupValidationConfig;
queryOptions?: CypherQueryOptions;
cypherQueryOptions?: CypherQueryOptions;
}

export type ValidationConfig = {
Expand Down
8 changes: 0 additions & 8 deletions packages/graphql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@ export {
export * as directives from "./graphql/directives";
export * as scalars from "./graphql/scalars";
export {
CypherConnectComponentsPlanner,
CypherExpressionEngine,
CypherInterpretedPipesFallback,
CypherOperatorEngine,
CypherPlanner,
CypherReplanning,
CypherRuntime,
CypherUpdateStrategy,
DeleteInfo,
DriverConfig,
EventMeta,
Expand Down
4 changes: 1 addition & 3 deletions packages/graphql/src/schema/resolvers/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ export const wrapResolver =
executionContext: context.executionContext,
};

if (config.queryOptions) {
executorConstructorParam.queryOptions = config.queryOptions;
}
executorConstructorParam.cypherQueryOptions = context.cypherQueryOptions || config.cypherQueryOptions;

if (context.driverConfig?.database) {
executorConstructorParam.database = context.driverConfig?.database;
Expand Down
63 changes: 8 additions & 55 deletions packages/graphql/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,65 +299,18 @@ export type TimeStampOperations = "CREATE" | "UPDATE";

export type CallbackOperations = "CREATE" | "UPDATE";

export enum CypherRuntime {
INTERPRETED = "interpreted",
SLOTTED = "slotted",
PIPELINED = "pipelined",
}

export enum CypherPlanner {
COST = "cost",
IDP = "idp",
DP = "dp",
}

export enum CypherConnectComponentsPlanner {
GREEDY = "greedy",
IDP = "idp",
}

export enum CypherUpdateStrategy {
DEFAULT = "default",
EAGER = "eager",
}

export enum CypherExpressionEngine {
DEFAULT = "default",
INTERPRETED = "interpreted",
COMPILED = "compiled",
}

export enum CypherOperatorEngine {
DEFAULT = "default",
INTERPRETED = "interpreted",
COMPILED = "compiled",
}

export enum CypherInterpretedPipesFallback {
DEFAULT = "default",
DISABLED = "disabled",
WHITELISTED_PLANS_ONLY = "whitelisted_plans_only",
ALL = "all",
}

export enum CypherReplanning {
DEFAULT = "default",
FORCE = "force",
SKIP = "skip",
}

/*
Object keys and enum values map to values at https://neo4j.com/docs/cypher-manual/current/query-tuning/query-options/#cypher-query-options
*/
export interface CypherQueryOptions {
runtime?: CypherRuntime;
planner?: CypherPlanner;
connectComponentsPlanner?: CypherConnectComponentsPlanner;
updateStrategy?: CypherUpdateStrategy;
expressionEngine?: CypherExpressionEngine;
operatorEngine?: CypherOperatorEngine;
interpretedPipesFallback?: CypherInterpretedPipesFallback;
replan?: CypherReplanning;
runtime?: "interpreted" | "slotted" | "pipelined";
planner?: "cost" | "idp" | "dp";
connectComponentsPlanner?: "greedy" | "idp";
updateStrategy?: "default" | "eager";
expressionEngine?: "default" | "interpreted" | "compiled";
operatorEngine?: "default" | "interpreted" | "compiled";
interpretedPipesFallback?: "default" | "disabled" | "whitelisted_plans_only" | "all";
replan?: "default" | "force" | "skip";
}

/** The startup validation checks to run */
Expand Down
10 changes: 5 additions & 5 deletions packages/graphql/src/types/neo4j-graphql-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ import type { CypherQueryOptions, DriverConfig, RequestLike } from ".";
import type { JWTPayload } from "jose";

export interface Neo4jGraphQLContext {
/**
* Configures which {@link https://neo4j.com/docs/cypher-manual/current/query-tuning/query-options/ | Cypher query options}
* when executing the translated query.
*/
cypherQueryOptions?: CypherQueryOptions;
/**
* @deprecated Use the {@link executionContext} property instead.
*/
Expand All @@ -48,11 +53,6 @@ export interface Neo4jGraphQLContext {
* ```
*/
jwt?: JWTPayload;
/**
* Configures which {@link https://neo4j.com/docs/cypher-manual/current/query-tuning/query-options/ | Cypher query options}
* when executing the translated query.
*/
queryOptions?: CypherQueryOptions;
/**
* The bearer token to be decoded/verified for use in authentication and authorization.
* Normally found in the Authorization HTTP header. Can be provided with or without authentication scheme.
Expand Down
30 changes: 10 additions & 20 deletions packages/graphql/src/utils/execute.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@

import type { Driver } from "neo4j-driver";
import type { Neo4jGraphQL } from "../classes";
import {
CypherConnectComponentsPlanner,
CypherExpressionEngine,
CypherInterpretedPipesFallback,
CypherOperatorEngine,
CypherPlanner,
CypherReplanning,
CypherRuntime,
CypherUpdateStrategy,
} from "../types";
import execute from "./execute";
import { trimmer } from ".";
import { ContextBuilder } from "../../tests/utils/builders/context-builder";
Expand Down Expand Up @@ -176,7 +166,7 @@ describe("execute", () => {
executionContext: driver,
database,
bookmarks,
queryOptions: {},
cypherQueryOptions: {},
}),
info: undefined,
}).instance(),
Expand Down Expand Up @@ -255,15 +245,15 @@ describe("execute", () => {
executionContext: driver,
database,
bookmarks,
queryOptions: {
runtime: CypherRuntime.INTERPRETED,
planner: CypherPlanner.COST,
connectComponentsPlanner: CypherConnectComponentsPlanner.GREEDY,
updateStrategy: CypherUpdateStrategy.DEFAULT,
expressionEngine: CypherExpressionEngine.COMPILED,
operatorEngine: CypherOperatorEngine.COMPILED,
interpretedPipesFallback: CypherInterpretedPipesFallback.ALL,
replan: CypherReplanning.DEFAULT,
cypherQueryOptions: {
runtime: "interpreted",
planner: "cost",
connectComponentsPlanner: "greedy",
updateStrategy: "default",
expressionEngine: "compiled",
operatorEngine: "compiled",
interpretedPipesFallback: "all",
replan: "default",
},
}),
info: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { graphql } from "graphql";
import { generate } from "randomstring";
import Neo4j from "../neo4j";
import { Neo4jGraphQL } from "../../../src/classes";
import { CypherRuntime } from "../../../src";

describe("query options", () => {
let driver: Driver;
Expand Down Expand Up @@ -56,7 +55,7 @@ describe("query options", () => {
const neoSchema = new Neo4jGraphQL({
typeDefs,
driver,
config: { queryOptions: { runtime: CypherRuntime.INTERPRETED } },
config: { cypherQueryOptions: { runtime: "interpreted" } },
});

const id = generate({
Expand Down

0 comments on commit 2167c9a

Please sign in to comment.