@contember/engine-content-api 2.0.0-beta.5 → 2.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/development/src/mapper/delete/DeleteExecutor.cjs +1 -1
- package/dist/development/src/mapper/delete/DeleteExecutor.cjs.map +1 -1
- package/dist/development/src/mapper/delete/DeleteExecutor.js +1 -1
- package/dist/development/src/mapper/delete/DeleteExecutor.js.map +1 -1
- package/dist/production/src/mapper/delete/DeleteExecutor.cjs +1 -1
- package/dist/production/src/mapper/delete/DeleteExecutor.cjs.map +1 -1
- package/dist/production/src/mapper/delete/DeleteExecutor.js +1 -1
- package/dist/production/src/mapper/delete/DeleteExecutor.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/mapper/delete/DeleteExecutor.ts +1 -1
- package/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.ts +3 -3
- package/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/delete/restrictOnDelete.test.ts +2 -2
- package/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.ts +2 -2
- package/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.ts +3 -3
- package/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/connect.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/update/oneHasOneOwning/connect.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/update/oneHasOneOwning/create.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/update/oneHasOneOwning/delete.test.ts +2 -2
|
@@ -187,7 +187,7 @@ class DeleteExecutor {
|
|
|
187
187
|
return orphanColumns.reduce((qb2, column) => qb2.select(["root_", column], `_${column}`), qb);
|
|
188
188
|
}
|
|
189
189
|
createFetchByIdQueryBuilder(entity, relation, values) {
|
|
190
|
-
return Database.SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(relation.joiningColumn.columnName, values));
|
|
190
|
+
return Database.SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(["root_", relation.joiningColumn.columnName], values));
|
|
191
191
|
}
|
|
192
192
|
filterPlannedForDelete(state, entity, values) {
|
|
193
193
|
return values.filter((it) => !state.isPlannedDelete(entity.name, it.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeleteExecutor.cjs","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(relation.joiningColumn.columnName, values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["schema","MutationNothingToDo","NothingToDoReason","DeleteState","MutationDeleteOk","BeforeDeleteEvent","MutationUpdateOk","BeforeUpdateEvent","ImplementationException","AfterUpdateEvent","DeleteBuilder","findRelationsWithOrphanRemoval","SelectBuilder","MutationNoResultError","MutationEntryNotFoundError","findOwningRelations","Model","assertNever","formatConstraintViolationMessage","MutationConstraintViolationError","ConstraintType","Acl","values","getEntity","Literal","qb","entity","ids"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeleteExecutor.cjs","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(['root_', relation.joiningColumn.columnName], values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["schema","MutationNothingToDo","NothingToDoReason","DeleteState","MutationDeleteOk","BeforeDeleteEvent","MutationUpdateOk","BeforeUpdateEvent","ImplementationException","AfterUpdateEvent","DeleteBuilder","findRelationsWithOrphanRemoval","SelectBuilder","MutationNoResultError","MutationEntryNotFoundError","findOwningRelations","Model","assertNever","formatConstraintViolationMessage","MutationConstraintViolationError","ConstraintType","Acl","values","getEntity","Literal","qb","entity","ids"],"mappings":"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"}
|
|
@@ -185,7 +185,7 @@ class DeleteExecutor {
|
|
|
185
185
|
return orphanColumns.reduce((qb2, column) => qb2.select(["root_", column], `_${column}`), qb);
|
|
186
186
|
}
|
|
187
187
|
createFetchByIdQueryBuilder(entity, relation, values) {
|
|
188
|
-
return SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(relation.joiningColumn.columnName, values));
|
|
188
|
+
return SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(["root_", relation.joiningColumn.columnName], values));
|
|
189
189
|
}
|
|
190
190
|
filterPlannedForDelete(state, entity, values) {
|
|
191
191
|
return values.filter((it) => !state.isPlannedDelete(entity.name, it.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeleteExecutor.js","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(relation.joiningColumn.columnName, values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["values","qb","entity","ids"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeleteExecutor.js","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(['root_', relation.joiningColumn.columnName], values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["values","qb","entity","ids"],"mappings":"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"}
|
|
@@ -187,7 +187,7 @@ class DeleteExecutor {
|
|
|
187
187
|
return orphanColumns.reduce((qb2, column) => qb2.select(["root_", column], `_${column}`), qb);
|
|
188
188
|
}
|
|
189
189
|
createFetchByIdQueryBuilder(entity, relation, values) {
|
|
190
|
-
return Database.SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(relation.joiningColumn.columnName, values));
|
|
190
|
+
return Database.SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(["root_", relation.joiningColumn.columnName], values));
|
|
191
191
|
}
|
|
192
192
|
filterPlannedForDelete(state, entity, values) {
|
|
193
193
|
return values.filter((it) => !state.isPlannedDelete(entity.name, it.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeleteExecutor.cjs","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(relation.joiningColumn.columnName, values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["schema","MutationNothingToDo","NothingToDoReason","DeleteState","MutationDeleteOk","BeforeDeleteEvent","MutationUpdateOk","BeforeUpdateEvent","ImplementationException","AfterUpdateEvent","DeleteBuilder","findRelationsWithOrphanRemoval","SelectBuilder","MutationNoResultError","MutationEntryNotFoundError","findOwningRelations","Model","assertNever","formatConstraintViolationMessage","MutationConstraintViolationError","ConstraintType","Acl","values","getEntity","Literal","qb","entity","ids"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeleteExecutor.cjs","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(['root_', relation.joiningColumn.columnName], values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["schema","MutationNothingToDo","NothingToDoReason","DeleteState","MutationDeleteOk","BeforeDeleteEvent","MutationUpdateOk","BeforeUpdateEvent","ImplementationException","AfterUpdateEvent","DeleteBuilder","findRelationsWithOrphanRemoval","SelectBuilder","MutationNoResultError","MutationEntryNotFoundError","findOwningRelations","Model","assertNever","formatConstraintViolationMessage","MutationConstraintViolationError","ConstraintType","Acl","values","getEntity","Literal","qb","entity","ids"],"mappings":"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"}
|
|
@@ -185,7 +185,7 @@ class DeleteExecutor {
|
|
|
185
185
|
return orphanColumns.reduce((qb2, column) => qb2.select(["root_", column], `_${column}`), qb);
|
|
186
186
|
}
|
|
187
187
|
createFetchByIdQueryBuilder(entity, relation, values) {
|
|
188
|
-
return SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(relation.joiningColumn.columnName, values));
|
|
188
|
+
return SelectBuilder.create().from(entity.tableName, "root_").select(["root_", entity.primaryColumn], "id").select(["root_", relation.joiningColumn.columnName], "ref").where((expr) => expr.in(["root_", relation.joiningColumn.columnName], values));
|
|
189
189
|
}
|
|
190
190
|
filterPlannedForDelete(state, entity, values) {
|
|
191
191
|
return values.filter((it) => !state.isPlannedDelete(entity.name, it.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeleteExecutor.js","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(relation.joiningColumn.columnName, values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["values","qb","entity","ids"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DeleteExecutor.js","sources":["../../../../../../packages/engine-content-api/src/mapper/delete/DeleteExecutor.ts"],"sourcesContent":["import { Acl, Input, Model } from '@contember/schema'\nimport { assertNever } from '../../utils'\nimport { Client, DeleteBuilder, Literal, SelectBuilder } from '@contember/database'\nimport { PathFactory, WhereBuilder } from '../select'\nimport { PredicateFactory } from '../../acl'\nimport { UpdateBuilderFactory } from '../update'\nimport {\n\tConstraintType,\n\tMutationConstraintViolationError,\n\tMutationDeleteOk,\n\tMutationEntryNotFoundError,\n\tMutationNoResultError,\n\tMutationNothingToDo,\n\tMutationResultList,\n\tMutationUpdateOk,\n\tNothingToDoReason,\n} from '../Result'\nimport { Mapper } from '../Mapper'\nimport { CheckedPrimary } from '../CheckedPrimary'\nimport { DeleteState } from './DeleteState'\nimport {\n\tEntityReferenceRow,\n\tfindOwningRelations,\n\tfindRelationsWithOrphanRemoval,\n\tformatConstraintViolationMessage,\n\tOneHasOneOwningRelationTuple,\n} from './helpers'\nimport { getEntity } from '@contember/schema-utils'\nimport { AfterUpdateEvent, BeforeDeleteEvent, BeforeUpdateEvent, EventManager } from '../EventManager'\nimport { ImplementationException } from '../../exception'\n\ntype DeleteQueue = [entity: Model.Entity, ids: Input.PrimaryValue[]][]\n\ntype DeleteInfoRow = { allowed: boolean; id: Input.PrimaryValue } & { [K in `_${string}`]: Input.PrimaryValue }\n\nexport class DeleteExecutor {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly whereBuilder: WhereBuilder,\n\t\tprivate readonly updateBuilderFactory: UpdateBuilderFactory,\n\t\tprivate readonly pathFactory: PathFactory,\n\t) {\n\t}\n\n\tpublic async execute(\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tby: Input.UniqueWhere | CheckedPrimary,\n\t\tfilter?: Input.OptionalWhere,\n\t): Promise<MutationResultList> {\n\t\treturn mapper.mutex.execute(async () => {\n\t\t\tconst [primaryValue, err] = await mapper.getPrimaryValue(entity, by)\n\t\t\tif (err) return [err]\n\n\t\t\tif (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {\n\t\t\t\treturn [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]\n\t\t\t}\n\n\t\t\tconst primaryWhere = { [entity.primary]: { eq: primaryValue } }\n\t\t\tconst where = filter ? { and: [primaryWhere, filter] } : primaryWhere\n\t\t\tconst state = new DeleteState(mapper.deletedEntities)\n\t\t\tconst deletePrimary = await this.collectDeleteInfo(state, mapper, entity, where)\n\n\t\t\tconst deleteQueue: DeleteQueue = [[entity, deletePrimary]]\n\t\t\tawait this.collectOrphanRemovals(state, mapper, deleteQueue)\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn state.getResult()\n\t\t\t}\n\t\t\tconst result = state.getResult()\n\t\t\tconst entryToEventMap = new Map<MutationUpdateOk, BeforeUpdateEvent>()\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationDeleteOk) {\n\t\t\t\t\tawait mapper.eventManager.fire(new BeforeDeleteEvent(entry.entity, entry.primary))\n\t\t\t\t} else if (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeUpdateEvent = new BeforeUpdateEvent(entry.entity, [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t}], entry.primary)\n\t\t\t\t\tentryToEventMap.set(entry, beforeUpdateEvent)\n\t\t\t\t\tawait mapper.eventManager.fire(beforeUpdateEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.executeDeletes(deleteQueue, mapper.db)\n\n\t\t\tfor (const entry of result) {\n\t\t\t\tif (entry instanceof MutationUpdateOk) {\n\t\t\t\t\tconst beforeEvent = entryToEventMap.get(entry)\n\t\t\t\t\tif (!beforeEvent) {\n\t\t\t\t\t\tthrow new ImplementationException()\n\t\t\t\t\t}\n\t\t\t\t\tconst data = [{\n\t\t\t\t\t\tcolumnName: Object.keys(entry.values)[0],\n\t\t\t\t\t\tfieldName: Object.keys(entry.input)[0],\n\t\t\t\t\t\tcolumnType: 'text',\n\t\t\t\t\t\tvalue: null,\n\t\t\t\t\t\told: Object.values(entry.oldValues ?? {})[0],\n\t\t\t\t\t}]\n\t\t\t\t\tconst afterEvent = new AfterUpdateEvent(entry.entity, data, entry.primary)\n\t\t\t\t\tbeforeEvent.afterEvent = afterEvent\n\t\t\t\t\tawait mapper.eventManager.fire(afterEvent)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.confirmDeleted()\n\n\t\t\treturn state.getResult()\n\t\t})\n\t}\n\n\tprivate async executeDeletes(deleteQueue: DeleteQueue, db: Client): Promise<void> {\n\t\tfor (const [entity, ids] of deleteQueue) {\n\t\t\tif (ids.length === 0) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tawait DeleteBuilder.create()\n\t\t\t\t.from(entity.tableName)\n\t\t\t\t.where(expr => expr.in(entity.primaryColumn, ids))\n\t\t\t\t.execute(db)\n\t\t}\n\t}\n\n\tprivate async collectDeleteInfo(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = SelectBuilder.create<DeleteInfoRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowedFlag = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\t\tconst qbWithWhere = this.whereBuilder.build(qbWithAllowedFlag, entity, this.pathFactory.create([]), where)\n\n\t\tconst fullResult = await qbWithWhere.getResult(mapper.db)\n\n\t\tif (fullResult.length === 0) {\n\t\t\tstate.pushFailResult(new MutationNoResultError([]))\n\t\t\treturn []\n\t\t}\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, fullResult)\n\n\t\tconst disallowed: Input.PrimaryValue[] = result.filter(it => !it.allowed).map(it => it.id)\n\t\tif (disallowed.length) {\n\t\t\tstate.pushFailResult(new MutationEntryNotFoundError([], { [entity.primary]: { in: disallowed } }))\n\t\t\treturn []\n\t\t}\n\n\t\treturn await this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectOnDeleteInfo(state: DeleteState, mapper: Mapper, entity: Model.Entity, values: Input.PrimaryValue[]): Promise<void> {\n\t\tif (values.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst owningRelations = findOwningRelations(this.schema, entity)\n\t\tfor (const [owningEntity, relation] of owningRelations) {\n\t\t\tif (owningEntity.view) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (relation.joiningColumn.onDelete === Model.OnDelete.restrict) {\n\t\t\t\tawait this.collectRestrictResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.cascade) {\n\t\t\t\tawait this.collectCascadeResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else if (relation.joiningColumn.onDelete === Model.OnDelete.setNull) {\n\t\t\t\tawait this.collectSetNullResult(state, mapper, owningEntity, relation, values)\n\t\t\t} else {\n\t\t\t\tassertNever(relation.joiningColumn.onDelete)\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate async collectCascadeResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.createDeletePredicate(entity)\n\t\tconst orphanRemovals = findRelationsWithOrphanRemoval(this.schema, entity)\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithOrphanColumns = this.qbOrphanColumns(qb, orphanRemovals)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qbWithOrphanColumns)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length > 0) {\n\t\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t\t+ ' OnDelete behaviour of this relation is set to \"cascade\". This is possibly caused by ACL denial.'\n\n\t\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t\t\treturn\n\t\t}\n\n\t\tawait this.processDeleteResult(state, mapper, entity, result, orphanRemovals)\n\t}\n\n\n\tprivate async collectSetNullResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tconst predicate = this.predicateFactory.create(entity, Acl.Operation.update, [relation.name])\n\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst qbWithAllowed = this.qbWithAllowed(entity, predicate, qb)\n\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qbWithAllowed.getResult(mapper.db))\n\n\t\tconst disallowed = result.filter(it => !it.allowed)\n\n\t\tif (disallowed.length === 0) {\n\t\t\tconst input = { [relation.name]: { disconnect: true } }\n\t\t\tconst values = { [relation.joiningColumn.columnName]: null }\n\n\t\t\tstate.pushOkResult(result.map(it => new MutationUpdateOk([], entity, it.id, input, values, { [relation.joiningColumn.columnName]: it.ref })))\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(disallowed, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"set null\". This is possibly caused by ACL denial.'\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\n\tprivate async collectRestrictResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\trelation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation,\n\t\tvalues: Input.PrimaryValue[],\n\t): Promise<void> {\n\t\tif (mapper.constraintHelper.areConstraintsDeferred('foreignKey')) {\n\t\t\treturn\n\t\t}\n\t\tconst qb = this.createFetchByIdQueryBuilder(entity, relation, values)\n\t\tconst result = this.filterPlannedForDelete(state, entity, await qb.getResult(mapper.db))\n\n\t\tif (result.length === 0) {\n\t\t\treturn\n\t\t}\n\n\t\tconst message = formatConstraintViolationMessage(result, entity, relation)\n\t\t\t+ ' OnDelete behaviour of this relation is set to \"restrict\". You might consider changing it to \"setNull\" or \"cascade\".'\n\n\t\tstate.pushFailResult(new MutationConstraintViolationError([], ConstraintType.foreignKey, message))\n\t}\n\n\tprivate async collectOrphanRemovals(state: DeleteState, mapper: Mapper, deleteQueue: DeleteQueue) {\n\t\tdo {\n\t\t\tif (!state.isOk()) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst orphanRemoval = state.fetchOrphanRemovals()\n\t\t\tif (orphanRemoval === null) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tconst entity = getEntity(this.schema, orphanRemoval[0])\n\t\t\tconst orphanResult = await this.collectDeleteInfo(state, mapper, entity, { [entity.primary]: { in: orphanRemoval[1] } })\n\t\t\tdeleteQueue.push([entity, orphanResult])\n\n\t\t} while (true)\n\t}\n\n\tprivate qbWithAllowed<R>(entity: Model.Entity, predicate: Input.OptionalWhere, selectQb: SelectBuilder<R>): SelectBuilder<R & { allowed: boolean }> {\n\t\treturn this.whereBuilder.buildAdvanced<R & { allowed: boolean }>(entity, this.pathFactory.create([]), predicate, cb => {\n\t\t\tconst qb = selectQb.select(expr => expr.selectCondition(cb), 'allowed')\n\t\t\treturn (qb === selectQb ? qb.select(new Literal('true'), 'allowed') : qb) as SelectBuilder<R & { allowed: boolean }>\n\t\t})\n\t}\n\n\tprivate qbOrphanColumns<R>(qb: SelectBuilder<R>, orphanRemovals: OneHasOneOwningRelationTuple[]): SelectBuilder<R> {\n\t\tconst orphanColumns = orphanRemovals.map(([, rel]) => rel.joiningColumn.columnName)\n\t\treturn orphanColumns.reduce((qb, column) => qb.select(['root_', column], `_${column}`), qb)\n\t}\n\n\tprivate createFetchByIdQueryBuilder(entity: Model.Entity, relation: Model.ManyHasOneRelation | Model.OneHasOneOwningRelation, values: Input.PrimaryValue[]) {\n\t\treturn SelectBuilder.create<EntityReferenceRow>()\n\t\t\t.from(entity.tableName, 'root_')\n\t\t\t.select(['root_', entity.primaryColumn], 'id')\n\t\t\t.select(['root_', relation.joiningColumn.columnName], 'ref')\n\t\t\t.where(expr => expr.in(['root_', relation.joiningColumn.columnName], values))\n\t}\n\n\tprivate filterPlannedForDelete<R extends {id: Input.PrimaryValue}>(state: DeleteState, entity: Model.Entity, values: R[]): R[] {\n\t\treturn values.filter(it => !state.isPlannedDelete(entity.name, it.id))\n\t}\n\n\n\tprivate async processDeleteResult(\n\t\tstate: DeleteState,\n\t\tmapper: Mapper,\n\t\tentity: Model.Entity,\n\t\tresult: DeleteInfoRow[],\n\t\torphanRemovals: OneHasOneOwningRelationTuple[],\n\t): Promise<Input.PrimaryValue[]> {\n\t\tconst ids = result.map(it => it.id)\n\t\tstate.markPlannedDelete(entity.name, ids)\n\t\tstate.pushOkResult(ids.map(id => new MutationDeleteOk([], entity, id)))\n\n\t\tawait this.collectOnDeleteInfo(state, mapper, entity, ids)\n\n\t\tfor (const [entity, relation] of orphanRemovals) {\n\t\t\tconst ids = result.map(it => it[`_${relation.joiningColumn.columnName}`]).filter(it => it !== null)\n\t\t\tif (ids.length) {\n\t\t\t\tstate.addOrphanRemoval(entity.name, ids)\n\t\t\t}\n\t\t}\n\t\treturn ids\n\t}\n}\n"],"names":["values","qb","entity","ids"],"mappings":"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"}
|