@contember/schema-migrations 1.1.0-alpha.4 → 1.1.0-alpha.7

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 (166) hide show
  1. package/dist/src/MigrationFilesManager.js +5 -1
  2. package/dist/src/MigrationFilesManager.js.map +1 -1
  3. package/dist/src/SchemaDiffer.d.ts.map +1 -1
  4. package/dist/src/SchemaDiffer.js +2 -0
  5. package/dist/src/SchemaDiffer.js.map +1 -1
  6. package/dist/src/index.js +5 -1
  7. package/dist/src/index.js.map +1 -1
  8. package/dist/src/modifications/ModificationHandlerFactory.d.ts.map +1 -1
  9. package/dist/src/modifications/ModificationHandlerFactory.js +2 -0
  10. package/dist/src/modifications/ModificationHandlerFactory.js.map +1 -1
  11. package/dist/src/modifications/acl/index.js +5 -1
  12. package/dist/src/modifications/acl/index.js.map +1 -1
  13. package/dist/src/modifications/columns/CreateColumnModification.d.ts.map +1 -1
  14. package/dist/src/modifications/columns/CreateColumnModification.js +1 -0
  15. package/dist/src/modifications/columns/CreateColumnModification.js.map +1 -1
  16. package/dist/src/modifications/columns/UpdateColumnDefinitionModification.d.ts +8 -1
  17. package/dist/src/modifications/columns/UpdateColumnDefinitionModification.d.ts.map +1 -1
  18. package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js +16 -0
  19. package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js.map +1 -1
  20. package/dist/src/modifications/columns/UpdateColumnNameModification.d.ts.map +1 -1
  21. package/dist/src/modifications/columns/UpdateColumnNameModification.js +62 -3
  22. package/dist/src/modifications/columns/UpdateColumnNameModification.js.map +1 -1
  23. package/dist/src/modifications/columns/index.js +5 -1
  24. package/dist/src/modifications/columns/index.js.map +1 -1
  25. package/dist/src/modifications/constraints/index.js +5 -1
  26. package/dist/src/modifications/constraints/index.js.map +1 -1
  27. package/dist/src/modifications/differs/index.js +5 -1
  28. package/dist/src/modifications/differs/index.js.map +1 -1
  29. package/dist/src/modifications/entities/CreateEntityModification.d.ts +3 -1
  30. package/dist/src/modifications/entities/CreateEntityModification.d.ts.map +1 -1
  31. package/dist/src/modifications/entities/CreateEntityModification.js +10 -3
  32. package/dist/src/modifications/entities/CreateEntityModification.js.map +1 -1
  33. package/dist/src/modifications/entities/CreateViewModification.d.ts +3 -1
  34. package/dist/src/modifications/entities/CreateViewModification.d.ts.map +1 -1
  35. package/dist/src/modifications/entities/CreateViewModification.js +4 -1
  36. package/dist/src/modifications/entities/CreateViewModification.js.map +1 -1
  37. package/dist/src/modifications/entities/ToggleEventLogModification.d.ts +7 -0
  38. package/dist/src/modifications/entities/ToggleEventLogModification.d.ts.map +1 -0
  39. package/dist/src/modifications/entities/ToggleEventLogModification.js +63 -0
  40. package/dist/src/modifications/entities/ToggleEventLogModification.js.map +1 -0
  41. package/dist/src/modifications/entities/index.d.ts +1 -0
  42. package/dist/src/modifications/entities/index.d.ts.map +1 -1
  43. package/dist/src/modifications/entities/index.js +6 -1
  44. package/dist/src/modifications/entities/index.js.map +1 -1
  45. package/dist/src/modifications/enums/CreateEnumModification.d.ts +1 -1
  46. package/dist/src/modifications/enums/CreateEnumModification.d.ts.map +1 -1
  47. package/dist/src/modifications/enums/UpdateEnumModification.d.ts +1 -1
  48. package/dist/src/modifications/enums/UpdateEnumModification.d.ts.map +1 -1
  49. package/dist/src/modifications/enums/enumUtils.d.ts +1 -1
  50. package/dist/src/modifications/enums/enumUtils.d.ts.map +1 -1
  51. package/dist/src/modifications/enums/enumUtils.js.map +1 -1
  52. package/dist/src/modifications/enums/index.js +5 -1
  53. package/dist/src/modifications/enums/index.js.map +1 -1
  54. package/dist/src/modifications/fields/UpdateFieldNameModification.d.ts +1 -0
  55. package/dist/src/modifications/fields/UpdateFieldNameModification.d.ts.map +1 -1
  56. package/dist/src/modifications/fields/UpdateFieldNameModification.js +13 -2
  57. package/dist/src/modifications/fields/UpdateFieldNameModification.js.map +1 -1
  58. package/dist/src/modifications/fields/index.js +5 -1
  59. package/dist/src/modifications/fields/index.js.map +1 -1
  60. package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.d.ts +2 -1
  61. package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.d.ts.map +1 -1
  62. package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.js +3 -2
  63. package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.js.map +1 -1
  64. package/dist/src/modifications/relations/CreateRelationModification.d.ts +5 -4
  65. package/dist/src/modifications/relations/CreateRelationModification.d.ts.map +1 -1
  66. package/dist/src/modifications/relations/CreateRelationModification.js +10 -2
  67. package/dist/src/modifications/relations/CreateRelationModification.js.map +1 -1
  68. package/dist/src/modifications/relations/ToggleManyHasManyEventLogModification.d.ts +8 -0
  69. package/dist/src/modifications/relations/ToggleManyHasManyEventLogModification.d.ts.map +1 -0
  70. package/dist/src/modifications/relations/ToggleManyHasManyEventLogModification.js +81 -0
  71. package/dist/src/modifications/relations/ToggleManyHasManyEventLogModification.js.map +1 -0
  72. package/dist/src/modifications/relations/UpdateRelationOrderByModification.d.ts +1 -1
  73. package/dist/src/modifications/relations/UpdateRelationOrderByModification.d.ts.map +1 -1
  74. package/dist/src/modifications/relations/index.d.ts +1 -0
  75. package/dist/src/modifications/relations/index.d.ts.map +1 -1
  76. package/dist/src/modifications/relations/index.js +6 -1
  77. package/dist/src/modifications/relations/index.js.map +1 -1
  78. package/dist/src/modifications/relations/normalization.d.ts +8 -0
  79. package/dist/src/modifications/relations/normalization.d.ts.map +1 -0
  80. package/dist/src/modifications/relations/normalization.js +16 -0
  81. package/dist/src/modifications/relations/normalization.js.map +1 -0
  82. package/dist/src/modifications/utils/createJunctionTable.d.ts.map +1 -1
  83. package/dist/src/modifications/utils/createJunctionTable.js +4 -2
  84. package/dist/src/modifications/utils/createJunctionTable.js.map +1 -1
  85. package/dist/src/modifications/utils/renameConstraintsHelper.d.ts.map +1 -1
  86. package/dist/src/modifications/utils/renameConstraintsHelper.js.map +1 -1
  87. package/dist/src/modifications/utils/schemaUpdateUtils.d.ts.map +1 -1
  88. package/dist/src/modifications/utils/schemaUpdateUtils.js.map +1 -1
  89. package/dist/src/modifications/utils/sqlUpdateUtils.d.ts +2 -0
  90. package/dist/src/modifications/utils/sqlUpdateUtils.d.ts.map +1 -1
  91. package/dist/src/modifications/utils/sqlUpdateUtils.js +9 -1
  92. package/dist/src/modifications/utils/sqlUpdateUtils.js.map +1 -1
  93. package/dist/src/modifications/validation/index.js +5 -1
  94. package/dist/src/modifications/validation/index.js.map +1 -1
  95. package/dist/src/tsconfig.tsbuildinfo +1 -1
  96. package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.js +3 -0
  97. package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.js.map +1 -1
  98. package/dist/tests/cases/integration/createEntity.test.js +6 -0
  99. package/dist/tests/cases/integration/createEntity.test.js.map +1 -1
  100. package/dist/tests/cases/integration/createManyHasMany.test.js +6 -0
  101. package/dist/tests/cases/integration/createManyHasMany.test.js.map +1 -1
  102. package/dist/tests/cases/integration/createManyHasOne.test.js +3 -0
  103. package/dist/tests/cases/integration/createManyHasOne.test.js.map +1 -1
  104. package/dist/tests/cases/integration/createOneHasMany.test.js +3 -0
  105. package/dist/tests/cases/integration/createOneHasMany.test.js.map +1 -1
  106. package/dist/tests/cases/integration/createOneHasOne.test.js +6 -0
  107. package/dist/tests/cases/integration/createOneHasOne.test.js.map +1 -1
  108. package/dist/tests/cases/integration/createView.test.js +3 -0
  109. package/dist/tests/cases/integration/createView.test.js.map +1 -1
  110. package/dist/tests/cases/integration/toggleEventLog.test.d.ts +2 -0
  111. package/dist/tests/cases/integration/toggleEventLog.test.d.ts.map +1 -0
  112. package/dist/tests/cases/integration/toggleEventLog.test.js +68 -0
  113. package/dist/tests/cases/integration/toggleEventLog.test.js.map +1 -0
  114. package/dist/tests/cases/integration/toggleJunctionEventLog.test.d.ts +2 -0
  115. package/dist/tests/cases/integration/toggleJunctionEventLog.test.d.ts.map +1 -0
  116. package/dist/tests/cases/integration/toggleJunctionEventLog.test.js +75 -0
  117. package/dist/tests/cases/integration/toggleJunctionEventLog.test.js.map +1 -0
  118. package/dist/tests/cases/integration/updateFieldName.test.js +40 -0
  119. package/dist/tests/cases/integration/updateFieldName.test.js.map +1 -1
  120. package/dist/tests/cases/integration/updateView.test.js +27 -0
  121. package/dist/tests/cases/integration/updateView.test.js.map +1 -1
  122. package/dist/tests/scripts/checkCreateConsistentMigrations.js +5 -0
  123. package/dist/tests/scripts/checkCreateConsistentMigrations.js.map +1 -1
  124. package/dist/tests/src/tests.d.ts +1 -1
  125. package/dist/tests/src/tests.d.ts.map +1 -1
  126. package/dist/tests/src/tests.js +19 -39
  127. package/dist/tests/src/tests.js.map +1 -1
  128. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  129. package/package.json +7 -8
  130. package/src/SchemaDiffer.ts +4 -0
  131. package/src/modifications/ModificationHandlerFactory.ts +4 -0
  132. package/src/modifications/columns/CreateColumnModification.ts +1 -0
  133. package/src/modifications/columns/UpdateColumnDefinitionModification.ts +30 -1
  134. package/src/modifications/columns/UpdateColumnNameModification.ts +62 -3
  135. package/src/modifications/entities/CreateEntityModification.ts +14 -4
  136. package/src/modifications/entities/CreateViewModification.ts +7 -2
  137. package/src/modifications/entities/ToggleEventLogModification.ts +83 -0
  138. package/src/modifications/entities/index.ts +1 -0
  139. package/src/modifications/enums/CreateEnumModification.ts +1 -1
  140. package/src/modifications/enums/UpdateEnumModification.ts +1 -1
  141. package/src/modifications/enums/enumUtils.ts +1 -1
  142. package/src/modifications/fields/UpdateFieldNameModification.ts +26 -4
  143. package/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.ts +4 -3
  144. package/src/modifications/relations/CreateRelationModification.ts +17 -5
  145. package/src/modifications/relations/ToggleManyHasManyEventLogModification.ts +102 -0
  146. package/src/modifications/relations/UpdateRelationOrderByModification.ts +1 -1
  147. package/src/modifications/relations/index.ts +1 -0
  148. package/src/modifications/relations/normalization.ts +21 -0
  149. package/src/modifications/utils/createJunctionTable.ts +4 -2
  150. package/src/modifications/utils/renameConstraintsHelper.ts +2 -2
  151. package/src/modifications/utils/schemaUpdateUtils.ts +2 -2
  152. package/src/modifications/utils/sqlUpdateUtils.ts +8 -0
  153. package/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.ts +3 -0
  154. package/tests/cases/integration/createEntity.test.ts +6 -0
  155. package/tests/cases/integration/createManyHasMany.test.ts +6 -0
  156. package/tests/cases/integration/createManyHasOne.test.ts +3 -0
  157. package/tests/cases/integration/createOneHasMany.test.ts +3 -0
  158. package/tests/cases/integration/createOneHasOne.test.ts +6 -0
  159. package/tests/cases/integration/createView.test.ts +3 -0
  160. package/tests/cases/integration/toggleEventLog.test.ts +54 -0
  161. package/tests/cases/integration/toggleJunctionEventLog.test.ts +63 -0
  162. package/tests/cases/integration/updateFieldName.test.ts +47 -0
  163. package/tests/cases/integration/updateView.test.ts +27 -0
  164. package/tests/scripts/checkCreateConsistentMigrations.ts +6 -1
  165. package/tests/src/tests.ts +18 -19
  166. package/tests/tsconfig.json +3 -0
