@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.
Files changed (119) hide show
  1. package/dist/src/mapper/MapperContainer.js +1 -1
  2. package/dist/src/mapper/MapperContainer.js.map +1 -1
  3. package/dist/src/mapper/delete/DeleteExecutor.js +2 -2
  4. package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
  5. package/dist/src/mapper/select/Path.d.ts +1 -0
  6. package/dist/src/mapper/select/Path.d.ts.map +1 -1
  7. package/dist/src/mapper/select/Path.js +4 -1
  8. package/dist/src/mapper/select/Path.js.map +1 -1
  9. package/dist/src/mapper/select/WhereBuilder.d.ts +2 -1
  10. package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
  11. package/dist/src/mapper/select/WhereBuilder.js +85 -27
  12. package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
  13. package/dist/src/resolvers/ExecutionContainerFactory.d.ts +1 -1
  14. package/dist/src/resolvers/ExecutionContainerFactory.d.ts.map +1 -1
  15. package/dist/src/resolvers/GraphQlQueryAstFactory.d.ts +1 -2
  16. package/dist/src/resolvers/GraphQlQueryAstFactory.d.ts.map +1 -1
  17. package/dist/src/resolvers/GraphQlQueryAstFactory.js +2 -2
  18. package/dist/src/resolvers/GraphQlQueryAstFactory.js.map +1 -1
  19. package/dist/src/resolvers/MutationResolver.d.ts.map +1 -1
  20. package/dist/src/resolvers/MutationResolver.js +10 -0
  21. package/dist/src/resolvers/MutationResolver.js.map +1 -1
  22. package/dist/src/schema/EnumsProvider.d.ts.map +1 -1
  23. package/dist/src/schema/EnumsProvider.js +1 -2
  24. package/dist/src/schema/EnumsProvider.js.map +1 -1
  25. package/dist/src/schema/OrderByTypeProvider.d.ts +1 -1
  26. package/dist/src/schema/OrderByTypeProvider.d.ts.map +1 -1
  27. package/dist/src/schema/OrderByTypeProvider.js +1 -1
  28. package/dist/src/schema/OrderByTypeProvider.js.map +1 -1
  29. package/dist/src/schema/WhereTypeProvider.d.ts +1 -2
  30. package/dist/src/schema/WhereTypeProvider.d.ts.map +1 -1
  31. package/dist/src/schema/WhereTypeProvider.js.map +1 -1
  32. package/dist/src/schema/entities/FieldArgsVisitor.d.ts +1 -2
  33. package/dist/src/schema/entities/FieldArgsVisitor.d.ts.map +1 -1
  34. package/dist/src/schema/entities/FieldArgsVisitor.js.map +1 -1
  35. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts.map +1 -1
  36. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js.map +1 -1
  37. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts.map +1 -1
  38. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js.map +1 -1
  39. package/dist/src/schema/utils.d.ts +1 -1
  40. package/dist/src/schema/utils.d.ts.map +1 -1
  41. package/dist/src/tsconfig.tsbuildinfo +1 -1
  42. package/dist/tests/cases/bugs/bug102.test.js +6 -6
  43. package/dist/tests/cases/bugs/bug102.test.js.map +1 -1
  44. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js +5 -5
  45. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js.map +1 -1
  46. package/dist/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.js +5 -5
  47. package/dist/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.js.map +1 -1
  48. package/dist/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.js +5 -5
  49. package/dist/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.js.map +1 -1
  50. package/dist/tests/cases/integration/graphQlRequests/delete/deleteById.test.js +5 -5
  51. package/dist/tests/cases/integration/graphQlRequests/delete/deleteById.test.js.map +1 -1
  52. package/dist/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.js +5 -5
  53. package/dist/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.js.map +1 -1
  54. package/dist/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.js +5 -5
  55. package/dist/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.js.map +1 -1
  56. package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js +17 -15
  57. package/dist/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.js.map +1 -1
  58. package/dist/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.js +4 -5
  59. package/dist/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.js.map +1 -1
  60. package/dist/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.js +5 -3
  61. package/dist/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.js.map +1 -1
  62. package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.js +5 -5
  63. package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.js.map +1 -1
  64. package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.js +5 -5
  65. package/dist/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.js.map +1 -1
  66. package/dist/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.js +10 -10
  67. package/dist/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.js.map +1 -1
  68. package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.js +5 -5
  69. package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.js.map +1 -1
  70. package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.js +5 -5
  71. package/dist/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.js.map +1 -1
  72. package/dist/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.js +5 -5
  73. package/dist/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.js.map +1 -1
  74. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +4 -4
  75. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
  76. package/dist/tests/cases/unit/whereBuilder.test.js +60 -4
  77. package/dist/tests/cases/unit/whereBuilder.test.js.map +1 -1
  78. package/dist/tests/src/test.js +2 -2
  79. package/dist/tests/src/test.js.map +1 -1
  80. package/dist/tests/src/testGraphql.d.ts.map +1 -1
  81. package/dist/tests/src/testGraphql.js +9 -5
  82. package/dist/tests/src/testGraphql.js.map +1 -1
  83. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +12 -11
  85. package/src/mapper/MapperContainer.ts +1 -1
  86. package/src/mapper/delete/DeleteExecutor.ts +2 -2
  87. package/src/mapper/select/Path.ts +4 -1
  88. package/src/mapper/select/WhereBuilder.ts +97 -48
  89. package/src/resolvers/ExecutionContainerFactory.ts +1 -1
  90. package/src/resolvers/GraphQlQueryAstFactory.ts +5 -4
  91. package/src/resolvers/MutationResolver.ts +9 -1
  92. package/src/schema/EnumsProvider.ts +2 -4
  93. package/src/schema/OrderByTypeProvider.ts +9 -2
  94. package/src/schema/WhereTypeProvider.ts +1 -2
  95. package/src/schema/entities/FieldArgsVisitor.ts +1 -2
  96. package/src/schema/mutations/CreateEntityRelationInputFieldVisitor.ts +1 -2
  97. package/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.ts +7 -2
  98. package/src/schema/utils.ts +1 -1
  99. package/src/tsconfig.json +0 -3
  100. package/tests/cases/bugs/bug102.test.ts +6 -6
  101. package/tests/cases/integration/graphQlRequests/delete/aclDelete.test.ts +5 -5
  102. package/tests/cases/integration/graphQlRequests/delete/additionalDeleteFilter.test.ts +5 -5
  103. package/tests/cases/integration/graphQlRequests/delete/cascadeDelete.test.ts +5 -5
  104. package/tests/cases/integration/graphQlRequests/delete/deleteById.test.ts +5 -5
  105. package/tests/cases/integration/graphQlRequests/delete/orphanRemoval.test.ts +5 -5
  106. package/tests/cases/integration/graphQlRequests/delete/setNullOnDelete.test.ts +5 -5
  107. package/tests/cases/integration/graphQlRequests/query/filter/manyHasManyOwnerRelation.test.ts +17 -15
  108. package/tests/cases/integration/graphQlRequests/query/filter/oneHasManyRelation.test.ts +4 -5
  109. package/tests/cases/integration/graphQlRequests/query/unique/oneHasManyUnique.test.ts +5 -3
  110. package/tests/cases/integration/graphQlRequests/update/manyHasManyInverse/delete.test.ts +5 -5
  111. package/tests/cases/integration/graphQlRequests/update/manyHasManyOwning/delete.test.ts +5 -5
  112. package/tests/cases/integration/graphQlRequests/update/manyHasOne/delete.test.ts +10 -10
  113. package/tests/cases/integration/graphQlRequests/update/oneHasMany/combination.test.ts +5 -5
  114. package/tests/cases/integration/graphQlRequests/update/oneHasMany/delete.test.ts +5 -5
  115. package/tests/cases/integration/graphQlRequests/update/oneHasOneInverse/delete.test.ts +5 -5
  116. package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +2 -3
  117. package/tests/cases/unit/whereBuilder.test.ts +68 -4
  118. package/tests/src/test.ts +1 -1
  119. 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.17",
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.17",
14
- "@contember/dic": "^1.2.0-alpha.17",
15
- "@contember/engine-common": "^1.2.0-alpha.17",
16
- "@contember/logger": "^1.2.0-alpha.17",
17
- "@contember/graphql-utils": "^1.2.0-alpha.17",
18
- "@contember/schema": "^1.2.0-alpha.17",
19
- "@contember/schema-utils": "^1.2.0-alpha.17",
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.17",
25
- "@contember/engine-api-tester": "^1.2.0-alpha.17",
26
- "@contember/schema-definition": "^1.2.0-alpha.17",
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.rootAlias + this.path.join('_')
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(entity, path, optimizedWhere, cb => qb.where(clause => cb(clause)), false)
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(entity, path, optimizedWhere, callback, false)
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
- entity: Model.Entity,
50
- path: Path,
51
- where: Input.OptionalWhere,
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(clause, entity, path, where, allowManyJoin, joinList))
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: SqlConditionBuilder,
66
- entity: Model.Entity,
67
- path: Path,
68
- where: Input.OptionalWhere,
69
- allowManyJoin: boolean,
70
- joinList: WhereJoinDefinition[],
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(clause2, entity, path, where, allowManyJoin, joinList),
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(clause3, entity, path, where, allowManyJoin, joinList)),
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(clause, entity, path, expr, allowManyJoin, joinList),
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(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
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)})`), 'sub2_')
185
- .leftJoin(context.targetEntity.tableName, 'sub_', it =>
186
- it.columnsEq(['sub2_', entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]),
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, 'sub_')
191
- .where(it => it.columnsEq([tableName, entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]))
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
- this.pathFactory.create([], 'sub_'),
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, 'junction_')
268
+ .from(joiningTable.tableName, junctionPath.alias)
220
269
  .select(it => it.raw('1'))
221
- .where(it => it.columnsEq(outerColumn, ['junction_', fromColumn]))
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, 'junction_', toColumn, columnType, primaryCondition),
278
+ this.conditionBuilder.build(condition, junctionPath.alias, toColumn, columnType, primaryCondition),
230
279
  )
231
280
  }
232
281
 
233
- const qbJoined = qb.join(targetEntity.tableName, 'sub_', clause =>
234
- clause.compareColumns(['junction_', toColumn], Operator.eq, ['sub_', targetEntity.primary]),
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/execution/values'
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, Kind,
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 { GraphQLInputFieldConfig, GraphQLInputFieldConfigMap, GraphQLInputType } from 'graphql/type/definition'
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/type/definition'
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 { GraphQLBoolean, GraphQLInputObjectType, GraphQLString } from 'graphql'
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'
@@ -1,5 +1,5 @@
1
1
  import { capitalizeFirstLetter } from '../utils'
2
- import { GraphQLFieldResolver } from 'graphql/type/definition'
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
@@ -11,9 +11,6 @@
11
11
  {
12
12
  "path": "../../dic/src"
13
13
  },
14
- {
15
- "path": "../../engine-common/src"
16
- },
17
14
  {
18
15
  "path": "../../graphql-utils/src"
19
16
  },
@@ -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
- from "public"."person_locale" as "sub_"
55
- left join "public"."language" as "sub_locale" on "sub_"."locale_id" = "sub_locale"."id"
56
- where "root_"."id" = "sub_"."person_id" and "sub_locale"."slug" = ? and not("sub_"."url_slug" is null))`,
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"