@contember/engine-content-api 1.3.6 → 1.4.0-alpha.2

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 (122) hide show
  1. package/dist/src/ExecutionContainer.d.ts +4 -4
  2. package/dist/src/ExecutionContainer.d.ts.map +1 -1
  3. package/dist/src/ExecutionContainer.js +5 -2
  4. package/dist/src/ExecutionContainer.js.map +1 -1
  5. package/dist/src/extensions/EntityFieldsProvider.d.ts +1 -1
  6. package/dist/src/extensions/EntityFieldsProvider.d.ts.map +1 -1
  7. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.d.ts +1 -1
  8. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.d.ts.map +1 -1
  9. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.js +12 -2
  10. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.js.map +1 -1
  11. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts +16 -9
  12. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts.map +1 -1
  13. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js +21 -13
  14. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js.map +1 -1
  15. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.d.ts +1 -1
  16. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.d.ts.map +1 -1
  17. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.js +8 -2
  18. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.js.map +1 -1
  19. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts +16 -9
  20. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
  21. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +17 -12
  22. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
  23. package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.d.ts +2 -0
  24. package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.d.ts.map +1 -1
  25. package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.js +18 -14
  26. package/dist/src/introspection/IntrospectionSchemaDefinitionFactory.js.map +1 -1
  27. package/dist/src/introspection/index.d.ts +1 -2
  28. package/dist/src/introspection/index.d.ts.map +1 -1
  29. package/dist/src/introspection/index.js +4 -4
  30. package/dist/src/introspection/index.js.map +1 -1
  31. package/dist/src/mapper/ErrorUtils.d.ts +3 -3
  32. package/dist/src/mapper/ErrorUtils.d.ts.map +1 -1
  33. package/dist/src/mapper/ErrorUtils.js +2 -2
  34. package/dist/src/mapper/ErrorUtils.js.map +1 -1
  35. package/dist/src/mapper/Mapper.d.ts +2 -3
  36. package/dist/src/mapper/Mapper.d.ts.map +1 -1
  37. package/dist/src/mapper/Mapper.js +1 -1
  38. package/dist/src/mapper/Mapper.js.map +1 -1
  39. package/dist/src/mapper/MapperFactory.d.ts +3 -3
  40. package/dist/src/mapper/MapperFactory.d.ts.map +1 -1
  41. package/dist/src/mapper/MapperFactory.js.map +1 -1
  42. package/dist/src/mapper/Result.d.ts +2 -2
  43. package/dist/src/mapper/Result.d.ts.map +1 -1
  44. package/dist/src/mapper/Result.js.map +1 -1
  45. package/dist/src/mapper/delete/DeleteExecutor.js +1 -1
  46. package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
  47. package/dist/src/mapper/insert/Inserter.d.ts +3 -2
  48. package/dist/src/mapper/insert/Inserter.d.ts.map +1 -1
  49. package/dist/src/mapper/insert/Inserter.js.map +1 -1
  50. package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts +3 -5
  51. package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
  52. package/dist/src/mapper/select/handlers/FieldsVisitor.js +8 -4
  53. package/dist/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
  54. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts +3 -5
  55. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts.map +1 -1
  56. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js +3 -4
  57. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js.map +1 -1
  58. package/dist/src/mapper/update/Updater.d.ts +2 -2
  59. package/dist/src/mapper/update/Updater.d.ts.map +1 -1
  60. package/dist/src/mapper/update/Updater.js.map +1 -1
  61. package/dist/src/resolvers/MutationResolver.d.ts +3 -2
  62. package/dist/src/resolvers/MutationResolver.d.ts.map +1 -1
  63. package/dist/src/resolvers/MutationResolver.js +20 -18
  64. package/dist/src/resolvers/MutationResolver.js.map +1 -1
  65. package/dist/src/schema/EntityTypeProvider.d.ts.map +1 -1
  66. package/dist/src/schema/EntityTypeProvider.js +23 -26
  67. package/dist/src/schema/EntityTypeProvider.js.map +1 -1
  68. package/dist/src/schema/GraphQlSchemaBuilder.d.ts.map +1 -1
  69. package/dist/src/schema/GraphQlSchemaBuilder.js +3 -1
  70. package/dist/src/schema/GraphQlSchemaBuilder.js.map +1 -1
  71. package/dist/src/tsconfig.tsbuildinfo +1 -1
  72. package/dist/tests/cases/integration/graphQlDb/update/deferedConstraints.test.js +1 -1
  73. package/dist/tests/cases/integration/graphQlDb/update/deferedConstraints.test.js.map +1 -1
  74. package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.d.ts +2 -0
  75. package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.d.ts.map +1 -0
  76. package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.js +170 -0
  77. package/dist/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.js.map +1 -0
  78. package/dist/tests/src/test.js +1 -1
  79. package/dist/tests/src/test.js.map +1 -1
  80. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  81. package/graphql.codegen.yml +1 -1
  82. package/package.json +12 -13
  83. package/src/ExecutionContainer.ts +13 -6
  84. package/src/extensions/EntityFieldsProvider.ts +1 -1
  85. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducer.ts +12 -5
  86. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.ts +33 -24
  87. package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProvider.ts +8 -5
  88. package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +28 -17
  89. package/src/introspection/IntrospectionSchemaDefinitionFactory.ts +22 -14
  90. package/src/introspection/index.ts +1 -2
  91. package/src/mapper/ErrorUtils.ts +8 -7
  92. package/src/mapper/Mapper.ts +4 -4
  93. package/src/mapper/MapperFactory.ts +3 -3
  94. package/src/mapper/Result.ts +2 -3
  95. package/src/mapper/delete/DeleteExecutor.ts +1 -1
  96. package/src/mapper/insert/Inserter.ts +3 -2
  97. package/src/mapper/select/handlers/FieldsVisitor.ts +9 -5
  98. package/src/mapper/select/handlers/FieldsVisitorFactory.ts +3 -6
  99. package/src/mapper/update/Updater.ts +3 -2
  100. package/src/resolvers/MutationResolver.ts +29 -22
  101. package/src/schema/EntityTypeProvider.ts +32 -41
  102. package/src/schema/GraphQlSchemaBuilder.ts +3 -1
  103. package/tests/cases/integration/graphQlDb/update/deferedConstraints.test.ts +1 -1
  104. package/tests/cases/integration/graphQlDb/update/deferredUniqueConstraints.test.ts +169 -0
  105. package/tests/cases/integration/graphQlSchema/schema-acl-allowed.gql +1 -0
  106. package/tests/cases/integration/graphQlSchema/schema-acl-create-only.gql +1 -0
  107. package/tests/cases/integration/graphQlSchema/schema-acl-restricted-create.gql +1 -0
  108. package/tests/cases/integration/graphQlSchema/schema-acl-restricted-delete.gql +1 -0
  109. package/tests/cases/integration/graphQlSchema/schema-acl-restricted-update.gql +1 -0
  110. package/tests/cases/integration/graphQlSchema/schema-acl.gql +1 -0
  111. package/tests/cases/integration/graphQlSchema/schema-aliased-type.gql +1 -0
  112. package/tests/cases/integration/graphQlSchema/schema-basic.gql +1 -0
  113. package/tests/cases/integration/graphQlSchema/schema-bug-66.gql +1 -0
  114. package/tests/cases/integration/graphQlSchema/schema-custom-primary.gql +1 -0
  115. package/tests/cases/integration/graphQlSchema/schema-has-many-reduction.gql +1 -0
  116. package/tests/cases/integration/graphQlSchema/schema-new-builder.gql +1 -0
  117. package/tests/src/test.ts +3 -3
  118. package/dist/src/introspection/content-schema.graphql.d.ts +0 -4
  119. package/dist/src/introspection/content-schema.graphql.d.ts.map +0 -1
  120. package/dist/src/introspection/content-schema.graphql.js +0 -113
  121. package/dist/src/introspection/content-schema.graphql.js.map +0 -1
  122. package/src/introspection/content-schema.graphql.ts +0 -113