@@ -26,7 +26,24 @@ export const UpdateColumnDefinitionModification: ModificationHandlerStatic<Updat
26
26
  type: newType,
27
27
  notNull: field.nullable !== definition.nullable ? !definition.nullable : undefined,
28
28
  using: newType !== undefined ? `${wrapIdentifier(field.columnName)}::${newType}` : undefined,
29
+ sequenceGenerated: field.sequence && !definition.sequence ? false : (!field.sequence ? definition.sequence : undefined),
29
30
  })
31
+
32
+ const seqAlter = []
33
+ if (field.sequence && definition.sequence) {
34
+ if (field.sequence.precedence !== definition.sequence.precedence) {
35
+ seqAlter.push(`SET GENERATED ${definition.sequence.precedence}`)
36
+ }
37
+ if (field.sequence.start !== definition.sequence.start && typeof definition.sequence.start == 'number') {
38
+ seqAlter.push(`SET START WITH ${definition.sequence.start}`)
39
+ }
40
+ if (definition.sequence.restart) {
41
+ seqAlter.push('RESTART')
42
+ }
43
+ }
44
+ if (seqAlter.length > 0) {
45
+ builder.sql(`ALTER TABLE ${wrapIdentifier(entity.tableName)} ALTER ${wrapIdentifier(field.columnName)} ${seqAlter.join(' ')}`)
46
+ }
30
47
  }
