@contember/engine-content-api 1.2.0-alpha.17 → 1.2.0-alpha.19
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/src/mapper/MapperContainer.js +1 -1
- package/dist/src/mapper/MapperContainer.js.map +1 -1
- package/dist/src/mapper/delete/DeleteExecutor.js +2 -2
- package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
- package/dist/src/mapper/select/Path.d.ts +1 -0
- package/dist/src/mapper/select/Path.d.ts.map +1 -1
- package/dist/src/mapper/select/Path.js +4 -1
- package/dist/src/mapper/select/Path.js.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.d.ts +2 -1
- package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.js +85 -27
- package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
- package/dist/src/resolvers/ExecutionContainerFactory.d.ts +1 -1
- package/dist/src/resolvers/ExecutionContainerFactory.d.ts.map +1 -1
- package/dist/src/resolvers/GraphQlQueryAstFactory.d.ts +1 -2
- package/dist/src/resolvers/GraphQlQueryAstFactory.d.ts.map +1 -1
- package/dist/src/resolvers/GraphQlQueryAstFactory.js +2 -2
- package/dist/src/resolvers/GraphQlQueryAstFactory.js.map +1 -1
- package/dist/src/resolvers/MutationResolver.d.ts.map +1 -1
- package/dist/src/resolvers/MutationResolver.js +10 -0
- package/dist/src/resolvers/MutationResolver.js.map +1 -1
- package/dist/src/schema/EnumsProvider.d.ts.map +1 -1
- package/dist/src/schema/EnumsProvider.js +1 -2
- package/dist/src/schema/EnumsProvider.js.map +1 -1
- package/dist/src/schema/OrderByTypeProvider.d.ts +1 -1
- package/dist/src/schema/OrderByTypeProvider.d.ts.map +1 -1
- package/dist/src/schema/OrderByTypeProvider.js +1 -1
- package/dist/src/schema/OrderByTypeProvider.js.map +1 -1
- package/dist/src/schema/WhereTypeProvider.d.ts +1 -2
- package/dist/src/schema/WhereTypeProvider.d.ts.map +1 -1
- package/dist/src/schema/WhereTypeProvider.js.map +1 -1
- package/dist/src/schema/entities/FieldArgsVisitor.d.ts +1 -2
- package/dist/src/schema/entities/FieldArgsVisitor.d.ts.map +1 -1
- package/dist/src/schema/entities/FieldArgsVisitor.js.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js.map +1 -1
- package/dist/src/schema/utils.d.ts +1 -1
- package/dist/src/schema/utils.d.ts.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/bugs/bug102.test.js +6 -6
- package/dist/tests/cases/bugs/bug102.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/deleteById.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/deleteById.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js +17 -15
- package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.js +4 -5
- package/dist/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.js +5 -3
- package/dist/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.js +10 -10
- package/dist/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.js +5 -5
- package/dist/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +4 -4
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
- package/dist/tests/cases/unit/whereBuilder.test.js +60 -4
- package/dist/tests/cases/unit/whereBuilder.test.js.map +1 -1
- package/dist/tests/src/test.js +2 -2
- package/dist/tests/src/test.js.map +1 -1
- package/dist/tests/src/testGraphql.d.ts.map +1 -1
- package/dist/tests/src/testGraphql.js +9 -5
- package/dist/tests/src/testGraphql.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -11
- package/src/mapper/MapperContainer.ts +1 -1
- package/src/mapper/delete/DeleteExecutor.ts +2 -2
- package/src/mapper/select/Path.ts +4 -1
- package/src/mapper/select/WhereBuilder.ts +97 -48
- package/src/resolvers/ExecutionContainerFactory.ts +1 -1
- package/src/resolvers/GraphQlQueryAstFactory.ts +5 -4
- package/src/resolvers/MutationResolver.ts +9 -1
- package/src/schema/EnumsProvider.ts +2 -4
- package/src/schema/OrderByTypeProvider.ts +9 -2
- package/src/schema/WhereTypeProvider.ts +1 -2
- package/src/schema/entities/FieldArgsVisitor.ts +1 -2
- package/src/schema/mutations/CreateEntityRelationInputFieldVisitor.ts +1 -2
- package/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.ts +7 -2
- package/src/schema/utils.ts +1 -1
- package/src/tsconfig.json +0 -3
- package/tests/cases/bugs/bug102.test.ts +6 -6
- package/tests/cases/integration/graphQlRequests/delete/aclDelete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/delete/deleteById.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.ts +17 -15
- package/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.ts +4 -5
- package/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.ts +5 -3
- package/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.ts +10 -10
- package/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.ts +5 -5
- package/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.ts +5 -5
- package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +2 -3
- package/tests/cases/unit/whereBuilder.test.ts +68 -4
- package/tests/src/test.ts +1 -1
- package/tests/src/testGraphql.ts +9 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.19",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -10,20 +10,21 @@
|
|
|
10
10
|
"test": "vitest --no-threads"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@contember/database": "^1.2.0-alpha.
|
|
14
|
-
"@contember/dic": "^1.2.0-alpha.
|
|
15
|
-
"@contember/
|
|
16
|
-
"@contember/
|
|
17
|
-
"@contember/
|
|
18
|
-
"@contember/schema": "^1.2.0-alpha.
|
|
19
|
-
"@contember/schema-utils": "^1.2.0-alpha.
|
|
13
|
+
"@contember/database": "^1.2.0-alpha.19",
|
|
14
|
+
"@contember/dic": "^1.2.0-alpha.19",
|
|
15
|
+
"@contember/logger": "^1.2.0-alpha.19",
|
|
16
|
+
"@contember/graphql-utils": "^1.2.0-alpha.19",
|
|
17
|
+
"@contember/schema": "^1.2.0-alpha.19",
|
|
18
|
+
"@contember/schema-definition": "^1.2.0-alpha.19",
|
|
19
|
+
"@contember/schema-utils": "^1.2.0-alpha.19",
|
|
20
20
|
"@graphql-tools/schema": "^8.3.5",
|
|
21
|
+
"fast-deep-equal": "^3.1.3",
|
|
21
22
|
"graphql-tag": "^2.12.5"
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
|
-
"@contember/database-tester": "^1.2.0-alpha.
|
|
25
|
-
"@contember/engine-api-tester": "^1.2.0-alpha.
|
|
26
|
-
"@contember/schema-definition": "^1.2.0-alpha.
|
|
25
|
+
"@contember/database-tester": "^1.2.0-alpha.19",
|
|
26
|
+
"@contember/engine-api-tester": "^1.2.0-alpha.19",
|
|
27
|
+
"@contember/schema-definition": "^1.2.0-alpha.19",
|
|
27
28
|
"@graphql-codegen/cli": "^2.6.2",
|
|
28
29
|
"@graphql-codegen/typescript": "^2.5.1",
|
|
29
30
|
"@graphql-codegen/typescript-operations": "^2.4.2",
|
|
@@ -65,7 +65,7 @@ export const createMapperContainer = ({ permissions, schema, identityVariables,
|
|
|
65
65
|
.addService('whereOptimized', () =>
|
|
66
66
|
new WhereOptimizer(schema.model, new ConditionOptimizer()))
|
|
67
67
|
.addService('whereBuilder', ({ joinBuilder, conditionBuilder, pathFactory, whereOptimized }) =>
|
|
68
|
-
new WhereBuilder(schema.model, joinBuilder, conditionBuilder, pathFactory, whereOptimized))
|
|
68
|
+
new WhereBuilder(schema.model, joinBuilder, conditionBuilder, pathFactory, whereOptimized, schema.settings.useExistsInHasManyFilter === true))
|
|
69
69
|
.addService('orderByBuilder', ({ joinBuilder }) =>
|
|
70
70
|
new OrderByBuilder(schema.model, joinBuilder))
|
|
71
71
|
.addService('relationFetcher', ({ whereBuilder, orderByBuilder, predicatesInjector, pathFactory }) =>
|
|
@@ -36,7 +36,6 @@ export class DeleteExecutor {
|
|
|
36
36
|
filter?: Input.OptionalWhere,
|
|
37
37
|
): Promise<MutationResultList> {
|
|
38
38
|
return mapper.mutex.execute(async () => {
|
|
39
|
-
await mapper.constraintHelper.setFkConstraintsDeferred()
|
|
40
39
|
const primaryValue = await mapper.getPrimaryValue(entity, by)
|
|
41
40
|
if (!primaryValue) {
|
|
42
41
|
return [new MutationEntryNotFoundError([], by as Input.UniqueWhere)]
|
|
@@ -44,13 +43,14 @@ export class DeleteExecutor {
|
|
|
44
43
|
if (mapper.deletedEntities.isDeleted(entity.name, primaryValue)) {
|
|
45
44
|
return [new MutationNothingToDo([], NothingToDoReason.alreadyDeleted)]
|
|
46
45
|
}
|
|
46
|
+
await mapper.constraintHelper.setFkConstraintsDeferred()
|
|
47
47
|
const primaryWhere = { [entity.primary]: { eq: primaryValue } }
|
|
48
48
|
const result = await this.delete(mapper, entity, filter ? { and: [primaryWhere, filter] } : primaryWhere)
|
|
49
|
+
await mapper.constraintHelper.setFkConstraintsImmediate()
|
|
49
50
|
if (result.length === 0) {
|
|
50
51
|
return [new MutationNoResultError([])]
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
await mapper.constraintHelper.setFkConstraintsImmediate()
|
|
54
54
|
return [new MutationDeleteOk([], entity, primaryValue)]
|
|
55
55
|
})
|
|
56
56
|
}
|
|
@@ -27,6 +27,9 @@ export class PathFactory {
|
|
|
27
27
|
export class Path {
|
|
28
28
|
public readonly alias = this.createAlias()
|
|
29
29
|
|
|
30
|
+
public get fullAlias() {
|
|
31
|
+
return this.rootAlias + this.path.join('_')
|
|
32
|
+
}
|
|
30
33
|
constructor(
|
|
31
34
|
public readonly path: string[],
|
|
32
35
|
private readonly aliasContext: AliasContext,
|
|
@@ -44,7 +47,7 @@ export class Path {
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
private createAlias(): string {
|
|
47
|
-
const alias = this.
|
|
50
|
+
const alias = this.fullAlias
|
|
48
51
|
|
|
49
52
|
// intentionally not allowing == MAX_IDENTIFIER_LENGTH
|
|
50
53
|
if (alias.length < MAX_IDENTIFIER_LENGTH) {
|
|
@@ -20,6 +20,7 @@ export class WhereBuilder {
|
|
|
20
20
|
private readonly conditionBuilder: ConditionBuilder,
|
|
21
21
|
private readonly pathFactory: PathFactory,
|
|
22
22
|
private readonly whereOptimizer: WhereOptimizer,
|
|
23
|
+
private readonly useExistsInHasManyFilter: boolean,
|
|
23
24
|
) {}
|
|
24
25
|
|
|
25
26
|
public build(
|
|
@@ -30,7 +31,13 @@ export class WhereBuilder {
|
|
|
30
31
|
optimizationHints: WhereOptimizationHints = {},
|
|
31
32
|
) {
|
|
32
33
|
const optimizedWhere = this.whereOptimizer.optimize(where, entity, optimizationHints)
|
|
33
|
-
return this.buildInternal(
|
|
34
|
+
return this.buildInternal({
|
|
35
|
+
entity,
|
|
36
|
+
path,
|
|
37
|
+
where: optimizedWhere,
|
|
38
|
+
callback: cb => qb.where(clause => cb(clause)),
|
|
39
|
+
allowManyJoin: false,
|
|
40
|
+
})
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
|
|
@@ -42,32 +49,41 @@ export class WhereBuilder {
|
|
|
42
49
|
optimizationHints: WhereOptimizationHints = {},
|
|
43
50
|
) {
|
|
44
51
|
const optimizedWhere = this.whereOptimizer.optimize(where, entity, optimizationHints)
|
|
45
|
-
return this.buildInternal(
|
|
52
|
+
return this.buildInternal({
|
|
53
|
+
entity,
|
|
54
|
+
path,
|
|
55
|
+
where: optimizedWhere,
|
|
56
|
+
callback,
|
|
57
|
+
allowManyJoin: false,
|
|
58
|
+
})
|
|
46
59
|
}
|
|
47
60
|
|
|
48
|
-
private buildInternal(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
|
|
53
|
-
allowManyJoin: boolean,
|
|
61
|
+
private buildInternal({
|
|
62
|
+
callback,
|
|
63
|
+
...args
|
|
64
|
+
}: { entity: Model.Entity; path: Path; where: Input.OptionalWhere; callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>; allowManyJoin: boolean },
|
|
54
65
|
) {
|
|
55
66
|
const joinList: WhereJoinDefinition[] = []
|
|
56
67
|
|
|
57
|
-
const qbWithWhere = callback(clause => this.buildRecursive(
|
|
68
|
+
const qbWithWhere = callback(clause => this.buildRecursive({
|
|
69
|
+
conditionBuilder: clause,
|
|
70
|
+
joinList: joinList,
|
|
71
|
+
...args,
|
|
72
|
+
}))
|
|
58
73
|
return joinList.reduce<SelectBuilder<SelectBuilder.Result>>(
|
|
59
74
|
(qb, { path, entity, relationName }) => this.joinBuilder.join(qb, path, entity, relationName),
|
|
60
75
|
qbWithWhere,
|
|
61
76
|
)
|
|
62
77
|
}
|
|
63
78
|
|
|
64
|
-
private buildRecursive(
|
|
65
|
-
conditionBuilder
|
|
66
|
-
entity
|
|
67
|
-
path
|
|
68
|
-
where
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
private buildRecursive({
|
|
80
|
+
conditionBuilder,
|
|
81
|
+
entity,
|
|
82
|
+
path,
|
|
83
|
+
where,
|
|
84
|
+
joinList,
|
|
85
|
+
allowManyJoin,
|
|
86
|
+
}: { conditionBuilder: SqlConditionBuilder; entity: Model.Entity; path: Path; where: Input.OptionalWhere; joinList: WhereJoinDefinition[]; allowManyJoin: boolean },
|
|
71
87
|
): SqlConditionBuilder {
|
|
72
88
|
const tableName = path.alias
|
|
73
89
|
|
|
@@ -76,7 +92,14 @@ export class WhereBuilder {
|
|
|
76
92
|
conditionBuilder = conditionBuilder.and(clause =>
|
|
77
93
|
expr.reduce(
|
|
78
94
|
(clause2, where) =>
|
|
79
|
-
!where ? clause2 : this.buildRecursive(
|
|
95
|
+
!where ? clause2 : this.buildRecursive({
|
|
96
|
+
conditionBuilder: clause2,
|
|
97
|
+
entity,
|
|
98
|
+
path,
|
|
99
|
+
where,
|
|
100
|
+
joinList,
|
|
101
|
+
allowManyJoin,
|
|
102
|
+
}),
|
|
80
103
|
clause,
|
|
81
104
|
),
|
|
82
105
|
)
|
|
@@ -88,7 +111,14 @@ export class WhereBuilder {
|
|
|
88
111
|
(clause2, where) =>
|
|
89
112
|
!where
|
|
90
113
|
? clause2
|
|
91
|
-
: clause2.and(clause3 => this.buildRecursive(
|
|
114
|
+
: clause2.and(clause3 => this.buildRecursive({
|
|
115
|
+
conditionBuilder: clause3,
|
|
116
|
+
entity,
|
|
117
|
+
path,
|
|
118
|
+
where,
|
|
119
|
+
joinList,
|
|
120
|
+
allowManyJoin,
|
|
121
|
+
})),
|
|
92
122
|
clause,
|
|
93
123
|
),
|
|
94
124
|
)
|
|
@@ -96,7 +126,14 @@ export class WhereBuilder {
|
|
|
96
126
|
if (where.not !== undefined) {
|
|
97
127
|
const expr = where.not
|
|
98
128
|
conditionBuilder = conditionBuilder.not(clause =>
|
|
99
|
-
this.buildRecursive(
|
|
129
|
+
this.buildRecursive({
|
|
130
|
+
conditionBuilder: clause,
|
|
131
|
+
entity,
|
|
132
|
+
path,
|
|
133
|
+
where: expr,
|
|
134
|
+
joinList,
|
|
135
|
+
allowManyJoin,
|
|
136
|
+
}),
|
|
100
137
|
)
|
|
101
138
|
}
|
|
102
139
|
|
|
@@ -105,8 +142,9 @@ export class WhereBuilder {
|
|
|
105
142
|
continue
|
|
106
143
|
}
|
|
107
144
|
|
|
145
|
+
const targetPath = path.for(fieldName)
|
|
146
|
+
|
|
108
147
|
const joinedWhere = ({ targetEntity, relation, entity }: Model.AnyRelationContext): SqlConditionBuilder => {
|
|
109
|
-
const targetPath = path.for(fieldName)
|
|
110
148
|
const relationWhere = where[fieldName] as Input.Where
|
|
111
149
|
if (Object.keys(relationWhere).length === 0) {
|
|
112
150
|
return conditionBuilder
|
|
@@ -126,7 +164,14 @@ export class WhereBuilder {
|
|
|
126
164
|
|
|
127
165
|
joinList.push({ path: targetPath, entity, relationName: relation.name })
|
|
128
166
|
|
|
129
|
-
return this.buildRecursive(
|
|
167
|
+
return this.buildRecursive({
|
|
168
|
+
conditionBuilder,
|
|
169
|
+
entity: targetEntity,
|
|
170
|
+
path: targetPath,
|
|
171
|
+
where: relationWhere,
|
|
172
|
+
joinList,
|
|
173
|
+
allowManyJoin,
|
|
174
|
+
})
|
|
130
175
|
}
|
|
131
176
|
|
|
132
177
|
conditionBuilder = acceptFieldVisitor<SqlConditionBuilder>(this.schema, entity, fieldName, {
|
|
@@ -138,7 +183,7 @@ export class WhereBuilder {
|
|
|
138
183
|
visitOneHasOneOwning: joinedWhere,
|
|
139
184
|
visitManyHasOne: joinedWhere,
|
|
140
185
|
visitManyHasManyInverse: context => {
|
|
141
|
-
if (allowManyJoin) {
|
|
186
|
+
if (allowManyJoin && !this.useExistsInHasManyFilter) {
|
|
142
187
|
return joinedWhere(context)
|
|
143
188
|
}
|
|
144
189
|
|
|
@@ -151,11 +196,12 @@ export class WhereBuilder {
|
|
|
151
196
|
context.targetEntity,
|
|
152
197
|
context.targetRelation.joiningTable,
|
|
153
198
|
'inverse',
|
|
199
|
+
targetPath,
|
|
154
200
|
),
|
|
155
201
|
)
|
|
156
202
|
},
|
|
157
203
|
visitManyHasManyOwning: context => {
|
|
158
|
-
if (allowManyJoin) {
|
|
204
|
+
if (allowManyJoin && !this.useExistsInHasManyFilter) {
|
|
159
205
|
return joinedWhere(context)
|
|
160
206
|
}
|
|
161
207
|
|
|
@@ -168,11 +214,12 @@ export class WhereBuilder {
|
|
|
168
214
|
context.targetEntity,
|
|
169
215
|
context.relation.joiningTable,
|
|
170
216
|
'owning',
|
|
217
|
+
targetPath,
|
|
171
218
|
),
|
|
172
219
|
)
|
|
173
220
|
},
|
|
174
221
|
visitOneHasMany: context => {
|
|
175
|
-
if (allowManyJoin) {
|
|
222
|
+
if (allowManyJoin && !this.useExistsInHasManyFilter) {
|
|
176
223
|
return joinedWhere(context)
|
|
177
224
|
}
|
|
178
225
|
|
|
@@ -181,23 +228,23 @@ export class WhereBuilder {
|
|
|
181
228
|
const qb = this.hasRootIsNull(relationWhere, context.targetEntity)
|
|
182
229
|
? SelectBuilder.create()
|
|
183
230
|
.select(it => it.raw('1'))
|
|
184
|
-
.from(new Literal(`(select ${wrapIdentifier(tableName)}.${wrapIdentifier(entity.primaryColumn)})`), '
|
|
185
|
-
.leftJoin(context.targetEntity.tableName,
|
|
186
|
-
it.columnsEq(['
|
|
231
|
+
.from(new Literal(`(select ${wrapIdentifier(tableName)}.${wrapIdentifier(entity.primaryColumn)})`), targetPath.for('tmp_').alias)
|
|
232
|
+
.leftJoin(context.targetEntity.tableName, targetPath.alias, it =>
|
|
233
|
+
it.columnsEq([targetPath.for('tmp_').alias, entity.primaryColumn], [targetPath.alias, context.targetRelation.joiningColumn.columnName]),
|
|
187
234
|
)
|
|
188
235
|
: SelectBuilder.create()
|
|
189
236
|
.select(it => it.raw('1'))
|
|
190
|
-
.from(context.targetEntity.tableName,
|
|
191
|
-
.where(it => it.columnsEq([tableName, entity.primaryColumn], [
|
|
237
|
+
.from(context.targetEntity.tableName, targetPath.alias)
|
|
238
|
+
.where(it => it.columnsEq([tableName, entity.primaryColumn], [targetPath.alias, context.targetRelation.joiningColumn.columnName]))
|
|
192
239
|
|
|
193
240
|
return conditionBuilder.exists(
|
|
194
|
-
this.buildInternal(
|
|
195
|
-
context.targetEntity,
|
|
196
|
-
|
|
197
|
-
relationWhere,
|
|
198
|
-
cb => qb.where(clause => cb(clause)),
|
|
199
|
-
true,
|
|
200
|
-
),
|
|
241
|
+
this.buildInternal({
|
|
242
|
+
entity: context.targetEntity,
|
|
243
|
+
path: targetPath,
|
|
244
|
+
where: relationWhere,
|
|
245
|
+
callback: cb => qb.where(clause => cb(clause)),
|
|
246
|
+
allowManyJoin: true,
|
|
247
|
+
}),
|
|
201
248
|
)
|
|
202
249
|
},
|
|
203
250
|
})
|
|
@@ -212,13 +259,15 @@ export class WhereBuilder {
|
|
|
212
259
|
targetEntity: Model.Entity,
|
|
213
260
|
joiningTable: Model.JoiningTable,
|
|
214
261
|
fromSide: 'owning' | 'inverse',
|
|
262
|
+
path: Path,
|
|
215
263
|
) {
|
|
216
264
|
const fromColumn = fromSide === 'owning' ? joiningTable.joiningColumn.columnName : joiningTable.inverseJoiningColumn.columnName
|
|
217
265
|
const toColumn = fromSide === 'owning' ? joiningTable.inverseJoiningColumn.columnName : joiningTable.joiningColumn.columnName
|
|
266
|
+
const junctionPath = path.for('junction_')
|
|
218
267
|
const qb = SelectBuilder.create<SelectBuilder.Result>()
|
|
219
|
-
.from(joiningTable.tableName,
|
|
268
|
+
.from(joiningTable.tableName, junctionPath.alias)
|
|
220
269
|
.select(it => it.raw('1'))
|
|
221
|
-
.where(it => it.columnsEq(outerColumn, [
|
|
270
|
+
.where(it => it.columnsEq(outerColumn, [junctionPath.alias, fromColumn]))
|
|
222
271
|
|
|
223
272
|
const primaryCondition = this.transformWhereToPrimaryCondition(relationWhere, targetEntity.primary)
|
|
224
273
|
if (primaryCondition !== null) {
|
|
@@ -226,20 +275,20 @@ export class WhereBuilder {
|
|
|
226
275
|
const columnType = (targetEntity.fields[targetEntity.primary] as Model.AnyColumn).columnType
|
|
227
276
|
|
|
228
277
|
return qb.where(condition =>
|
|
229
|
-
this.conditionBuilder.build(condition,
|
|
278
|
+
this.conditionBuilder.build(condition, junctionPath.alias, toColumn, columnType, primaryCondition),
|
|
230
279
|
)
|
|
231
280
|
}
|
|
232
281
|
|
|
233
|
-
const qbJoined = qb.join(targetEntity.tableName,
|
|
234
|
-
clause.compareColumns([
|
|
235
|
-
)
|
|
236
|
-
return this.buildInternal(
|
|
237
|
-
targetEntity,
|
|
238
|
-
this.pathFactory.create([], 'sub_'),
|
|
239
|
-
relationWhere,
|
|
240
|
-
cb => qbJoined.where(clause => cb(clause)),
|
|
241
|
-
true,
|
|
282
|
+
const qbJoined = qb.join(targetEntity.tableName, path.alias, clause =>
|
|
283
|
+
clause.compareColumns([junctionPath.alias, toColumn], Operator.eq, [path.alias, targetEntity.primary]),
|
|
242
284
|
)
|
|
285
|
+
return this.buildInternal({
|
|
286
|
+
entity: targetEntity,
|
|
287
|
+
path: this.pathFactory.create([], path.fullAlias),
|
|
288
|
+
where: relationWhere,
|
|
289
|
+
callback: cb => qbJoined.where(clause => cb(clause)),
|
|
290
|
+
allowManyJoin: true,
|
|
291
|
+
})
|
|
243
292
|
}
|
|
244
293
|
|
|
245
294
|
private transformWhereToPrimaryCondition(where: Input.Where, primaryField: string): Input.Condition<never> | null {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { ValidationResolver } from './ValidationResolver'
|
|
16
16
|
import { Providers } from '@contember/schema-utils'
|
|
17
17
|
import { GraphQlQueryAstFactory } from './GraphQlQueryAstFactory'
|
|
18
|
-
import { getArgumentValues } from 'graphql
|
|
18
|
+
import { getArgumentValues } from 'graphql'
|
|
19
19
|
import { createMapperContainer } from '../mapper'
|
|
20
20
|
|
|
21
21
|
export interface ExecutionContainer {
|
|
@@ -2,17 +2,18 @@ import { isIt, ResolveInfoUtils } from '../utils'
|
|
|
2
2
|
import {
|
|
3
3
|
FieldNode as GraphQlFieldNode,
|
|
4
4
|
FragmentSpreadNode,
|
|
5
|
+
getArgumentValues,
|
|
5
6
|
GraphQLObjectType,
|
|
6
7
|
GraphQLOutputType,
|
|
7
8
|
GraphQLResolveInfo,
|
|
8
9
|
isListType,
|
|
9
10
|
isNonNullType,
|
|
10
|
-
isObjectType,
|
|
11
|
+
isObjectType,
|
|
12
|
+
Kind,
|
|
13
|
+
SelectionSetNode,
|
|
11
14
|
} from 'graphql'
|
|
12
|
-
import { SelectionSetNode } from 'graphql/language/ast'
|
|
13
|
-
import { getArgumentValues } from 'graphql/execution/values'
|
|
14
15
|
import { FieldNode, ObjectNode } from '../inputProcessing'
|
|
15
|
-
import { isDeepStrictEqual } from 'util'
|
|
16
|
+
import { isDeepStrictEqual } from 'node:util'
|
|
16
17
|
|
|
17
18
|
type NodeFilter = (node: GraphQlFieldNode, path: string[]) => boolean
|
|
18
19
|
type AnyNode = ObjectNode | FieldNode
|
|
@@ -62,6 +62,7 @@ export class MutationResolver {
|
|
|
62
62
|
|
|
63
63
|
return this.transaction(async (mapper, trx) => {
|
|
64
64
|
if (options?.deferForeignKeyConstraints) {
|
|
65
|
+
logger.debug('MutationResolver: deferring foreign constraints')
|
|
65
66
|
await mapper.constraintHelper.setFkConstraintsDeferred()
|
|
66
67
|
}
|
|
67
68
|
const validationResult: Record<string, Result.MutationFieldResult> = {}
|
|
@@ -145,7 +146,7 @@ export class MutationResolver {
|
|
|
145
146
|
}
|
|
146
147
|
|
|
147
148
|
const meta = readOperationMeta(fieldConfig.extensions)
|
|
148
|
-
|
|
149
|
+
logger.debug('MutationResolver: Resolving a field', { field: field.alias })
|
|
149
150
|
const result: {
|
|
150
151
|
ok: boolean
|
|
151
152
|
validation?: Result.ValidationResult
|
|
@@ -169,6 +170,7 @@ export class MutationResolver {
|
|
|
169
170
|
})()
|
|
170
171
|
|
|
171
172
|
if (!result.ok) {
|
|
173
|
+
logger.debug('MutationResolver: Field evaluation failed', { result, field: field.alias })
|
|
172
174
|
const validationErrors = result.validation ? prefixErrors(result.validation.errors, field.alias) : []
|
|
173
175
|
const executionErrors = prefixErrors(result.errors, field.alias)
|
|
174
176
|
return {
|
|
@@ -193,12 +195,14 @@ export class MutationResolver {
|
|
|
193
195
|
trxResult[field.alias] = result
|
|
194
196
|
}
|
|
195
197
|
if (options?.deferForeignKeyConstraints) {
|
|
198
|
+
logger.debug('MutationResolver: validating fk constraints')
|
|
196
199
|
const constraintsResult = await tryMutation(this.schema, async () => {
|
|
197
200
|
await mapper.constraintHelper.setFkConstraintsImmediate()
|
|
198
201
|
return []
|
|
199
202
|
})
|
|
200
203
|
const errorResponse = this.createErrorResponse(constraintsResult)
|
|
201
204
|
if (errorResponse) {
|
|
205
|
+
logger.debug('MutationResolver: deferred fk validation failed', { errorResponse })
|
|
202
206
|
return { ...errorResponse, ...validationResult }
|
|
203
207
|
}
|
|
204
208
|
}
|
|
@@ -469,13 +473,17 @@ export class MutationResolver {
|
|
|
469
473
|
return await retryTransaction(
|
|
470
474
|
async () => {
|
|
471
475
|
return await this.db.transaction(async trx => {
|
|
476
|
+
logger.debug('MutationResolver: Starting mutation transaction')
|
|
472
477
|
await trx.connection.query(Connection.REPEATABLE_READ)
|
|
473
478
|
await this.systemVariablesSetup(trx)
|
|
474
479
|
const mapper = this.mapperFactory(trx)
|
|
475
480
|
|
|
476
481
|
const result = await cb(mapper, trx)
|
|
477
482
|
if (!result.ok) {
|
|
483
|
+
logger.debug('MutationResolver: Transaction failed, rolling back', { result })
|
|
478
484
|
await trx.connection.rollback()
|
|
485
|
+
} else {
|
|
486
|
+
logger.debug('MutationResolver: Transaction ok, committing')
|
|
479
487
|
}
|
|
480
488
|
return result
|
|
481
489
|
})
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { GraphQLEnumType } from 'graphql'
|
|
2
|
-
import { GraphQLEnumValueConfigMap } from 'graphql/type/definition'
|
|
1
|
+
import { GraphQLEnumType, GraphQLEnumValueConfigMap } from 'graphql'
|
|
3
2
|
import { Model } from '@contember/schema'
|
|
4
|
-
import { singletonFactory } from '../utils'
|
|
5
|
-
import { capitalizeFirstLetter } from '../utils'
|
|
3
|
+
import { capitalizeFirstLetter, singletonFactory } from '../utils'
|
|
6
4
|
|
|
7
5
|
export class EnumsProvider {
|
|
8
6
|
private schema: Model.Schema
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GraphQLBoolean,
|
|
3
|
+
GraphQLEnumType,
|
|
4
|
+
GraphQLInputFieldConfig,
|
|
5
|
+
GraphQLInputFieldConfigMap,
|
|
6
|
+
GraphQLInputObjectType,
|
|
7
|
+
GraphQLInputType,
|
|
8
|
+
GraphQLInt,
|
|
9
|
+
} from 'graphql'
|
|
2
10
|
import { Acl, Model } from '@contember/schema'
|
|
3
11
|
import { acceptFieldVisitor } from '@contember/schema-utils'
|
|
4
12
|
import { singletonFactory } from '../utils'
|
|
5
13
|
import { GqlTypeName } from './utils'
|
|
6
14
|
import { Authorizator } from '../acl'
|
|
7
15
|
import { FieldAccessVisitor } from './FieldAccessVisitor'
|
|
8
|
-
import { GraphQLBoolean, GraphQLEnumType, GraphQLInputObjectType, GraphQLInt } from 'graphql'
|
|
9
16
|
|
|
10
17
|
export class OrderByTypeProvider {
|
|
11
18
|
private orderBySingleton = singletonFactory(name => this.createEntityOrderByType(name))
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Acl, Model } from '@contember/schema'
|
|
2
2
|
import { acceptFieldVisitor, getEntity } from '@contember/schema-utils'
|
|
3
|
-
import { GraphQLInputObjectType, GraphQLList } from 'graphql'
|
|
4
|
-
import { GraphQLInputFieldConfig, GraphQLInputFieldConfigMap } from 'graphql/type/definition'
|
|
3
|
+
import { GraphQLInputFieldConfig, GraphQLInputFieldConfigMap, GraphQLInputObjectType, GraphQLList } from 'graphql'
|
|
5
4
|
import { capitalizeFirstLetter, getFieldsForUniqueWhere, singletonFactory } from '../utils'
|
|
6
5
|
import { ColumnTypeResolver } from './ColumnTypeResolver'
|
|
7
6
|
import { ConditionTypeProvider } from './ConditionTypeProvider'
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Model } from '@contember/schema'
|
|
2
2
|
import { WhereTypeProvider } from '../WhereTypeProvider'
|
|
3
|
-
import { GraphQLFieldConfigArgumentMap } from 'graphql
|
|
3
|
+
import { GraphQLFieldConfigArgumentMap, GraphQLInt, GraphQLList, GraphQLNonNull } from 'graphql'
|
|
4
4
|
import { OrderByTypeProvider } from '../OrderByTypeProvider'
|
|
5
|
-
import { GraphQLInt, GraphQLList, GraphQLNonNull } from 'graphql'
|
|
6
5
|
|
|
7
6
|
export class FieldArgsVisitor implements
|
|
8
7
|
Model.ColumnVisitor<GraphQLFieldConfigArgumentMap | undefined>,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { GraphQLInputObjectType, GraphQLString } from 'graphql'
|
|
1
|
+
import { GraphQLInputFieldConfigMap, GraphQLInputObjectType, GraphQLString } from 'graphql'
|
|
2
2
|
import { Input, Model } from '@contember/schema'
|
|
3
3
|
import { GqlTypeName } from '../utils'
|
|
4
4
|
import { WhereTypeProvider } from '../WhereTypeProvider'
|
|
5
5
|
import { Accessor, Interface } from '../../utils'
|
|
6
6
|
import { EntityInputProvider, EntityInputType } from './EntityInputProvider'
|
|
7
|
-
import { GraphQLInputFieldConfigMap } from 'graphql/type/definition'
|
|
8
7
|
import { CreateEntityRelationAllowedOperationsVisitor } from './CreateEntityRelationAllowedOperationsVisitor'
|
|
9
8
|
import { acceptFieldVisitor } from '@contember/schema-utils'
|
|
10
9
|
import { ImplementationException } from '../../exception'
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
GraphQLBoolean,
|
|
3
|
+
GraphQLInputFieldConfig,
|
|
4
|
+
GraphQLInputFieldConfigMap,
|
|
5
|
+
GraphQLInputObjectType,
|
|
6
|
+
GraphQLString,
|
|
7
|
+
} from 'graphql'
|
|
2
8
|
import { Acl, Input, Model } from '@contember/schema'
|
|
3
9
|
import { GqlTypeName } from '../utils'
|
|
4
10
|
import { WhereTypeProvider } from '../WhereTypeProvider'
|
|
5
11
|
import { Accessor, filterObject } from '../../utils'
|
|
6
12
|
import { EntityInputProvider, EntityInputType } from './EntityInputProvider'
|
|
7
|
-
import { GraphQLInputFieldConfig, GraphQLInputFieldConfigMap } from 'graphql/type/definition'
|
|
8
13
|
import { acceptFieldVisitor } from '@contember/schema-utils'
|
|
9
14
|
import { UpdateEntityRelationAllowedOperationsVisitor } from './UpdateEntityRelationAllowedOperationsVisitor'
|
|
10
15
|
import { Authorizator } from '../../acl'
|
package/src/schema/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { capitalizeFirstLetter } from '../utils'
|
|
2
|
-
import { GraphQLFieldResolver } from 'graphql
|
|
2
|
+
import { GraphQLFieldResolver } from 'graphql'
|
|
3
3
|
|
|
4
4
|
export const GqlTypeName = (strings: TemplateStringsArray, ...values: string[]) => {
|
|
5
5
|
return strings.reduce((combined, string, i) => {
|
package/src/tsconfig.json
CHANGED
|
@@ -48,12 +48,12 @@ test('Filter by has many with additional join', async () => {
|
|
|
48
48
|
executes: [
|
|
49
49
|
{
|
|
50
50
|
sql: SQL`
|
|
51
|
-
select "root_"."id" as "root_id", "root_"."short_name" as "root_shortName", "root_"."id" as "root_id"
|
|
52
|
-
from "public"."person" as "root_"
|
|
53
|
-
where exists (select 1
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
select "root_"."id" as "root_id", "root_"."short_name" as "root_shortName", "root_"."id" as "root_id"
|
|
52
|
+
from "public"."person" as "root_"
|
|
53
|
+
where exists (select 1
|
|
54
|
+
from "public"."person_locale" as "root_locales"
|
|
55
|
+
left join "public"."language" as "root_locales_locale" on "root_locales"."locale_id" = "root_locales_locale"."id"
|
|
56
|
+
where "root_"."id" = "root_locales"."person_id" and "root_locales_locale"."slug" = ? and not("root_locales"."url_slug" is null))`,
|
|
57
57
|
response: { rows: [{ root_id: testUuid(1), root_shortName: 'John' }] },
|
|
58
58
|
parameters: ['cs'],
|
|
59
59
|
},
|
|
@@ -50,12 +50,12 @@ test('delete post with acl', async () => {
|
|
|
50
50
|
],
|
|
51
51
|
},
|
|
52
52
|
},
|
|
53
|
+
{
|
|
54
|
+
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
55
|
+
parameters: [testUuid(1)],
|
|
56
|
+
response: { rows: [{ id: testUuid(1) }] },
|
|
57
|
+
},
|
|
53
58
|
...sqlDeferred([
|
|
54
|
-
{
|
|
55
|
-
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
56
|
-
parameters: [testUuid(1)],
|
|
57
|
-
response: { rows: [{ id: testUuid(1) }] },
|
|
58
|
-
},
|
|
59
59
|
{
|
|
60
60
|
sql: SQL`delete from "public"."post"
|
|
61
61
|
where "id" in (select "root_"."id"
|
|
@@ -34,12 +34,12 @@ test('delete post with additional filter', async () => {
|
|
|
34
34
|
],
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
39
|
+
parameters: [testUuid(1)],
|
|
40
|
+
response: { rows: [{ id: testUuid(1) }] },
|
|
41
|
+
},
|
|
37
42
|
...sqlDeferred([
|
|
38
|
-
{
|
|
39
|
-
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
40
|
-
parameters: [testUuid(1)],
|
|
41
|
-
response: { rows: [{ id: testUuid(1) }] },
|
|
42
|
-
},
|
|
43
43
|
{
|
|
44
44
|
sql: SQL`delete from "public"."post"
|
|
45
45
|
where "id" in (select "root_"."id"
|
|
@@ -39,12 +39,12 @@ test('delete author with posts and locales cascade delete', async () => {
|
|
|
39
39
|
],
|
|
40
40
|
},
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
sql: SQL`select "root_"."id" from "public"."author" as "root_" where "root_"."id" = ?`,
|
|
44
|
+
parameters: [testUuid(1)],
|
|
45
|
+
response: { rows: [{ id: testUuid(1) }] },
|
|
46
|
+
},
|
|
42
47
|
...sqlDeferred([
|
|
43
|
-
{
|
|
44
|
-
sql: SQL`select "root_"."id" from "public"."author" as "root_" where "root_"."id" = ?`,
|
|
45
|
-
parameters: [testUuid(1)],
|
|
46
|
-
response: { rows: [{ id: testUuid(1) }] },
|
|
47
|
-
},
|
|
48
48
|
{
|
|
49
49
|
sql: SQL`delete from "public"."author"
|
|
50
50
|
where "id" in (select "root_"."id"
|
|
@@ -57,12 +57,12 @@ test('delete post by id', async () => {
|
|
|
57
57
|
],
|
|
58
58
|
},
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
62
|
+
parameters: [testUuid(1)],
|
|
63
|
+
response: { rows: [{ id: testUuid(1) }] },
|
|
64
|
+
},
|
|
60
65
|
...sqlDeferred([
|
|
61
|
-
{
|
|
62
|
-
sql: SQL`select "root_"."id" from "public"."post" as "root_" where "root_"."id" = ?`,
|
|
63
|
-
parameters: [testUuid(1)],
|
|
64
|
-
response: { rows: [{ id: testUuid(1) }] },
|
|
65
|
-
},
|
|
66
66
|
{
|
|
67
67
|
sql: SQL`delete from "public"."post"
|
|
68
68
|
where "id" in (select "root_"."id"
|