@@ -3,6 +3,7 @@ import {
3
3
  AfterCommitEvent,
4
4
  BeforeCommitEvent,
5
5
  ConstraintType,
6
+ convertError,
6
7
  getInsertPrimary,
7
8
  InputErrorKind,
8
9
  Mapper,
@@ -16,18 +17,20 @@ import { ValidationResolver } from './ValidationResolver'
16
17
  import { GraphQLResolveInfo } from 'graphql'
17
18
  import { GraphQlQueryAstFactory } from './GraphQlQueryAstFactory'
18
19
  import { ImplementationException } from '../exception'
19
- import { retryTransaction } from '@contember/database'
20
+ import { DatabaseMetadata, retryTransaction } from '@contember/database'
20
21
  import { Operation, readOperationMeta } from '../schema'
21
22
  import { assertNever } from '../utils'
22
23
  import { InputPreValidator } from '../input-validation'
23
24
  import { ObjectNode } from '../inputProcessing'
24
25
  import { executeReadOperations } from './ReadHelpers'
25
26
  import { logger } from '@contember/logger'
26
- import { SchemaDatabaseMetadata } from '@contember/schema-utils'
27
27
 
28
28
  type WithoutNode<T extends { node: any }> = Pick<T, Exclude<keyof T, 'node'>>
29
29
 
30
- type TransactionOptions = { deferForeignKeyConstraints?: boolean }
30
+ type TransactionOptions = {
31
+ deferForeignKeyConstraints?: boolean
32
+ deferUniqueConstraints?: boolean
33
+ }
31
34
 
32
35
  export class MutationResolver {
33
36
  constructor(
@@ -35,7 +38,7 @@ export class MutationResolver {
35
38
  private readonly mapperFactory: MapperFactory,
36
39
  private readonly inputValidator: InputPreValidator,
37
40
  private readonly graphqlQueryAstFactory: GraphQlQueryAstFactory,
38
- private readonly schemaDatabaseMetadata: SchemaDatabaseMetadata,
41
+ private readonly schemaDatabaseMetadata: DatabaseMetadata,
39
42
  ) {}
40
43
 
41
44
  public async resolveTransaction(info: GraphQLResolveInfo, options: TransactionOptions): Promise<Result.TransactionResult> {
@@ -65,7 +68,11 @@ export class MutationResolver {
65
68
  return this.transaction(async mapper => {
66
69
  if (options?.deferForeignKeyConstraints) {
67
70
  logger.debug('MutationResolver: deferring foreign constraints')
68
- await mapper.constraintHelper.setFkConstraintsDeferred()
71
+ await mapper.constraintHelper.setConstraintsDeferred('foreignKey')
72
+ }
73
+ if (options?.deferUniqueConstraints) {
74
+ logger.debug('MutationResolver: deferring unique constraints')
75
+ await mapper.constraintHelper.setConstraintsDeferred('unique')
69
76
  }
70
77
  const validationResult: Record<string, Result.MutationFieldResult> = {}
71
78
  const validationErrors: Result.ValidationError[] = []
@@ -196,18 +203,6 @@ export class MutationResolver {
196
203
  }
197
204
  trxResult[field.alias] = result
198
205
  }
199
- if (options?.deferForeignKeyConstraints) {
200
- logger.debug('MutationResolver: validating fk constraints')
201
- const constraintsResult = await tryMutation(this.schema, this.schemaDatabaseMetadata, async () => {
202
- await mapper.constraintHelper.setFkConstraintsImmediate()
203
- return []
204
- })
205
- const errorResponse = this.createErrorResponse(constraintsResult)
206
- if (errorResponse) {
207
- logger.debug('MutationResolver: deferred fk validation failed', { errorResponse })
208
- return { ...errorResponse, ...validationResult }
209
- }
210
- }
211
206
 
212
207
  return {
213
208
  __typename: 'MutationTransaction',
@@ -474,20 +469,31 @@ export class MutationResolver {
474
469
  ): Promise<R> {
475
470
  return await retryTransaction(
476
471
  async () => {
477
- const [result, mapper] = await this.mapperFactory.transaction(async mapper => {
472
+ return await this.mapperFactory.transaction(async mapper => {
478
473
  logger.debug('MutationResolver: Starting mutation transaction')
479
474
  const result = await cb(mapper)
480
475
  if (!result.ok) {
481
476
  logger.debug('MutationResolver: Transaction failed, rolling back', { result })
482
477
  await mapper.db.connection.rollback()
483
478
  } else {
479
+ await mapper.eventManager.fire(new BeforeCommitEvent())
480
+
484
481
  logger.debug('MutationResolver: Transaction ok, committing')
482
+ try {
483
+ await mapper.db.connection.commit()
484
+ } catch (e) {
485
+ const err = convertError(this.schema, this.schemaDatabaseMetadata, e)
486
+ const errorResponse = this.createErrorResponse([err])
487
+ if (!errorResponse) {
488
+ throw new ImplementationException()
489
+ }
490
+ return { ...result, ...errorResponse }
491
+ }
492
+
493
+ await mapper.eventManager.fire(new AfterCommitEvent())
485
494
  }
486
- await mapper.eventManager.fire(new BeforeCommitEvent())
487
- return [result, mapper]
495
+ return result
488
496
  })
489
- await mapper.eventManager.fire(new AfterCommitEvent())
490
- return result
491
497
  },
492
498
  message => logger.warn(message),
493
499
  {
@@ -496,6 +502,7 @@ export class MutationResolver {
496
502
  maxTimeout: 1000,
497
503
  },
498
504
  )
505
+
499
506
  }
500
507
 
501
508
  private createErrorResponse(result: MutationResultList) {
@@ -46,7 +46,8 @@ export class EntityTypeProvider {
46
46
  private readonly columnTypeResolver: ColumnTypeResolver,
47
47
  private readonly whereTypeProvider: WhereTypeProvider,
48
48
  private readonly orderByTypeProvider: OrderByTypeProvider,
49
- ) {}
49
+ ) {
50
+ }
50
51
 
51
52
  public registerEntityFieldProvider(key: string, provider: EntityFieldsProvider): void {
52
53
  this.entityFieldProviders[key] = provider
@@ -76,19 +77,16 @@ export class EntityTypeProvider {
76
77
  private getEntityFields(entityName: string) {
77
78
  const entity = getEntityFromSchema(this.schema, entityName)
78
79
  const accessVisitor = new FieldAccessVisitor(Acl.Operation.read, this.authorizator)
79
- const accessibleFields = Object.keys(entity.fields).filter(fieldName =>
80
- acceptFieldVisitor(this.schema, entity, fieldName, accessVisitor),
81
- )
82
- const metaFields: { [field: string]: GraphQLFieldConfig<any, any> } = accessibleFields.reduce(
83
- (result, fieldName) => ({
84
- ...result,
85
- [fieldName]: {
86
- type: this.fieldMeta,
87
- resolve: aliasAwareResolver,
88
- },
89
- }),
90
- {},
80
+ const accessibleFields = Object.values(entity.fields).filter(field =>
81
+ acceptFieldVisitor(this.schema, entity, field.name, accessVisitor),
91
82
  )
83
+ const metaFields: { [field: string]: GraphQLFieldConfig<any, any> } = {}
84
+ for (const field of accessibleFields) {
85
+ metaFields[field.name] = {
86
+ type: this.fieldMeta,
87
+ resolve: aliasAwareResolver,
88
+ }
89
+ }
92
90
 
93
91
  const metaField = {
94
92
  type: new GraphQLObjectType({
@@ -98,36 +96,29 @@ export class EntityTypeProvider {
98
96
  resolve: aliasAwareResolver,
99
97
  }
100
98
 
101
- const fields: { [field: string]: GraphQLFieldConfig<any, any> } = accessibleFields.reduce(
102
- (result, fieldName) => {
103
- const fieldTypeVisitor = new FieldTypeVisitor(this.columnTypeResolver, this, this.authorizator)
104
- const type: GraphQLOutputType = acceptFieldVisitor(this.schema, entity, fieldName, fieldTypeVisitor)
99
+ let fields: { [field: string]: GraphQLFieldConfig<any, any> } = {
100
+ _meta: metaField,
101
+ }
102
+
103
+ for (const field of accessibleFields) {
104
+ const fieldTypeVisitor = new FieldTypeVisitor(this.columnTypeResolver, this, this.authorizator)
105
+ const type: GraphQLOutputType = acceptFieldVisitor(this.schema, entity, field.name, fieldTypeVisitor)
105
106
 
106
- const fieldArgsVisitor = new FieldArgsVisitor(this.whereTypeProvider, this.orderByTypeProvider)
107
- return {
108
- ...result,
109
- [fieldName]: {
110
- type,
111
- args: acceptFieldVisitor(this.schema, entity, fieldName, fieldArgsVisitor),
112
- resolve: aliasAwareResolver,
113
- },
114
- }
115
- },
116
- {
117
- _meta: metaField,
118
- },
119
- )
107
+ const fieldArgsVisitor = new FieldArgsVisitor(this.whereTypeProvider, this.orderByTypeProvider)
108
+ fields[field.name] = {
109
+ type,
110
+ args: acceptFieldVisitor(this.schema, entity, field.name, fieldArgsVisitor),
111
+ resolve: aliasAwareResolver,
112
+ }
113
+ }
120
114
 
121
- return Object.entries(this.entityFieldProviders)
122
- .map(([key, provider]) =>
123
- Object.entries(provider.getFields(entity, accessibleFields))
124
- .map(([fieldName, fieldConfig]): [string, GraphQLFieldConfig<any, any>] => [
125
- fieldName,
126
- { ...fieldConfig, extensions: { ...(fieldConfig.extensions || {}), extensionKey: key } },
127
- ])
128
- .reduce((result, [name, value]) => ({ ...result, [name]: value }), {}),
129
- )
130
- .reduce((result, providerFields) => ({ ...result, ...providerFields }), fields)
115
+ for (const [key, provider] of Object.entries(this.entityFieldProviders)) {
116
+ fields = {
117
+ ...fields,
118
+ ...provider.getFields(entity, accessibleFields),
119
+ }
120
+ }
121
+ return fields
131
122
  }
132
123
 
133
124
  private createConnection(entityName: string) {
@@ -76,6 +76,7 @@ export class GraphQlSchemaBuilder {
76
76
  name: 'MutationTransactionOptions',
77
77
  fields: {
78
78
  deferForeignKeyConstraints: { type: GraphQLBoolean },
79
+ deferUniqueConstraints: { type: GraphQLBoolean },
79
80
  },
80
81
  })
81
82
  const mutationTransactionType = new GraphQLObjectType({
@@ -102,10 +103,11 @@ export class GraphQlSchemaBuilder {
102
103
  type: new GraphQLNonNull(
103
104
  mutationTransactionType,
104
105
  ),
105
- resolve: async (parent, args: { options?: { deferForeignKeyConstraints?: boolean } }, context: Context, info) => {
106
+ resolve: async (parent, args: { options?: { deferForeignKeyConstraints?: boolean; deferUniqueConstraints?: boolean } }, context: Context, info) => {
106
107
  return context.timer(`GraphQL.mutation.${info.fieldName}`, () =>
107
108
  context.executionContainer.mutationResolver.resolveTransaction(info, {
108
109
  deferForeignKeyConstraints: args.options?.deferForeignKeyConstraints ?? false,
110
+ deferUniqueConstraints: args.options?.deferUniqueConstraints ?? false,
109
111
  }),
110
112
  )
111
113
  },
@@ -196,7 +196,7 @@ test('delete with unsuccessfully deferring constraints', async () => {
196
196
  ok: false,
197
197
  errorMessage: 'Execution has failed:\nunknown field: ForeignKeyConstraintViolation (Cannot delete row 123e4567-e89b-12d3-a456-000000000004 of entity Attachment, because it is still referenced from Reference::attachment. This is possibly caused by ACL denial or by missing "on delete cascade")',
198
198
  updatePost: {
199
- ok: false,
199
+ ok: true,
200
200
  errorMessage: null,
201
201
  },
202
202
  },
@@ -0,0 +1,169 @@
1
+ import { test } from 'vitest'
2
+ import { c, createSchema } from '@contember/schema-definition'
3
+ import { GQL } from '../../../../src/tags'
4
+ import { testUuid } from '../../../../src/testUuid'
5
+ import { executeDbTest } from '@contember/engine-api-tester'
6
+
7
+ namespace DeferredUniqueModel {
8
+ export class Post {
9
+ slug = c.stringColumn().unique()
10
+ order = c.intColumn().unique({ timing: 'deferrable' })
11
+ }
12
+ }
13
+
14
+ test('update without deferring unique constraints', async () => {
15
+ await executeDbTest({
16
+ schema: createSchema(DeferredUniqueModel),
17
+ seed: [
18
+ {
19
+ query: `mutation {
20
+ postA: createPost(data: {slug: "a", order: 1}) {
21
+ ok
22
+ node {
23
+ id
24
+ }
25
+ }
26
+ postB: createPost(data: {slug: "b", order: 2}) {
27
+ ok
28
+ node {
29
+ id
30
+ }
31
+ }
32
+ }`,
33
+ },
34
+ ],
35
+ query: GQL`
36
+ mutation {
37
+ transaction {
38
+ ok
39
+ errorMessage
40
+ upA: updatePost(by: {slug: "a"}, data: {order: 2}) {
41
+ ok
42
+ errorMessage
43
+ }
44
+ upB: updatePost(by: {slug: "b"}, data: {order: 1}) {
45
+ ok
46
+ errorMessage
47
+ }
48
+ }
49
+ }
50
+ `,
51
+ return: {
52
+ transaction: {
53
+ ok: false,
54
+ errorMessage: 'Execution has failed:\nupA.order: UniqueConstraintViolation (Value (2) already exists in unique columns (order) on entity Post)',
55
+ upA: {
56
+ ok: false,
57
+ errorMessage: 'Execution has failed:\norder: UniqueConstraintViolation (Value (2) already exists in unique columns (order) on entity Post)',
58
+ },
59
+ upB: {
60
+ ok: false,
61
+ errorMessage: null,
62
+ },
63
+ },
64
+ },
65
+ })
66
+ })
67
+
68
+ test('update with deferring unique constraints', async () => {
69
+ await executeDbTest({
70
+ schema: createSchema(DeferredUniqueModel),
71
+ seed: [
72
+ {
73
+ query: `mutation {
74
+
75
+ postA: createPost(data: {slug: "a", order: 1}) {
76
+ ok
77
+ node {
78
+ id
79
+ }
80
+ }
81
+ postB: createPost(data: {slug: "b", order: 2}) {
82
+ ok
83
+ node {
84
+ id
85
+ }
86
+ }
87
+ }`,
88
+ },
89
+ ],
90
+ query: GQL`
91
+ mutation {
92
+ transaction(options: {deferUniqueConstraints: true}) {
93
+ ok
94
+ errorMessage
95
+ upA: updatePost(by: {slug: "a"}, data: {order: 2}) {
96
+ ok
97
+ errorMessage
98
+ }
99
+ upB: updatePost(by: {slug: "b"}, data: {order: 1}) {
100
+ ok
101
+ errorMessage
102
+ }
103
+ }
104
+ }
105
+ `,
106
+ return: {
107
+ transaction: {
108
+ ok: true,
109
+ errorMessage: null,
110
+ upA: {
111
+ ok: true,
112
+ errorMessage: null,
113
+ },
114
+ upB: {
115
+ ok: true,
116
+ errorMessage: null,
117
+ },
118
+ },
119
+ },
120
+ })
121
+ })
122
+
123
+
124
+ test('update with failed deferred unique constraints', async () => {
125
+ await executeDbTest({
126
+ schema: createSchema(DeferredUniqueModel),
127
+ seed: [
128
+ {
129
+ query: `mutation {
130
+
131
+ postA: createPost(data: {slug: "a", order: 1}) {
132
+ ok
133
+ node {
134
+ id
135
+ }
136
+ }
137
+ postB: createPost(data: {slug: "b", order: 2}) {
138
+ ok
139
+ node {
140
+ id
141
+ }
142
+ }
143
+ }`,
144
+ },
145
+ ],
146
+ query: GQL`
147
+ mutation {
148
+ transaction(options: {deferUniqueConstraints: true}) {
149
+ ok
150
+ errorMessage
151
+ upA: updatePost(by: {slug: "a"}, data: {order: 2}) {
152
+ ok
153
+ errorMessage
154
+ }
155
+ }
156
+ }
157
+ `,
158
+ return: {
159
+ transaction: {
160
+ ok: false,
161
+ errorMessage: 'Execution has failed:\norder: UniqueConstraintViolation (Value (2) already exists in unique columns (order) on entity Post)',
162
+ upA: {
163
+ ok: true,
164
+ errorMessage: null,
165
+ },
166
+ },
167
+ },
168
+ })
169
+ })
@@ -417,4 +417,5 @@ type MutationTransaction {
417
417
 
418
418
  input MutationTransactionOptions {
419
419
  deferForeignKeyConstraints: Boolean
420
+ deferUniqueConstraints: Boolean
420
421
  }
@@ -226,4 +226,5 @@ type MutationTransaction {
226
226
 
227
227
  input MutationTransactionOptions {
228
228
  deferForeignKeyConstraints: Boolean
229
+ deferUniqueConstraints: Boolean
229
230
  }
@@ -306,4 +306,5 @@ type MutationTransaction {
306
306
 
307
307
  input MutationTransactionOptions {
308
308
  deferForeignKeyConstraints: Boolean
309
+ deferUniqueConstraints: Boolean
309
310
  }
@@ -399,4 +399,5 @@ type MutationTransaction {
399
399
 
400
400
  input MutationTransactionOptions {
401
401
  deferForeignKeyConstraints: Boolean
402
+ deferUniqueConstraints: Boolean
402
403
  }
@@ -335,4 +335,5 @@ type MutationTransaction {
335
335
 
336
336
  input MutationTransactionOptions {
337
337
  deferForeignKeyConstraints: Boolean
338
+ deferUniqueConstraints: Boolean
338
339
  }
@@ -218,4 +218,5 @@ type MutationTransaction {
218
218
 
219
219
  input MutationTransactionOptions {
220
220
  deferForeignKeyConstraints: Boolean
221
+ deferUniqueConstraints: Boolean
221
222
  }
@@ -223,4 +223,5 @@ type MutationTransaction {
223
223
 
224
224
  input MutationTransactionOptions {
225
225
  deferForeignKeyConstraints: Boolean
226
+ deferUniqueConstraints: Boolean
226
227
  }
@@ -838,4 +838,5 @@ type MutationTransaction {
838
838
 
839
839
  input MutationTransactionOptions {
840
840
  deferForeignKeyConstraints: Boolean
841
+ deferUniqueConstraints: Boolean
841
842
  }
@@ -537,4 +537,5 @@ type MutationTransaction {
537
537
 
538
538
  input MutationTransactionOptions {
539
539
  deferForeignKeyConstraints: Boolean
540
+ deferUniqueConstraints: Boolean
540
541
  }
@@ -848,4 +848,5 @@ type MutationTransaction {
848
848
 
849
849
  input MutationTransactionOptions {
850
850
  deferForeignKeyConstraints: Boolean
851
+ deferUniqueConstraints: Boolean
851
852
  }
@@ -450,4 +450,5 @@ type MutationTransaction {
450
450
 
451
451
  input MutationTransactionOptions {
452
452
  deferForeignKeyConstraints: Boolean
453
+ deferUniqueConstraints: Boolean
453
454
  }
@@ -909,4 +909,5 @@ type MutationTransaction {
909
909
 
910
910
  input MutationTransactionOptions {
911
911
  deferForeignKeyConstraints: Boolean
912
+ deferUniqueConstraints: Boolean
912
913
  }
package/tests/src/test.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Acl, Model, Schema, Validation } from '@contember/schema'
2
2
  import { Authorizator, GraphQlSchemaBuilderFactory, ExecutionContainerFactory } from '../../src'
3
- import { AllowAllPermissionFactory, dummySchemaDatabaseMetadata, emptySchema } from '@contember/schema-utils'
3
+ import { AllowAllPermissionFactory, emptySchema } from '@contember/schema-utils'
4
4
  import { executeGraphQlTest } from './testGraphql'
5
- import { Client } from '@contember/database'
5
+ import { Client, emptyDatabaseMetadata } from '@contember/database'
6
6
  import { createConnectionMock } from '@contember/database-tester'
7
7
  import { createUuidGenerator } from '@contember/engine-api-tester'
8
8
  import { SQL } from './tags'
@@ -111,7 +111,7 @@ export const execute = async (test: Test) => {
111
111
  systemSchema: 'system',
112
112
  stage: { id: '00000000-0000-0000-0000-000000000000', slug: 'live' },
113
113
  project: { slug: 'test' },
114
- schemaDatabaseMetadata: dummySchemaDatabaseMetadata,
114
+ schemaDatabaseMetadata: emptyDatabaseMetadata,
115
115
  }),
116
116
  timer: (label: any, cb: any) => cb(),
117
117
  },
@@ -1,4 +0,0 @@
1
- import { DocumentNode } from 'graphql';
2
- declare const schema: DocumentNode;
3
- export default schema;
4
- //# sourceMappingURL=content-schema.graphql.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-schema.graphql.d.ts","sourceRoot":"","sources":["../../../src/introspection/content-schema.graphql.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,QAAA,MAAM,MAAM,EAAE,YA2Gb,CAAA;AAED,eAAe,MAAM,CAAA"}
@@ -1,113 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const graphql_tag_1 = require("graphql-tag");
4
- const schema = (0, graphql_tag_1.gql) `
5
- scalar Json
6
-
7
- type Query {
8
- schema: _Schema
9
- }
10
-
11
- type _Schema {
12
- enums: [_Enum!]!
13
- entities: [_Entity!]!
14
- }
15
-
16
- type _Entity {
17
- name: String!
18
- customPrimaryAllowed: Boolean!
19
- fields: [_Field!]!
20
- unique: [_UniqueConstraint!]!
21
- }
22
-
23
- type _UniqueConstraint {
24
- fields: [String!]!
25
- }
26
-
27
- interface _Field {
28
- name: String!
29
- type: String!
30
- nullable: Boolean
31
- rules: [_Rule!]!
32
- validators: [_Validator!]!
33
- }
34
-
35
- type _Column implements _Field {
36
- name: String!
37
- type: String!
38
- enumName: String
39
- defaultValue: Json
40
- nullable: Boolean!
41
- rules: [_Rule!]!
42
- validators: [_Validator!]!
43
- }
44
-
45
- enum _OnDeleteBehaviour {
46
- restrict
47
- cascade
48
- setNull
49
- }
50
-
51
- enum _RelationSide {
52
- owning
53
- inverse
54
- }
55
- enum _OrderByDirection {
56
- asc
57
- desc
58
- }
59
- type _OrderBy {
60
- path: [String!]!
61
- direction: _OrderByDirection!
62
- }
63
-
64
- type _Relation implements _Field {
65
- name: String!
66
- type: String!
67
- side: _RelationSide!
68
- targetEntity: String!
69
- ownedBy: String
70
- inversedBy: String
71
- nullable: Boolean
72
- onDelete: _OnDeleteBehaviour
73
- orphanRemoval: Boolean
74
- orderBy: [_OrderBy!]
75
- rules: [_Rule!]!
76
- validators: [_Validator!]!
77
- }
78
-
79
- type _Rule {
80
- message: _RuleMessage
81
- validator: Int!
82
- }
83
-
84
- type _Validator {
85
- operation: String!
86
- arguments: [_Argument!]!
87
- }
88
-
89
- union _Argument = _ValidatorArgument | _PathArgument | _LiteralArgument
90
-
91
- type _ValidatorArgument {
92
- validator: Int!
93
- }
94
-
95
- type _PathArgument {
96
- path: [String!]!
97
- }
98
-
99
- type _LiteralArgument {
100
- value: Json
101
- }
102
-
103
- type _RuleMessage {
104
- text: String
105
- }
106
-
107
- type _Enum {
108
- name: String!
109
- values: [String!]!
110
- }
111
- `;
112
- exports.default = schema;
113
- //# sourceMappingURL=content-schema.graphql.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"content-schema.graphql.js","sourceRoot":"","sources":["../../../src/introspection/content-schema.graphql.ts"],"names":[],"mappings":";;AAAA,6CAAiC;AAGjC,MAAM,MAAM,GAAiB,IAAA,iBAAG,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2G/B,CAAA;AAED,kBAAe,MAAM,CAAA"}