31
48
 
32
49
  public getSchemaUpdater(): SchemaUpdater {
@@ -83,8 +100,20 @@ export const UpdateColumnDefinitionModification: ModificationHandlerStatic<Updat
83
100
  }
84
101
  }
85
102
 
103
+ type SequenceDefinitionAlter =
104
+ & Model.AnyColumn['sequence']
105
+ & {
106
+ restart?: boolean
107
+ }
108
+
109
+ type ColumnDefinitionAlter =
110
+ & Model.AnyColumn
111
+ & {
112
+ sequence?: SequenceDefinitionAlter
113
+ }
114
+
86
115
  export interface UpdateColumnDefinitionModificationData {
87
116
  entityName: string
88
117
  fieldName: string
89
- definition: Model.AnyColumn
118
+ definition: ColumnDefinitionAlter
90
119
  }
@@ -3,6 +3,7 @@ import { Model, Schema } from '@contember/schema'
3
3
  import { SchemaUpdater, updateEntity, updateField, updateModel } from '../utils/schemaUpdateUtils'
4
4
  import { ModificationHandlerStatic } from '../ModificationHandler'
5
5
  import { updateColumns } from '../utils/diffUtils'
6
+ import { acceptFieldVisitor } from '@contember/schema-utils'
6
7
 
