From 17fce41cd7b63f0f2fd06d596b874aaa97d8752b Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Tue, 8 Aug 2023 15:25:36 +0100 Subject: [PATCH 1/7] Pass info into Executor rather than putting in context --- packages/graphql/src/classes/Subgraph.ts | 1 + packages/graphql/src/schema/resolvers/field/cypher.ts | 1 + packages/graphql/src/schema/resolvers/mutation/create.ts | 1 + packages/graphql/src/schema/resolvers/mutation/delete.ts | 1 + packages/graphql/src/schema/resolvers/mutation/update.ts | 1 + packages/graphql/src/schema/resolvers/query/aggregate.ts | 1 + packages/graphql/src/schema/resolvers/query/fulltext.ts | 1 + packages/graphql/src/schema/resolvers/query/global-node.ts | 1 + packages/graphql/src/schema/resolvers/query/read.ts | 1 + packages/graphql/src/utils/execute.ts | 5 ++++- 10 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/graphql/src/classes/Subgraph.ts b/packages/graphql/src/classes/Subgraph.ts index e819500e98..e6d75b7d80 100644 --- a/packages/graphql/src/classes/Subgraph.ts +++ b/packages/graphql/src/classes/Subgraph.ts @@ -145,6 +145,7 @@ export class Subgraph { params, defaultAccessMode: "READ", context, + info, }); return executeResult.records[0]?.this; diff --git a/packages/graphql/src/schema/resolvers/field/cypher.ts b/packages/graphql/src/schema/resolvers/field/cypher.ts index 200a740af0..895247193b 100644 --- a/packages/graphql/src/schema/resolvers/field/cypher.ts +++ b/packages/graphql/src/schema/resolvers/field/cypher.ts @@ -49,6 +49,7 @@ export function cypherResolver({ params, defaultAccessMode: "WRITE", context, + info, }); const values = executeResult.result.records.map((record) => { diff --git a/packages/graphql/src/schema/resolvers/mutation/create.ts b/packages/graphql/src/schema/resolvers/mutation/create.ts index eef7238345..ae2cb015ab 100644 --- a/packages/graphql/src/schema/resolvers/mutation/create.ts +++ b/packages/graphql/src/schema/resolvers/mutation/create.ts @@ -36,6 +36,7 @@ export function createResolver({ node }: { node: Node }) { params, defaultAccessMode: "WRITE", context, + info, }); const nodeProjection = info.fieldNodes[0]?.selectionSet?.selections.find( diff --git a/packages/graphql/src/schema/resolvers/mutation/delete.ts b/packages/graphql/src/schema/resolvers/mutation/delete.ts index 3978a5eb2f..d6658b96ed 100644 --- a/packages/graphql/src/schema/resolvers/mutation/delete.ts +++ b/packages/graphql/src/schema/resolvers/mutation/delete.ts @@ -36,6 +36,7 @@ export function deleteResolver({ node, composer }: { node: Node; composer: Schem params, defaultAccessMode: "WRITE", context, + info, }); publishEventsToSubscriptionMechanism(executeResult, context.features?.subscriptions, context.schemaModel); diff --git a/packages/graphql/src/schema/resolvers/mutation/update.ts b/packages/graphql/src/schema/resolvers/mutation/update.ts index 80741f1752..9430085a11 100644 --- a/packages/graphql/src/schema/resolvers/mutation/update.ts +++ b/packages/graphql/src/schema/resolvers/mutation/update.ts @@ -36,6 +36,7 @@ export function updateResolver({ node, composer }: { node: Node; composer: Schem params, defaultAccessMode: "WRITE", context, + info, }); publishEventsToSubscriptionMechanism(executeResult, context.features?.subscriptions, context.schemaModel); diff --git a/packages/graphql/src/schema/resolvers/query/aggregate.ts b/packages/graphql/src/schema/resolvers/query/aggregate.ts index b76ed9ccc3..f5c5c8823b 100644 --- a/packages/graphql/src/schema/resolvers/query/aggregate.ts +++ b/packages/graphql/src/schema/resolvers/query/aggregate.ts @@ -42,6 +42,7 @@ export function aggregateResolver({ node }: { node: Node }) { params, defaultAccessMode: "READ", context, + info, }); return Object.values(executeResult.records[0] || {})[0]; diff --git a/packages/graphql/src/schema/resolvers/query/fulltext.ts b/packages/graphql/src/schema/resolvers/query/fulltext.ts index ca8f886d41..bc4070b320 100644 --- a/packages/graphql/src/schema/resolvers/query/fulltext.ts +++ b/packages/graphql/src/schema/resolvers/query/fulltext.ts @@ -38,6 +38,7 @@ export function fulltextResolver( params, defaultAccessMode: "READ", context, + info, }); return executeResult.records; } diff --git a/packages/graphql/src/schema/resolvers/query/global-node.ts b/packages/graphql/src/schema/resolvers/query/global-node.ts index d83d1fb35b..bda3371899 100644 --- a/packages/graphql/src/schema/resolvers/query/global-node.ts +++ b/packages/graphql/src/schema/resolvers/query/global-node.ts @@ -66,6 +66,7 @@ export function globalNodeResolver({ nodes }: { nodes: Node[] }) { params, defaultAccessMode: "READ", context, + info, }); let obj = null; diff --git a/packages/graphql/src/schema/resolvers/query/read.ts b/packages/graphql/src/schema/resolvers/query/read.ts index 87ffffb925..5a1c53ba17 100644 --- a/packages/graphql/src/schema/resolvers/query/read.ts +++ b/packages/graphql/src/schema/resolvers/query/read.ts @@ -36,6 +36,7 @@ export function findResolver({ node }: { node: Node }) { params, defaultAccessMode: "READ", context, + info, }); return executeResult.records.map((x) => x.this); diff --git a/packages/graphql/src/utils/execute.ts b/packages/graphql/src/utils/execute.ts index 64fbc33eaf..3e6375e170 100644 --- a/packages/graphql/src/utils/execute.ts +++ b/packages/graphql/src/utils/execute.ts @@ -21,6 +21,7 @@ import type { SessionMode, QueryResult } from "neo4j-driver"; import Debug from "debug"; import { DEBUG_EXECUTE } from "../constants"; import type { Context } from "../types"; +import type { GraphQLResolveInfo } from "graphql"; const debug = Debug(DEBUG_EXECUTE); @@ -36,13 +37,15 @@ async function execute({ params, defaultAccessMode, context, + info, }: { cypher: string; params: any; defaultAccessMode: SessionMode; context: Context; + info?: GraphQLResolveInfo; }): Promise { - const result = await context.executor.execute(cypher, params, defaultAccessMode, context.info); + const result = await context.executor.execute(cypher, params, defaultAccessMode, info); if (!result) { throw new Error("Unable to execute query against Neo4j database"); From 2459de1f973686bb9c64a923a22be5109cafd4ec Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 10 Aug 2023 11:05:06 +0100 Subject: [PATCH 2/7] Typings for fulltext in current context --- .../graphql/src/classes/CallbackBucket.ts | 2 +- .../schema/parse/parse-fulltext-directive.ts | 4 ++-- .../src/schema/resolvers/query/fulltext.ts | 15 ++++++++----- .../src/translate/batch-create/parser.test.ts | 3 --- .../create-create-and-params.test.ts | 5 ----- .../create-disconnect-and-params.test.ts | 8 ------- .../create-projection-and-params.test.ts | 2 -- .../translate/create-projection-and-params.ts | 4 ++-- .../create-update-and-params.test.ts | 7 ------ .../graphql/src/translate/translate-read.ts | 10 ++++----- .../translate/translate-top-level-match.ts | 10 ++++++--- packages/graphql/src/types/index.ts | 9 ++++---- packages/graphql/src/utils/execute.test.ts | 22 ------------------- .../tests/utils/builders/context-builder.ts | 5 ----- 14 files changed, 32 insertions(+), 74 deletions(-) diff --git a/packages/graphql/src/classes/CallbackBucket.ts b/packages/graphql/src/classes/CallbackBucket.ts index 4dfdab2c5e..89c8bb5950 100644 --- a/packages/graphql/src/classes/CallbackBucket.ts +++ b/packages/graphql/src/classes/CallbackBucket.ts @@ -49,7 +49,7 @@ export class CallbackBucket { const callbackFunction = (this.context?.callbacks as Neo4jGraphQLCallbacks)[cb.functionName] as ( parent?: Record, args?: Record, - context?: Record + context?: Context ) => Promise; const param = await callbackFunction(cb.parent, {}, this.context); diff --git a/packages/graphql/src/schema/parse/parse-fulltext-directive.ts b/packages/graphql/src/schema/parse/parse-fulltext-directive.ts index 51030d43e8..795ee00efd 100644 --- a/packages/graphql/src/schema/parse/parse-fulltext-directive.ts +++ b/packages/graphql/src/schema/parse/parse-fulltext-directive.ts @@ -18,7 +18,7 @@ */ import type { ArgumentNode, DirectiveNode, ObjectTypeDefinitionNode } from "graphql"; -import type { FullText, FulltextIndex } from "../../types"; +import type { FullText, FulltextContext } from "../../types"; import type { ObjectFields } from "../get-obj-field-meta"; import { parseValueNode } from "../../schema-model/parser/parse-value-node"; @@ -38,7 +38,7 @@ function parseFulltextDirective({ definition: ObjectTypeDefinitionNode; }): FullText { const indexesArg = directive.arguments?.find((arg) => arg.name.value === "indexes") as ArgumentNode; - const value = parseValueNode(indexesArg.value) as FulltextIndex[]; + const value = parseValueNode(indexesArg.value) as FulltextContext[]; const compatibleFields = nodeFields.primitiveFields.filter( (f) => ["String", "ID"].includes(f.typeMeta.name) && !f.typeMeta.array ); diff --git a/packages/graphql/src/schema/resolvers/query/fulltext.ts b/packages/graphql/src/schema/resolvers/query/fulltext.ts index bc4070b320..2abb207d39 100644 --- a/packages/graphql/src/schema/resolvers/query/fulltext.ts +++ b/packages/graphql/src/schema/resolvers/query/fulltext.ts @@ -22,13 +22,13 @@ import type { GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; import { translateRead } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context, FulltextIndex } from "../../../types"; +import type { Context, FulltextContext } from "../../../types"; import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import Cypher from "@neo4j/cypher-builder"; export function fulltextResolver( { node }: { node: Node }, - index: FulltextIndex + index: FulltextContext ): ObjectTypeComposerFieldConfigDefinition { async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { const context = createFulltextContext(index, args, _context, info); @@ -58,7 +58,12 @@ export function fulltextResolver( }; } -function createFulltextContext(index: FulltextIndex, args: any, _context: unknown, info: GraphQLResolveInfo): Context { +function createFulltextContext( + index: FulltextContext, + args: any, + _context: unknown, + info: GraphQLResolveInfo +): Context { const context = _context as Context; context.resolveTree = getNeo4jResolveTree(info, { args }); context.resolveTree.args.options = { @@ -66,7 +71,7 @@ function createFulltextContext(index: FulltextIndex, args: any, _context: unknow limit: context.resolveTree.args.limit, offset: context.resolveTree.args.offset, }; - context.fulltextIndex = index; - context.fulltextIndex.scoreVariable = new Cypher.Variable(); + context.fulltext = index; + context.fulltext.scoreVariable = new Cypher.Variable(); return context; } diff --git a/packages/graphql/src/translate/batch-create/parser.test.ts b/packages/graphql/src/translate/batch-create/parser.test.ts index 16ef7deb7c..e0619a861c 100644 --- a/packages/graphql/src/translate/batch-create/parser.test.ts +++ b/packages/graphql/src/translate/batch-create/parser.test.ts @@ -73,7 +73,6 @@ describe("TreeDescriptor Parser", () => { movieNode = nodes.find((node) => node.name === "Movie") as unknown as Node; context = new ContextBuilder({ - neoSchema: { nodes, relationships }, nodes, relationships, schema, @@ -105,7 +104,6 @@ describe("TreeDescriptor Parser", () => { }; const movieNode = nodes.find((node) => node.name === "Movie") as unknown as Node; const context = new ContextBuilder({ - neoSchema: { nodes, relationships }, nodes, relationships, schema, @@ -326,7 +324,6 @@ describe("TreeDescriptor Parser", () => { }; const movieNode = nodes.find((node) => node.name === "Movie") as unknown as Node; const context = new ContextBuilder({ - neoSchema: { nodes, relationships }, nodes, relationships, schema, diff --git a/packages/graphql/src/translate/create-create-and-params.test.ts b/packages/graphql/src/translate/create-create-and-params.test.ts index b2707ce096..8e4290706b 100644 --- a/packages/graphql/src/translate/create-create-and-params.test.ts +++ b/packages/graphql/src/translate/create-create-and-params.test.ts @@ -83,12 +83,7 @@ describe("createCreateAndParams", () => { pointFields: [], }).instance(); - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - nodes: [node], - }; const context = new ContextBuilder({ - neoSchema, schemaModel: new Neo4jGraphQLSchemaModel({ concreteEntities: [new ConcreteEntity({ name: "Movie", labels: ["Movie"] })], compositeEntities: [], diff --git a/packages/graphql/src/translate/create-disconnect-and-params.test.ts b/packages/graphql/src/translate/create-disconnect-and-params.test.ts index 1fb24a9ff4..c9941e06f0 100644 --- a/packages/graphql/src/translate/create-disconnect-and-params.test.ts +++ b/packages/graphql/src/translate/create-disconnect-and-params.test.ts @@ -19,7 +19,6 @@ import { ContextBuilder } from "../../tests/utils/builders/context-builder"; import { NodeBuilder } from "../../tests/utils/builders/node-builder"; -import type { Neo4jGraphQL } from "../classes"; import { Neo4jDatabaseInfo } from "../classes/Neo4jDatabaseInfo"; import { RelationshipQueryDirectionOption } from "../constants"; import { defaultNestedOperations } from "../graphql/directives/relationship"; @@ -91,14 +90,7 @@ describe("createDisconnectAndParams", () => { interfaces: [], }).instance(); - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - nodes: [node], - relationships: [], - }; - const context = new ContextBuilder({ - neoSchema, nodes: [node], relationships: [], neo4jDatabaseInfo: new Neo4jDatabaseInfo("4.4.0"), diff --git a/packages/graphql/src/translate/create-projection-and-params.test.ts b/packages/graphql/src/translate/create-projection-and-params.test.ts index 2b9ba0264f..9eb2e2f2d8 100644 --- a/packages/graphql/src/translate/create-projection-and-params.test.ts +++ b/packages/graphql/src/translate/create-projection-and-params.test.ts @@ -87,7 +87,6 @@ describe("createProjectionAndParams", () => { }).instance(); const context = new ContextBuilder({ - neoSchema: { nodes: [node] }, schemaModel: new Neo4jGraphQLSchemaModel({ concreteEntities: [new ConcreteEntity({ name: "Movie", labels: ["Movie"] })], compositeEntities: [], @@ -170,7 +169,6 @@ describe("createProjectionAndParams", () => { }).instance(); const context = new ContextBuilder({ - neoSchema: { nodes: [node] }, schemaModel: new Neo4jGraphQLSchemaModel({ concreteEntities: [new ConcreteEntity({ name: "Movie", labels: ["Movie"] })], compositeEntities: [], diff --git a/packages/graphql/src/translate/create-projection-and-params.ts b/packages/graphql/src/translate/create-projection-and-params.ts index 75a4ac049c..47c7d2909b 100644 --- a/packages/graphql/src/translate/create-projection-and-params.ts +++ b/packages/graphql/src/translate/create-projection-and-params.ts @@ -352,7 +352,7 @@ export default function createProjectionAndParams({ } let existingProjection = { ...resolveTree.fieldsByTypeName[node.name] }; - if (context.fulltextIndex) { + if (context.fulltext) { return createFulltextProjection({ resolveTree, node, @@ -500,7 +500,7 @@ function createFulltextProjection({ }; } - const nodeContext = { ...context, fulltextIndex: false }; + const nodeContext = { ...context, fulltext: undefined }; return createProjectionAndParams({ resolveTree: nodeResolveTree, diff --git a/packages/graphql/src/translate/create-update-and-params.test.ts b/packages/graphql/src/translate/create-update-and-params.test.ts index 955e6af39a..4e3452e09d 100644 --- a/packages/graphql/src/translate/create-update-and-params.test.ts +++ b/packages/graphql/src/translate/create-update-and-params.test.ts @@ -18,7 +18,6 @@ */ import createUpdateAndParams from "./create-update-and-params"; -import type { Neo4jGraphQL } from "../classes"; import { CallbackBucket } from "../classes/CallbackBucket"; import type { BaseField } from "../types"; import { trimmer } from "../utils"; @@ -72,13 +71,7 @@ describe("createUpdateAndParams", () => { primitiveFields: [idField], }).instance(); - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - nodes: [node], - }; - const context = new ContextBuilder({ - neoSchema, schemaModel: new Neo4jGraphQLSchemaModel({ concreteEntities: [new ConcreteEntity({ name: "Movie", labels: ["Movie"] })], compositeEntities: [], diff --git a/packages/graphql/src/translate/translate-read.ts b/packages/graphql/src/translate/translate-read.ts index 363bc6de23..cca4fc5f96 100644 --- a/packages/graphql/src/translate/translate-read.ts +++ b/packages/graphql/src/translate/translate-read.ts @@ -83,7 +83,7 @@ export function translateRead( const optionsInput = (resolveTree.args.options || {}) as GraphQLOptionsArg; - if (context.fulltextIndex) { + if (context.fulltext) { optionsInput.sort = optionsInput.sort?.[node?.singular] || optionsInput.sort; } @@ -102,7 +102,7 @@ export function translateRead( target: matchNode, projectionClause: orderClause as Cypher.With, nodeField: node.singular, - fulltextScoreVariable: context.fulltextIndex?.scoreVariable, + fulltextScoreVariable: context.fulltext?.scoreVariable, cypherFields: node.cypherFields, cypherFieldAliasMap, graphElement: node, @@ -115,10 +115,10 @@ export function translateRead( let returnClause = new Cypher.Return([projectionExpression, varName]); - if (context.fulltextIndex?.scoreVariable) { + if (context.fulltext?.scoreVariable) { returnClause = new Cypher.Return( [projectionExpression, varName], - [context.fulltextIndex?.scoreVariable, SCORE_FIELD] + [context.fulltext?.scoreVariable, SCORE_FIELD] ); } @@ -140,7 +140,7 @@ export function translateRead( target: matchNode, projectionClause: orderClause as Cypher.With, nodeField: node.singular, - fulltextScoreVariable: context.fulltextIndex?.scoreVariable, + fulltextScoreVariable: context.fulltext?.scoreVariable, cypherFields: node.cypherFields, cypherFieldAliasMap, graphElement: node, diff --git a/packages/graphql/src/translate/translate-top-level-match.ts b/packages/graphql/src/translate/translate-top-level-match.ts index a1834ca4be..e1107a69a2 100644 --- a/packages/graphql/src/translate/translate-top-level-match.ts +++ b/packages/graphql/src/translate/translate-top-level-match.ts @@ -86,7 +86,7 @@ export function createMatchClause({ whereOperators = node.getLabels(context).map((label) => { return Cypher.in(new Cypher.Param(label), Cypher.labels(matchNode)); }); - } else if (context.fulltextIndex) { + } else if (context.fulltext) { ({ matchClause, whereOperators } = createFulltextMatchClause(matchNode, where, node, context)); where = where?.[node.singular]; } @@ -172,13 +172,17 @@ function createFulltextMatchClause( matchClause: Cypher.Yield; whereOperators: Cypher.Predicate[]; } { + if (!context.fulltext) { + throw new Error("Full-text context not defined"); + } + // TODO: remove indexName assignment and undefined check once the name argument has been removed. - const indexName = context.fulltextIndex.indexName || context.fulltextIndex.name; + const indexName = context.fulltext.indexName || context.fulltext.name; if (indexName === undefined) { throw new Error("The name of the fulltext index should be defined using the indexName argument."); } const phraseParam = new Cypher.Param(context.resolveTree.args.phrase); - const scoreVar = context.fulltextIndex.scoreVariable; + const scoreVar = context.fulltext.scoreVariable; const matchClause = Cypher.db.index.fulltext .queryNodes(indexName, phraseParam) diff --git a/packages/graphql/src/types/index.ts b/packages/graphql/src/types/index.ts index 07903405f1..018a9731be 100644 --- a/packages/graphql/src/types/index.ts +++ b/packages/graphql/src/types/index.ts @@ -55,19 +55,20 @@ export interface Context extends Neo4jGraphQLContext { extensions?: Record; authorization: AuthorizationContext; neo4jDatabaseInfo?: Neo4jDatabaseInfo; - [k: string]: any; + fulltext?: FulltextContext; } -export type FulltextIndex = { +export type FulltextContext = { name: string | undefined; fields: string[]; queryType: string; queryName: string | undefined; indexName: string | undefined; // TODO: not undefined once name is removed. + scoreVariable: Cypher.Variable; }; export type FullText = { - indexes: FulltextIndex[]; + indexes: FulltextContext[]; }; /** @@ -420,7 +421,7 @@ export type CallbackReturnValue = string | number | boolean | undefined | null; export type Neo4jGraphQLCallback = ( parent: Record, args: Record, - context: Record + context: Context ) => CallbackReturnValue | Promise; export type Neo4jGraphQLCallbacks = Record; diff --git a/packages/graphql/src/utils/execute.test.ts b/packages/graphql/src/utils/execute.test.ts index 737475c1fa..e2cefa089c 100644 --- a/packages/graphql/src/utils/execute.test.ts +++ b/packages/graphql/src/utils/execute.test.ts @@ -18,7 +18,6 @@ */ import type { Driver } from "neo4j-driver"; -import type { Neo4jGraphQL } from "../classes"; import execute from "./execute"; import { trimmer } from "."; import { ContextBuilder } from "../../tests/utils/builders/context-builder"; @@ -84,18 +83,11 @@ describe("execute", () => { _config: {}, }; - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - // @ts-ignore - options: {}, - }; - const executeResult = await execute({ cypher, params, defaultAccessMode, context: new ContextBuilder({ - neoSchema, executor: new Executor({ executionContext: driver, sessionConfig: { @@ -170,18 +162,11 @@ describe("execute", () => { _config: {}, }; - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - // @ts-ignore - options: {}, - }; - const executeResult = await execute({ cypher, params, defaultAccessMode, context: new ContextBuilder({ - neoSchema, executor: new Executor({ executionContext: driver, sessionConfig: { @@ -260,18 +245,11 @@ describe("execute", () => { _config: {}, }; - // @ts-ignore - const neoSchema: Neo4jGraphQL = { - // @ts-ignore - options: {}, - }; - const executeResult = await execute({ cypher: inputCypher, params, defaultAccessMode, context: new ContextBuilder({ - neoSchema, executor: new Executor({ executionContext: driver, sessionConfig: { diff --git a/packages/graphql/tests/utils/builders/context-builder.ts b/packages/graphql/tests/utils/builders/context-builder.ts index 06d48a902e..95c9ffdf69 100644 --- a/packages/graphql/tests/utils/builders/context-builder.ts +++ b/packages/graphql/tests/utils/builders/context-builder.ts @@ -21,7 +21,6 @@ import type * as neo4j from "neo4j-driver"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { GraphQLResolveInfo } from "graphql"; import { GraphQLSchema } from "graphql"; -import { Neo4jGraphQL } from "../../../src/classes"; import type { Neo4jDatabaseInfo } from "../../../src/classes/Neo4jDatabaseInfo"; import type { Context } from "../../../src/types"; import { Builder } from "./builder"; @@ -34,11 +33,7 @@ import type { CompositeEntity } from "../../../src/schema-model/entity/Composite export class ContextBuilder extends Builder { constructor(newOptions: Partial = {}) { super({ - driver: {} as neo4j.Driver, resolveTree: {} as ResolveTree, - neoSchema: new Neo4jGraphQL({ - typeDefs: "", - }), nodes: [], relationships: [], schemaModel: new Neo4jGraphQLSchemaModel({ From 6ed508de475bb96f464fdaeaa00743cf90acf79c Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 10 Aug 2023 11:15:58 +0100 Subject: [PATCH 3/7] Remove unused context entries --- packages/graphql/src/classes/CallbackBucket.ts | 4 +++- packages/graphql/src/schema/resolvers/wrapper.ts | 5 ----- packages/graphql/src/translate/batch-create/parser.test.ts | 6 +----- packages/graphql/src/types/index.ts | 6 +----- packages/graphql/tests/utils/builders/context-builder.ts | 2 -- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/packages/graphql/src/classes/CallbackBucket.ts b/packages/graphql/src/classes/CallbackBucket.ts index 89c8bb5950..095a148fda 100644 --- a/packages/graphql/src/classes/CallbackBucket.ts +++ b/packages/graphql/src/classes/CallbackBucket.ts @@ -46,7 +46,9 @@ export class CallbackBucket { await Promise.all( this.callbacks.map(async (cb) => { - const callbackFunction = (this.context?.callbacks as Neo4jGraphQLCallbacks)[cb.functionName] as ( + const callbackFunction = (this.context?.features.populatedBy?.callbacks as Neo4jGraphQLCallbacks)[ + cb.functionName + ] as ( parent?: Record, args?: Record, context?: Context diff --git a/packages/graphql/src/schema/resolvers/wrapper.ts b/packages/graphql/src/schema/resolvers/wrapper.ts index dc3fe3a925..8bb3831a9d 100644 --- a/packages/graphql/src/schema/resolvers/wrapper.ts +++ b/packages/graphql/src/schema/resolvers/wrapper.ts @@ -64,8 +64,6 @@ export const wrapResolver = (next) => // TODO: type this as Neo4jGraphQLContext async (root, args, context: Context, info: GraphQLResolveInfo) => { - const callbacks = features.populatedBy?.callbacks; - if (debug.enabled) { const query = print(info.operation); @@ -84,13 +82,10 @@ export const wrapResolver = context.executionContext = driver; } - context.info = info; - context.nodes = nodes; context.relationships = relationships; context.schemaModel = schemaModel; context.subscriptionsEnabled = Boolean(features.subscriptions); - context.callbacks = callbacks; context.features = features; if (!context.jwt) { diff --git a/packages/graphql/src/translate/batch-create/parser.test.ts b/packages/graphql/src/translate/batch-create/parser.test.ts index e0619a861c..21de2de39b 100644 --- a/packages/graphql/src/translate/batch-create/parser.test.ts +++ b/packages/graphql/src/translate/batch-create/parser.test.ts @@ -29,7 +29,6 @@ describe("TreeDescriptor Parser", () => { let typeDefs; let movieNode; let context; - let schema; let nodes; let relationships; @@ -67,7 +66,7 @@ describe("TreeDescriptor Parser", () => { const neoSchema = new Neo4jGraphQL({ typeDefs, }); - schema = await neoSchema.getSchema(); + await neoSchema.getSchema(); nodes = neoSchema["nodes"]; relationships = neoSchema["relationships"]; @@ -75,7 +74,6 @@ describe("TreeDescriptor Parser", () => { context = new ContextBuilder({ nodes, relationships, - schema, }).instance(); }); @@ -106,7 +104,6 @@ describe("TreeDescriptor Parser", () => { const context = new ContextBuilder({ nodes, relationships, - schema, }).instance(); const treeDescriptor = Array.isArray(graphQLInput) ? mergeTreeDescriptors( @@ -326,7 +323,6 @@ describe("TreeDescriptor Parser", () => { const context = new ContextBuilder({ nodes, relationships, - schema, }).instance(); const treeDescriptor = Array.isArray(graphQLInput) ? mergeTreeDescriptors( diff --git a/packages/graphql/src/types/index.ts b/packages/graphql/src/types/index.ts index 018a9731be..6c2dcae240 100644 --- a/packages/graphql/src/types/index.ts +++ b/packages/graphql/src/types/index.ts @@ -19,7 +19,7 @@ import type Cypher from "@neo4j/cypher-builder"; import type { EventEmitter } from "events"; -import type { DirectiveNode, GraphQLResolveInfo, GraphQLSchema, InputValueDefinitionNode, TypeNode } from "graphql"; +import type { DirectiveNode, InputValueDefinitionNode, TypeNode } from "graphql"; import type { Directive } from "graphql-compose"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { JWTVerifyOptions, RemoteJWKSetOptions } from "jose"; @@ -43,16 +43,12 @@ type AuthorizationContext = { export interface Context extends Neo4jGraphQLContext { resolveTree: ResolveTree; - info: GraphQLResolveInfo; nodes: Node[]; relationships: Relationship[]; schemaModel: Neo4jGraphQLSchemaModel; - schema: GraphQLSchema; - callbacks?: Neo4jGraphQLCallbacks; features: ContextFeatures; subscriptionsEnabled: boolean; executor: Executor; - extensions?: Record; authorization: AuthorizationContext; neo4jDatabaseInfo?: Neo4jDatabaseInfo; fulltext?: FulltextContext; diff --git a/packages/graphql/tests/utils/builders/context-builder.ts b/packages/graphql/tests/utils/builders/context-builder.ts index 95c9ffdf69..b98c830cd4 100644 --- a/packages/graphql/tests/utils/builders/context-builder.ts +++ b/packages/graphql/tests/utils/builders/context-builder.ts @@ -20,7 +20,6 @@ import type * as neo4j from "neo4j-driver"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { GraphQLResolveInfo } from "graphql"; -import { GraphQLSchema } from "graphql"; import type { Neo4jDatabaseInfo } from "../../../src/classes/Neo4jDatabaseInfo"; import type { Context } from "../../../src/types"; import { Builder } from "./builder"; @@ -42,7 +41,6 @@ export class ContextBuilder extends Builder { operations: {}, annotations: [], }), - schema: new GraphQLSchema({}), subscriptionsEnabled: false, executionContext: {} as neo4j.Driver, executor: new Executor({ executionContext: {} as neo4j.Driver }), From 730b9a9bdd528dba76aec343ea0d441905e74949 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 10 Aug 2023 13:17:16 +0100 Subject: [PATCH 4/7] Remove some unneeded context references --- .../create-aggregate-where-and-params.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/graphql/src/translate/create-aggregate-where-and-params.ts b/packages/graphql/src/translate/create-aggregate-where-and-params.ts index 1b5eacd8ed..d8069d8374 100644 --- a/packages/graphql/src/translate/create-aggregate-where-and-params.ts +++ b/packages/graphql/src/translate/create-aggregate-where-and-params.ts @@ -77,8 +77,7 @@ export function aggregatePreComputedWhereFields({ refNode, relationship, aggregationTarget, - cypherRelation, - context + cypherRelation ); const predicateVariable = new Cypher.Variable(); @@ -98,8 +97,7 @@ function aggregateWhere( refNode: Node, relationship: Relationship | undefined, aggregationTarget: Cypher.Node, - cypherRelation: Cypher.Relationship, - context: Context + cypherRelation: Cypher.Relationship ): Cypher.Predicate[] { const innerPredicatesRes: Cypher.Predicate[] = []; Object.entries(aggregateWhereInput).forEach(([key, value]) => { @@ -111,7 +109,7 @@ function aggregateWhere( const refNodeOrRelation = key === "edge" ? relationship : refNode; if (!refNodeOrRelation) throw new Error(`Edge filter ${key} on undefined relationship`); - const innerPredicates = aggregateEntityWhere(value, refNodeOrRelation, target, context); + const innerPredicates = aggregateEntityWhere(value, refNodeOrRelation, target); innerPredicatesRes.push(...innerPredicates); } else if (isLogicalOperator(key)) { @@ -122,8 +120,7 @@ function aggregateWhere( refNode, relationship, aggregationTarget, - cypherRelation, - context + cypherRelation ); logicalPredicates.push(...innerPredicates); }); @@ -157,15 +154,14 @@ function createCountPredicateAndProjection( function aggregateEntityWhere( aggregateEntityWhereInput: WhereFilter, refNodeOrRelation: Node | Relationship, - target: Cypher.Node | Cypher.Relationship, - context: Context + target: Cypher.Node | Cypher.Relationship ): Cypher.Predicate[] { const innerPredicatesRes: Cypher.Predicate[] = []; Object.entries(aggregateEntityWhereInput).forEach(([key, value]) => { if (isLogicalOperator(key)) { const logicalPredicates: Cypher.Predicate[] = []; asArray(value).forEach((whereInput) => { - const innerPredicates = aggregateEntityWhere(whereInput, refNodeOrRelation, target, context); + const innerPredicates = aggregateEntityWhere(whereInput, refNodeOrRelation, target); logicalPredicates.push(...innerPredicates); }); const logicalPredicate = getLogicalPredicate(key, logicalPredicates); From 293372fabb006ce3262776e2c50a07c4a4e80a77 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Thu, 10 Aug 2023 13:17:41 +0100 Subject: [PATCH 5/7] Add context types --- .../types/neo4j-graphql-composed-context.ts | 49 +++++++++++++++++++ .../src/types/neo4j-graphql-context.ts | 2 + .../types/neo4j-graphql-resolver-context.ts | 33 +++++++++++++ .../get-neo4j-graphql-resolver-context.ts | 42 ++++++++++++++++ 4 files changed, 126 insertions(+) create mode 100644 packages/graphql/src/types/neo4j-graphql-composed-context.ts create mode 100644 packages/graphql/src/types/neo4j-graphql-resolver-context.ts create mode 100644 packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts diff --git a/packages/graphql/src/types/neo4j-graphql-composed-context.ts b/packages/graphql/src/types/neo4j-graphql-composed-context.ts new file mode 100644 index 0000000000..b16c2e9eb2 --- /dev/null +++ b/packages/graphql/src/types/neo4j-graphql-composed-context.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { AuthorizationContext, ContextFeatures, FulltextContext } from "."; +import type { Neo4jDatabaseInfo, Node, Relationship } from "../classes"; +import type { Executor } from "../classes/Executor"; +import type { Neo4jGraphQLSchemaModel } from "../schema-model/Neo4jGraphQLSchemaModel"; +import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; + +export interface Neo4jGraphQLInternalComposedContext { + /** + * @deprecated + */ + nodes: Node[]; + /** + * @deprecated + */ + relationships: Relationship[]; + schemaModel: Neo4jGraphQLSchemaModel; + features: ContextFeatures; + subscriptionsEnabled: boolean; + executor: Executor; + authorization: AuthorizationContext; + neo4jDatabaseInfo?: Neo4jDatabaseInfo; + fulltext?: FulltextContext; +} + +export interface Neo4jGraphQLComposedContext extends Neo4jGraphQLContext { + /** + * @internal + */ + _neo4j: Neo4jGraphQLInternalComposedContext; +} diff --git a/packages/graphql/src/types/neo4j-graphql-context.ts b/packages/graphql/src/types/neo4j-graphql-context.ts index 18204fdfd8..2879ba5bfc 100644 --- a/packages/graphql/src/types/neo4j-graphql-context.ts +++ b/packages/graphql/src/types/neo4j-graphql-context.ts @@ -47,6 +47,8 @@ export interface Neo4jGraphQLContext { * A decoded JWT payload which can be provided for use in authentication and authorization. * Takes precedence over {@link token} if both are present in the context. * + * Will be populated with the decoded {@link token} if authorization has been enabled in the library. + * * @example * ``` * { diff --git a/packages/graphql/src/types/neo4j-graphql-resolver-context.ts b/packages/graphql/src/types/neo4j-graphql-resolver-context.ts new file mode 100644 index 0000000000..d0c6e909ce --- /dev/null +++ b/packages/graphql/src/types/neo4j-graphql-resolver-context.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { ResolveTree } from "graphql-parse-resolve-info"; +import type { Neo4jGraphQLInternalComposedContext } from "./neo4j-graphql-composed-context"; +import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; + +export interface Neo4jGraphQLInternalResolverContext extends Neo4jGraphQLInternalComposedContext { + resolveTree: ResolveTree; +} + +export interface Neo4jGraphQLResolverContext extends Neo4jGraphQLContext { + /** + * @internal + */ + _neo4j: Neo4jGraphQLInternalResolverContext; +} diff --git a/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts b/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts new file mode 100644 index 0000000000..fab54b57dd --- /dev/null +++ b/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { GraphQLResolveInfo } from "graphql"; +import type { Neo4jGraphQLComposedContext } from "../types/neo4j-graphql-composed-context"; +import type { + Neo4jGraphQLInternalResolverContext, + Neo4jGraphQLResolverContext, +} from "../types/neo4j-graphql-resolver-context"; +import getNeo4jResolveTree from "./get-neo4j-resolve-tree"; + +export function getNeo4jGraphQLResolverContext({ + context, + info, + args, +}: { + context: Neo4jGraphQLComposedContext; + info: GraphQLResolveInfo; + args: unknown; +}): Neo4jGraphQLResolverContext { + const resolveTree = getNeo4jResolveTree(info, { args }); + + const internalContext: Neo4jGraphQLInternalResolverContext = { ...context._neo4j, resolveTree }; + + return { ...context, _neo4j: internalContext }; +} From bc94dcf70a5cf12592047efd978af46898d46ad8 Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Fri, 11 Aug 2023 18:12:48 +0100 Subject: [PATCH 6/7] Switch to new context typings --- .../graphql/src/classes/CallbackBucket.ts | 12 +- packages/graphql/src/classes/Node.test.ts | 12 +- packages/graphql/src/classes/Node.ts | 7 +- .../graphql/src/classes/NodeDirective.test.ts | 8 +- packages/graphql/src/classes/NodeDirective.ts | 8 +- packages/graphql/src/classes/Subgraph.ts | 25 ++- .../graphql/src/schema/create-global-nodes.ts | 3 +- .../src/schema/resolvers/field/cypher.ts | 15 +- .../src/schema/resolvers/mutation/create.ts | 15 +- .../src/schema/resolvers/mutation/delete.ts | 13 +- .../src/schema/resolvers/mutation/update.ts | 15 +- .../src/schema/resolvers/query/aggregate.ts | 12 +- .../src/schema/resolvers/query/fulltext.ts | 44 +++-- .../src/schema/resolvers/query/global-node.ts | 16 +- .../src/schema/resolvers/query/read.ts | 12 +- .../schema/resolvers/query/root-connection.ts | 21 ++- .../src/schema/resolvers/wrapper.test.ts | 25 --- .../graphql/src/schema/resolvers/wrapper.ts | 150 +++++++++++------- .../authorization/check-authentication.ts | 4 +- .../create-authorization-after-and-params.ts | 5 +- .../create-authorization-before-and-params.ts | 5 +- .../create-authorization-after-predicate.ts | 9 +- .../create-authorization-before-predicate.ts | 9 +- .../create-authorization-filter-predicate.ts | 5 +- ...create-authorization-validate-predicate.ts | 5 +- .../utils/apply-authentication.ts | 10 +- .../utils/populate-where-params.ts | 11 +- ...ate-authorization-jwt-payload-predicate.ts | 7 +- .../create-authorization-where-predicate.ts | 7 +- .../src/translate/batch-create/parser.ts | 22 +-- .../UnwindCreateVisitor.ts | 13 +- .../connection-projection.ts | 5 +- .../create-connection-clause.ts | 9 +- .../connection-clause/create-edge-subquery.ts | 5 +- .../create-aggregate-where-and-params.ts | 5 +- .../translate/create-connect-and-params.ts | 5 +- .../create-connect-or-create-and-params.ts | 13 +- .../src/translate/create-create-and-params.ts | 4 +- .../src/translate/create-delete-and-params.ts | 4 +- .../translate/create-disconnect-and-params.ts | 5 +- .../translate/create-projection-and-params.ts | 7 +- .../create-relationship-validation-string.ts | 4 +- .../src/translate/create-update-and-params.ts | 5 +- .../create-field-aggregation.ts | 5 +- .../field-aggregations-auth.ts | 5 +- .../src/translate/field-aggregations/utils.ts | 13 +- .../subquery/create-projection-subquery.ts | 5 +- .../translate-cypher-directive-projection.ts | 5 +- .../src/translate/translate-aggregate.ts | 13 +- .../graphql/src/translate/translate-create.ts | 4 +- .../graphql/src/translate/translate-delete.ts | 13 +- .../graphql/src/translate/translate-read.ts | 5 +- .../translate/translate-resolve-reference.ts | 4 +- .../translate/translate-top-level-cypher.ts | 10 +- .../translate/translate-top-level-match.ts | 9 +- .../graphql/src/translate/translate-update.ts | 5 +- .../graphql/src/translate/unwind-create.ts | 4 +- .../create-connection-where-and-params.ts | 5 +- .../translate/where/create-parameter-where.ts | 4 +- .../where/create-where-and-params.ts | 5 +- .../translate/where/create-where-predicate.ts | 7 +- .../create-connection-operation.ts | 5 +- .../create-property-where.ts | 5 +- .../create-relationship-operation.ts | 9 +- packages/graphql/src/types/index.ts | 2 +- .../types/neo4j-graphql-composed-context.ts | 49 ------ ...s => neo4j-graphql-translation-context.ts} | 17 +- packages/graphql/src/utils/execute.test.ts | 3 - packages/graphql/src/utils/execute.ts | 4 +- .../get-neo4j-graphql-resolver-context.ts | 42 ----- ...eration-subgraph-compatibility.e2e.test.ts | 6 +- .../custom-resolvers.int.test.ts | 8 +- .../graphql/tests/tck/utils/tck-test-utils.ts | 5 +- .../tests/utils/builders/context-builder.ts | 2 - 74 files changed, 447 insertions(+), 427 deletions(-) delete mode 100644 packages/graphql/src/types/neo4j-graphql-composed-context.ts rename packages/graphql/src/types/{neo4j-graphql-resolver-context.ts => neo4j-graphql-translation-context.ts} (61%) delete mode 100644 packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts diff --git a/packages/graphql/src/classes/CallbackBucket.ts b/packages/graphql/src/classes/CallbackBucket.ts index 095a148fda..b208707860 100644 --- a/packages/graphql/src/classes/CallbackBucket.ts +++ b/packages/graphql/src/classes/CallbackBucket.ts @@ -17,7 +17,9 @@ * limitations under the License. */ -import type { Context, Neo4jGraphQLCallbacks } from "../types"; +import type { Neo4jGraphQLCallbacks } from "../types"; +import type { Neo4jGraphQLContext } from "../types/neo4j-graphql-context"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export interface Callback { functionName: string; @@ -27,9 +29,9 @@ export interface Callback { export class CallbackBucket { public callbacks: Callback[]; - private context: Context; + private context: Neo4jGraphQLTranslationContext; - constructor(context: Context) { + constructor(context: Neo4jGraphQLTranslationContext) { this.context = context; this.callbacks = []; } @@ -46,12 +48,12 @@ export class CallbackBucket { await Promise.all( this.callbacks.map(async (cb) => { - const callbackFunction = (this.context?.features.populatedBy?.callbacks as Neo4jGraphQLCallbacks)[ + const callbackFunction = (this.context.features.populatedBy?.callbacks as Neo4jGraphQLCallbacks)[ cb.functionName ] as ( parent?: Record, args?: Record, - context?: Context + context?: Neo4jGraphQLContext ) => Promise; const param = await callbackFunction(cb.parent, {}, this.context); diff --git a/packages/graphql/src/classes/Node.test.ts b/packages/graphql/src/classes/Node.test.ts index 4fb3f20625..d33267ffba 100644 --- a/packages/graphql/src/classes/Node.test.ts +++ b/packages/graphql/src/classes/Node.test.ts @@ -861,7 +861,6 @@ describe("Node", () => { jwt: { movielabel: "Movie", }, - myKey: "key", }) .instance(); @@ -881,14 +880,10 @@ describe("Node", () => { }) .instance(); - const context = new ContextBuilder() - .with({ - myKey: "Movie", - }) - .instance(); + const context = new ContextBuilder().instance(); - const labels = node.getLabels(context); - const labelString = node.getLabelString(context); + const labels = node.getLabels({ ...context, myKey: "Movie" } as Record); + const labelString = node.getLabelString({ ...context, myKey: "Movie" } as Record); expect(labels).toEqual(["Movie"]); expect(labelString).toBe(":Movie"); @@ -908,7 +903,6 @@ describe("Node", () => { jwt: { movielabel: "Movie", }, - myKey: "key", }) .instance(); diff --git a/packages/graphql/src/classes/Node.ts b/packages/graphql/src/classes/Node.ts index df84918c4f..6287cfeaa2 100644 --- a/packages/graphql/src/classes/Node.ts +++ b/packages/graphql/src/classes/Node.ts @@ -22,7 +22,6 @@ import type { DirectiveNode, NamedTypeNode } from "graphql"; import pluralize from "pluralize"; import type { ConnectionField, - Context, CustomEnumField, CustomScalarField, CypherField, @@ -45,6 +44,7 @@ import type { NodeDirective } from "./NodeDirective"; import type { QueryOptionsDirective } from "./QueryOptionsDirective"; import type { SchemaConfiguration } from "../schema/schema-configuration"; import { leadingUnderscores } from "../utils/leading-underscore"; +import type { Neo4jGraphQLContext } from "../types/neo4j-graphql-context"; export interface NodeConstructor extends GraphElementConstructor { name: string; @@ -235,7 +235,6 @@ class Node extends GraphElement { }; } - public get fulltextTypeNames(): FulltextTypeNames { return { result: `${this.pascalCaseSingular}FulltextResult`, @@ -284,11 +283,11 @@ class Node extends GraphElement { }; } - public getLabelString(context: Context): string { + public getLabelString(context: Neo4jGraphQLContext): string { return this.nodeDirective?.getLabelsString(this.name, context) || `:${this.name}`; } - public getLabels(context: Context): string[] { + public getLabels(context: Neo4jGraphQLContext): string[] { return this.nodeDirective?.getLabels(this.name, context) || [this.name]; } diff --git a/packages/graphql/src/classes/NodeDirective.test.ts b/packages/graphql/src/classes/NodeDirective.test.ts index ba6012088d..ff314c271b 100644 --- a/packages/graphql/src/classes/NodeDirective.test.ts +++ b/packages/graphql/src/classes/NodeDirective.test.ts @@ -59,11 +59,15 @@ describe("NodeDirective", () => { }); test("should escape context labels", () => { - const context = new ContextBuilder({ escapeTest1: "123-321", escapeTest2: "He`l`lo" }).instance(); + const context = new ContextBuilder().instance(); const instance = new NodeDirective({ labels: ["label", "$context.escapeTest1", "$context.escapeTest2"], }); - const labelString = instance.getLabelsString("label", context); + const labelString = instance.getLabelsString("label", { + ...context, + escapeTest1: "123-321", + escapeTest2: "He`l`lo", + } as Record); expect(labelString).toBe(":label:`123-321`:`He``l``lo`"); }); diff --git a/packages/graphql/src/classes/NodeDirective.ts b/packages/graphql/src/classes/NodeDirective.ts index 9d4cdfc61c..af1a60b515 100644 --- a/packages/graphql/src/classes/NodeDirective.ts +++ b/packages/graphql/src/classes/NodeDirective.ts @@ -19,8 +19,8 @@ import dotProp from "dot-prop"; import { Neo4jGraphQLError } from "./Error"; -import type { Context } from "../types"; import Cypher from "@neo4j/cypher-builder"; +import type { Neo4jGraphQLContext } from "../types/neo4j-graphql-context"; export interface NodeDirectiveConstructor { labels?: string[]; @@ -33,7 +33,7 @@ export class NodeDirective { this.labels = input.labels || []; } - public getLabelsString(typeName: string, context: Context): string { + public getLabelsString(typeName: string, context: Neo4jGraphQLContext): string { if (!typeName) { throw new Neo4jGraphQLError("Could not generate label string in @node directive due to empty typeName"); } @@ -41,12 +41,12 @@ export class NodeDirective { return `:${labels.join(":")}`; } - public getLabels(typeName: string, context: Context): string[] { + public getLabels(typeName: string, context: Neo4jGraphQLContext): string[] { const labels = !this.labels.length ? [typeName] : this.labels; return this.mapLabelsWithContext(labels, context); } - private mapLabelsWithContext(labels: string[], context: Context): string[] { + private mapLabelsWithContext(labels: string[], context: Neo4jGraphQLContext): string[] { return labels.map((label: string) => { if (label.startsWith("$")) { // Trim $context. OR $ off the beginning of the string diff --git a/packages/graphql/src/classes/Subgraph.ts b/packages/graphql/src/classes/Subgraph.ts index e6d75b7d80..6f3ed32c25 100644 --- a/packages/graphql/src/classes/Subgraph.ts +++ b/packages/graphql/src/classes/Subgraph.ts @@ -31,10 +31,12 @@ import type { import { Kind, parse, print } from "graphql"; import type { Neo4jGraphQLSchemaModel } from "../schema-model/Neo4jGraphQLSchemaModel"; import { translateResolveReference } from "../translate/translate-resolve-reference"; -import type { Context, Node } from "../types"; +import type { Node } from "../types"; import { execute } from "../utils"; import getNeo4jResolveTree from "../utils/get-neo4j-resolve-tree"; import { isInArray } from "../utils/is-in-array"; +import type { Neo4jGraphQLComposedContext } from "../schema/resolvers/wrapper"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; // TODO fetch the directive names from the spec const federationDirectiveNames = [ @@ -53,7 +55,11 @@ const federationDirectiveNames = [ type FederationDirectiveName = (typeof federationDirectiveNames)[number]; -type ReferenceResolver = (reference, context: Context, info: GraphQLResolveInfo) => Promise; +type ReferenceResolver = ( + reference, + context: Neo4jGraphQLComposedContext, + info: GraphQLResolveInfo +) => Promise; export class Subgraph { private importArgument: Map; @@ -127,7 +133,11 @@ export class Subgraph { } private getReferenceResolver(nodes: Node[]): ReferenceResolver { - const __resolveReference = async (reference, context: Context, info: GraphQLResolveInfo): Promise => { + const __resolveReference = async ( + reference, + context: Neo4jGraphQLComposedContext, + info: GraphQLResolveInfo + ): Promise => { const { __typename } = reference; const node = nodes.find((n) => n.name === __typename); @@ -136,9 +146,13 @@ export class Subgraph { throw new Error("Unable to find matching node"); } - context.resolveTree = getNeo4jResolveTree(info); + (context as Neo4jGraphQLTranslationContext).resolveTree = getNeo4jResolveTree(info); - const { cypher, params } = translateResolveReference({ context, node, reference }); + const { cypher, params } = translateResolveReference({ + context: context as Neo4jGraphQLTranslationContext, + node, + reference, + }); const executeResult = await execute({ cypher, @@ -150,6 +164,7 @@ export class Subgraph { return executeResult.records[0]?.this; }; + return __resolveReference; } diff --git a/packages/graphql/src/schema/create-global-nodes.ts b/packages/graphql/src/schema/create-global-nodes.ts index faae4e3db3..cb49bab10c 100644 --- a/packages/graphql/src/schema/create-global-nodes.ts +++ b/packages/graphql/src/schema/create-global-nodes.ts @@ -22,6 +22,7 @@ import type { ObjectTypeComposerFieldConfigAsObjectDefinition, SchemaComposer } import { nodeDefinitions } from "graphql-relay"; import type { Context, Node } from "../types"; import { globalNodeResolver } from "./resolvers/query/global-node"; +import type { Neo4jGraphQLComposedContext } from "./resolvers/wrapper"; // returns true if globalNodeFields added or false if not export function addGlobalNodeFields(nodes: Node[], composer: SchemaComposer): boolean { @@ -29,7 +30,7 @@ export function addGlobalNodeFields(nodes: Node[], composer: SchemaComposer): bo if (globalNodes.length === 0) return false; - const fetchById = (id: string, context: Context, info: GraphQLResolveInfo) => { + const fetchById = (id: string, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) => { const resolver = globalNodeResolver({ nodes: globalNodes }); return resolver.resolve(null, { id }, context, info); }; diff --git a/packages/graphql/src/schema/resolvers/field/cypher.ts b/packages/graphql/src/schema/resolvers/field/cypher.ts index 895247193b..03c982a0df 100644 --- a/packages/graphql/src/schema/resolvers/field/cypher.ts +++ b/packages/graphql/src/schema/resolvers/field/cypher.ts @@ -19,10 +19,13 @@ import type { GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; -import type { Context, CypherField } from "../../../types"; +import type { CypherField } from "../../../types"; import { graphqlArgsToCompose } from "../../to-compose"; import { isNeoInt } from "../../../utils/utils"; import { translateTopLevelCypher } from "../../../translate"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; export function cypherResolver({ field, @@ -33,17 +36,19 @@ export function cypherResolver({ statement: string; type: "Query" | "Mutation"; }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info); + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; const { cypher, params } = translateTopLevelCypher({ - context, - info, + context: context as Neo4jGraphQLTranslationContext, field, args, type, statement, }); + const executeResult = await execute({ cypher, params, diff --git a/packages/graphql/src/schema/resolvers/mutation/create.ts b/packages/graphql/src/schema/resolvers/mutation/create.ts index ae2cb015ab..434d7615f3 100644 --- a/packages/graphql/src/schema/resolvers/mutation/create.ts +++ b/packages/graphql/src/schema/resolvers/mutation/create.ts @@ -21,15 +21,18 @@ import { Kind, type FieldNode, type GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; import { translateCreate } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context } from "../../../types"; -import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import { publishEventsToSubscriptionMechanism } from "../../subscriptions/publish-events-to-subscription-mechanism"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createResolver({ node }: { node: Node }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info, { args }); - const { cypher, params } = await translateCreate({ context, node }); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info, { args }); + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; + + const { cypher, params } = await translateCreate({ context: context as Neo4jGraphQLTranslationContext, node }); const executeResult = await execute({ cypher, diff --git a/packages/graphql/src/schema/resolvers/mutation/delete.ts b/packages/graphql/src/schema/resolvers/mutation/delete.ts index d6658b96ed..defcd9bc7f 100644 --- a/packages/graphql/src/schema/resolvers/mutation/delete.ts +++ b/packages/graphql/src/schema/resolvers/mutation/delete.ts @@ -20,17 +20,20 @@ import type { GraphQLResolveInfo } from "graphql"; import type { SchemaComposer } from "graphql-compose"; import { translateDelete } from "../../../translate"; -import type { Context } from "../../../types"; import type { Node } from "../../../classes"; import { publishEventsToSubscriptionMechanism } from "../../subscriptions/publish-events-to-subscription-mechanism"; import { execute } from "../../../utils"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function deleteResolver({ node, composer }: { node: Node; composer: SchemaComposer }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info, { args }); - const { cypher, params } = translateDelete({ context, node }); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info, { args }); + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; + + const { cypher, params } = translateDelete({ context: context as Neo4jGraphQLTranslationContext, node }); const executeResult = await execute({ cypher, params, diff --git a/packages/graphql/src/schema/resolvers/mutation/update.ts b/packages/graphql/src/schema/resolvers/mutation/update.ts index 9430085a11..615aabbe69 100644 --- a/packages/graphql/src/schema/resolvers/mutation/update.ts +++ b/packages/graphql/src/schema/resolvers/mutation/update.ts @@ -21,16 +21,19 @@ import { Kind, type FieldNode, type GraphQLResolveInfo } from "graphql"; import type { SchemaComposer } from "graphql-compose"; import type { Node } from "../../../classes"; import { translateUpdate } from "../../../translate"; -import type { Context } from "../../../types"; import { execute } from "../../../utils"; -import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import { publishEventsToSubscriptionMechanism } from "../../subscriptions/publish-events-to-subscription-mechanism"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function updateResolver({ node, composer }: { node: Node; composer: SchemaComposer }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info, { args }); - const [cypher, params] = await translateUpdate({ context, node }); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info, { args }); + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; + + const [cypher, params] = await translateUpdate({ context: context as Neo4jGraphQLTranslationContext, node }); const executeResult = await execute({ cypher, params, diff --git a/packages/graphql/src/schema/resolvers/query/aggregate.ts b/packages/graphql/src/schema/resolvers/query/aggregate.ts index f5c5c8823b..490e31c637 100644 --- a/packages/graphql/src/schema/resolvers/query/aggregate.ts +++ b/packages/graphql/src/schema/resolvers/query/aggregate.ts @@ -20,17 +20,19 @@ import type { GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; import type { Node } from "../../../classes"; -import type { Context } from "../../../types"; import { translateAggregate } from "../../../translate"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function aggregateResolver({ node }: { node: Node }) { - async function resolve(_root: any, _args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info); + async function resolve(_root: any, _args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info); + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; const [aggregateCypher, aggregateParams] = translateAggregate({ - context, + context: context as Neo4jGraphQLTranslationContext, node, }); diff --git a/packages/graphql/src/schema/resolvers/query/fulltext.ts b/packages/graphql/src/schema/resolvers/query/fulltext.ts index 2abb207d39..0fb9d9edff 100644 --- a/packages/graphql/src/schema/resolvers/query/fulltext.ts +++ b/packages/graphql/src/schema/resolvers/query/fulltext.ts @@ -22,17 +22,33 @@ import type { GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; import { translateRead } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context, FulltextContext } from "../../../types"; -import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { FulltextContext } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; export function fulltextResolver( { node }: { node: Node }, index: FulltextContext ): ObjectTypeComposerFieldConfigDefinition { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = createFulltextContext(index, args, _context, info); - const { cypher, params } = translateRead({ context, node }, node.singular); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + context.fulltext = index; + context.fulltext.scoreVariable = new Cypher.Variable(); + + const resolveTree = getNeo4jResolveTree(info, { args }); + resolveTree.args.options = { + sort: resolveTree.args.sort, + limit: resolveTree.args.limit, + offset: resolveTree.args.offset, + }; + + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; + + const { cypher, params } = translateRead( + { context: context as Neo4jGraphQLTranslationContext, node }, + node.singular + ); const executeResult = await execute({ cypher, params, @@ -57,21 +73,3 @@ export function fulltextResolver( }, }; } - -function createFulltextContext( - index: FulltextContext, - args: any, - _context: unknown, - info: GraphQLResolveInfo -): Context { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info, { args }); - context.resolveTree.args.options = { - sort: context.resolveTree.args.sort, - limit: context.resolveTree.args.limit, - offset: context.resolveTree.args.offset, - }; - context.fulltext = index; - context.fulltext.scoreVariable = new Cypher.Variable(); - return context; -} diff --git a/packages/graphql/src/schema/resolvers/query/global-node.ts b/packages/graphql/src/schema/resolvers/query/global-node.ts index bda3371899..8c3b2e302e 100644 --- a/packages/graphql/src/schema/resolvers/query/global-node.ts +++ b/packages/graphql/src/schema/resolvers/query/global-node.ts @@ -23,12 +23,18 @@ import { parseResolveInfo } from "graphql-parse-resolve-info"; import { execute } from "../../../utils"; import { translateRead } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context } from "../../../types"; -import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import { fromGlobalId } from "../../../utils/global-ids"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function globalNodeResolver({ nodes }: { nodes: Node[] }) { - async function resolve(_root: any, args: { id: string }, context: Context, info: GraphQLResolveInfo) { + async function resolve( + _root: any, + args: { id: string }, + context: Neo4jGraphQLComposedContext, + info: GraphQLResolveInfo + ) { const { typeName, field, id } = fromGlobalId(args.id); if (!typeName || !field || !id) return null; @@ -58,9 +64,9 @@ export function globalNodeResolver({ nodes }: { nodes: Node[] }) { fieldsByTypeName, }; - context.resolveTree = getNeo4jResolveTree(info, { resolveTree }); + (context as Neo4jGraphQLTranslationContext).resolveTree = getNeo4jResolveTree(info, { resolveTree }); - const { cypher, params } = translateRead({ context, node }); + const { cypher, params } = translateRead({ context: context as Neo4jGraphQLTranslationContext, node }); const executeResult = await execute({ cypher, params, diff --git a/packages/graphql/src/schema/resolvers/query/read.ts b/packages/graphql/src/schema/resolvers/query/read.ts index 5a1c53ba17..772ee40df0 100644 --- a/packages/graphql/src/schema/resolvers/query/read.ts +++ b/packages/graphql/src/schema/resolvers/query/read.ts @@ -21,15 +21,17 @@ import type { GraphQLResolveInfo } from "graphql"; import { execute } from "../../../utils"; import { translateRead } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context } from "../../../types"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function findResolver({ node }: { node: Node }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - context.resolveTree = getNeo4jResolveTree(info, { args }); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info, { args }); - const { cypher, params } = translateRead({ context, node }); + (context as Neo4jGraphQLTranslationContext).resolveTree = resolveTree; + + const { cypher, params } = translateRead({ context: context as Neo4jGraphQLTranslationContext, node }); const executeResult = await execute({ cypher, diff --git a/packages/graphql/src/schema/resolvers/query/root-connection.ts b/packages/graphql/src/schema/resolvers/query/root-connection.ts index 26a9ceaca2..eca2ec497b 100644 --- a/packages/graphql/src/schema/resolvers/query/root-connection.ts +++ b/packages/graphql/src/schema/resolvers/query/root-connection.ts @@ -24,24 +24,31 @@ import type { PageInfo } from "graphql-relay"; import { execute } from "../../../utils"; import { translateRead } from "../../../translate"; import type { Node } from "../../../classes"; -import type { Context } from "../../../types"; -import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; import { isNeoInt } from "../../../utils/utils"; import { createConnectionWithEdgeProperties } from "../../pagination"; import { graphqlDirectivesToCompose } from "../../to-compose"; +import type { Neo4jGraphQLComposedContext } from "../wrapper"; +import getNeo4jResolveTree from "../../../utils/get-neo4j-resolve-tree"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function rootConnectionResolver({ node, composer }: { node: Node; composer: SchemaComposer }) { - async function resolve(_root: any, args: any, _context: unknown, info: GraphQLResolveInfo) { - const context = _context as Context; - const resolveTree = getNeo4jResolveTree(info); + async function resolve(_root: any, args: any, context: Neo4jGraphQLComposedContext, info: GraphQLResolveInfo) { + const resolveTree = getNeo4jResolveTree(info, { args }); const edgeTree = resolveTree.fieldsByTypeName[`${upperFirst(node.plural)}Connection`]?.edges; const nodeTree = edgeTree?.fieldsByTypeName[`${node.name}Edge`]?.node; const resolveTreeForContext = nodeTree || resolveTree; - context.resolveTree = { ...resolveTreeForContext, args: resolveTree.args }; + (context as Neo4jGraphQLTranslationContext).resolveTree = { + ...resolveTreeForContext, + args: resolveTree.args, + }; - const { cypher, params } = translateRead({ context, node, isRootConnectionField: true }); + const { cypher, params } = translateRead({ + context: context as Neo4jGraphQLTranslationContext, + node, + isRootConnectionField: true, + }); const executeResult = await execute({ cypher, diff --git a/packages/graphql/src/schema/resolvers/wrapper.test.ts b/packages/graphql/src/schema/resolvers/wrapper.test.ts index 8c5315d8fe..0db496827e 100644 --- a/packages/graphql/src/schema/resolvers/wrapper.test.ts +++ b/packages/graphql/src/schema/resolvers/wrapper.test.ts @@ -93,31 +93,6 @@ describe("wrapper test", () => { expect(resolver).toHaveBeenCalledTimes(1); }); - test("should NOT initialise neo4jDatabaseInfo if version is present in the Context", async () => { - const resolverDecorator = wrapResolver(wrapResolverArgs); - const resolvedResult = "Resolved value"; - executeRead.mockReturnValueOnce({ - records: [["4.5.0", "enterprise"]], - }); - const contextVersion = new Neo4jDatabaseInfo("1.1.0", "enterprise"); - const resolver = jest.fn((_root, _args, context: Context) => { - expect(context).toBeDefined(); - expect(context.neo4jDatabaseInfo).toBeDefined(); - expect(context.neo4jDatabaseInfo).toStrictEqual(contextVersion); - return resolvedResult; - }); - const wrappedResolver = resolverDecorator(resolver); - const res = await wrappedResolver( - {}, - {}, - { neo4jDatabaseInfo: contextVersion } as Context, - {} as GraphQLResolveInfo - ); - expect(res).toBe(resolvedResult); - expect(executeRead).toHaveBeenCalledTimes(0); - expect(resolver).toHaveBeenCalledTimes(1); - }); - test("should not invoke dbms.components if neo4jDatabaseInfo is already initialised", async () => { const resolverDecorator = wrapResolver(wrapResolverArgs); const resolvedResult = "Resolved value"; diff --git a/packages/graphql/src/schema/resolvers/wrapper.ts b/packages/graphql/src/schema/resolvers/wrapper.ts index 8bb3831a9d..f6e7ec01d0 100644 --- a/packages/graphql/src/schema/resolvers/wrapper.ts +++ b/packages/graphql/src/schema/resolvers/wrapper.ts @@ -18,7 +18,7 @@ */ import Debug from "debug"; -import type { GraphQLResolveInfo } from "graphql"; +import type { GraphQLFieldResolver, GraphQLResolveInfo } from "graphql"; import { print } from "graphql"; import type { Driver } from "neo4j-driver"; import { Neo4jError } from "neo4j-driver"; @@ -26,13 +26,13 @@ import type { Node, Relationship } from "../../classes"; import type { Neo4jDatabaseInfo } from "../../classes/Neo4jDatabaseInfo"; import { getNeo4jDatabaseInfo } from "../../classes/Neo4jDatabaseInfo"; import { Executor } from "../../classes/Executor"; -import type { ExecutorConstructorParam } from "../../classes/Executor"; import { AUTH_FORBIDDEN_ERROR, DEBUG_GRAPHQL } from "../../constants"; -import type { Context, ContextFeatures } from "../../types"; +import type { AuthorizationContext, ContextFeatures, FulltextContext } from "../../types"; import type { SubscriptionConnectionContext, SubscriptionContext } from "./subscriptions/types"; import type { Neo4jGraphQLSchemaModel } from "../../schema-model/Neo4jGraphQLSchemaModel"; import Cypher from "@neo4j/cypher-builder"; import type { Neo4jGraphQLAuthorization } from "../../classes/authorization/Neo4jGraphQLAuthorization"; +import type { Neo4jGraphQLContext } from "../../types/neo4j-graphql-context"; const debug = Debug(DEBUG_GRAPHQL); @@ -47,6 +47,27 @@ export type WrapResolverArguments = { authorization?: Neo4jGraphQLAuthorization; }; +/** + * The type describing the context generated by {@link wrapResolver}. + */ +export interface Neo4jGraphQLComposedContext extends Neo4jGraphQLContext { + /** + * @deprecated The use of this field is now deprecated in favour of {@link schemaModel}. + */ + nodes: Node[]; + /** + * @deprecated The use of this field is now deprecated in favour of {@link schemaModel}. + */ + relationships: Relationship[]; + schemaModel: Neo4jGraphQLSchemaModel; + features: ContextFeatures; + subscriptionsEnabled: boolean; + executor: Executor; + authorization: AuthorizationContext; + neo4jDatabaseInfo?: Neo4jDatabaseInfo; + fulltext?: FulltextContext; +} + let neo4jDatabaseInfo: Neo4jDatabaseInfo; export const wrapResolver = @@ -60,10 +81,8 @@ export const wrapResolver = authorization, features, }: WrapResolverArguments) => - // TODO: strongly type this, so that context argument accepts "full" context - (next) => - // TODO: type this as Neo4jGraphQLContext - async (root, args, context: Context, info: GraphQLResolveInfo) => { + (next: GraphQLFieldResolver) => + async (root, args, context: Neo4jGraphQLContext, info: GraphQLResolveInfo) => { if (debug.enabled) { const query = print(info.operation); @@ -82,66 +101,40 @@ export const wrapResolver = context.executionContext = driver; } - context.nodes = nodes; - context.relationships = relationships; - context.schemaModel = schemaModel; - context.subscriptionsEnabled = Boolean(features.subscriptions); - context.features = features; + const subscriptionsEnabled = Boolean(features.subscriptions); + const authorizationContext = await getAuthorizationContext(context, authorization, jwtPayloadFieldsMap); if (!context.jwt) { - if (authorization) { - try { - context.jwt = await authorization.decode(context); - const isAuthenticated = true; - context.authorization = { - isAuthenticated, - jwt: context.jwt, - jwtParam: new Cypher.NamedParam("jwt", context.jwt), - isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), - claims: jwtPayloadFieldsMap, - }; - } catch (e) { - const isAuthenticated = false; - context.authorization = { - isAuthenticated, - jwtParam: new Cypher.NamedParam("jwt", {}), - isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), - }; - } - } - } else { - const isAuthenticated = true; - const jwt = context.jwt; - - context.authorization = { - isAuthenticated, - jwt, - jwtParam: new Cypher.NamedParam("jwt", jwt), - isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), - }; + context.jwt = authorizationContext.jwt; } - const executorConstructorParam: ExecutorConstructorParam = { + const executor = new Executor({ executionContext: context.executionContext, - }; - - executorConstructorParam.cypherQueryOptions = context.cypherQueryOptions; - - executorConstructorParam.sessionConfig = context.sessionConfig; + cypherQueryOptions: context.cypherQueryOptions, + sessionConfig: context.sessionConfig, + }); - context.executor = new Executor(executorConstructorParam); - - if (!context.neo4jDatabaseInfo?.version) { - if (dbInfo) { - neo4jDatabaseInfo = dbInfo; - } - if (!neo4jDatabaseInfo?.version) { - neo4jDatabaseInfo = await getNeo4jDatabaseInfo(context.executor); - } - context.neo4jDatabaseInfo = neo4jDatabaseInfo; + if (dbInfo) { + neo4jDatabaseInfo = dbInfo; + } + if (!neo4jDatabaseInfo?.version) { + neo4jDatabaseInfo = await getNeo4jDatabaseInfo(executor); } - return next(root, args, context, info); + const internalContext = { + nodes, + relationships, + schemaModel, + features, + subscriptionsEnabled, + executor, + neo4jDatabaseInfo, + authorization: authorizationContext, + // Consider anything in here overrides + ...context, + }; + + return next(root, args, { ...context, ...internalContext }, info); }; export const wrapSubscription = @@ -186,3 +179,42 @@ export const wrapSubscription = return next(root, args, { ...context, ...contextParams, ...subscriptionContext }, info); }; + +async function getAuthorizationContext( + context: Neo4jGraphQLContext, + authorization?: Neo4jGraphQLAuthorization, + jwtPayloadFieldsMap?: Map +): Promise { + if (!context.jwt) { + if (authorization) { + try { + context.jwt = await authorization.decode(context); + const isAuthenticated = true; + return { + isAuthenticated, + jwt: context.jwt, + jwtParam: new Cypher.NamedParam("jwt", context.jwt), + isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), + claims: jwtPayloadFieldsMap, + }; + } catch (e) { + const isAuthenticated = false; + return { + isAuthenticated, + jwtParam: new Cypher.NamedParam("jwt", {}), + isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), + }; + } + } + } + + const isAuthenticated = true; + const jwt = context.jwt; + + return { + isAuthenticated, + jwt, + jwtParam: new Cypher.NamedParam("jwt", jwt), + isAuthenticatedParam: new Cypher.NamedParam("isAuthenticated", isAuthenticated), + }; +} diff --git a/packages/graphql/src/translate/authorization/check-authentication.ts b/packages/graphql/src/translate/authorization/check-authentication.ts index 148fc57135..0f31e7b9a5 100644 --- a/packages/graphql/src/translate/authorization/check-authentication.ts +++ b/packages/graphql/src/translate/authorization/check-authentication.ts @@ -18,13 +18,13 @@ */ import type { Node } from "../../classes"; -import type { Context } from "../../types"; import type { ConcreteEntity } from "../../schema-model/entity/ConcreteEntity"; import type { AuthenticationAnnotation, AuthenticationOperation, } from "../../schema-model/annotation/AuthenticationAnnotation"; import { applyAuthentication } from "./utils/apply-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; export function checkAuthentication({ context, @@ -32,7 +32,7 @@ export function checkAuthentication({ targetOperations, field, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; targetOperations: AuthenticationOperation[]; field?: string; diff --git a/packages/graphql/src/translate/authorization/compatibility/create-authorization-after-and-params.ts b/packages/graphql/src/translate/authorization/compatibility/create-authorization-after-and-params.ts index ee09f6e05a..b7e2e6767d 100644 --- a/packages/graphql/src/translate/authorization/compatibility/create-authorization-after-and-params.ts +++ b/packages/graphql/src/translate/authorization/compatibility/create-authorization-after-and-params.ts @@ -18,11 +18,12 @@ */ import Cypher from "@neo4j/cypher-builder"; -import type { Context, Node } from "../../../types"; +import type { Node } from "../../../types"; import type { AuthorizationOperation } from "../../../types/authorization"; import { createAuthorizationAfterPredicate } from "../create-authorization-after-predicate"; import type { NodeMap } from "../types/node-map"; import { compilePredicateReturn } from "./compile-predicate-return"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export type AuthorizationAfterAndParams = { cypher: string; @@ -50,7 +51,7 @@ export function createAuthorizationAfterAndParams({ nodes, operations, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; nodes: StringNodeMap[]; operations: AuthorizationOperation[]; }): AuthorizationAfterAndParams | undefined { diff --git a/packages/graphql/src/translate/authorization/compatibility/create-authorization-before-and-params.ts b/packages/graphql/src/translate/authorization/compatibility/create-authorization-before-and-params.ts index d9a75eae09..ec0eb2a831 100644 --- a/packages/graphql/src/translate/authorization/compatibility/create-authorization-before-and-params.ts +++ b/packages/graphql/src/translate/authorization/compatibility/create-authorization-before-and-params.ts @@ -18,11 +18,12 @@ */ import Cypher from "@neo4j/cypher-builder"; -import type { Context, Node } from "../../../types"; +import type { Node } from "../../../types"; import type { AuthorizationOperation } from "../../../types/authorization"; import { createAuthorizationBeforePredicate } from "../create-authorization-before-predicate"; import type { NodeMap } from "../types/node-map"; import { compilePredicateReturn } from "./compile-predicate-return"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export type AuthorizationBeforeAndParams = { cypher: string; @@ -50,7 +51,7 @@ export function createAuthorizationBeforeAndParams({ nodes, operations, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; nodes: StringNodeMap[]; operations: AuthorizationOperation[]; }): AuthorizationBeforeAndParams | undefined { diff --git a/packages/graphql/src/translate/authorization/create-authorization-after-predicate.ts b/packages/graphql/src/translate/authorization/create-authorization-after-predicate.ts index 30f299ab1d..7208fba4f7 100644 --- a/packages/graphql/src/translate/authorization/create-authorization-after-predicate.ts +++ b/packages/graphql/src/translate/authorization/create-authorization-after-predicate.ts @@ -19,11 +19,12 @@ import Cypher from "@neo4j/cypher-builder"; import type { AuthorizationAnnotation } from "../../schema-model/annotation/AuthorizationAnnotation"; -import type { Node, Context, PredicateReturn } from "../../types"; +import type { Node, PredicateReturn } from "../../types"; import type { AuthorizationOperation } from "../../types/authorization"; import { createAuthorizationValidatePredicate } from "./rules/create-authorization-validate-predicate"; import type { ConcreteEntity } from "../../schema-model/entity/ConcreteEntity"; import type { NodeMap } from "./types/node-map"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; function createNodePredicate({ context, @@ -33,7 +34,7 @@ function createNodePredicate({ fieldName, conditionForEvaluation, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; variable: Cypher.Node; node: Node; operations: AuthorizationOperation[]; @@ -73,7 +74,7 @@ function createNodeAuthorizationPredicate({ fieldName, conditionForEvaluation, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; entity: ConcreteEntity; variable: Cypher.Node; @@ -105,7 +106,7 @@ export function createAuthorizationAfterPredicate({ operations, conditionForEvaluation, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; nodes: NodeMap[]; operations: AuthorizationOperation[]; conditionForEvaluation?: Cypher.Predicate; diff --git a/packages/graphql/src/translate/authorization/create-authorization-before-predicate.ts b/packages/graphql/src/translate/authorization/create-authorization-before-predicate.ts index ade45efe60..0156ccdc64 100644 --- a/packages/graphql/src/translate/authorization/create-authorization-before-predicate.ts +++ b/packages/graphql/src/translate/authorization/create-authorization-before-predicate.ts @@ -19,12 +19,13 @@ import Cypher from "@neo4j/cypher-builder"; import type { AuthorizationAnnotation } from "../../schema-model/annotation/AuthorizationAnnotation"; -import type { Node, Context, PredicateReturn } from "../../types"; +import type { Node, PredicateReturn } from "../../types"; import type { AuthorizationOperation } from "../../types/authorization"; import { createAuthorizationFilterPredicate } from "./rules/create-authorization-filter-predicate"; import { createAuthorizationValidatePredicate } from "./rules/create-authorization-validate-predicate"; import type { ConcreteEntity } from "../../schema-model/entity/ConcreteEntity"; import type { NodeMap } from "./types/node-map"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; function createNodePredicate({ context, @@ -33,7 +34,7 @@ function createNodePredicate({ operations, fieldName, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; variable: Cypher.Node; operations: AuthorizationOperation[]; @@ -70,7 +71,7 @@ function createNodeAuthorizationPredicate({ operations, fieldName, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; entity: ConcreteEntity; variable: Cypher.Node; @@ -135,7 +136,7 @@ export function createAuthorizationBeforePredicate({ nodes, operations, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; nodes: NodeMap[]; operations: AuthorizationOperation[]; }): PredicateReturn | undefined { diff --git a/packages/graphql/src/translate/authorization/rules/create-authorization-filter-predicate.ts b/packages/graphql/src/translate/authorization/rules/create-authorization-filter-predicate.ts index 273a25adb2..c377b30086 100644 --- a/packages/graphql/src/translate/authorization/rules/create-authorization-filter-predicate.ts +++ b/packages/graphql/src/translate/authorization/rules/create-authorization-filter-predicate.ts @@ -20,11 +20,12 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node } from "../../../classes"; import type { AuthorizationFilterRule } from "../../../schema-model/annotation/AuthorizationAnnotation"; -import type { Context, PredicateReturn } from "../../../types"; +import type { PredicateReturn } from "../../../types"; import type { AuthorizationOperation } from "../../../types/authorization"; import { getOrCreateCypherNode } from "../../utils/get-or-create-cypher-variable"; import { createAuthorizationWherePredicate } from "../where/create-authorization-where-predicate"; import { findMatchingRules } from "../utils/find-matching-rules"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createAuthorizationFilterPredicate({ context, @@ -33,7 +34,7 @@ export function createAuthorizationFilterPredicate({ variable, operations, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; rules: AuthorizationFilterRule[]; variable: string | Cypher.Node; diff --git a/packages/graphql/src/translate/authorization/rules/create-authorization-validate-predicate.ts b/packages/graphql/src/translate/authorization/rules/create-authorization-validate-predicate.ts index ce9f42e0f0..41be2a8ebc 100644 --- a/packages/graphql/src/translate/authorization/rules/create-authorization-validate-predicate.ts +++ b/packages/graphql/src/translate/authorization/rules/create-authorization-validate-predicate.ts @@ -21,11 +21,12 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node } from "../../../classes"; import { AUTH_FORBIDDEN_ERROR } from "../../../constants"; import type { AuthorizationValidateRule } from "../../../schema-model/annotation/AuthorizationAnnotation"; -import type { Context, PredicateReturn } from "../../../types"; +import type { PredicateReturn } from "../../../types"; import type { AuthorizationOperation, AuthorizationValidateWhen } from "../../../types/authorization"; import { getOrCreateCypherNode } from "../../utils/get-or-create-cypher-variable"; import { createAuthorizationWherePredicate } from "../where/create-authorization-where-predicate"; import { findMatchingRules } from "../utils/find-matching-rules"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createAuthorizationValidatePredicate({ when, @@ -37,7 +38,7 @@ export function createAuthorizationValidatePredicate({ conditionForEvaluation, }: { when: AuthorizationValidateWhen; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; rules: AuthorizationValidateRule[]; variable: string | Cypher.Node; diff --git a/packages/graphql/src/translate/authorization/utils/apply-authentication.ts b/packages/graphql/src/translate/authorization/utils/apply-authentication.ts index ae2945c2ca..855d864363 100644 --- a/packages/graphql/src/translate/authorization/utils/apply-authentication.ts +++ b/packages/graphql/src/translate/authorization/utils/apply-authentication.ts @@ -20,10 +20,16 @@ import { Neo4jGraphQLError } from "../../../classes"; import { AUTHORIZATION_UNAUTHENTICATED } from "../../../constants"; import type { Annotation } from "../../../schema-model/annotation/Annotation"; -import type { Context } from "../../../types"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; import { filterByValues } from "./filter-by-values"; -export function applyAuthentication({ context, annotation }: { context: Context; annotation: Annotation }): void { +export function applyAuthentication({ + context, + annotation, +}: { + context: Neo4jGraphQLTranslationContext; + annotation: Annotation; +}): void { if (!context.authorization.isAuthenticated) { throw new Neo4jGraphQLError(AUTHORIZATION_UNAUTHENTICATED); } diff --git a/packages/graphql/src/translate/authorization/utils/populate-where-params.ts b/packages/graphql/src/translate/authorization/utils/populate-where-params.ts index e5f4a94f40..a6d366fd75 100644 --- a/packages/graphql/src/translate/authorization/utils/populate-where-params.ts +++ b/packages/graphql/src/translate/authorization/utils/populate-where-params.ts @@ -19,9 +19,16 @@ import Cypher from "@neo4j/cypher-builder"; import dotProp from "dot-prop"; -import type { Context, GraphQLWhereArg } from "../../../types"; +import type { GraphQLWhereArg } from "../../../types"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; -export function populateWhereParams({ where, context }: { where: GraphQLWhereArg; context: Context }): GraphQLWhereArg { +export function populateWhereParams({ + where, + context, +}: { + where: GraphQLWhereArg; + context: Neo4jGraphQLTranslationContext; +}): GraphQLWhereArg { const parsed: GraphQLWhereArg = {}; Object.entries(where).forEach(([k, v]) => { diff --git a/packages/graphql/src/translate/authorization/where/create-authorization-jwt-payload-predicate.ts b/packages/graphql/src/translate/authorization/where/create-authorization-jwt-payload-predicate.ts index 3ade894c3f..842361c114 100644 --- a/packages/graphql/src/translate/authorization/where/create-authorization-jwt-payload-predicate.ts +++ b/packages/graphql/src/translate/authorization/where/create-authorization-jwt-payload-predicate.ts @@ -18,19 +18,20 @@ */ import Cypher from "@neo4j/cypher-builder"; -import type { Context, GraphQLWhereArg } from "../../../types"; +import type { GraphQLWhereArg } from "../../../types"; import { asArray } from "../../../utils/utils"; import { getOrCreateCypherVariable } from "../../utils/get-or-create-cypher-variable"; import type { LogicalOperator } from "../../utils/logical-operators"; import { getLogicalPredicate, isLogicalOperator } from "../../utils/logical-operators"; import { createParameterWhere } from "../../where/create-parameter-where"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createJwtPayloadWherePredicate({ where, context, }: { where: GraphQLWhereArg; - context: Context; + context: Neo4jGraphQLTranslationContext; }): Cypher.Predicate | undefined { const fields = Object.entries(where); const predicates: Cypher.Predicate[] = []; @@ -70,7 +71,7 @@ function createNestedPredicate({ }: { key: LogicalOperator; value: Array; - context: Context; + context: Neo4jGraphQLTranslationContext; }): Cypher.Predicate | undefined { const nested: Cypher.Predicate[] = []; diff --git a/packages/graphql/src/translate/authorization/where/create-authorization-where-predicate.ts b/packages/graphql/src/translate/authorization/where/create-authorization-where-predicate.ts index 94745d0bd8..cb0005cfa5 100644 --- a/packages/graphql/src/translate/authorization/where/create-authorization-where-predicate.ts +++ b/packages/graphql/src/translate/authorization/where/create-authorization-where-predicate.ts @@ -20,13 +20,14 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node } from "../../../classes"; import type { AuthorizationWhere } from "../../../schema-model/annotation/AuthorizationAnnotation"; -import type { Context, GraphQLWhereArg, PredicateReturn } from "../../../types"; +import type { GraphQLWhereArg, PredicateReturn } from "../../../types"; import { asArray } from "../../../utils/utils"; import type { LogicalOperator } from "../../utils/logical-operators"; import { getLogicalPredicate, isLogicalOperator } from "../../utils/logical-operators"; import { createWherePredicate } from "../../where/create-where-predicate"; import { createJwtPayloadWherePredicate } from "./create-authorization-jwt-payload-predicate"; import { populateWhereParams } from "../utils/populate-where-params"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createAuthorizationWherePredicate({ where, @@ -35,7 +36,7 @@ export function createAuthorizationWherePredicate({ target, }: { where: AuthorizationWhere; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; target: Cypher.Variable; }): PredicateReturn { @@ -114,7 +115,7 @@ function createNestedPredicate({ target, }: { key: LogicalOperator; - context: Context; + context: Neo4jGraphQLTranslationContext; value: Array; node: Node; target: Cypher.Variable; diff --git a/packages/graphql/src/translate/batch-create/parser.ts b/packages/graphql/src/translate/batch-create/parser.ts index 4d24ed3766..5042a5f12e 100644 --- a/packages/graphql/src/translate/batch-create/parser.ts +++ b/packages/graphql/src/translate/batch-create/parser.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Context, RelationField } from "../../types"; +import type { RelationField } from "../../types"; import type { GraphQLCreateInput, TreeDescriptor } from "./types"; import { UnsupportedUnwindOptimization } from "./types"; import type { GraphElement, Node, Relationship } from "../../classes"; @@ -26,12 +26,12 @@ import Cypher from "@neo4j/cypher-builder"; import type { AST } from "./GraphQLInputAST/GraphQLInputAST"; import { CreateAST, NestedCreateAST } from "./GraphQLInputAST/GraphQLInputAST"; import mapToDbProperty from "../../utils/map-to-db-property"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; function getRelationshipFields( node: Node, key: string, - value: any, - context: Context + context: Neo4jGraphQLTranslationContext ): [RelationField | undefined, Node[]] { const relationField = node.relationFields.find((x) => key === x.fieldName); const refNodes: Node[] = []; @@ -49,7 +49,7 @@ function getRelationshipFields( export function inputTreeToCypherMap( input: GraphQLCreateInput[] | GraphQLCreateInput, node: Node, - context: Context, + context: Neo4jGraphQLTranslationContext, parentKey?: string, relationship?: Relationship ): Cypher.List | Cypher.Map { @@ -62,7 +62,7 @@ export function inputTreeToCypherMap( } const properties = (Object.entries(input) as GraphQLCreateInput).reduce( (obj: Record, [key, value]: [string, Record]) => { - const [relationField, relatedNodes] = getRelationshipFields(node, key, {}, context); + const [relationField, relatedNodes] = getRelationshipFields(node, key, context); if (relationField && relationField.properties) { relationship = context.relationships.find( (x) => x.properties === relationField.properties @@ -123,13 +123,13 @@ function isScalarOrEnum(fieldName: string, graphElement: GraphElement) { export function getTreeDescriptor( input: GraphQLCreateInput, node: Node, - context: Context, + context: Neo4jGraphQLTranslationContext, parentKey?: string, relationship?: Relationship ): TreeDescriptor { return Object.entries(input).reduce( (previous, [key, value]) => { - const [relationField, relatedNodes] = getRelationshipFields(node, key, value, context); + const [relationField, relatedNodes] = getRelationshipFields(node, key, context); if (relationField && relationField.properties) { relationship = context.relationships.find( (x) => x.properties === relationField.properties @@ -192,9 +192,9 @@ export function mergeTreeDescriptors(input: TreeDescriptor[]): TreeDescriptor { ); } -function parser(input: TreeDescriptor, node: Node, context: Context, parentASTNode: AST): AST { +function parser(input: TreeDescriptor, node: Node, context: Neo4jGraphQLTranslationContext, parentASTNode: AST): AST { Object.entries(input.children).forEach(([key, value]) => { - const [relationField, relatedNodes] = getRelationshipFields(node, key, {}, context); + const [relationField, relatedNodes] = getRelationshipFields(node, key, context); if (relationField) { let edge; @@ -266,7 +266,7 @@ function raiseOnNotSupportedProperty(graphElement: GraphElement) { }); } -export function parseCreate(input: TreeDescriptor, node: Node, context: Context) { +export function parseCreate(input: TreeDescriptor, node: Node, context: Neo4jGraphQLTranslationContext) { const nodeProperties = input.properties; raiseOnNotSupportedProperty(node); raiseAttributeAmbiguity(input.properties, node); @@ -278,7 +278,7 @@ export function parseCreate(input: TreeDescriptor, node: Node, context: Context) function parseNestedCreate( input: TreeDescriptor, node: Node, - context: Context, + context: Neo4jGraphQLTranslationContext, parentNode: Node, relationshipPropertyPath: string, relationship: [RelationField | undefined, Node[]], diff --git a/packages/graphql/src/translate/batch-create/unwind-create-visitors/UnwindCreateVisitor.ts b/packages/graphql/src/translate/batch-create/unwind-create-visitors/UnwindCreateVisitor.ts index 0273ee4298..9b27721c49 100644 --- a/packages/graphql/src/translate/batch-create/unwind-create-visitors/UnwindCreateVisitor.ts +++ b/packages/graphql/src/translate/batch-create/unwind-create-visitors/UnwindCreateVisitor.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Context, PredicateReturn, RelationField } from "../../../types"; +import type { PredicateReturn, RelationField } from "../../../types"; import type { CallbackBucket } from "../../../classes/CallbackBucket"; import type { Visitor, @@ -36,6 +36,7 @@ import mapToDbProperty from "../../../utils/map-to-db-property"; import { getCypherRelationshipDirection } from "../../../utils/get-relationship-direction"; import { createAuthorizationAfterPredicate } from "../../authorization/create-authorization-after-predicate"; import { checkAuthentication } from "../../authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; type UnwindCreateScopeDefinition = { unwindVar: Cypher.Variable; @@ -48,12 +49,12 @@ type UnwindCreateEnvironment = Record; diff --git a/packages/graphql/src/translate/connection-clause/create-connection-clause.ts b/packages/graphql/src/translate/connection-clause/create-connection-clause.ts index 560e2cb2fe..bc44f4885d 100644 --- a/packages/graphql/src/translate/connection-clause/create-connection-clause.ts +++ b/packages/graphql/src/translate/connection-clause/create-connection-clause.ts @@ -20,7 +20,7 @@ import type { Integer } from "neo4j-driver"; import type { ResolveTree } from "graphql-parse-resolve-info"; import Cypher from "@neo4j/cypher-builder"; -import type { ConnectionField, ConnectionWhereArg, Context, CypherFieldReferenceMap } from "../../types"; +import type { ConnectionField, ConnectionWhereArg, CypherFieldReferenceMap } from "../../types"; import type { Node } from "../../classes"; import { filterTruthy } from "../../utils/utils"; import { hasExplicitNodeInInterfaceWhere } from "../where/property-operations/create-connection-operation"; @@ -28,6 +28,7 @@ import { getOrCreateCypherNode } from "../utils/get-or-create-cypher-variable"; import { createSortAndLimitProjection } from "./create-sort-and-limit"; import { createEdgeSubquery } from "./create-edge-subquery"; import { checkAuthentication } from "../authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; export function createConnectionClause({ resolveTree, @@ -39,7 +40,7 @@ export function createConnectionClause({ }: { resolveTree: ResolveTree; field: ConnectionField; - context: Context; + context: Neo4jGraphQLTranslationContext; nodeVariable: Cypher.Node; returnVariable: Cypher.Variable; cypherFieldAliasMap: CypherFieldReferenceMap; @@ -121,7 +122,7 @@ function createConnectionClauseForUnions({ }: { resolveTree: ResolveTree; field: ConnectionField; - context: Context; + context: Neo4jGraphQLTranslationContext; nodeVariable: Cypher.Node; returnVariable: Cypher.Variable; cypherFieldAliasMap: CypherFieldReferenceMap; @@ -206,7 +207,7 @@ function createConnectionSubquery({ }: { resolveTree: ResolveTree; field: ConnectionField; - context: Context; + context: Neo4jGraphQLTranslationContext; parentNode: Cypher.Node; relatedNode: Node; returnVariable: Cypher.Variable; diff --git a/packages/graphql/src/translate/connection-clause/create-edge-subquery.ts b/packages/graphql/src/translate/connection-clause/create-edge-subquery.ts index 6499b07351..d7922aa9af 100644 --- a/packages/graphql/src/translate/connection-clause/create-edge-subquery.ts +++ b/packages/graphql/src/translate/connection-clause/create-edge-subquery.ts @@ -18,7 +18,7 @@ */ import type { ResolveTree } from "graphql-parse-resolve-info"; -import type { ConnectionField, ConnectionWhereArg, Context, CypherFieldReferenceMap } from "../../types"; +import type { ConnectionField, ConnectionWhereArg, CypherFieldReferenceMap } from "../../types"; import type { Node } from "../../classes"; import type Relationship from "../../classes/Relationship"; import Cypher from "@neo4j/cypher-builder"; @@ -29,6 +29,7 @@ import { getEdgeSortFieldKeys } from "./get-sort-fields"; import { createSortAndLimitProjection } from "./create-sort-and-limit"; import { getCypherRelationshipDirection } from "../../utils/get-relationship-direction"; import { createAuthorizationBeforePredicate } from "../authorization/create-authorization-before-predicate"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; /** Create the match, filtering and projection of the edge and the nested node */ export function createEdgeSubquery({ @@ -45,7 +46,7 @@ export function createEdgeSubquery({ }: { resolveTree: ResolveTree; field: ConnectionField; - context: Context; + context: Neo4jGraphQLTranslationContext; parentNode: Cypher.Node; relatedNode: Node; returnVariable: Cypher.Variable; diff --git a/packages/graphql/src/translate/create-aggregate-where-and-params.ts b/packages/graphql/src/translate/create-aggregate-where-and-params.ts index d8069d8374..cedfa441b2 100644 --- a/packages/graphql/src/translate/create-aggregate-where-and-params.ts +++ b/packages/graphql/src/translate/create-aggregate-where-and-params.ts @@ -19,7 +19,7 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node, Relationship } from "../classes"; -import type { RelationField, Context, GraphQLWhereArg, PredicateReturn } from "../types"; +import type { RelationField, GraphQLWhereArg, PredicateReturn } from "../types"; import type { AggregationFieldRegexGroups } from "./where/utils"; import { aggregationFieldRegEx, whereRegEx } from "./where/utils"; import { @@ -31,6 +31,7 @@ import { isLogicalOperator, getLogicalPredicate } from "./utils/logical-operator import mapToDbProperty from "../utils/map-to-db-property"; import { asArray } from "../utils/utils"; import { getCypherRelationshipDirection } from "../utils/get-relationship-direction"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; type WhereFilter = Record; @@ -54,7 +55,7 @@ export function aggregatePreComputedWhereFields({ value: GraphQLWhereArg; relationField: RelationField; relationship: Relationship | undefined; - context: Context; + context: Neo4jGraphQLTranslationContext; matchNode: Cypher.Variable; }): PredicateReturn { const refNode = context.nodes.find((x) => x.name === relationField.typeMeta.name) as Node; diff --git a/packages/graphql/src/translate/create-connect-and-params.ts b/packages/graphql/src/translate/create-connect-and-params.ts index 403567e22b..cef0dee0f7 100644 --- a/packages/graphql/src/translate/create-connect-and-params.ts +++ b/packages/graphql/src/translate/create-connect-and-params.ts @@ -18,7 +18,7 @@ */ import type { Node, Relationship } from "../classes"; -import type { RelationField, Context } from "../types"; +import type { RelationField } from "../types"; import createWhereAndParams from "./where/create-where-and-params"; import createSetRelationshipPropertiesAndParams from "./create-set-relationship-properties-and-params"; import createRelationshipValidationString from "./create-relationship-validation-string"; @@ -30,6 +30,7 @@ import { caseWhere } from "../utils/case-where"; import { createAuthorizationBeforeAndParams } from "./authorization/compatibility/create-authorization-before-and-params"; import { createAuthorizationAfterAndParams } from "./authorization/compatibility/create-authorization-after-and-params"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { connects: string[]; @@ -55,7 +56,7 @@ function createConnectAndParams({ varName: string; relationField: RelationField; parentVar: string; - context: Context; + context: Neo4jGraphQLTranslationContext; callbackBucket: CallbackBucket; refNodes: Node[]; labelOverride?: string; diff --git a/packages/graphql/src/translate/create-connect-or-create-and-params.ts b/packages/graphql/src/translate/create-connect-or-create-and-params.ts index 1a7292a2fe..f22569b350 100644 --- a/packages/graphql/src/translate/create-connect-or-create-and-params.ts +++ b/packages/graphql/src/translate/create-connect-or-create-and-params.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { RelationField, Context, PrimitiveField, PredicateReturn } from "../types"; +import type { RelationField, PrimitiveField, PredicateReturn } from "../types"; import type { Node, Relationship } from "../classes"; import { Neo4jGraphQLError } from "../classes"; import type { CallbackBucket } from "../classes/CallbackBucket"; @@ -32,6 +32,7 @@ import { createAuthorizationBeforePredicate } from "./authorization/create-autho import { createAuthorizationAfterPredicate } from "./authorization/create-authorization-after-predicate"; import { checkAuthentication } from "./authorization/check-authentication"; import { compileCypher } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; type CreateOrConnectInput = { where?: { @@ -60,7 +61,7 @@ export function createConnectOrCreateAndParams({ relationField: RelationField; refNode: Node; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; withVars: string[]; callbackBucket: CallbackBucket; }): Cypher.CypherResult { @@ -141,7 +142,7 @@ function createConnectOrCreatePartialStatement({ relationField: RelationField; refNode: Node; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; callbackBucket: CallbackBucket; withVars: string[]; }): Cypher.Clause { @@ -222,7 +223,7 @@ function mergeStatement({ input: CreateOrConnectInput; refNode: Node; parentRefNode: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; relationField: RelationField; parentNode: Cypher.Node; varName: string; @@ -318,7 +319,7 @@ function createAuthorizationBeforeConnectOrCreate({ sourceNode, sourceName, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; sourceNode: Node; sourceName: string; targetNode: Node; @@ -363,7 +364,7 @@ function createAuthorizationAfterConnectOrCreate({ targetNode, targetName, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; sourceNode: Node; sourceName: string; targetNode: Node; diff --git a/packages/graphql/src/translate/create-create-and-params.ts b/packages/graphql/src/translate/create-create-and-params.ts index e8e0022f0a..5b0220d04a 100644 --- a/packages/graphql/src/translate/create-create-and-params.ts +++ b/packages/graphql/src/translate/create-create-and-params.ts @@ -20,7 +20,6 @@ import type { Node, Relationship } from "../classes"; import { Neo4jGraphQLError } from "../classes/Error"; import type { CallbackBucket } from "../classes/CallbackBucket"; -import type { Context } from "../types"; import createConnectAndParams from "./create-connect-and-params"; import createSetRelationshipPropertiesAndParams from "./create-set-relationship-properties-and-params"; import mapToDbProperty from "../utils/map-to-db-property"; @@ -33,6 +32,7 @@ import { addCallbackAndSetParam } from "./utils/callback-utils"; import { findConflictingProperties } from "../utils/is-property-clash"; import { createAuthorizationAfterAndParams } from "./authorization/compatibility/create-authorization-after-and-params"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { creates: string[]; @@ -59,7 +59,7 @@ function createCreateAndParams({ input: any; varName: string; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; callbackBucket: CallbackBucket; withVars: string[]; includeRelationshipValidation?: boolean; diff --git a/packages/graphql/src/translate/create-delete-and-params.ts b/packages/graphql/src/translate/create-delete-and-params.ts index 6e582bc960..c2840fbd14 100644 --- a/packages/graphql/src/translate/create-delete-and-params.ts +++ b/packages/graphql/src/translate/create-delete-and-params.ts @@ -18,7 +18,6 @@ */ import type { Node, Relationship } from "../classes"; -import type { Context } from "../types"; import createConnectionWhereAndParams from "./where/create-connection-where-and-params"; import { META_CYPHER_VARIABLE } from "../constants"; import { createEventMetaObject } from "./subscriptions/create-event-meta"; @@ -28,6 +27,7 @@ import Cypher from "@neo4j/cypher-builder"; import { caseWhere } from "../utils/case-where"; import { createAuthorizationBeforeAndParams } from "./authorization/compatibility/create-authorization-before-and-params"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { strs: string[]; @@ -51,7 +51,7 @@ function createDeleteAndParams({ chainStr?: string; node: Node; withVars: string[]; - context: Context; + context: Neo4jGraphQLTranslationContext; parameterPrefix: string; recursing?: boolean; }): [string, any] { diff --git a/packages/graphql/src/translate/create-disconnect-and-params.ts b/packages/graphql/src/translate/create-disconnect-and-params.ts index 341543060e..f147b7dc70 100644 --- a/packages/graphql/src/translate/create-disconnect-and-params.ts +++ b/packages/graphql/src/translate/create-disconnect-and-params.ts @@ -18,7 +18,7 @@ */ import type { Node, Relationship } from "../classes"; -import type { RelationField, Context } from "../types"; +import type { RelationField } from "../types"; import createConnectionWhereAndParams from "./where/create-connection-where-and-params"; import { createConnectionEventMetaObject } from "./subscriptions/create-connection-event-meta"; import { filterMetaVariable } from "./subscriptions/filter-meta-variable"; @@ -27,6 +27,7 @@ import { caseWhere } from "../utils/case-where"; import { createAuthorizationBeforeAndParams } from "./authorization/compatibility/create-authorization-before-and-params"; import { createAuthorizationAfterAndParams } from "./authorization/compatibility/create-authorization-after-and-params"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { disconnects: string[]; @@ -51,7 +52,7 @@ function createDisconnectAndParams({ varName: string; relationField: RelationField; parentVar: string; - context: Context; + context: Neo4jGraphQLTranslationContext; refNodes: Node[]; labelOverride?: string; parentNode: Node; diff --git a/packages/graphql/src/translate/create-projection-and-params.ts b/packages/graphql/src/translate/create-projection-and-params.ts index 47c7d2909b..efef4e431a 100644 --- a/packages/graphql/src/translate/create-projection-and-params.ts +++ b/packages/graphql/src/translate/create-projection-and-params.ts @@ -21,7 +21,7 @@ import type { ResolveTree } from "graphql-parse-resolve-info"; import { mergeDeep } from "@graphql-tools/utils"; import Cypher from "@neo4j/cypher-builder"; import type { Node } from "../classes"; -import type { GraphQLOptionsArg, GraphQLWhereArg, Context, GraphQLSortArg, CypherFieldReferenceMap } from "../types"; +import type { GraphQLOptionsArg, GraphQLWhereArg, GraphQLSortArg, CypherFieldReferenceMap } from "../types"; import { createDatetimeExpression } from "./projection/elements/create-datetime-element"; import { createPointExpression } from "./projection/elements/create-point-element"; import mapToDbProperty from "../utils/map-to-db-property"; @@ -37,6 +37,7 @@ import { translateCypherDirectiveProjection } from "./projection/subquery/transl import { createAuthorizationBeforePredicate } from "./authorization/create-authorization-before-predicate"; import { checkAuthentication } from "./authorization/check-authentication"; import { compileCypher } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { projection: Cypher.Expr[]; @@ -69,7 +70,7 @@ export default function createProjectionAndParams({ }: { resolveTree: ResolveTree; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; varName: Cypher.Node; literalElements?: boolean; resolveType?: boolean; @@ -481,7 +482,7 @@ function createFulltextProjection({ }: { resolveTree: ResolveTree; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; varName: Cypher.Node; literalElements?: boolean; resolveType?: boolean; diff --git a/packages/graphql/src/translate/create-relationship-validation-string.ts b/packages/graphql/src/translate/create-relationship-validation-string.ts index 280a86da26..08c8b87975 100644 --- a/packages/graphql/src/translate/create-relationship-validation-string.ts +++ b/packages/graphql/src/translate/create-relationship-validation-string.ts @@ -19,7 +19,7 @@ import type { Node } from "../classes"; import { RELATIONSHIP_REQUIREMENT_PREFIX } from "../constants"; -import type { Context } from "../types"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; function createRelationshipValidationString({ node, @@ -28,7 +28,7 @@ function createRelationshipValidationString({ relationshipFieldNotOverwritable, }: { node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; varName: string; relationshipFieldNotOverwritable?: string; }): string { diff --git a/packages/graphql/src/translate/create-update-and-params.ts b/packages/graphql/src/translate/create-update-and-params.ts index 24eac4dd87..a3ad2d5f70 100644 --- a/packages/graphql/src/translate/create-update-and-params.ts +++ b/packages/graphql/src/translate/create-update-and-params.ts @@ -20,7 +20,7 @@ import pluralize from "pluralize"; import type { Node, Relationship } from "../classes"; import { Neo4jGraphQLError } from "../classes"; -import type { BaseField, Context } from "../types"; +import type { BaseField } from "../types"; import createConnectAndParams from "./create-connect-and-params"; import createDisconnectAndParams from "./create-disconnect-and-params"; import createCreateAndParams from "./create-create-and-params"; @@ -45,6 +45,7 @@ import { caseWhere } from "../utils/case-where"; import { createAuthorizationBeforeAndParams } from "./authorization/compatibility/create-authorization-before-and-params"; import { createAuthorizationAfterAndParams } from "./authorization/compatibility/create-authorization-after-and-params"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; interface Res { strs: string[]; @@ -78,7 +79,7 @@ export default function createUpdateAndParams({ chainStr?: string; node: Node; withVars: string[]; - context: Context; + context: Neo4jGraphQLTranslationContext; callbackBucket: CallbackBucket; parameterPrefix: string; includeRelationshipValidation?: boolean; diff --git a/packages/graphql/src/translate/field-aggregations/create-field-aggregation.ts b/packages/graphql/src/translate/field-aggregations/create-field-aggregation.ts index 130826fd5c..6e1a459391 100644 --- a/packages/graphql/src/translate/field-aggregations/create-field-aggregation.ts +++ b/packages/graphql/src/translate/field-aggregations/create-field-aggregation.ts @@ -19,7 +19,7 @@ import type { ResolveTree } from "graphql-parse-resolve-info"; import type { GraphElement, Node } from "../../classes"; -import type { Context, GraphQLWhereArg } from "../../types"; +import type { GraphQLWhereArg } from "../../types"; import { getFieldType, AggregationType, getReferenceNode, getFieldByName, getReferenceRelation } from "./utils"; import * as AggregationSubQueries from "./aggregation-sub-queries"; import { createFieldAggregationAuth } from "./field-aggregations-auth"; @@ -31,6 +31,7 @@ import { getCypherRelationshipDirection } from "../../utils/get-relationship-dir import Cypher from "@neo4j/cypher-builder"; import { createWherePredicate } from "../where/create-where-predicate"; import { checkAuthentication } from "../authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; type AggregationFields = { count?: ResolveTree; @@ -44,7 +45,7 @@ export function createFieldAggregation({ node, field, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; nodeVar: Cypher.Node; node: Node; field: ResolveTree; diff --git a/packages/graphql/src/translate/field-aggregations/field-aggregations-auth.ts b/packages/graphql/src/translate/field-aggregations/field-aggregations-auth.ts index aca9fb82e4..82aa1973c1 100644 --- a/packages/graphql/src/translate/field-aggregations/field-aggregations-auth.ts +++ b/packages/graphql/src/translate/field-aggregations/field-aggregations-auth.ts @@ -17,10 +17,11 @@ * limitations under the License. */ -import type { Context, PredicateReturn } from "../../types"; +import type { PredicateReturn } from "../../types"; import type { Node } from "../../classes"; import Cypher from "@neo4j/cypher-builder"; import { createAuthorizationBeforePredicate } from "../authorization/create-authorization-before-predicate"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; export type AggregationAuth = { params: Record; @@ -33,7 +34,7 @@ export function createFieldAggregationAuth({ subqueryNodeAlias, }: { node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; subqueryNodeAlias: Cypher.Node; }): PredicateReturn | undefined { const authPredicates: Cypher.Predicate[] = []; diff --git a/packages/graphql/src/translate/field-aggregations/utils.ts b/packages/graphql/src/translate/field-aggregations/utils.ts index 8dd6981821..d1217a3383 100644 --- a/packages/graphql/src/translate/field-aggregations/utils.ts +++ b/packages/graphql/src/translate/field-aggregations/utils.ts @@ -19,7 +19,8 @@ import type { ResolveTree } from "graphql-parse-resolve-info"; import type { Node, Relationship } from "../../classes"; -import type { Context, RelationField, ConnectionField } from "../../types"; +import type { RelationField, ConnectionField } from "../../types"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; export enum AggregationType { Int = "IntAggregateSelection", @@ -41,11 +42,17 @@ export function getFieldType(field: ResolveTree): AggregationType | undefined { return undefined; } -export function getReferenceNode(context: Context, relationField: RelationField): Node | undefined { +export function getReferenceNode( + context: Neo4jGraphQLTranslationContext, + relationField: RelationField +): Node | undefined { return context.nodes.find((x) => x.name === relationField.typeMeta.name); } -export function getReferenceRelation(context: Context, connectionField: ConnectionField): Relationship | undefined { +export function getReferenceRelation( + context: Neo4jGraphQLTranslationContext, + connectionField: ConnectionField +): Relationship | undefined { return context.relationships.find((x) => x.name === connectionField.relationshipTypeName); } diff --git a/packages/graphql/src/translate/projection/subquery/create-projection-subquery.ts b/packages/graphql/src/translate/projection/subquery/create-projection-subquery.ts index 003af1378f..52b4532cff 100644 --- a/packages/graphql/src/translate/projection/subquery/create-projection-subquery.ts +++ b/packages/graphql/src/translate/projection/subquery/create-projection-subquery.ts @@ -18,13 +18,14 @@ */ import type { Node } from "../../../classes"; -import type { Context, GraphQLOptionsArg, GraphQLWhereArg, RelationField } from "../../../types"; +import type { GraphQLOptionsArg, GraphQLWhereArg, RelationField } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; import { createWherePredicate } from "../../where/create-where-predicate"; import type { CypherRelationshipDirection } from "../../../utils/get-relationship-direction"; import { addSortAndLimitOptionsToClause } from "./add-sort-and-limit-to-clause"; import { createAuthorizationBeforePredicate } from "../../authorization/create-authorization-before-predicate"; import { compileCypher } from "../../../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createProjectionSubquery({ parentNode, @@ -45,7 +46,7 @@ export function createProjectionSubquery({ parentNode: Cypher.Node; whereInput?: GraphQLWhereArg; node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; nestedProjection: Cypher.Expr; nestedSubqueries: Cypher.Clause[]; targetNode: Cypher.Node; diff --git a/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts b/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts index cfaab5a49a..f332571a63 100644 --- a/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts +++ b/packages/graphql/src/translate/projection/subquery/translate-cypher-directive-projection.ts @@ -19,11 +19,12 @@ import type { ResolveTree } from "graphql-parse-resolve-info"; import type { Node } from "../../../classes"; -import type { GraphQLSortArg, Context, CypherField, CypherFieldReferenceMap } from "../../../types"; +import type { GraphQLSortArg, CypherField, CypherFieldReferenceMap } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; import createProjectionAndParams from "../../create-projection-and-params"; import { CompositeEntity } from "../../../schema-model/entity/CompositeEntity"; import { compileCypher } from "../../../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; interface Res { projection: Cypher.Expr[]; @@ -43,7 +44,7 @@ export function translateCypherDirectiveProjection({ res, cypherFieldAliasMap, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; cypherField: CypherField; field: ResolveTree; node: Node; diff --git a/packages/graphql/src/translate/translate-aggregate.ts b/packages/graphql/src/translate/translate-aggregate.ts index f509f09a08..78c8a01e73 100644 --- a/packages/graphql/src/translate/translate-aggregate.ts +++ b/packages/graphql/src/translate/translate-aggregate.ts @@ -19,13 +19,20 @@ import Cypher from "@neo4j/cypher-builder"; import type { Node } from "../classes"; -import type { BaseField, Context, GraphQLWhereArg, PrimitiveField, TemporalField } from "../types"; +import type { BaseField, GraphQLWhereArg, PrimitiveField, TemporalField } from "../types"; import { createAuthorizationBeforePredicate } from "./authorization/create-authorization-before-predicate"; import { createDatetimeElement } from "./projection/elements/create-datetime-element"; import { translateTopLevelMatch } from "./translate-top-level-match"; import { compileCypher } from "../utils/compile-cypher"; - -function translateAggregate({ node, context }: { node: Node; context: Context }): [Cypher.Clause, any] { +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; + +function translateAggregate({ + node, + context, +}: { + node: Node; + context: Neo4jGraphQLTranslationContext; +}): [Cypher.Clause, any] { const { fieldsByTypeName } = context.resolveTree; const varName = "this"; let cypherParams: Record = context.cypherParams ? { ...context.cypherParams } : {}; diff --git a/packages/graphql/src/translate/translate-create.ts b/packages/graphql/src/translate/translate-create.ts index 8e150e346e..f09af684b7 100644 --- a/packages/graphql/src/translate/translate-create.ts +++ b/packages/graphql/src/translate/translate-create.ts @@ -20,7 +20,6 @@ import type { Node } from "../classes"; import createProjectionAndParams from "./create-projection-and-params"; import createCreateAndParams from "./create-create-and-params"; -import type { Context } from "../types"; import { META_CYPHER_VARIABLE } from "../constants"; import { filterTruthy } from "../utils/utils"; import { CallbackBucket } from "../classes/CallbackBucket"; @@ -29,6 +28,7 @@ import unwindCreate from "./unwind-create"; import { UnsupportedUnwindOptimization } from "./batch-create/types"; import type { ResolveTree } from "graphql-parse-resolve-info"; import { compileCypher, compileCypherIfExists } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; type ProjectionAndParamsResult = { projection: Cypher.Expr; @@ -46,7 +46,7 @@ export default async function translateCreate({ context, node, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; }): Promise<{ cypher: string; params: Record }> { const { resolveTree } = context; diff --git a/packages/graphql/src/translate/translate-delete.ts b/packages/graphql/src/translate/translate-delete.ts index bfd5c9e94a..d9188c07c2 100644 --- a/packages/graphql/src/translate/translate-delete.ts +++ b/packages/graphql/src/translate/translate-delete.ts @@ -18,7 +18,7 @@ */ import type { Node } from "../classes"; -import type { Context, GraphQLWhereArg } from "../types"; +import type { GraphQLWhereArg } from "../types"; import { META_CYPHER_VARIABLE } from "../constants"; import createDeleteAndParams from "./create-delete-and-params"; import { translateTopLevelMatch } from "./translate-top-level-match"; @@ -26,8 +26,15 @@ import { createEventMeta } from "./subscriptions/create-event-meta"; import Cypher from "@neo4j/cypher-builder"; import { createConnectionEventMetaObject } from "./subscriptions/create-connection-event-meta"; import { checkAuthentication } from "./authorization/check-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; -export function translateDelete({ context, node }: { context: Context; node: Node }): Cypher.CypherResult { +export function translateDelete({ + context, + node, +}: { + context: Neo4jGraphQLTranslationContext; + node: Node; +}): Cypher.CypherResult { const { resolveTree } = context; const deleteInput = resolveTree.args.delete; const varName = "this"; @@ -92,7 +99,7 @@ export function translateDelete({ context, node }: { context: Context; node: Nod return result; } -function getDeleteReturn(context: Context): Array { +function getDeleteReturn(context: Neo4jGraphQLTranslationContext): Array { return context.subscriptionsEnabled ? [ `WITH collect(${META_CYPHER_VARIABLE}) AS ${META_CYPHER_VARIABLE}`, diff --git a/packages/graphql/src/translate/translate-read.ts b/packages/graphql/src/translate/translate-read.ts index cca4fc5f96..35f128e645 100644 --- a/packages/graphql/src/translate/translate-read.ts +++ b/packages/graphql/src/translate/translate-read.ts @@ -20,12 +20,13 @@ import { cursorToOffset } from "graphql-relay"; import type { Node } from "../classes"; import createProjectionAndParams from "./create-projection-and-params"; -import type { GraphQLOptionsArg, Context, GraphQLWhereArg, CypherFieldReferenceMap } from "../types"; +import type { GraphQLOptionsArg, GraphQLWhereArg, CypherFieldReferenceMap } from "../types"; import { createMatchClause } from "./translate-top-level-match"; import Cypher from "@neo4j/cypher-builder"; import { addSortAndLimitOptionsToClause } from "./projection/subquery/add-sort-and-limit-to-clause"; import { SCORE_FIELD } from "../graphql/directives/fulltext"; import { compileCypher } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export function translateRead( { @@ -33,7 +34,7 @@ export function translateRead( context, isRootConnectionField, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; isRootConnectionField?: boolean; }, diff --git a/packages/graphql/src/translate/translate-resolve-reference.ts b/packages/graphql/src/translate/translate-resolve-reference.ts index 205e89dad1..d7d237c006 100644 --- a/packages/graphql/src/translate/translate-resolve-reference.ts +++ b/packages/graphql/src/translate/translate-resolve-reference.ts @@ -19,17 +19,17 @@ import type { Node } from "../classes"; import createProjectionAndParams from "./create-projection-and-params"; -import type { Context } from "../types"; import { createMatchClause } from "./translate-top-level-match"; import Cypher from "@neo4j/cypher-builder"; import { compileCypher } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export function translateResolveReference({ node, context, reference, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; reference: any; }): Cypher.CypherResult { diff --git a/packages/graphql/src/translate/translate-top-level-cypher.ts b/packages/graphql/src/translate/translate-top-level-cypher.ts index 3bf4a6373b..6760e624b8 100644 --- a/packages/graphql/src/translate/translate-top-level-cypher.ts +++ b/packages/graphql/src/translate/translate-top-level-cypher.ts @@ -17,28 +17,25 @@ * limitations under the License. */ -import type { GraphQLResolveInfo } from "graphql"; import createProjectionAndParams from "./create-projection-and-params"; -import type { Context, CypherField } from "../types"; +import type { CypherField } from "../types"; import { AUTH_FORBIDDEN_ERROR, AUTHORIZATION_UNAUTHENTICATED } from "../constants"; import Cypher from "@neo4j/cypher-builder"; -import getNeo4jResolveTree from "../utils/get-neo4j-resolve-tree"; import { CompositeEntity } from "../schema-model/entity/CompositeEntity"; import { Neo4jGraphQLError } from "../classes"; import { filterByValues } from "./authorization/utils/filter-by-values"; import { compileCypher } from "../utils/compile-cypher"; import { applyAuthentication } from "./authorization/utils/apply-authentication"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export function translateTopLevelCypher({ context, - info, field, args, type, statement, }: { - context: Context; - info: GraphQLResolveInfo; + context: Neo4jGraphQLTranslationContext; field: CypherField; args: any; statement: string; @@ -66,7 +63,6 @@ export function translateTopLevelCypher({ } } - context.resolveTree = getNeo4jResolveTree(info); const { resolveTree } = context; let params = { ...args, diff --git a/packages/graphql/src/translate/translate-top-level-match.ts b/packages/graphql/src/translate/translate-top-level-match.ts index e1107a69a2..7af4aa8606 100644 --- a/packages/graphql/src/translate/translate-top-level-match.ts +++ b/packages/graphql/src/translate/translate-top-level-match.ts @@ -17,13 +17,14 @@ * limitations under the License. */ -import type { Context, GraphQLWhereArg } from "../types"; +import type { GraphQLWhereArg } from "../types"; import type { Node } from "../classes"; import Cypher from "@neo4j/cypher-builder"; import { createWherePredicate } from "./where/create-where-predicate"; import { SCORE_FIELD } from "../graphql/directives/fulltext"; import { createAuthorizationBeforePredicate } from "./authorization/create-authorization-before-predicate"; import type { AuthorizationOperation } from "../types/authorization"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export function translateTopLevelMatch({ matchNode, @@ -33,7 +34,7 @@ export function translateTopLevelMatch({ where, }: { matchNode: Cypher.Node; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; operation: AuthorizationOperation; where: GraphQLWhereArg | undefined; @@ -63,7 +64,7 @@ export function createMatchClause({ where, }: { matchNode: Cypher.Node; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; operation: AuthorizationOperation; where: GraphQLWhereArg | undefined; @@ -167,7 +168,7 @@ function createFulltextMatchClause( matchNode: Cypher.Node, whereInput: GraphQLWhereArg | undefined, node: Node, - context: Context + context: Neo4jGraphQLTranslationContext ): { matchClause: Cypher.Yield; whereOperators: Cypher.Predicate[]; diff --git a/packages/graphql/src/translate/translate-update.ts b/packages/graphql/src/translate/translate-update.ts index 00194c3fac..ea56925d52 100644 --- a/packages/graphql/src/translate/translate-update.ts +++ b/packages/graphql/src/translate/translate-update.ts @@ -18,7 +18,7 @@ */ import type { Node, Relationship } from "../classes"; -import type { Context, CypherFieldReferenceMap, GraphQLWhereArg, RelationField } from "../types"; +import type { CypherFieldReferenceMap, GraphQLWhereArg, RelationField } from "../types"; import createProjectionAndParams from "./create-projection-and-params"; import createCreateAndParams from "./create-create-and-params"; import createUpdateAndParams from "./create-update-and-params"; @@ -35,13 +35,14 @@ import Cypher from "@neo4j/cypher-builder"; import { createConnectionEventMeta } from "../translate/subscriptions/create-connection-event-meta"; import { filterMetaVariable } from "../translate/subscriptions/filter-meta-variable"; import { compileCypher } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export default async function translateUpdate({ node, context, }: { node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; }): Promise<[string, any]> { const { resolveTree } = context; const updateInput = resolveTree.args.update; diff --git a/packages/graphql/src/translate/unwind-create.ts b/packages/graphql/src/translate/unwind-create.ts index 1ba180c2be..2c9d3c6e20 100644 --- a/packages/graphql/src/translate/unwind-create.ts +++ b/packages/graphql/src/translate/unwind-create.ts @@ -18,7 +18,6 @@ */ import type { Node } from "../classes"; -import type { Context } from "../types"; import type { GraphQLCreateInput } from "./batch-create/types"; import { UnsupportedUnwindOptimization } from "./batch-create/types"; import { mergeTreeDescriptors, getTreeDescriptor, parseCreate } from "./batch-create/parser"; @@ -29,12 +28,13 @@ import { filterTruthy } from "../utils/utils"; import { CallbackBucket } from "../classes/CallbackBucket"; import Cypher from "@neo4j/cypher-builder"; import { compileCypher, compileCypherIfExists } from "../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../types/neo4j-graphql-translation-context"; export default async function unwindCreate({ context, node, }: { - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; }): Promise<{ cypher: string; params: Record }> { if (context.subscriptionsEnabled) { diff --git a/packages/graphql/src/translate/where/create-connection-where-and-params.ts b/packages/graphql/src/translate/where/create-connection-where-and-params.ts index ebb47e26f8..23fca8ba26 100644 --- a/packages/graphql/src/translate/where/create-connection-where-and-params.ts +++ b/packages/graphql/src/translate/where/create-connection-where-and-params.ts @@ -18,10 +18,11 @@ */ import type { Node, Relationship } from "../../classes"; -import type { ConnectionWhereArg, Context } from "../../types"; +import type { ConnectionWhereArg } from "../../types"; import Cypher from "@neo4j/cypher-builder"; import { createConnectionWherePropertyOperation } from "./property-operations/create-connection-operation"; import { compileCypher } from "../../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; export default function createConnectionWhereAndParams({ whereInput, @@ -33,7 +34,7 @@ export default function createConnectionWhereAndParams({ parameterPrefix, }: { whereInput: ConnectionWhereArg; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; nodeVariable: string; relationship: Relationship; diff --git a/packages/graphql/src/translate/where/create-parameter-where.ts b/packages/graphql/src/translate/where/create-parameter-where.ts index cc7f4615c0..8b0c79305b 100644 --- a/packages/graphql/src/translate/where/create-parameter-where.ts +++ b/packages/graphql/src/translate/where/create-parameter-where.ts @@ -21,7 +21,7 @@ import Cypher from "@neo4j/cypher-builder"; import type { WhereRegexGroups } from "./utils"; import { whereRegEx } from "./utils"; import { createBaseOperation } from "./property-operations/create-comparison-operation"; -import type { Context } from "../../types"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; /** Translates a property into its predicate filter */ export function createParameterWhere({ @@ -31,7 +31,7 @@ export function createParameterWhere({ }: { key: string; value: any; - context: Context; + context: Neo4jGraphQLTranslationContext; }): Cypher.Predicate | undefined { const match = whereRegEx.exec(key); if (!match) { diff --git a/packages/graphql/src/translate/where/create-where-and-params.ts b/packages/graphql/src/translate/where/create-where-and-params.ts index 695eaa814c..8dcb007edd 100644 --- a/packages/graphql/src/translate/where/create-where-and-params.ts +++ b/packages/graphql/src/translate/where/create-where-and-params.ts @@ -17,11 +17,12 @@ * limitations under the License. */ -import type { GraphQLWhereArg, Context } from "../../types"; +import type { GraphQLWhereArg } from "../../types"; import type { Node } from "../../classes"; import { createWherePredicate } from "./create-where-predicate"; import Cypher from "@neo4j/cypher-builder"; import { compileCypherIfExists } from "../../utils/compile-cypher"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; // TODO: Remove this method and replace for directly using createWherePredicate /** Wraps createCypherWhereParams with the old interface for compatibility with old way of composing cypher */ @@ -34,7 +35,7 @@ export default function createWhereAndParams({ recursing, }: { node: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; whereInput: GraphQLWhereArg; varName: string; chainStr?: string; diff --git a/packages/graphql/src/translate/where/create-where-predicate.ts b/packages/graphql/src/translate/where/create-where-predicate.ts index 98b6844c82..767731d45f 100644 --- a/packages/graphql/src/translate/where/create-where-predicate.ts +++ b/packages/graphql/src/translate/where/create-where-predicate.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { GraphQLWhereArg, Context, PredicateReturn } from "../../types"; +import type { GraphQLWhereArg, PredicateReturn } from "../../types"; import type { GraphElement } from "../../classes"; import Cypher from "@neo4j/cypher-builder"; // Recursive function @@ -25,6 +25,7 @@ import { createPropertyWhere } from "./property-operations/create-property-where import type { LogicalOperator } from "../utils/logical-operators"; import { isLogicalOperator, getLogicalPredicate } from "../utils/logical-operators"; import { asArray, filterTruthy } from "../../utils/utils"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; /** Translate a target node and GraphQL input into a Cypher operation or valid where expression */ export function createWherePredicate({ @@ -37,7 +38,7 @@ export function createWherePredicate({ }: { targetElement: Cypher.Variable; whereInput: GraphQLWhereArg; - context: Context; + context: Neo4jGraphQLTranslationContext; element: GraphElement; useExistExpr?: boolean; checkParameterExistence?: boolean; @@ -98,7 +99,7 @@ function createNestedPredicate({ key: LogicalOperator; element: GraphElement; targetElement: Cypher.Variable; - context: Context; + context: Neo4jGraphQLTranslationContext; value: Array; useExistExpr?: boolean; checkParameterExistence?: boolean; diff --git a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts index 8658770857..f8aeb606ef 100644 --- a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts +++ b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts @@ -28,6 +28,7 @@ import { asArray, filterTruthy } from "../../../utils/utils"; import { getLogicalPredicate, isLogicalOperator } from "../../utils/logical-operators"; import { createRelationPredicate } from "./create-relationship-operation"; import { getCypherRelationshipDirection } from "../../../utils/get-relationship-direction"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createConnectionOperation({ connectionField, @@ -40,7 +41,7 @@ export function createConnectionOperation({ }: { connectionField: ConnectionField; value: any; - context: Context; + context: Neo4jGraphQLTranslationContext; parentNode: Cypher.Node; operator: string | undefined; useExistExpr?: boolean; @@ -125,7 +126,7 @@ export function createConnectionWherePropertyOperation({ checkParameterExistence, }: { whereInput: ConnectionWhereArg; - context: Context; + context: Neo4jGraphQLTranslationContext; node: Node; edge: Relationship; edgeRef: Cypher.Variable; diff --git a/packages/graphql/src/translate/where/property-operations/create-property-where.ts b/packages/graphql/src/translate/where/property-operations/create-property-where.ts index 0b2a99666d..06a0dea843 100644 --- a/packages/graphql/src/translate/where/property-operations/create-property-where.ts +++ b/packages/graphql/src/translate/where/property-operations/create-property-where.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Context, PredicateReturn } from "../../../types"; +import type { PredicateReturn } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; import type { GraphElement } from "../../../classes"; import { Node } from "../../../classes"; @@ -33,6 +33,7 @@ import { createComparisonOperation } from "./create-comparison-operation"; import { createRelationshipOperation } from "./create-relationship-operation"; import { aggregatePreComputedWhereFields } from "../../create-aggregate-where-and-params"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; /** Translates a property into its predicate filter */ export function createPropertyWhere({ @@ -48,7 +49,7 @@ export function createPropertyWhere({ value: any; element: GraphElement; targetElement: Cypher.Variable; - context: Context; + context: Neo4jGraphQLTranslationContext; useExistExpr?: boolean; checkParameterExistence?: boolean; }): PredicateReturn { diff --git a/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts b/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts index 964a71ea98..b84ea3502c 100644 --- a/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts +++ b/packages/graphql/src/translate/where/property-operations/create-relationship-operation.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import type { Context, GraphQLWhereArg, RelationField, PredicateReturn } from "../../../types"; +import type { GraphQLWhereArg, RelationField, PredicateReturn } from "../../../types"; import Cypher from "@neo4j/cypher-builder"; import { createWherePredicate } from "../create-where-predicate"; @@ -27,6 +27,7 @@ import type { WhereOperator } from "../types"; import type { Node, Relationship } from "../../../classes"; import { createConnectionWherePropertyOperation } from "./create-connection-operation"; import { getCypherRelationshipDirection } from "../../../utils/get-relationship-direction"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; export function createRelationshipOperation({ relationField, @@ -39,7 +40,7 @@ export function createRelationshipOperation({ checkParameterExistence, }: { relationField: RelationField; - context: Context; + context: Neo4jGraphQLTranslationContext; parentNode: Cypher.Node; operator: string | undefined; value: GraphQLWhereArg; @@ -108,7 +109,7 @@ export function createRelationPredicate({ targetPattern: Cypher.Pattern; targetRelationship: Cypher.Relationship; refNode: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; relationField: RelationField; whereInput: GraphQLWhereArg; whereOperator: WhereOperator; @@ -303,7 +304,7 @@ function createRelationPredicateWithSubqueries({ innerOperation: Cypher.Predicate; listPredicateStr: ListPredicate; refNode: Node; - context: Context; + context: Neo4jGraphQLTranslationContext; whereInput: any; refEdge?: Relationship; checkParameterExistence?: boolean; diff --git a/packages/graphql/src/types/index.ts b/packages/graphql/src/types/index.ts index 6c2dcae240..ea83920dc9 100644 --- a/packages/graphql/src/types/index.ts +++ b/packages/graphql/src/types/index.ts @@ -33,7 +33,7 @@ import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; export { Node } from "../classes"; -type AuthorizationContext = { +export type AuthorizationContext = { jwt?: JwtPayload; jwtParam: Cypher.Param; isAuthenticated: boolean; diff --git a/packages/graphql/src/types/neo4j-graphql-composed-context.ts b/packages/graphql/src/types/neo4j-graphql-composed-context.ts deleted file mode 100644 index b16c2e9eb2..0000000000 --- a/packages/graphql/src/types/neo4j-graphql-composed-context.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { AuthorizationContext, ContextFeatures, FulltextContext } from "."; -import type { Neo4jDatabaseInfo, Node, Relationship } from "../classes"; -import type { Executor } from "../classes/Executor"; -import type { Neo4jGraphQLSchemaModel } from "../schema-model/Neo4jGraphQLSchemaModel"; -import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; - -export interface Neo4jGraphQLInternalComposedContext { - /** - * @deprecated - */ - nodes: Node[]; - /** - * @deprecated - */ - relationships: Relationship[]; - schemaModel: Neo4jGraphQLSchemaModel; - features: ContextFeatures; - subscriptionsEnabled: boolean; - executor: Executor; - authorization: AuthorizationContext; - neo4jDatabaseInfo?: Neo4jDatabaseInfo; - fulltext?: FulltextContext; -} - -export interface Neo4jGraphQLComposedContext extends Neo4jGraphQLContext { - /** - * @internal - */ - _neo4j: Neo4jGraphQLInternalComposedContext; -} diff --git a/packages/graphql/src/types/neo4j-graphql-resolver-context.ts b/packages/graphql/src/types/neo4j-graphql-translation-context.ts similarity index 61% rename from packages/graphql/src/types/neo4j-graphql-resolver-context.ts rename to packages/graphql/src/types/neo4j-graphql-translation-context.ts index d0c6e909ce..e0bce7476e 100644 --- a/packages/graphql/src/types/neo4j-graphql-resolver-context.ts +++ b/packages/graphql/src/types/neo4j-graphql-translation-context.ts @@ -18,16 +18,13 @@ */ import type { ResolveTree } from "graphql-parse-resolve-info"; -import type { Neo4jGraphQLInternalComposedContext } from "./neo4j-graphql-composed-context"; -import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; +import type { Neo4jGraphQLComposedContext } from "../schema/resolvers/wrapper"; -export interface Neo4jGraphQLInternalResolverContext extends Neo4jGraphQLInternalComposedContext { +/** + * A small extension to {@link Neo4jGraphQLComposedContext}, adding the {@link resolveTree} field. + * This field cannot be added during resolvers composition, because it gets overridden if executing multiple queries under the same operation. + * Each individual resolver populates this field. + */ +export interface Neo4jGraphQLTranslationContext extends Neo4jGraphQLComposedContext { resolveTree: ResolveTree; } - -export interface Neo4jGraphQLResolverContext extends Neo4jGraphQLContext { - /** - * @internal - */ - _neo4j: Neo4jGraphQLInternalResolverContext; -} diff --git a/packages/graphql/src/utils/execute.test.ts b/packages/graphql/src/utils/execute.test.ts index e2cefa089c..682fbd406b 100644 --- a/packages/graphql/src/utils/execute.test.ts +++ b/packages/graphql/src/utils/execute.test.ts @@ -95,7 +95,6 @@ describe("execute", () => { bookmarks, }, }), - info: undefined, }).instance(), }); @@ -175,7 +174,6 @@ describe("execute", () => { }, cypherQueryOptions: {}, }), - info: undefined, }).instance(), }); @@ -267,7 +265,6 @@ describe("execute", () => { replan: "default", }, }), - info: undefined, }).instance(), }); diff --git a/packages/graphql/src/utils/execute.ts b/packages/graphql/src/utils/execute.ts index 3e6375e170..cbb11c2247 100644 --- a/packages/graphql/src/utils/execute.ts +++ b/packages/graphql/src/utils/execute.ts @@ -20,8 +20,8 @@ import type { SessionMode, QueryResult } from "neo4j-driver"; import Debug from "debug"; import { DEBUG_EXECUTE } from "../constants"; -import type { Context } from "../types"; import type { GraphQLResolveInfo } from "graphql"; +import type { Neo4jGraphQLComposedContext } from "../schema/resolvers/wrapper"; const debug = Debug(DEBUG_EXECUTE); @@ -42,7 +42,7 @@ async function execute({ cypher: string; params: any; defaultAccessMode: SessionMode; - context: Context; + context: Neo4jGraphQLComposedContext; info?: GraphQLResolveInfo; }): Promise { const result = await context.executor.execute(cypher, params, defaultAccessMode, info); diff --git a/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts b/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts deleted file mode 100644 index fab54b57dd..0000000000 --- a/packages/graphql/src/utils/get-neo4j-graphql-resolver-context.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { GraphQLResolveInfo } from "graphql"; -import type { Neo4jGraphQLComposedContext } from "../types/neo4j-graphql-composed-context"; -import type { - Neo4jGraphQLInternalResolverContext, - Neo4jGraphQLResolverContext, -} from "../types/neo4j-graphql-resolver-context"; -import getNeo4jResolveTree from "./get-neo4j-resolve-tree"; - -export function getNeo4jGraphQLResolverContext({ - context, - info, - args, -}: { - context: Neo4jGraphQLComposedContext; - info: GraphQLResolveInfo; - args: unknown; -}): Neo4jGraphQLResolverContext { - const resolveTree = getNeo4jResolveTree(info, { args }); - - const internalContext: Neo4jGraphQLInternalResolverContext = { ...context._neo4j, resolveTree }; - - return { ...context, _neo4j: internalContext }; -} diff --git a/packages/graphql/tests/e2e/federation/apollo-federation-subgraph-compatibility/apollo-federation-subgraph-compatibility.e2e.test.ts b/packages/graphql/tests/e2e/federation/apollo-federation-subgraph-compatibility/apollo-federation-subgraph-compatibility.e2e.test.ts index f63ccdf878..1060d52f64 100644 --- a/packages/graphql/tests/e2e/federation/apollo-federation-subgraph-compatibility/apollo-federation-subgraph-compatibility.e2e.test.ts +++ b/packages/graphql/tests/e2e/federation/apollo-federation-subgraph-compatibility/apollo-federation-subgraph-compatibility.e2e.test.ts @@ -132,10 +132,10 @@ describe("Tests copied from https://github.com/apollographql/apollo-federation-s typeDefs: products, resolvers: { User: { - averageProductsCreatedPerYear: (_source, _args, context) => { + averageProductsCreatedPerYear: (_source, _args, _context, info) => { return Math.floor( - context.resolveTree.args.representations[0].totalProductsCreated / - context.resolveTree.args.representations[0].yearsOfEmployment + info.variableValues.representations[0].totalProductsCreated / + info.variableValues.representations[0].yearsOfEmployment ); }, }, diff --git a/packages/graphql/tests/integration/directives/authorization/custom-resolvers.int.test.ts b/packages/graphql/tests/integration/directives/authorization/custom-resolvers.int.test.ts index d11a46ed99..c167ebbdd5 100644 --- a/packages/graphql/tests/integration/directives/authorization/custom-resolvers.int.test.ts +++ b/packages/graphql/tests/integration/directives/authorization/custom-resolvers.int.test.ts @@ -66,7 +66,7 @@ describe("auth/custom-resolvers", () => { typeDefs, resolvers: { Query: { - me: (_, __, ctx) => ({ id: ctx.authorization.jwt.sub }), + me: (_, __, ctx) => ({ id: ctx.jwt.sub }), }, }, features: { @@ -113,7 +113,7 @@ describe("auth/custom-resolvers", () => { const neoSchema = new Neo4jGraphQL({ typeDefs, - resolvers: { Mutation: { me: (_, __, ctx) => ({ id: ctx.authorization.jwt.sub }) } }, + resolvers: { Mutation: { me: (_, __, ctx) => ({ id: ctx.jwt.sub }) } }, features: { authorization: { key: secret, @@ -160,7 +160,7 @@ describe("auth/custom-resolvers", () => { typeDefs, resolvers: { Query: { me: () => ({}) }, - User: { customId: (_, __, ctx) => ctx.authorization.jwt.sub }, + User: { customId: (_, __, ctx) => ctx.jwt.sub }, }, features: { authorization: { @@ -214,7 +214,7 @@ describe("auth/custom-resolvers", () => { typeDefs, resolvers: { Query: { - me: (_, __, ctx) => ({ id: ctx.authorization.jwt.sub }), + me: (_, __, ctx) => ({ id: ctx.jwt.sub }), }, }, }); diff --git a/packages/graphql/tests/tck/utils/tck-test-utils.ts b/packages/graphql/tests/tck/utils/tck-test-utils.ts index 37c91a2ac7..966d78b7a8 100644 --- a/packages/graphql/tests/tck/utils/tck-test-utils.ts +++ b/packages/graphql/tests/tck/utils/tck-test-utils.ts @@ -65,7 +65,10 @@ export async function translateQuery( ): Promise<{ cypher: string; params: Record }> { const driverBuilder = new DriverBuilder(); const neo4jDatabaseInfo = new Neo4jDatabaseInfo(options?.neo4jVersion ?? "4.4"); - let contextValue: Record = { executionContext: driverBuilder.instance(), neo4jDatabaseInfo }; + let contextValue: Record = { + executionContext: driverBuilder.instance(), + neo4jDatabaseInfo, + }; if (options?.token) { contextValue.token = options.token; diff --git a/packages/graphql/tests/utils/builders/context-builder.ts b/packages/graphql/tests/utils/builders/context-builder.ts index b98c830cd4..b61e64c2d4 100644 --- a/packages/graphql/tests/utils/builders/context-builder.ts +++ b/packages/graphql/tests/utils/builders/context-builder.ts @@ -19,7 +19,6 @@ import type * as neo4j from "neo4j-driver"; import type { ResolveTree } from "graphql-parse-resolve-info"; -import type { GraphQLResolveInfo } from "graphql"; import type { Neo4jDatabaseInfo } from "../../../src/classes/Neo4jDatabaseInfo"; import type { Context } from "../../../src/types"; import { Builder } from "./builder"; @@ -45,7 +44,6 @@ export class ContextBuilder extends Builder { executionContext: {} as neo4j.Driver, executor: new Executor({ executionContext: {} as neo4j.Driver }), neo4jDatabaseInfo: {} as Neo4jDatabaseInfo, - info: {} as GraphQLResolveInfo, features: {}, authorization: { jwtParam: new Cypher.Param({}), From da34e8e3c306d30ee52dc14765513789b2dd5a6a Mon Sep 17 00:00:00 2001 From: Darrell Warde Date: Fri, 11 Aug 2023 18:23:34 +0100 Subject: [PATCH 7/7] Remove legacy Context type --- .../graphql/src/schema/create-global-nodes.ts | 8 +++-- .../schema/resolvers/field/defaultField.ts | 4 +-- .../graphql/src/schema/resolvers/field/id.ts | 4 +-- .../src/schema/resolvers/wrapper.test.ts | 16 ++++----- .../check-schema-authentication.ts | 36 ------------------- .../utils/populate-where-params.test.ts | 4 +-- .../where/create-where-and-params.test.ts | 12 ++++--- .../create-connection-operation.ts | 2 +- packages/graphql/src/types/index.ts | 18 +--------- .../tests/utils/builders/context-builder.ts | 10 +++--- 10 files changed, 34 insertions(+), 80 deletions(-) delete mode 100644 packages/graphql/src/translate/authorization/check-schema-authentication.ts diff --git a/packages/graphql/src/schema/create-global-nodes.ts b/packages/graphql/src/schema/create-global-nodes.ts index cb49bab10c..f26abf5494 100644 --- a/packages/graphql/src/schema/create-global-nodes.ts +++ b/packages/graphql/src/schema/create-global-nodes.ts @@ -20,7 +20,7 @@ import type { GraphQLResolveInfo } from "graphql"; import type { ObjectTypeComposerFieldConfigAsObjectDefinition, SchemaComposer } from "graphql-compose"; import { nodeDefinitions } from "graphql-relay"; -import type { Context, Node } from "../types"; +import type { Node } from "../types"; import { globalNodeResolver } from "./resolvers/query/global-node"; import type { Neo4jGraphQLComposedContext } from "./resolvers/wrapper"; @@ -41,7 +41,11 @@ export function addGlobalNodeFields(nodes: Node[], composer: SchemaComposer): bo composer.createInterfaceTC(nodeInterface); composer.Query.addFields({ - node: nodeField as ObjectTypeComposerFieldConfigAsObjectDefinition, + node: nodeField as ObjectTypeComposerFieldConfigAsObjectDefinition< + null, + Neo4jGraphQLComposedContext, + { id: string } + >, }); return true; } diff --git a/packages/graphql/src/schema/resolvers/field/defaultField.ts b/packages/graphql/src/schema/resolvers/field/defaultField.ts index 7bd4197056..55fd668fa1 100644 --- a/packages/graphql/src/schema/resolvers/field/defaultField.ts +++ b/packages/graphql/src/schema/resolvers/field/defaultField.ts @@ -18,13 +18,13 @@ */ import type { FieldNode, GraphQLResolveInfo } from "graphql"; +import type { Neo4jGraphQLContext } from "../../../types/neo4j-graphql-context"; /** * Based on the default field resolver used by graphql-js that accounts for aliased fields * @link https://github.com/graphql/graphql-js/blob/main/src/execution/execute.ts#L999-L1015 */ - -export function defaultFieldResolver(source: any, args: any, context: unknown, info: GraphQLResolveInfo) { +export function defaultFieldResolver(source, args, context: Neo4jGraphQLContext, info: GraphQLResolveInfo) { if ((typeof source === "object" && source !== null) || typeof source === "function") { const fieldNode = info.fieldNodes[0] as FieldNode; diff --git a/packages/graphql/src/schema/resolvers/field/id.ts b/packages/graphql/src/schema/resolvers/field/id.ts index 3669b7e488..55628a3422 100644 --- a/packages/graphql/src/schema/resolvers/field/id.ts +++ b/packages/graphql/src/schema/resolvers/field/id.ts @@ -20,7 +20,7 @@ import type { GraphQLResolveInfo } from "graphql"; import { defaultFieldResolver } from "./defaultField"; import { isNeoInt } from "../../../utils/utils"; -import type { Context } from "../../../types"; +import type { Neo4jGraphQLContext } from "../../../types/neo4j-graphql-context"; function serializeValue(value) { if (isNeoInt(value)) { @@ -34,7 +34,7 @@ function serializeValue(value) { return value; } -export function idResolver(source, args, context: Context, info: GraphQLResolveInfo) { +export function idResolver(source, args, context: Neo4jGraphQLContext, info: GraphQLResolveInfo) { const value = defaultFieldResolver(source, args, context, info); if (Array.isArray(value)) { diff --git a/packages/graphql/src/schema/resolvers/wrapper.test.ts b/packages/graphql/src/schema/resolvers/wrapper.test.ts index 0db496827e..7306704d8d 100644 --- a/packages/graphql/src/schema/resolvers/wrapper.test.ts +++ b/packages/graphql/src/schema/resolvers/wrapper.test.ts @@ -21,7 +21,7 @@ import * as semver from "semver"; import type { GraphQLResolveInfo, GraphQLSchema } from "graphql"; import type { Session, Driver } from "neo4j-driver"; import { Neo4jDatabaseInfo } from "../../classes/Neo4jDatabaseInfo"; -import type { Context } from "../../types"; +import type { Neo4jGraphQLComposedContext } from "./wrapper"; import { wrapSubscription } from "./wrapper"; describe("wrapper test", () => { @@ -79,7 +79,7 @@ describe("wrapper test", () => { executeRead.mockReturnValueOnce({ records: [["4.4.0", "enterprise"]], }); - const resolver = jest.fn((_root, _args, context: Context) => { + const resolver = jest.fn((_root, _args, context: Neo4jGraphQLComposedContext) => { expect(context).toBeDefined(); expect(context.neo4jDatabaseInfo).toBeDefined(); expect(context.neo4jDatabaseInfo?.edition).toBe("enterprise"); @@ -87,7 +87,7 @@ describe("wrapper test", () => { return resolvedResult; }); const wrappedResolver = resolverDecorator(resolver); - const res = await wrappedResolver({}, {}, {} as Context, {} as GraphQLResolveInfo); + const res = await wrappedResolver({}, {}, {} as Neo4jGraphQLComposedContext, {} as GraphQLResolveInfo); expect(res).toBe(resolvedResult); expect(executeRead).toHaveBeenCalledTimes(1); expect(resolver).toHaveBeenCalledTimes(1); @@ -96,7 +96,7 @@ describe("wrapper test", () => { test("should not invoke dbms.components if neo4jDatabaseInfo is already initialised", async () => { const resolverDecorator = wrapResolver(wrapResolverArgs); const resolvedResult = "Resolved value"; - const resolver = (_root, _args, context: Context) => { + const resolver = (_root, _args, context: Neo4jGraphQLComposedContext) => { expect(context).toBeDefined(); expect(context.neo4jDatabaseInfo).toBeDefined(); expect(context.neo4jDatabaseInfo).toEqual(new Neo4jDatabaseInfo("4.3.0", "enterprise")); @@ -107,13 +107,13 @@ describe("wrapper test", () => { records: [["4.3.0", "enterprise"]], }); const wrappedResolver = resolverDecorator(resolver); - const firstRes = await wrappedResolver({}, {}, {} as Context, {} as GraphQLResolveInfo); + const firstRes = await wrappedResolver({}, {}, {} as Neo4jGraphQLComposedContext, {} as GraphQLResolveInfo); expect(firstRes).toBe(resolvedResult); expect(executeRead).toHaveBeenCalledTimes(1); executeRead.mockReturnValueOnce({ records: [["4.4.0", "enterprise"]], }); - const secondRes = await wrappedResolver({}, {}, {} as Context, {} as GraphQLResolveInfo); + const secondRes = await wrappedResolver({}, {}, {} as Neo4jGraphQLComposedContext, {} as GraphQLResolveInfo); expect(secondRes).toBe(resolvedResult); expect(executeRead).toHaveBeenCalledTimes(1); }); @@ -134,14 +134,14 @@ describe("subscription wrapper test", () => { const resolverDecorator = wrapSubscription(args); const resolvedResult = "Resolved value"; - const resolver = (_root, _args, context: Context) => { + const resolver = (_root, _args, context: Neo4jGraphQLComposedContext) => { expect(context).toBeDefined(); expect(context.jwt).toEqual({ sub: "test" }); return resolvedResult; }; const wrappedResolver = resolverDecorator(resolver); - const context = { jwt: { sub: "test" } } as Context; + const context = { jwt: { sub: "test" } } as Neo4jGraphQLComposedContext; const res = await wrappedResolver({}, {}, context, {} as GraphQLResolveInfo); expect(res).toBe(resolvedResult); }); diff --git a/packages/graphql/src/translate/authorization/check-schema-authentication.ts b/packages/graphql/src/translate/authorization/check-schema-authentication.ts deleted file mode 100644 index ff8441c395..0000000000 --- a/packages/graphql/src/translate/authorization/check-schema-authentication.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) "Neo4j" - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { AuthenticationOperation } from "../../schema-model/annotation/AuthenticationAnnotation"; -import type { Context } from "../../types"; -import { applyAuthentication } from "./utils/apply-authentication"; - -export function checkSchemaAuthentication({ - context, - operation, -}: { - context: Context; - operation: AuthenticationOperation; -}): void { - const annotation = context.schemaModel.annotations.authentication; - - if (annotation && annotation.operations.has(operation)) { - applyAuthentication({ context, annotation }); - } -} diff --git a/packages/graphql/src/translate/authorization/utils/populate-where-params.test.ts b/packages/graphql/src/translate/authorization/utils/populate-where-params.test.ts index 11a6d21545..b21e512622 100644 --- a/packages/graphql/src/translate/authorization/utils/populate-where-params.test.ts +++ b/packages/graphql/src/translate/authorization/utils/populate-where-params.test.ts @@ -19,11 +19,11 @@ import Cypher from "@neo4j/cypher-builder"; import { ContextBuilder } from "../../../../tests/utils/builders/context-builder"; -import type { Context } from "../../../types"; import { populateWhereParams } from "./populate-where-params"; +import type { Neo4jGraphQLTranslationContext } from "../../../types/neo4j-graphql-translation-context"; describe("populateWhereParams", () => { - let context: Context; + let context: Neo4jGraphQLTranslationContext; let jwtParam: Cypher.Param; beforeAll(() => { diff --git a/packages/graphql/src/translate/where/create-where-and-params.test.ts b/packages/graphql/src/translate/where/create-where-and-params.test.ts index 992705e7c7..368b228e78 100644 --- a/packages/graphql/src/translate/where/create-where-and-params.test.ts +++ b/packages/graphql/src/translate/where/create-where-and-params.test.ts @@ -18,9 +18,9 @@ */ import createWhereAndParams from "./create-where-and-params"; -import type { Context } from "../../types"; import { ContextBuilder } from "../../../tests/utils/builders/context-builder"; import { NodeBuilder } from "../../../tests/utils/builders/node-builder"; +import type { Neo4jGraphQLTranslationContext } from "../../types/neo4j-graphql-translation-context"; describe("createWhereAndParams", () => { test("should be a function", () => { @@ -59,10 +59,12 @@ describe("createWhereAndParams", () => { id: node.toGlobalId("some title"), }; - // @ts-ignore - const context: Context = { neoSchema: { nodes: [] } }; - - const result = createWhereAndParams({ whereInput, varName, node, context }); + const result = createWhereAndParams({ + whereInput, + varName, + node, + context: {} as Neo4jGraphQLTranslationContext, + }); expect(result[0]).toBe(`WHERE this.title = $this_param0`); expect(result[1]).toBe(""); diff --git a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts index f8aeb606ef..ec0dd45095 100644 --- a/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts +++ b/packages/graphql/src/translate/where/property-operations/create-connection-operation.ts @@ -18,7 +18,7 @@ */ import Cypher from "@neo4j/cypher-builder"; -import type { ConnectionField, ConnectionWhereArg, Context, PredicateReturn } from "../../../types"; +import type { ConnectionField, ConnectionWhereArg, PredicateReturn } from "../../../types"; import type { Node, Relationship } from "../../../classes"; import type { WhereOperator } from "../types"; // Recursive function diff --git a/packages/graphql/src/types/index.ts b/packages/graphql/src/types/index.ts index ea83920dc9..f91036510c 100644 --- a/packages/graphql/src/types/index.ts +++ b/packages/graphql/src/types/index.ts @@ -24,10 +24,7 @@ import type { Directive } from "graphql-compose"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { JWTVerifyOptions, RemoteJWKSetOptions } from "jose"; import type { Integer } from "neo4j-driver"; -import type { Neo4jDatabaseInfo, Node, Relationship } from "../classes"; -import type { Executor } from "../classes/Executor"; import type { RelationshipNestedOperationsOption, RelationshipQueryDirectionOption } from "../constants"; -import type { Neo4jGraphQLSchemaModel } from "../schema-model/Neo4jGraphQLSchemaModel"; import type { JwtPayload } from "./jwt-payload"; import type { Neo4jGraphQLContext } from "./neo4j-graphql-context"; @@ -41,19 +38,6 @@ export type AuthorizationContext = { claims?: Map; }; -export interface Context extends Neo4jGraphQLContext { - resolveTree: ResolveTree; - nodes: Node[]; - relationships: Relationship[]; - schemaModel: Neo4jGraphQLSchemaModel; - features: ContextFeatures; - subscriptionsEnabled: boolean; - executor: Executor; - authorization: AuthorizationContext; - neo4jDatabaseInfo?: Neo4jDatabaseInfo; - fulltext?: FulltextContext; -} - export type FulltextContext = { name: string | undefined; fields: string[]; @@ -417,7 +401,7 @@ export type CallbackReturnValue = string | number | boolean | undefined | null; export type Neo4jGraphQLCallback = ( parent: Record, args: Record, - context: Context + context: Neo4jGraphQLContext ) => CallbackReturnValue | Promise; export type Neo4jGraphQLCallbacks = Record; diff --git a/packages/graphql/tests/utils/builders/context-builder.ts b/packages/graphql/tests/utils/builders/context-builder.ts index b61e64c2d4..d4ebd62db5 100644 --- a/packages/graphql/tests/utils/builders/context-builder.ts +++ b/packages/graphql/tests/utils/builders/context-builder.ts @@ -20,16 +20,16 @@ import type * as neo4j from "neo4j-driver"; import type { ResolveTree } from "graphql-parse-resolve-info"; import type { Neo4jDatabaseInfo } from "../../../src/classes/Neo4jDatabaseInfo"; -import type { Context } from "../../../src/types"; import { Builder } from "./builder"; import { Executor } from "../../../src/classes/Executor"; import { Neo4jGraphQLSchemaModel } from "../../../src/schema-model/Neo4jGraphQLSchemaModel"; import Cypher from "@neo4j/cypher-builder"; import type { ConcreteEntity } from "../../../src/schema-model/entity/ConcreteEntity"; import type { CompositeEntity } from "../../../src/schema-model/entity/CompositeEntity"; +import type { Neo4jGraphQLTranslationContext } from "../../../src/types/neo4j-graphql-translation-context"; -export class ContextBuilder extends Builder { - constructor(newOptions: Partial = {}) { +export class ContextBuilder extends Builder { + constructor(newOptions: Partial = {}) { super({ resolveTree: {} as ResolveTree, nodes: [], @@ -54,12 +54,12 @@ export class ContextBuilder extends Builder { }); } - public with(newOptions: Partial): ContextBuilder { + public with(newOptions: Partial): ContextBuilder { this.options = { ...this.options, ...newOptions }; return this; } - public instance(): Context { + public instance(): Neo4jGraphQLTranslationContext { return this.options; } }