diff --git a/packages/graphql/src/api-v6/queryIR/DeleteOperation.ts b/packages/graphql/src/api-v6/queryIR/DeleteOperation.ts index a0f173abaa..5530d0eda5 100644 --- a/packages/graphql/src/api-v6/queryIR/DeleteOperation.ts +++ b/packages/graphql/src/api-v6/queryIR/DeleteOperation.ts @@ -32,24 +32,28 @@ export class V6DeleteOperation extends MutationOperation { public readonly target: ConcreteEntityAdapter | InterfaceEntityAdapter; private selection: EntitySelection; private filters: Filter[]; + private nestedOperations: V6DeleteOperation[]; constructor({ target, selection, + nestedOperations = [], filters = [], }: { target: ConcreteEntityAdapter | InterfaceEntityAdapter; selection: EntitySelection; filters?: Filter[]; + nestedOperations?: V6DeleteOperation[]; }) { super(); this.target = target; this.selection = selection; this.filters = filters; + this.nestedOperations = nestedOperations; } public getChildren(): QueryASTNode[] { - return [this.selection, ...this.filters]; + return [this.selection, ...this.filters, ...this.nestedOperations]; } public transpile(context: QueryASTContext): OperationTranspileResult { @@ -57,6 +61,9 @@ export class V6DeleteOperation extends MutationOperation { throw new Error("No parent node found!"); } const { selection, nestedContext } = this.selection.apply(context); + if (nestedContext.relationship) { + return this.transpileNested(selection, nestedContext); + } return this.transpileTopLevel(selection, nestedContext); } @@ -69,14 +76,50 @@ export class V6DeleteOperation extends MutationOperation { const predicate = this.getPredicate(context); const extraSelections = this.getExtraSelections(context); + const nestedOperations: (Cypher.Call | Cypher.With)[] = this.getNestedDeleteSubQueries(context); + let statements = [selection, ...extraSelections, ...filterSubqueries]; + statements = this.appendFilters(statements, predicate); + if (nestedOperations.length) { + statements.push(new Cypher.With("*"), ...nestedOperations); + } statements = this.appendDeleteClause(statements, context); const ret = Cypher.concat(...statements); return { clauses: [ret], projectionExpr: context.target }; } + private transpileNested( + selection: SelectionClause, + context: QueryASTContext + ): OperationTranspileResult { + this.validateSelection(selection); + if (!context.relationship) { + throw new Error("Transpile error: No relationship found!"); + } + const filterSubqueries = wrapSubqueriesInCypherCalls(context, this.filters, [context.target]); + const predicate = this.getPredicate(context); + const extraSelections = this.getExtraSelections(context); + const collect = Cypher.collect(context.target).distinct(); + const deleteVar = new Cypher.Variable(); + const withBeforeDeleteBlock = new Cypher.With(context.relationship, [collect, deleteVar]); + + const unwindDeleteVar = new Cypher.Variable(); + const deleteClause = new Cypher.Unwind([deleteVar, unwindDeleteVar]).detachDelete(unwindDeleteVar); + + const deleteBlock = new Cypher.Call(deleteClause).importWith(deleteVar); + const nestedOperations: (Cypher.Call | Cypher.With)[] = this.getNestedDeleteSubQueries(context); + const statements = this.appendFilters([selection, ...extraSelections, ...filterSubqueries], predicate); + + if (nestedOperations.length) { + statements.push(new Cypher.With("*"), ...nestedOperations); + } + statements.push(withBeforeDeleteBlock, deleteBlock); + const ret = Cypher.concat(...statements); + return { clauses: [ret], projectionExpr: Cypher.Null }; + } + private appendDeleteClause(clauses: Cypher.Clause[], context: QueryASTContext): Cypher.Clause[] { const lastClause = this.getLastClause(clauses); if ( @@ -120,6 +163,15 @@ export class V6DeleteOperation extends MutationOperation { return clauses; } + private getNestedDeleteSubQueries(context: QueryASTContext): Cypher.Call[] { + const nestedOperations: Cypher.Call[] = []; + for (const nestedDeleteOperation of this.nestedOperations) { + const { clauses } = nestedDeleteOperation.transpile(context); + nestedOperations.push(...clauses.map((c) => new Cypher.Call(c).importWith("*"))); + } + return nestedOperations; + } + private validateSelection(selection: SelectionClause): asserts selection is Cypher.Match | Cypher.With { if (!(selection instanceof Cypher.Match || selection instanceof Cypher.With)) { throw new Error("Cypher Yield statement is not a valid selection for Delete Operation"); diff --git a/packages/graphql/src/api-v6/queryIRFactory/DeleteOperationFactory.ts b/packages/graphql/src/api-v6/queryIRFactory/DeleteOperationFactory.ts index c3d06ce2a8..3ffa96e930 100644 --- a/packages/graphql/src/api-v6/queryIRFactory/DeleteOperationFactory.ts +++ b/packages/graphql/src/api-v6/queryIRFactory/DeleteOperationFactory.ts @@ -20,12 +20,16 @@ import type { Neo4jGraphQLSchemaModel } from "../../schema-model/Neo4jGraphQLSchemaModel"; import type { ConcreteEntity } from "../../schema-model/entity/ConcreteEntity"; import { ConcreteEntityAdapter } from "../../schema-model/entity/model-adapters/ConcreteEntityAdapter"; +import type { RelationshipAdapter } from "../../schema-model/relationship/model-adapters/RelationshipAdapter"; import { QueryAST } from "../../translate/queryAST/ast/QueryAST"; import { NodeSelection } from "../../translate/queryAST/ast/selection/NodeSelection"; -import { filterTruthy } from "../../utils/utils"; +import { RelationshipSelection } from "../../translate/queryAST/ast/selection/RelationshipSelection"; +import { isInterfaceEntity } from "../../translate/queryAST/utils/is-interface-entity"; +import { isUnionEntity } from "../../translate/queryAST/utils/is-union-entity"; +import { asArray, filterTruthy, isRecord } from "../../utils/utils"; import { V6DeleteOperation } from "../queryIR/DeleteOperation"; import { FilterFactory } from "./FilterFactory"; -import type { GraphQLTreeDelete } from "./resolve-tree-parser/graphql-tree/graphql-tree"; +import type { GraphQLTreeDelete, GraphQLTreeDeleteInput } from "./resolve-tree-parser/graphql-tree/graphql-tree"; export class DeleteOperationFactory { public schemaModel: Neo4jGraphQLSchemaModel; @@ -64,15 +68,122 @@ export class DeleteOperationFactory { }); const filters = filterTruthy([ - this.filterFactory.createFilters({ entity, where: graphQLTreeDelete.args.where }), + this.filterFactory.createFilters({ + entity, + where: graphQLTreeDelete.args.where, + }), ]); + const nestedDeleteOperations: V6DeleteOperation[] = []; + if (graphQLTreeDelete.args.input) { + nestedDeleteOperations.push( + ...this.createNestedDeleteOperations(graphQLTreeDelete.args.input, targetAdapter) + ); + } + const deleteOP = new V6DeleteOperation({ target: targetAdapter, selection, filters, + nestedOperations: nestedDeleteOperations, }); return deleteOP; } + + private createNestedDeleteOperations( + deleteArg: GraphQLTreeDeleteInput, + source: ConcreteEntityAdapter + ): V6DeleteOperation[] { + return filterTruthy( + Object.entries(deleteArg).flatMap(([key, valueArr]) => { + return asArray(valueArr).flatMap((value) => { + const relationship = source.findRelationship(key); + if (!relationship) { + throw new Error(`Failed to find relationship ${key}`); + } + const target = relationship.target; + + if (isInterfaceEntity(target)) { + // TODO: Implement createNestedDeleteOperationsForInterface + // return this.createNestedDeleteOperationsForInterface({ + // deleteArg: value, + // relationship, + // target, + // }); + return; + } + if (isUnionEntity(target)) { + // TODO: Implement createNestedDeleteOperationsForUnion + // return this.createNestedDeleteOperationsForUnion({ + // deleteArg: value, + // relationship, + // target, + // }); + return; + } + + return this.createNestedDeleteOperation({ + relationship, + target, + args: value as Record, + }); + }); + }) + ); + } + + private parseDeleteArgs( + args: Record, + isTopLevel: boolean + ): { + whereArg: { node: Record; edge: Record }; + deleteArg: Record; + } { + let whereArg; + const rawWhere = isRecord(args.where) ? args.where : {}; + if (isTopLevel) { + whereArg = { node: rawWhere.node ?? {}, edge: rawWhere.edge ?? {} }; + } else { + whereArg = { node: rawWhere, edge: {} }; + } + const deleteArg = isRecord(args.delete) ? args.delete : {}; + return { whereArg, deleteArg }; + } + + private createNestedDeleteOperation({ + relationship, + target, + args, + }: { + relationship: RelationshipAdapter; + target: ConcreteEntityAdapter; + args: Record; + }): V6DeleteOperation[] { + const { whereArg, deleteArg } = this.parseDeleteArgs(args, true); + + const selection = new RelationshipSelection({ + relationship, + directed: true, + optional: true, + targetOverride: target, + }); + + const filters = filterTruthy([ + this.filterFactory.createFilters({ + entity: target.entity, + where: whereArg, + }), + ]); + + const nestedDeleteOperations = this.createNestedDeleteOperations(deleteArg, target); + return [ + new V6DeleteOperation({ + target, + selection, + filters, + nestedOperations: nestedDeleteOperations, + }), + ]; + } } diff --git a/packages/graphql/src/api-v6/queryIRFactory/resolve-tree-parser/graphql-tree/graphql-tree.ts b/packages/graphql/src/api-v6/queryIRFactory/resolve-tree-parser/graphql-tree/graphql-tree.ts index 5196267d61..bcfa8366b0 100644 --- a/packages/graphql/src/api-v6/queryIRFactory/resolve-tree-parser/graphql-tree/graphql-tree.ts +++ b/packages/graphql/src/api-v6/queryIRFactory/resolve-tree-parser/graphql-tree/graphql-tree.ts @@ -26,6 +26,7 @@ import type { GraphQLWhere, GraphQLWhereTopLevel } from "./where"; // TODO GraphQLTreeCreateInput should be a union of PrimitiveTypes and relationship fields export type GraphQLTreeCreateInput = Record; export type GraphQLTreeUpdateInput = Record; +export type GraphQLTreeDeleteInput = Record; export type UpdateOperation = "set"; export type GraphQLTreeUpdateField = Record; @@ -34,6 +35,7 @@ export interface GraphQLTreeDelete extends GraphQLTreeNode { name: string; args: { where?: GraphQLWhereTopLevel; + input?: GraphQLTreeDeleteInput; }; } diff --git a/packages/graphql/src/api-v6/schema-generation/SchemaBuilder.ts b/packages/graphql/src/api-v6/schema-generation/SchemaBuilder.ts index 51098e4f7e..257b118f7d 100644 --- a/packages/graphql/src/api-v6/schema-generation/SchemaBuilder.ts +++ b/packages/graphql/src/api-v6/schema-generation/SchemaBuilder.ts @@ -59,7 +59,7 @@ export type InputFieldDefinition = { args?: Record; deprecationReason?: string | null; description?: string | null; - defaultValue: any; + defaultValue?: any; }; export class SchemaBuilder { diff --git a/packages/graphql/src/api-v6/schema-generation/schema-types/TopLevelEntitySchemaTypes.ts b/packages/graphql/src/api-v6/schema-generation/schema-types/TopLevelEntitySchemaTypes.ts index e4d9bebcb5..76a471e569 100644 --- a/packages/graphql/src/api-v6/schema-generation/schema-types/TopLevelEntitySchemaTypes.ts +++ b/packages/graphql/src/api-v6/schema-generation/schema-types/TopLevelEntitySchemaTypes.ts @@ -48,6 +48,7 @@ import { RelatedEntitySchemaTypes } from "./RelatedEntitySchemaTypes"; import type { SchemaTypes } from "./SchemaTypes"; import { TopLevelFilterSchemaTypes } from "./filter-schema-types/TopLevelFilterSchemaTypes"; import { TopLevelCreateSchemaTypes } from "./mutation-schema-types/TopLevelCreateSchemaTypes"; +import { TopLevelDeleteSchemaTypes } from "./mutation-schema-types/TopLevelDeleteSchemaTypes"; import { TopLevelUpdateSchemaTypes } from "./mutation-schema-types/TopLevelUpdateSchemaTypes"; export class TopLevelEntitySchemaTypes { @@ -58,6 +59,7 @@ export class TopLevelEntitySchemaTypes { private schemaTypes: SchemaTypes; private createSchemaTypes: TopLevelCreateSchemaTypes; private updateSchemaTypes: TopLevelUpdateSchemaTypes; + private deleteSchemaTypes: TopLevelDeleteSchemaTypes; constructor({ entity, @@ -75,6 +77,7 @@ export class TopLevelEntitySchemaTypes { this.schemaTypes = schemaTypes; this.createSchemaTypes = new TopLevelCreateSchemaTypes({ schemaBuilder, entity }); this.updateSchemaTypes = new TopLevelUpdateSchemaTypes({ schemaBuilder, entity, schemaTypes }); + this.deleteSchemaTypes = new TopLevelDeleteSchemaTypes({ schemaBuilder, entity, schemaTypes }); } public addTopLevelQueryField( @@ -179,6 +182,7 @@ export class TopLevelEntitySchemaTypes { name: this.entity.typeNames.deleteField, type: this.schemaTypes.staticTypes.deleteResponse, args: { + input: this.deleteSchemaTypes.deleteInput, where: this.filterSchemaTypes.operationWhereTopLevel, }, resolver, diff --git a/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/RelatedEntityDeleteSchemaTypes.ts b/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/RelatedEntityDeleteSchemaTypes.ts new file mode 100644 index 0000000000..25ef1f9837 --- /dev/null +++ b/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/RelatedEntityDeleteSchemaTypes.ts @@ -0,0 +1,97 @@ +/* + * 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 { InputTypeComposer } from "graphql-compose"; +import { ConcreteEntity } from "../../../../schema-model/entity/ConcreteEntity"; +import type { Relationship } from "../../../../schema-model/relationship/Relationship"; +import type { SchemaBuilder } from "../../SchemaBuilder"; +import { RelatedEntityFilterSchemaTypes } from "../filter-schema-types/RelatedEntityFilterSchemaTypes"; +import type { SchemaTypes } from "../SchemaTypes"; +import { TopLevelDeleteSchemaTypes } from "./TopLevelDeleteSchemaTypes"; + +export class RelatedEntityDeleteSchemaTypes { + private relationship: Relationship; + protected schemaTypes: SchemaTypes; + private schemaBuilder: SchemaBuilder; + constructor({ + relationship, + schemaBuilder, + schemaTypes, + }: { + schemaBuilder: SchemaBuilder; + relationship: Relationship; + schemaTypes: SchemaTypes; + }) { + this.relationship = relationship; + this.schemaBuilder = schemaBuilder; + this.schemaTypes = schemaTypes; + } + + public get deleteOperation(): InputTypeComposer { + return this.schemaBuilder.getOrCreateInputType( + this.relationship.typeNames.deleteOperation, + (_itc: InputTypeComposer) => { + return { + fields: { + delete: this.deleteInput, + }, + }; + } + ); + } + + public get deleteInput(): InputTypeComposer { + const relatedFilterSchemaTypes = new RelatedEntityFilterSchemaTypes({ + schemaBuilder: this.schemaBuilder, + relationship: this.relationship, + schemaTypes: this.schemaTypes, + }); + + if (this.relationship.target instanceof ConcreteEntity) { + const topLevelDeleteSchemaTypes = new TopLevelDeleteSchemaTypes({ + schemaBuilder: this.schemaBuilder, + entity: this.relationship.target, + schemaTypes: this.schemaTypes, + }); + + return this.schemaBuilder.getOrCreateInputType( + this.relationship.typeNames.deleteInput, + (_itc: InputTypeComposer) => { + return { + fields: { + input: topLevelDeleteSchemaTypes.deleteInput, + where: relatedFilterSchemaTypes.operationWhereTopLevel, + }, + }; + } + ); + } else { + return this.schemaBuilder.getOrCreateInputType( + this.relationship.typeNames.deleteInput, + (_itc: InputTypeComposer) => { + return { + fields: { + where: relatedFilterSchemaTypes.operationWhereTopLevel, + }, + }; + } + ); + } + } +} diff --git a/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/TopLevelDeleteSchemaTypes.ts b/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/TopLevelDeleteSchemaTypes.ts new file mode 100644 index 0000000000..6517355490 --- /dev/null +++ b/packages/graphql/src/api-v6/schema-generation/schema-types/mutation-schema-types/TopLevelDeleteSchemaTypes.ts @@ -0,0 +1,85 @@ +/* + * 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 { InputTypeComposer } from "graphql-compose"; +import type { ConcreteEntity } from "../../../../schema-model/entity/ConcreteEntity"; +import type { TopLevelEntityTypeNames } from "../../../schema-model/graphql-type-names/TopLevelEntityTypeNames"; +import type { InputFieldDefinition, SchemaBuilder } from "../../SchemaBuilder"; +import type { SchemaTypes } from "../SchemaTypes"; +import { RelatedEntityDeleteSchemaTypes } from "./RelatedEntityDeleteSchemaTypes"; + +export class TopLevelDeleteSchemaTypes { + private entityTypeNames: TopLevelEntityTypeNames; + private schemaBuilder: SchemaBuilder; + private entity: ConcreteEntity; + private schemaTypes: SchemaTypes; + + constructor({ + entity, + schemaBuilder, + schemaTypes, + }: { + entity: ConcreteEntity; + schemaBuilder: SchemaBuilder; + schemaTypes: SchemaTypes; + }) { + this.entity = entity; + this.entityTypeNames = entity.typeNames; + this.schemaBuilder = schemaBuilder; + this.schemaTypes = schemaTypes; + } + + public get deleteInput(): InputTypeComposer { + return this.schemaBuilder.getOrCreateInputType(this.entityTypeNames.deleteInput, (_itc: InputTypeComposer) => { + return { + fields: { + node: this.deleteNode, + }, + }; + }); + } + + public get deleteNode(): InputTypeComposer { + return this.schemaBuilder.getOrCreateInputType(this.entityTypeNames.deleteNode, (_itc: InputTypeComposer) => { + const relationshipFields = Array.from(this.entity.relationships.values()).reduce< + Record + >((acc, relationship) => { + const relatedEntityDeleteSchemaTypes = new RelatedEntityDeleteSchemaTypes({ + relationship, + schemaBuilder: this.schemaBuilder, + schemaTypes: this.schemaTypes, + }); + acc[relationship.name] = { + type: relatedEntityDeleteSchemaTypes.deleteOperation, + }; + return acc; + }, {}); + + const inputFields: Record = { + ...relationshipFields, + }; + + const isEmpty = Object.keys(inputFields).length === 0; + const fields = isEmpty ? { _emptyInput: this.schemaBuilder.types.boolean } : inputFields; + return { + fields, + }; + }); + } +} diff --git a/packages/graphql/src/api-v6/schema-model/graphql-type-names/RelatedEntityTypeNames.ts b/packages/graphql/src/api-v6/schema-model/graphql-type-names/RelatedEntityTypeNames.ts index 94fdb2896f..bb9d46bff8 100644 --- a/packages/graphql/src/api-v6/schema-model/graphql-type-names/RelatedEntityTypeNames.ts +++ b/packages/graphql/src/api-v6/schema-model/graphql-type-names/RelatedEntityTypeNames.ts @@ -83,4 +83,12 @@ export class RelatedEntityTypeNames extends EntityTypeNames { } return `${this.relationship.propertiesTypeName}Sort`; } + + public get deleteOperation(): string { + return `${this.relatedEntityTypeName}DeleteOperation`; + } + + public get deleteInput(): string { + return `${this.relatedEntityTypeName}DeleteInput`; + } } diff --git a/packages/graphql/src/api-v6/schema-model/graphql-type-names/TopLevelEntityTypeNames.ts b/packages/graphql/src/api-v6/schema-model/graphql-type-names/TopLevelEntityTypeNames.ts index ec7ed12423..6847970f9f 100644 --- a/packages/graphql/src/api-v6/schema-model/graphql-type-names/TopLevelEntityTypeNames.ts +++ b/packages/graphql/src/api-v6/schema-model/graphql-type-names/TopLevelEntityTypeNames.ts @@ -114,4 +114,12 @@ export class TopLevelEntityTypeNames extends EntityTypeNames { public get deleteField(): string { return `delete${upperFirst(plural(this.entityName))}`; } + + public get deleteNode(): string { + return `${upperFirst(this.entityName)}DeleteNode`; + } + + public get deleteInput(): string { + return `${upperFirst(this.entityName)}DeleteInput`; + } } diff --git a/packages/graphql/tests/api-v6/schema/directives/default-array.test.ts b/packages/graphql/tests/api-v6/schema/directives/default-array.test.ts index 3782b43d2c..f5d723bf6f 100644 --- a/packages/graphql/tests/api-v6/schema/directives/default-array.test.ts +++ b/packages/graphql/tests/api-v6/schema/directives/default-array.test.ts @@ -139,6 +139,14 @@ describe("@default on array fields", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -187,7 +195,7 @@ describe("@default on array fields", () => { type Mutation { createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/directives/default.test.ts b/packages/graphql/tests/api-v6/schema/directives/default.test.ts index 035926af02..9f1444d36e 100644 --- a/packages/graphql/tests/api-v6/schema/directives/default.test.ts +++ b/packages/graphql/tests/api-v6/schema/directives/default.test.ts @@ -174,6 +174,14 @@ describe("@default on fields", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -231,7 +239,7 @@ describe("@default on fields", () => { type Mutation { createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/directives/id.test.ts b/packages/graphql/tests/api-v6/schema/directives/id.test.ts index 716239b69e..59bd9ad6d8 100644 --- a/packages/graphql/tests/api-v6/schema/directives/id.test.ts +++ b/packages/graphql/tests/api-v6/schema/directives/id.test.ts @@ -105,6 +105,14 @@ describe("@id", () => { info: CreateInfo } + input ActorDeleteInput { + node: ActorDeleteNode + } + + input ActorDeleteNode { + movies: ActorMoviesDeleteOperation + } + type ActorEdge { cursor: String node: Actor @@ -119,6 +127,15 @@ describe("@id", () => { edges: ActorMoviesEdgeSort } + input ActorMoviesDeleteInput { + input: MovieDeleteInput + where: ActorMoviesOperationWhere + } + + input ActorMoviesDeleteOperation { + delete: ActorMoviesDeleteInput + } + type ActorMoviesEdge { cursor: String node: Movie @@ -261,6 +278,15 @@ describe("@id", () => { edges: MovieActorsEdgeSort } + input MovieActorsDeleteInput { + input: ActorDeleteInput + where: MovieActorsOperationWhere + } + + input MovieActorsDeleteOperation { + delete: MovieActorsDeleteInput + } + type MovieActorsEdge { cursor: String node: Actor @@ -337,6 +363,14 @@ describe("@id", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + actors: MovieActorsDeleteOperation + } + type MovieEdge { cursor: String node: Movie @@ -384,8 +418,8 @@ describe("@id", () => { type Mutation { createActors(input: [ActorCreateInput!]!): ActorCreateResponse createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteActors(where: ActorOperationWhere): DeleteResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteActors(input: ActorDeleteInput, where: ActorOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateActors(input: ActorUpdateInput!, where: ActorOperationWhere): ActorUpdateResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/directives/relayId.test.ts b/packages/graphql/tests/api-v6/schema/directives/relayId.test.ts index cffcff4029..11f823a1e8 100644 --- a/packages/graphql/tests/api-v6/schema/directives/relayId.test.ts +++ b/packages/graphql/tests/api-v6/schema/directives/relayId.test.ts @@ -109,6 +109,14 @@ describe("RelayId", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -155,7 +163,7 @@ describe("RelayId", () => { type Mutation { createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/relationship.test.ts b/packages/graphql/tests/api-v6/schema/relationship.test.ts index 4c9f189ad4..51c3aa713e 100644 --- a/packages/graphql/tests/api-v6/schema/relationship.test.ts +++ b/packages/graphql/tests/api-v6/schema/relationship.test.ts @@ -79,6 +79,14 @@ describe("Relationships", () => { info: CreateInfo } + input ActorDeleteInput { + node: ActorDeleteNode + } + + input ActorDeleteNode { + movies: ActorMoviesDeleteOperation + } + type ActorEdge { cursor: String node: Actor @@ -93,6 +101,15 @@ describe("Relationships", () => { edges: ActorMoviesEdgeSort } + input ActorMoviesDeleteInput { + input: MovieDeleteInput + where: ActorMoviesOperationWhere + } + + input ActorMoviesDeleteOperation { + delete: ActorMoviesDeleteInput + } + type ActorMoviesEdge { cursor: String node: Movie @@ -201,6 +218,15 @@ describe("Relationships", () => { edges: MovieActorsEdgeSort } + input MovieActorsDeleteInput { + input: ActorDeleteInput + where: MovieActorsOperationWhere + } + + input MovieActorsDeleteOperation { + delete: MovieActorsDeleteInput + } + type MovieActorsEdge { cursor: String node: Actor @@ -274,6 +300,14 @@ describe("Relationships", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + actors: MovieActorsDeleteOperation + } + type MovieEdge { cursor: String node: Movie @@ -318,8 +352,8 @@ describe("Relationships", () => { type Mutation { createActors(input: [ActorCreateInput!]!): ActorCreateResponse createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteActors(where: ActorOperationWhere): DeleteResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteActors(input: ActorDeleteInput, where: ActorOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateActors(input: ActorUpdateInput!, where: ActorOperationWhere): ActorUpdateResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } @@ -433,6 +467,14 @@ describe("Relationships", () => { info: CreateInfo } + input ActorDeleteInput { + node: ActorDeleteNode + } + + input ActorDeleteNode { + movies: ActorMoviesDeleteOperation + } + type ActorEdge { cursor: String node: Actor @@ -447,6 +489,15 @@ describe("Relationships", () => { edges: ActorMoviesEdgeSort } + input ActorMoviesDeleteInput { + input: MovieDeleteInput + where: ActorMoviesOperationWhere + } + + input ActorMoviesDeleteOperation { + delete: ActorMoviesDeleteInput + } + type ActorMoviesEdge { cursor: String node: Movie @@ -570,6 +621,15 @@ describe("Relationships", () => { edges: MovieActorsEdgeSort } + input MovieActorsDeleteInput { + input: ActorDeleteInput + where: MovieActorsOperationWhere + } + + input MovieActorsDeleteOperation { + delete: MovieActorsDeleteInput + } + type MovieActorsEdge { cursor: String node: Actor @@ -646,6 +706,14 @@ describe("Relationships", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + actors: MovieActorsDeleteOperation + } + type MovieEdge { cursor: String node: Movie @@ -690,8 +758,8 @@ describe("Relationships", () => { type Mutation { createActors(input: [ActorCreateInput!]!): ActorCreateResponse createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteActors(where: ActorOperationWhere): DeleteResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteActors(input: ActorDeleteInput, where: ActorOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateActors(input: ActorUpdateInput!, where: ActorOperationWhere): ActorUpdateResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/simple.test.ts b/packages/graphql/tests/api-v6/schema/simple.test.ts index 56b31a0359..106b64983b 100644 --- a/packages/graphql/tests/api-v6/schema/simple.test.ts +++ b/packages/graphql/tests/api-v6/schema/simple.test.ts @@ -87,6 +87,14 @@ describe("Simple Aura-API", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -129,7 +137,7 @@ describe("Simple Aura-API", () => { type Mutation { createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } @@ -219,6 +227,14 @@ describe("Simple Aura-API", () => { info: CreateInfo } + input ActorDeleteInput { + node: ActorDeleteNode + } + + input ActorDeleteNode { + _emptyInput: Boolean + } + type ActorEdge { cursor: String node: Actor @@ -306,6 +322,14 @@ describe("Simple Aura-API", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -349,8 +373,8 @@ describe("Simple Aura-API", () => { type Mutation { createActors(input: [ActorCreateInput!]!): ActorCreateResponse createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteActors(where: ActorOperationWhere): DeleteResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteActors(input: ActorDeleteInput, where: ActorOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateActors(input: ActorUpdateInput!, where: ActorOperationWhere): ActorUpdateResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } @@ -456,6 +480,14 @@ describe("Simple Aura-API", () => { movies: [Movie!]! } + input MovieDeleteInput { + node: MovieDeleteNode + } + + input MovieDeleteNode { + _emptyInput: Boolean + } + type MovieEdge { cursor: String node: Movie @@ -498,7 +530,7 @@ describe("Simple Aura-API", () => { type Mutation { createMovies(input: [MovieCreateInput!]!): MovieCreateResponse - deleteMovies(where: MovieOperationWhere): DeleteResponse + deleteMovies(input: MovieDeleteInput, where: MovieOperationWhere): DeleteResponse updateMovies(input: MovieUpdateInput!, where: MovieOperationWhere): MovieUpdateResponse } diff --git a/packages/graphql/tests/api-v6/schema/types/array.test.ts b/packages/graphql/tests/api-v6/schema/types/array.test.ts index c923b7d009..6ba7f68afc 100644 --- a/packages/graphql/tests/api-v6/schema/types/array.test.ts +++ b/packages/graphql/tests/api-v6/schema/types/array.test.ts @@ -201,8 +201,8 @@ describe("Scalars", () => { type Mutation { createNodeTypes(input: [NodeTypeCreateInput!]!): NodeTypeCreateResponse createRelatedNodes(input: [RelatedNodeCreateInput!]!): RelatedNodeCreateResponse - deleteNodeTypes(where: NodeTypeOperationWhere): DeleteResponse - deleteRelatedNodes(where: RelatedNodeOperationWhere): DeleteResponse + deleteNodeTypes(input: NodeTypeDeleteInput, where: NodeTypeOperationWhere): DeleteResponse + deleteRelatedNodes(input: RelatedNodeDeleteInput, where: RelatedNodeOperationWhere): DeleteResponse updateNodeTypes(input: NodeTypeUpdateInput!, where: NodeTypeOperationWhere): NodeTypeUpdateResponse updateRelatedNodes(input: RelatedNodeUpdateInput!, where: RelatedNodeOperationWhere): RelatedNodeUpdateResponse } @@ -259,6 +259,14 @@ describe("Scalars", () => { nodeTypes: [NodeType!]! } + input NodeTypeDeleteInput { + node: NodeTypeDeleteNode + } + + input NodeTypeDeleteNode { + relatedNode: NodeTypeRelatedNodeDeleteOperation + } + type NodeTypeEdge { cursor: String node: NodeType @@ -280,6 +288,15 @@ describe("Scalars", () => { pageInfo: PageInfo } + input NodeTypeRelatedNodeDeleteInput { + input: RelatedNodeDeleteInput + where: NodeTypeRelatedNodeOperationWhere + } + + input NodeTypeRelatedNodeDeleteOperation { + delete: NodeTypeRelatedNodeDeleteInput + } + type NodeTypeRelatedNodeEdge { cursor: String node: RelatedNode @@ -428,6 +445,14 @@ describe("Scalars", () => { relatedNodes: [RelatedNode!]! } + input RelatedNodeDeleteInput { + node: RelatedNodeDeleteNode + } + + input RelatedNodeDeleteNode { + _emptyInput: Boolean + } + type RelatedNodeEdge { cursor: String node: RelatedNode diff --git a/packages/graphql/tests/api-v6/schema/types/scalars.test.ts b/packages/graphql/tests/api-v6/schema/types/scalars.test.ts index 6fbbebe2b6..34d50f0048 100644 --- a/packages/graphql/tests/api-v6/schema/types/scalars.test.ts +++ b/packages/graphql/tests/api-v6/schema/types/scalars.test.ts @@ -175,8 +175,8 @@ describe("Scalars", () => { type Mutation { createNodeTypes(input: [NodeTypeCreateInput!]!): NodeTypeCreateResponse createRelatedNodes(input: [RelatedNodeCreateInput!]!): RelatedNodeCreateResponse - deleteNodeTypes(where: NodeTypeOperationWhere): DeleteResponse - deleteRelatedNodes(where: RelatedNodeOperationWhere): DeleteResponse + deleteNodeTypes(input: NodeTypeDeleteInput, where: NodeTypeOperationWhere): DeleteResponse + deleteRelatedNodes(input: RelatedNodeDeleteInput, where: RelatedNodeOperationWhere): DeleteResponse updateNodeTypes(input: NodeTypeUpdateInput!, where: NodeTypeOperationWhere): NodeTypeUpdateResponse updateRelatedNodes(input: RelatedNodeUpdateInput!, where: RelatedNodeOperationWhere): RelatedNodeUpdateResponse } @@ -237,6 +237,14 @@ describe("Scalars", () => { nodeTypes: [NodeType!]! } + input NodeTypeDeleteInput { + node: NodeTypeDeleteNode + } + + input NodeTypeDeleteNode { + relatedNode: NodeTypeRelatedNodeDeleteOperation + } + type NodeTypeEdge { cursor: String node: NodeType @@ -262,6 +270,15 @@ describe("Scalars", () => { edges: NodeTypeRelatedNodeEdgeSort } + input NodeTypeRelatedNodeDeleteInput { + input: RelatedNodeDeleteInput + where: NodeTypeRelatedNodeOperationWhere + } + + input NodeTypeRelatedNodeDeleteOperation { + delete: NodeTypeRelatedNodeDeleteInput + } + type NodeTypeRelatedNodeEdge { cursor: String node: RelatedNode @@ -434,6 +451,14 @@ describe("Scalars", () => { relatedNodes: [RelatedNode!]! } + input RelatedNodeDeleteInput { + node: RelatedNodeDeleteNode + } + + input RelatedNodeDeleteNode { + _emptyInput: Boolean + } + type RelatedNodeEdge { cursor: String node: RelatedNode diff --git a/packages/graphql/tests/api-v6/schema/types/spatial.test.ts b/packages/graphql/tests/api-v6/schema/types/spatial.test.ts index 776ec5eef2..0c71dbf481 100644 --- a/packages/graphql/tests/api-v6/schema/types/spatial.test.ts +++ b/packages/graphql/tests/api-v6/schema/types/spatial.test.ts @@ -99,8 +99,8 @@ describe("Spatial Types", () => { type Mutation { createNodeTypes(input: [NodeTypeCreateInput!]!): NodeTypeCreateResponse createRelatedNodes(input: [RelatedNodeCreateInput!]!): RelatedNodeCreateResponse - deleteNodeTypes(where: NodeTypeOperationWhere): DeleteResponse - deleteRelatedNodes(where: RelatedNodeOperationWhere): DeleteResponse + deleteNodeTypes(input: NodeTypeDeleteInput, where: NodeTypeOperationWhere): DeleteResponse + deleteRelatedNodes(input: RelatedNodeDeleteInput, where: RelatedNodeOperationWhere): DeleteResponse updateNodeTypes(input: NodeTypeUpdateInput!, where: NodeTypeOperationWhere): NodeTypeUpdateResponse updateRelatedNodes(input: RelatedNodeUpdateInput!, where: RelatedNodeOperationWhere): RelatedNodeUpdateResponse } @@ -141,6 +141,14 @@ describe("Spatial Types", () => { nodeTypes: [NodeType!]! } + input NodeTypeDeleteInput { + node: NodeTypeDeleteNode + } + + input NodeTypeDeleteNode { + relatedNode: NodeTypeRelatedNodeDeleteOperation + } + type NodeTypeEdge { cursor: String node: NodeType @@ -162,6 +170,15 @@ describe("Spatial Types", () => { pageInfo: PageInfo } + input NodeTypeRelatedNodeDeleteInput { + input: RelatedNodeDeleteInput + where: NodeTypeRelatedNodeOperationWhere + } + + input NodeTypeRelatedNodeDeleteOperation { + delete: NodeTypeRelatedNodeDeleteInput + } + type NodeTypeRelatedNodeEdge { cursor: String node: RelatedNode @@ -296,6 +313,14 @@ describe("Spatial Types", () => { relatedNodes: [RelatedNode!]! } + input RelatedNodeDeleteInput { + node: RelatedNodeDeleteNode + } + + input RelatedNodeDeleteNode { + _emptyInput: Boolean + } + type RelatedNodeEdge { cursor: String node: RelatedNode diff --git a/packages/graphql/tests/api-v6/schema/types/temporals.test.ts b/packages/graphql/tests/api-v6/schema/types/temporals.test.ts index eeb5e73eb3..d1c9612346 100644 --- a/packages/graphql/tests/api-v6/schema/types/temporals.test.ts +++ b/packages/graphql/tests/api-v6/schema/types/temporals.test.ts @@ -179,8 +179,8 @@ describe("Temporals", () => { type Mutation { createNodeTypes(input: [NodeTypeCreateInput!]!): NodeTypeCreateResponse createRelatedNodes(input: [RelatedNodeCreateInput!]!): RelatedNodeCreateResponse - deleteNodeTypes(where: NodeTypeOperationWhere): DeleteResponse - deleteRelatedNodes(where: RelatedNodeOperationWhere): DeleteResponse + deleteNodeTypes(input: NodeTypeDeleteInput, where: NodeTypeOperationWhere): DeleteResponse + deleteRelatedNodes(input: RelatedNodeDeleteInput, where: RelatedNodeOperationWhere): DeleteResponse updateNodeTypes(input: NodeTypeUpdateInput!, where: NodeTypeOperationWhere): NodeTypeUpdateResponse updateRelatedNodes(input: RelatedNodeUpdateInput!, where: RelatedNodeOperationWhere): RelatedNodeUpdateResponse } @@ -229,6 +229,14 @@ describe("Temporals", () => { nodeTypes: [NodeType!]! } + input NodeTypeDeleteInput { + node: NodeTypeDeleteNode + } + + input NodeTypeDeleteNode { + relatedNode: NodeTypeRelatedNodeDeleteOperation + } + type NodeTypeEdge { cursor: String node: NodeType @@ -254,6 +262,15 @@ describe("Temporals", () => { edges: NodeTypeRelatedNodeEdgeSort } + input NodeTypeRelatedNodeDeleteInput { + input: RelatedNodeDeleteInput + where: NodeTypeRelatedNodeOperationWhere + } + + input NodeTypeRelatedNodeDeleteOperation { + delete: NodeTypeRelatedNodeDeleteInput + } + type NodeTypeRelatedNodeEdge { cursor: String node: RelatedNode @@ -396,6 +413,14 @@ describe("Temporals", () => { relatedNodes: [RelatedNode!]! } + input RelatedNodeDeleteInput { + node: RelatedNodeDeleteNode + } + + input RelatedNodeDeleteNode { + _emptyInput: Boolean + } + type RelatedNodeEdge { cursor: String node: RelatedNode