7
8
  export const UpdateColumnNameModification: ModificationHandlerStatic<UpdateColumnNameModificationData> = class {
8
9
  static id = 'updateColumnName'
@@ -13,15 +14,73 @@ export const UpdateColumnNameModification: ModificationHandlerStatic<UpdateColum
13
14
  if (entity.view) {
14
15
  return
15
16
  }
16
- const field = entity.fields[this.data.fieldName] as Model.AnyColumn
17
- builder.renameColumn(entity.tableName, field.columnName, this.data.columnName)
17
+ acceptFieldVisitor(this.schema.model, entity, this.data.fieldName, {
18
+ visitColumn: (entity, column) => {
19
+ builder.renameColumn(entity.tableName, column.columnName, this.data.columnName)
20
+ },
21
+ visitManyHasOne: (entity, relation) => {
22
+ builder.renameColumn(entity.tableName, relation.joiningColumn.columnName, this.data.columnName)
23
+ },
24
+ visitOneHasOneOwning: (entity, relation) => {
25
+ builder.renameColumn(entity.tableName, relation.joiningColumn.columnName, this.data.columnName)
26
+ },
27
+ visitManyHasManyInverse: () => {
28
+ throw new Error('Cannot rename column of many-to-many relation')
29
+ },
30
+ visitManyHasManyOwning: () => {
31
+ throw new Error('Cannot rename column of many-to-many relation')
32
+ },
33
+ visitOneHasMany: () => {
34
+ throw new Error('Cannot rename column of one-to-many relation')
35
+ },
36
+ visitOneHasOneInverse: () => {
37
+ throw new Error('Cannot rename column of one-to-one inverse relation')
38
+ },
39
+ })
18
40
  }
19
41
 
20
42
  public getSchemaUpdater(): SchemaUpdater {
21
43
  return updateModel(
22
44
  updateEntity(
23
45
  this.data.entityName,
24
- updateField(this.data.fieldName, ({ field }) => ({ ...field, columnName: this.data.columnName })),
46
+ updateField(this.data.fieldName, ({ field, entity }) => acceptFieldVisitor<Model.AnyField>(this.schema.model, entity, field, {
47
+ visitColumn: (entity, column) => {
48
+ return {
49
+ ...column,
50
+ columnName: this.data.columnName,
51
+ }
52
+ },
53
+ visitManyHasOne: (entity, relation) => {
54
+ return {
55
+ ...relation,
56
+ joiningColumn: {
57
+ ...relation.joiningColumn,
58
+ columnName: this.data.columnName,
59
+ },
60
+ }
61
+ },
62
+ visitOneHasOneOwning: (entity, relation) => {
63
+ return {
64
+ ...relation,
65
+ joiningColumn: {
66
+ ...relation.joiningColumn,
67
+ columnName: this.data.columnName,
68
+ },
69
+ }
70
+ },
71
+ visitManyHasManyInverse: () => {
72
+ throw new Error('Cannot rename column of many-to-many relation')
73
+ },
74
+ visitManyHasManyOwning: () => {
75
+ throw new Error('Cannot rename column of many-to-many relation')
76
+ },
77
+ visitOneHasMany: () => {
78
+ throw new Error('Cannot rename column of one-to-many relation')
79
+ },
80
+ visitOneHasOneInverse: () => {
81
+ throw new Error('Cannot rename column of one-to-one inverse relation')
82
+ },
83
+ })),
25
84
  ),
26
85
  )
27
86
  }
@@ -20,15 +20,20 @@ export const CreateEntityModification: ModificationHandlerStatic<CreateEntityMod
20
20
  return
21
21
  }
22
22
  const primaryColumn = entity.fields[entity.primary] as Model.AnyColumn
23
+
23
24
  builder.createTable(entity.tableName, {
24
25
  [primaryColumn.name]: {
25
26
  primaryKey: true,
26
27
  type: primaryColumn.type === Model.ColumnType.Enum ? `"${primaryColumn.columnType}"` : primaryColumn.columnType,
27
28
  notNull: true,
29
+ sequenceGenerated: primaryColumn.sequence,
28
30
  },
29
31
  })
30
- createEventTrigger(builder, this.options.systemSchema, entity.tableName, [entity.primaryColumn])
31
- createEventTrxTrigger(builder, this.options.systemSchema, entity.tableName)
32
+
33
+ if (entity.eventLog?.enabled !== false) {
34
+ createEventTrigger(builder, this.options.systemSchema, entity.tableName, [entity.primaryColumn])
35
+ createEventTrxTrigger(builder, this.options.systemSchema, entity.tableName)
36
+ }
32
37
  }
33
38
 
34
39
  public getSchemaUpdater(): SchemaUpdater {
@@ -36,7 +41,10 @@ export const CreateEntityModification: ModificationHandlerStatic<CreateEntityMod
36
41
  ...model,
37
42
  entities: {
38
43
  ...model.entities,
39
- [this.data.entity.name]: this.data.entity,
44
+ [this.data.entity.name]: {
45
+ eventLog: { enabled: true },
46
+ ...this.data.entity,
47
+ },
40
48
  },
41
49
  }))
42
50
  }
@@ -68,6 +76,8 @@ export const CreateEntityModification: ModificationHandlerStatic<CreateEntityMod
68
76
  }
69
77
  }
70
78
 
79
+ type SomePartial<E, K extends keyof E> = Omit<E, K> & Partial<Pick<E, K>>
80
+
71
81
  export interface CreateEntityModificationData {
72
- entity: Model.Entity
82
+ entity: SomePartial<Model.Entity, 'eventLog'>
73
83
  }
@@ -21,7 +21,10 @@ export const CreateViewModification: ModificationHandlerStatic<CreateViewModific
21
21
  ...model,
22
22
  entities: {
23
23
  ...model.entities,
24
- [this.data.entity.name]: this.data.entity,
24
+ [this.data.entity.name]: {
25
+ eventLog: { enabled: true }, // not relevant here...
26
+ ...this.data.entity,
27
+ },
25
28
  },
26
29
  }))
27
30
  }
@@ -60,6 +63,8 @@ export const CreateViewModification: ModificationHandlerStatic<CreateViewModific
60
63
  }
61
64
  }
62
65
 
66
+ type SomePartial<E, K extends keyof E> = Omit<E, K> & Partial<Pick<E, K>>
67
+
63
68
  export interface CreateViewModificationData {
64
- entity: Model.Entity
69
+ entity: SomePartial<Model.Entity, 'eventLog'>
65
70
  }
@@ -0,0 +1,83 @@
1
+ import { MigrationBuilder } from '@contember/database-migrations'
2
+ import { Schema } from '@contember/schema'
3
+ import { SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils'
4
+ import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
5
+ import {
6
+ createEventTrigger,
7
+ createEventTrxTrigger,
8
+ dropEventTrigger,
9
+ dropEventTrxTrigger,
10
+ } from '../utils/sqlUpdateUtils'
11
+
12
+ export const ToggleEventLogModification: ModificationHandlerStatic<ToggleEventLogModificationData> = class {
13
+ static id = 'toggleEventLog'
14
+
15
+ constructor(
16
+ private readonly data: ToggleEventLogModificationData,
17
+ private readonly schema: Schema,
18
+ private readonly options: ModificationHandlerOptions,
19
+ ) {
20
+ }
21
+
22
+ public createSql(builder: MigrationBuilder): void {
23
+ const entity = this.schema.model.entities[this.data.entityName]
24
+ if (entity.view) {
25
+ return
26
+ }
27
+ if (this.data.enabled) {
28
+ createEventTrigger(builder, this.options.systemSchema, entity.tableName, [entity.primaryColumn])
29
+ createEventTrxTrigger(builder, this.options.systemSchema, entity.tableName)
30
+ } else {
31
+ dropEventTrigger(builder, entity.tableName)
32
+ dropEventTrxTrigger(builder, entity.tableName)
33
+ }
34
+ }
35
+
36
+ public getSchemaUpdater(): SchemaUpdater {
37
+ const { entityName, enabled } = this.data
38
+ return updateModel(
39
+ updateEntity(
40
+ entityName,
41
+ ({ entity: { eventLog, ...entity } }) => ({
42
+ ...entity,
43
+ eventLog: { enabled },
44
+ }),
45
+ ),
46
+ )
47
+ }
48
+
49
+ describe() {
50
+ return {
51
+ message: `${this.data.enabled ? 'Enable' : 'Disable'} event log for ${this.data.entityName}`,
52
+ }
53
+ }
54
+
55
+ static createModification(data: ToggleEventLogModificationData) {
56
+ return { modification: this.id, ...data }
57
+ }
58
+
59
+ static createDiff(originalSchema: Schema, updatedSchema: Schema) {
60
+ return Object.values(updatedSchema.model.entities)
61
+ .flatMap(updatedEntity => {
62
+ const origEntity = originalSchema.model.entities[updatedEntity.name]
63
+ if (!origEntity) {
64
+ return []
65
+ }
66
+ const newValue = updatedEntity.eventLog.enabled
67
+ const oldValue = origEntity.eventLog.enabled
68
+ if (newValue !== oldValue) {
69
+ return [ToggleEventLogModification.createModification({
70
+ entityName: updatedEntity.name,
71
+ enabled: newValue,
72
+ })]
73
+ }
74
+ return []
75
+ })
76
+
77
+ }
78
+ }
79
+
80
+ export interface ToggleEventLogModificationData {
81
+ entityName: string
82
+ enabled: boolean
83
+ }
@@ -1,5 +1,6 @@
1
1
  export * from './CreateEntityModification'
2
2
  export * from './CreateViewModification'
3
3
  export * from './RemoveEntityModification'
4
+ export * from './ToggleEventLogModification'
4
5
  export * from './UpdateEntityNameModification'
5
6
  export * from './UpdateEntityTableNameModification'
@@ -42,5 +42,5 @@ export const CreateEnumModification: ModificationHandlerStatic<CreateEnumModific
42
42
 
43
43
  export interface CreateEnumModificationData {
44
44
  enumName: string
45
- values: string[]
45
+ values: readonly string[]
46
46
  }
@@ -55,5 +55,5 @@ export const UpdateEnumModification: ModificationHandlerStatic<UpdateEnumModific
55
55
 
56
56
  export interface UpdateEnumModificationData {
57
57
  enumName: string
58
- values: string[]
58
+ values: readonly string[]
59
59
  }
@@ -1,6 +1,6 @@
1
1
  import { escapeSqlString } from '../../utils/escapeSqlString'
2
2
 
3
- export const createCheck = (values: string[]) => {
3
+ export const createCheck = (values: readonly string[]) => {
4
4
  const joinedValues = values.map(it => `'${escapeSqlString(it)}'`).join(',')
5
5
  return `VALUE IN(${joinedValues})`
6
6
  }
@@ -13,19 +13,32 @@ import {
13
13
  updateModel,
14
14
  updateSchema,
15
15
  } from '../utils/schemaUpdateUtils'
16
- import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
16
+ import { ModificationHandler, ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
17
17
  import { acceptFieldVisitor, NamingHelper, PredicateDefinitionProcessor } from '@contember/schema-utils'
18
18
  import { VERSION_ACL_PATCH, VERSION_UPDATE_CONSTRAINT_NAME } from '../ModificationVersions'
19
19
  import { renameConstraintSchemaUpdater, renameConstraintsSqlBuilder } from '../utils/renameConstraintsHelper'
20
20
  import { changeValue } from '../utils/valueUtils'
21
+ import { UpdateColumnNameModification } from '../columns'
22
+ import { NoopModification } from '../NoopModification'
21
23
 
22
24
  export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldNameModificationData> = class {
23
25
  static id = 'updateFieldName'
26
+
27
+ private renameColumnSubModification: ModificationHandler<any> = new NoopModification()
28
+
24
29
  constructor(
25
30
  private readonly data: UpdateFieldNameModificationData,
26
31
  private readonly schema: Schema,
27
32
  private readonly options: ModificationHandlerOptions,
28
- ) {}
33
+ ) {
34
+ if (this.data.columnName) {
35
+ this.renameColumnSubModification = new UpdateColumnNameModification({
36
+ entityName: this.data.entityName,
37
+ columnName: this.data.columnName,
38
+ fieldName: this.data.fieldName,
39
+ }, this.schema, this.options)
40
+ }
41
+ }
29
42
 
30
43
  public createSql(builder: MigrationBuilder): void {
31
44
  const entity = this.schema.model.entities[this.data.entityName]
@@ -35,6 +48,7 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
35
48
  if (this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME) {
36
49
  renameConstraintsSqlBuilder(builder, entity, this.getNewConstraintName.bind(this))
37
50
  }
51
+ this.renameColumnSubModification.createSql(builder)
38
52
  }
39
53
 
40
54
  public getSchemaUpdater(): SchemaUpdater {
@@ -101,7 +115,7 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
101
115
  })
102
116
  }),
103
117
  )
104
- const updateEntityName = updateEntity(this.data.entityName, ({ entity }) => {
118
+ const updateFieldName = updateEntity(this.data.entityName, ({ entity }) => {
105
119
  const { [this.data.fieldName]: updated, ...fields } = entity.fields
106
120
  return {
107
121
  ...entity,
@@ -153,10 +167,17 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
153
167
  : undefined
154
168
  return updateSchema(
155
169
  updateAclOp,
156
- updateModel(updateConstraintName, updateConstraintFields, updateRelationReferences, updateEntityName),
170
+ this.renameColumnSubModification.getSchemaUpdater(),
171
+ updateModel(
172
+ updateConstraintName,
173
+ updateConstraintFields,
174
+ updateRelationReferences,
175
+ updateFieldName,
176
+ ),
157
177
  )
158
178
  }
159
179
 
180
+
160
181
  private getNewConstraintName(constraint: Model.UniqueConstraint): string | null {
161
182
  const generatedName = NamingHelper.createUniqueConstraintName(this.data.entityName, constraint.fields)
162
183
  const isGenerated = constraint.name === generatedName
@@ -181,4 +202,5 @@ export interface UpdateFieldNameModificationData {
181
202
  entityName: string
182
203
  fieldName: string
183
204
  newFieldName: string
205
+ columnName?: string
184
206
  }
@@ -7,6 +7,7 @@ import { updateRelations } from '../utils/diffUtils'
7
7
  import { UpdateFieldNameModification } from '../fields'
8
8
  import { createJunctionTableSql } from '../utils/createJunctionTable'
9
9
  import { wrapIdentifier } from '@contember/database'
10
+ import { normalizeManyHasManyRelation, PartialManyHasManyRelation } from './normalization'
10
11
 
11
12
  export const ConvertOneHasManyToManyHasManyRelationModification: ModificationHandlerStatic<ConvertOneHasManyToManyHasManyRelationModificationData> = class {
12
13
  static id = 'convertOneHasManyToManyHasManyRelation'
@@ -33,7 +34,7 @@ export const ConvertOneHasManyToManyHasManyRelationModification: ModificationHan
33
34
  const { relation: oldRelation } = this.getRelation()
34
35
  const entity = this.schema.model.entities[this.data.entityName]
35
36
 
36
- createJunctionTableSql(builder, this.options.systemSchema, entity, targetEntity, this.data.owningSide)
37
+ createJunctionTableSql(builder, this.options.systemSchema, entity, targetEntity, normalizeManyHasManyRelation(this.data.owningSide))
37
38
  const joiningTable = this.data.owningSide.joiningTable
38
39
  builder.sql(`
39
40
  INSERT INTO ${wrapIdentifier(joiningTable.tableName)} (
@@ -51,7 +52,7 @@ export const ConvertOneHasManyToManyHasManyRelationModification: ModificationHan
51
52
  const { entityName } = this.data
52
53
  return updateSchema(
53
54
  this.subModification.getSchemaUpdater(),
54
- updateModel(updateEntity(entityName, addField(this.data.owningSide))),
55
+ updateModel(updateEntity(entityName, addField(normalizeManyHasManyRelation(this.data.owningSide)))),
55
56
  this.data.inverseSide ? updateModel(updateEntity(this.data.owningSide.target, addField(this.data.inverseSide))) : undefined,
56
57
  )
57
58
  }
@@ -104,6 +105,6 @@ export const ConvertOneHasManyToManyHasManyRelationModification: ModificationHan
104
105
  export interface ConvertOneHasManyToManyHasManyRelationModificationData {
105
106
  entityName: string
106
107
  fieldName: string
107
- owningSide: Model.ManyHasManyOwningRelation
108
+ owningSide: PartialManyHasManyRelation
108
109
  inverseSide?: Model.ManyHasManyInverseRelation
109
110
  }
@@ -13,6 +13,7 @@ import { isIt } from '../../utils/isIt'
13
13
  import { createFields } from '../utils/diffUtils'
14
14
  import { getPrimaryColumnType } from '../utils/getPrimaryColumnType'
15
15
  import { createJunctionTableSql } from '../utils/createJunctionTable'
16
+ import { normalizeManyHasManyRelation, PartialManyHasManyRelation } from './normalization'
16
17
 
17
18
 
18
19
  export const CreateRelationModification: ModificationHandlerStatic<CreateRelationModificationData> = class {
@@ -53,7 +54,7 @@ export const CreateRelationModification: ModificationHandlerStatic<CreateRelatio
53
54
  deferred: false,
54
55
  })
55
56
  }
56
- acceptRelationTypeVisitor(this.schema.model, entity, this.data.owningSide, {
57
+ acceptRelationTypeVisitor(this.schema.model, entity, this.getNormalizedOwningSide(), {
57
58
  visitManyHasOne: ({}, relation, {}, _) => {
58
59
  createOwningSide(relation)
59
60
  builder.addIndex(entity.tableName, relation.joiningColumn.columnName)
@@ -74,7 +75,7 @@ export const CreateRelationModification: ModificationHandlerStatic<CreateRelatio
74
75
 
75
76
  public getSchemaUpdater(): SchemaUpdater {
76
77
  return updateModel(
77
- updateEntity(this.data.entityName, addField(this.data.owningSide)),
78
+ updateEntity(this.data.entityName, addField(this.getNormalizedOwningSide())),
78
79
  this.data.inverseSide !== undefined
79
80
  ? updateEntity(this.data.owningSide.target, addField(this.data.inverseSide))
80
81
  : undefined,
@@ -112,10 +113,21 @@ export const CreateRelationModification: ModificationHandlerStatic<CreateRelatio
112
113
  })
113
114
  })
114
115
  }
116
+
117
+ private getNormalizedOwningSide(): Model.AnyOwningRelation {
118
+ if (this.data.owningSide.type === Model.RelationType.ManyHasMany) {
119
+ return normalizeManyHasManyRelation(this.data.owningSide)
120
+ }
121
+ return this.data.owningSide
122
+ }
115
123
  }
116
124
 
117
- export interface CreateRelationModificationData {
125
+
126
+ export type CreateRelationModificationData = {
118
127
  entityName: string
119
- owningSide: Model.AnyRelation & Model.OwningRelation
120
- inverseSide?: Model.AnyRelation & Model.InverseRelation
128
+ owningSide:
129
+ | Model.ManyHasOneRelation
130
+ | Model.OneHasOneOwningRelation
131
+ | PartialManyHasManyRelation
132
+ inverseSide?: Model.AnyInverseRelation
121
133
  }
@@ -0,0 +1,102 @@
1
+ import { MigrationBuilder } from '@contember/database-migrations'
2
+ import { Model, Schema } from '@contember/schema'
3
+ import { SchemaUpdater, updateEntity, updateField, updateModel } from '../utils/schemaUpdateUtils'
4
+ import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
5
+ import {
6
+ createEventTrigger,
7
+ createEventTrxTrigger,
8
+ dropEventTrigger,
9
+ dropEventTrxTrigger,
10
+ } from '../utils/sqlUpdateUtils'
11
+ import { isOwningRelation, isRelation } from '@contember/schema-utils'
12
+ import { updateRelations } from '../utils/diffUtils'
13
+ import { isIt } from '../../utils/isIt'
14
+
15
+ export const ToggleJunctionEventLogModification: ModificationHandlerStatic<ToggleJunctionEventLogModificationData> = class {
16
+ static id = 'toggleJunctionEventLog'
17
+
18
+ constructor(
19
+ private readonly data: ToggleJunctionEventLogModificationData,
20
+ private readonly schema: Schema,
21
+ private readonly options: ModificationHandlerOptions,
22
+ ) {
23
+ }
24
+
25
+ public createSql(builder: MigrationBuilder): void {
26
+ const entity = this.schema.model.entities[this.data.entityName]
27
+ const relation = entity.fields[this.data.fieldName]
28
+ if (!isRelation(relation) || relation.type !== Model.RelationType.ManyHasMany || !isOwningRelation(relation)) {
29
+ throw new Error('invalid field')
30
+ }
31
+ const tableName = relation.joiningTable.tableName
32
+ if (this.data.enabled) {
33
+ const primaryColumns = [
34
+ relation.joiningTable.joiningColumn.columnName,
35
+ relation.joiningTable.inverseJoiningColumn.columnName,
36
+ ]
37
+ createEventTrigger(builder, this.options.systemSchema, tableName, primaryColumns)
38
+ createEventTrxTrigger(builder, this.options.systemSchema, tableName)
39
+ } else {
40
+ dropEventTrigger(builder, tableName)
41
+ dropEventTrxTrigger(builder, tableName)
42
+ }
43
+ }
44
+
45
+ public getSchemaUpdater(): SchemaUpdater {
46
+ const { entityName, fieldName, enabled } = this.data
47
+ return updateModel(
48
+ updateEntity(
49
+ entityName,
50
+ updateField<Model.ManyHasManyOwningRelation>(fieldName, ({ field: { joiningTable: { eventLog, ...joiningTable }, ...field } }) => {
51
+ return {
52
+ ...field,
53
+ joiningTable: {
54
+ ...joiningTable,
55
+ eventLog: {
56
+ enabled,
57
+ },
58
+ },
59
+ }
60
+ }),
61
+ ),
62
+ )
63
+ }
64
+
65
+ describe() {
66
+ return {
67
+ message: `${this.data.enabled ? 'Enable' : 'Disable'} event log for ${this.data.entityName}.${this.data.fieldName}`,
68
+ }
69
+ }
70
+
71
+ static createModification(data: ToggleJunctionEventLogModificationData) {
72
+ return { modification: this.id, ...data }
73
+ }
74
+
75
+ static createDiff(originalSchema: Schema, updatedSchema: Schema) {
76
+ return updateRelations(originalSchema, updatedSchema, ({ originalRelation, updatedRelation, updatedEntity }) => {
77
+ if (
78
+ originalRelation.type === updatedRelation.type &&
79
+ isIt<Model.JoiningTableRelation>(updatedRelation, 'joiningTable') &&
80
+ isIt<Model.JoiningTableRelation>(originalRelation, 'joiningTable')
81
+ ) {
82
+ const newValue = updatedRelation.joiningTable.eventLog?.enabled ?? false
83
+ const oldValue = originalRelation.joiningTable.eventLog?.enabled ?? false
84
+ if (newValue !== oldValue) {
85
+ return ToggleJunctionEventLogModification.createModification({
86
+ entityName: updatedEntity.name,
87
+ fieldName: updatedRelation.name,
88
+ enabled: newValue,
89
+ })
90
+ }
91
+ }
92
+ return undefined
93
+ })
94
+
95
+ }
96
+ }
97
+
98
+ export interface ToggleJunctionEventLogModificationData {
99
+ entityName: string
100
+ fieldName: string
101
+ enabled: boolean
102
+ }
@@ -56,5 +56,5 @@ export const UpdateRelationOrderByModification: ModificationHandlerStatic<Update
56
56
  export interface UpdateRelationOrderByModificationData {
57
57
  entityName: string
58
58
  fieldName: string
59
- orderBy: Model.OrderBy[]
59
+ orderBy: readonly Model.OrderBy[]
60
60
  }
@@ -6,5 +6,6 @@ export * from './DisableOrphanRemovalModification'
6
6
  export * from './EnableOrphanRemovalModification'
7
7
  export * from './MakeRelationNotNullModification'
8
8
  export * from './MakeRelationNullableModification'
9
+ export * from './ToggleManyHasManyEventLogModification'
9
10
  export * from './UpdateRelationOnDeleteModification'
10
11
  export * from './UpdateRelationOrderByModification'
@@ -0,0 +1,21 @@
1
+ import { Model } from '@contember/schema'
2
+
3
+ type SomePartial<E, K extends keyof E> = Omit<E, K> & Partial<Pick<E, K>>
4
+
5
+ export type PartialManyHasManyRelation =
6
+ & Omit<Model.ManyHasManyOwningRelation, 'joiningTable'>
7
+ & {
8
+ joiningTable: SomePartial<Model.JoiningTable, 'eventLog'>
9
+ }
10
+
11
+ export const normalizeManyHasManyRelation = (rel: PartialManyHasManyRelation): Model.ManyHasManyOwningRelation => {
12
+ return {
13
+ ...rel,
14
+ joiningTable: {
15
+ eventLog: {
16
+ enabled: true,
17
+ },
18
+ ...rel.joiningTable,
19
+ },
20
+ }
21
+ }
@@ -36,6 +36,8 @@ export const createJunctionTableSql = (
36
36
  },
37
37
  },
38
38
  )
39
- createEventTrigger(builder, systemSchema, relation.joiningTable.tableName, primaryColumns)
40
- createEventTrxTrigger(builder, systemSchema, relation.joiningTable.tableName)
39
+ if (relation.joiningTable.eventLog.enabled) {
40
+ createEventTrigger(builder, systemSchema, relation.joiningTable.tableName, primaryColumns)
41
+ createEventTrxTrigger(builder, systemSchema, relation.joiningTable.tableName)
42
+ }
41
43
  }
@@ -1,4 +1,4 @@
1
- import { Model } from '@contember/schema'
1
+ import { Model, Writable } from '@contember/schema'
2
2
  import { MigrationBuilder } from '@contember/database-migrations'
3
3
  import { EntityUpdater } from './schemaUpdateUtils'
4
4
 
@@ -20,7 +20,7 @@ export const renameConstraintsSqlBuilder = (
20
20
 
21
21
  export const renameConstraintSchemaUpdater = (nameGenerator: NameGenerator): EntityUpdater => {
22
22
  return ({ entity }) => {
23
- const newConstraints: Model.UniqueConstraints = {}
23
+ const newConstraints: Writable<Model.UniqueConstraints> = {}
24
24
  for (const constraint of Object.values(entity.unique)) {
25
25
  const newName = nameGenerator(constraint)
26
26
  if (newName === null) {
@@ -1,4 +1,4 @@
1
- import { Acl, Model, Schema } from '@contember/schema'
1
+ import { Acl, Model, Schema, Writable } from '@contember/schema'
2
2
  import { SchemaUpdateError } from '../exceptions'
3
3
  import { isDefined } from '../../utils/isDefined'
4
4
  import { isInverseRelation, isOwningRelation, isRelation, PredicateDefinitionProcessor } from '@contember/schema-utils'
@@ -111,7 +111,7 @@ type EntityOperationHandler = {
111
111
  export const updateAclFieldPermissions =
112
112
  (updater: EntityAclFieldPermissionsUpdater): AclEntityPermissionsUpdater =>
113
113
  ({ entityPermissions, entityName }) => {
114
- const operations: Acl.EntityOperations = {}
114
+ const operations: Writable<Acl.EntityOperations> = {}
115
115
  const handlers: EntityOperationHandler = {
116
116
  create: value => updater(value, entityName, Acl.Operation.create),
117
117
  update: value => updater(value, entityName, Acl.Operation.update),