@contember/schema-migrations 1.1.0-alpha.2 → 1.1.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/MigrationDescriber.d.ts +3 -3
- package/dist/src/MigrationDescriber.d.ts.map +1 -1
- package/dist/src/MigrationDescriber.js +7 -4
- package/dist/src/MigrationDescriber.js.map +1 -1
- package/dist/src/SchemaDiffer.d.ts.map +1 -1
- package/dist/src/SchemaDiffer.js +5 -5
- package/dist/src/SchemaDiffer.js.map +1 -1
- package/dist/src/SchemaMigrator.d.ts.map +1 -1
- package/dist/src/SchemaMigrator.js +4 -1
- package/dist/src/SchemaMigrator.js.map +1 -1
- package/dist/src/modifications/ModificationHandler.d.ts +5 -1
- package/dist/src/modifications/ModificationHandler.d.ts.map +1 -1
- package/dist/src/modifications/ModificationHandlerFactory.d.ts +2 -2
- package/dist/src/modifications/ModificationHandlerFactory.d.ts.map +1 -1
- package/dist/src/modifications/ModificationHandlerFactory.js +3 -2
- package/dist/src/modifications/ModificationHandlerFactory.js.map +1 -1
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.d.ts.map +1 -1
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js +8 -5
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js.map +1 -1
- package/dist/src/modifications/entities/CreateEntityModification.d.ts.map +1 -1
- package/dist/src/modifications/entities/CreateEntityModification.js +4 -3
- package/dist/src/modifications/entities/CreateEntityModification.js.map +1 -1
- package/dist/src/modifications/entities/RemoveEntityModification.d.ts.map +1 -1
- package/dist/src/modifications/entities/RemoveEntityModification.js +7 -7
- package/dist/src/modifications/entities/RemoveEntityModification.js.map +1 -1
- package/dist/src/modifications/entities/UpdateEntityNameModification.d.ts.map +1 -1
- package/dist/src/modifications/entities/UpdateEntityNameModification.js +6 -6
- package/dist/src/modifications/entities/UpdateEntityNameModification.js.map +1 -1
- package/dist/src/modifications/fields/RemoveFieldModification.d.ts.map +1 -1
- package/dist/src/modifications/fields/RemoveFieldModification.js +3 -3
- package/dist/src/modifications/fields/RemoveFieldModification.js.map +1 -1
- package/dist/src/modifications/fields/UpdateFieldNameModification.d.ts.map +1 -1
- package/dist/src/modifications/fields/UpdateFieldNameModification.js +6 -6
- package/dist/src/modifications/fields/UpdateFieldNameModification.js.map +1 -1
- package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.d.ts +10 -0
- package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.d.ts.map +1 -0
- package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.js +84 -0
- package/dist/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.js.map +1 -0
- package/dist/src/modifications/relations/ConvertOneToManyRelationModification.d.ts.map +1 -1
- package/dist/src/modifications/relations/ConvertOneToManyRelationModification.js +3 -3
- package/dist/src/modifications/relations/ConvertOneToManyRelationModification.js.map +1 -1
- package/dist/src/modifications/relations/CreateRelationModification.d.ts.map +1 -1
- package/dist/src/modifications/relations/CreateRelationModification.js +6 -31
- package/dist/src/modifications/relations/CreateRelationModification.js.map +1 -1
- package/dist/src/modifications/relations/index.d.ts +1 -0
- package/dist/src/modifications/relations/index.d.ts.map +1 -1
- package/dist/src/modifications/relations/index.js +1 -0
- package/dist/src/modifications/relations/index.js.map +1 -1
- package/dist/src/modifications/utils/createJunctionTable.d.ts +4 -0
- package/dist/src/modifications/utils/createJunctionTable.d.ts.map +1 -0
- package/dist/src/modifications/utils/createJunctionTable.js +33 -0
- package/dist/src/modifications/utils/createJunctionTable.js.map +1 -0
- package/dist/src/modifications/utils/getPrimaryColumnType.d.ts +3 -0
- package/dist/src/modifications/utils/getPrimaryColumnType.d.ts.map +1 -0
- package/dist/src/modifications/utils/getPrimaryColumnType.js +9 -0
- package/dist/src/modifications/utils/getPrimaryColumnType.js.map +1 -0
- package/dist/src/modifications/utils/sqlUpdateUtils.d.ts +2 -2
- package/dist/src/modifications/utils/sqlUpdateUtils.d.ts.map +1 -1
- package/dist/src/modifications/utils/sqlUpdateUtils.js +4 -4
- package/dist/src/modifications/utils/sqlUpdateUtils.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.d.ts +2 -0
- package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.js +92 -0
- package/dist/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.js.map +1 -0
- package/dist/tests/cases/integration/updateColumnDefinition.test.js +1 -1
- package/dist/tests/cases/integration/updateColumnDefinition.test.js.map +1 -1
- package/dist/tests/src/tests.js +1 -1
- package/dist/tests/src/tests.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/MigrationDescriber.ts +16 -8
- package/src/SchemaDiffer.ts +7 -2
- package/src/SchemaMigrator.ts +4 -1
- package/src/modifications/ModificationHandler.ts +7 -1
- package/src/modifications/ModificationHandlerFactory.ts +5 -3
- package/src/modifications/columns/UpdateColumnDefinitionModification.ts +8 -6
- package/src/modifications/entities/CreateEntityModification.ts +8 -4
- package/src/modifications/entities/RemoveEntityModification.ts +8 -7
- package/src/modifications/entities/UpdateEntityNameModification.ts +6 -6
- package/src/modifications/fields/RemoveFieldModification.ts +4 -3
- package/src/modifications/fields/UpdateFieldNameModification.ts +6 -6
- package/src/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.ts +109 -0
- package/src/modifications/relations/ConvertOneToManyRelationModification.ts +7 -3
- package/src/modifications/relations/CreateRelationModification.ts +10 -36
- package/src/modifications/relations/index.ts +1 -0
- package/src/modifications/utils/createJunctionTable.ts +41 -0
- package/src/modifications/utils/getPrimaryColumnType.ts +6 -0
- package/src/modifications/utils/sqlUpdateUtils.ts +4 -4
- package/tests/cases/integration/convertOneHasManyToManyHasManyRelation.test.ts +81 -0
- package/tests/cases/integration/updateColumnDefinition.test.ts +1 -1
- package/tests/src/tests.ts +1 -1
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { MigrationBuilder } from '@contember/database-migrations'
|
|
2
2
|
import { Model, Schema } from '@contember/schema'
|
|
3
3
|
import { SchemaUpdater, updateModel } from '../utils/schemaUpdateUtils'
|
|
4
|
-
import { ModificationHandlerStatic } from '../ModificationHandler'
|
|
4
|
+
import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
5
5
|
import { createEventTrigger, createEventTrxTrigger } from '../utils/sqlUpdateUtils'
|
|
6
6
|
|
|
7
7
|
export const CreateEntityModification: ModificationHandlerStatic<CreateEntityModificationData> = class {
|
|
8
8
|
static id = 'createEntity'
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly data: CreateEntityModificationData,
|
|
11
|
+
private readonly schema: Schema,
|
|
12
|
+
private readonly options: ModificationHandlerOptions,
|
|
13
|
+
) {}
|
|
10
14
|
|
|
11
15
|
public createSql(builder: MigrationBuilder): void {
|
|
12
16
|
const entity = this.data.entity
|
|
@@ -23,8 +27,8 @@ export const CreateEntityModification: ModificationHandlerStatic<CreateEntityMod
|
|
|
23
27
|
notNull: true,
|
|
24
28
|
},
|
|
25
29
|
})
|
|
26
|
-
createEventTrigger(builder, entity.tableName, [entity.primaryColumn])
|
|
27
|
-
createEventTrxTrigger(builder, entity.tableName)
|
|
30
|
+
createEventTrigger(builder, this.options.systemSchema, entity.tableName, [entity.primaryColumn])
|
|
31
|
+
createEventTrxTrigger(builder, this.options.systemSchema, entity.tableName)
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
public getSchemaUpdater(): SchemaUpdater {
|
|
@@ -11,17 +11,18 @@ import {
|
|
|
11
11
|
updateModel,
|
|
12
12
|
updateSchema,
|
|
13
13
|
} from '../utils/schemaUpdateUtils'
|
|
14
|
-
import { ModificationHandlerStatic } from '../ModificationHandler'
|
|
14
|
+
import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
15
15
|
import { VERSION_ACL_PATCH, VERSION_REMOVE_REFERENCING_RELATIONS } from '../ModificationVersions'
|
|
16
16
|
import { isRelation, PredicateDefinitionProcessor } from '@contember/schema-utils'
|
|
17
17
|
import { RemoveFieldModification } from '../fields'
|
|
18
18
|
|
|
19
19
|
export const RemoveEntityModification: ModificationHandlerStatic<RemoveEntityModificationData> = class {
|
|
20
20
|
static id = 'removeEntity'
|
|
21
|
+
|
|
21
22
|
constructor(
|
|
22
23
|
private readonly data: RemoveEntityModificationData,
|
|
23
24
|
private readonly schema: Schema,
|
|
24
|
-
private readonly
|
|
25
|
+
private readonly options: ModificationHandlerOptions,
|
|
25
26
|
) {}
|
|
26
27
|
|
|
27
28
|
public createSql(builder: MigrationBuilder): void {
|
|
@@ -30,9 +31,9 @@ export const RemoveEntityModification: ModificationHandlerStatic<RemoveEntityMod
|
|
|
30
31
|
builder.dropView(entity.tableName)
|
|
31
32
|
return
|
|
32
33
|
}
|
|
33
|
-
if (this.formatVersion >= VERSION_REMOVE_REFERENCING_RELATIONS) {
|
|
34
|
+
if (this.options.formatVersion >= VERSION_REMOVE_REFERENCING_RELATIONS) {
|
|
34
35
|
this.getFieldsToRemove(this.schema).forEach(([entityName, fieldName]) => {
|
|
35
|
-
(new RemoveFieldModification({ entityName, fieldName }, this.schema, this.
|
|
36
|
+
(new RemoveFieldModification({ entityName, fieldName }, this.schema, this.options)).createSql(builder)
|
|
36
37
|
})
|
|
37
38
|
}
|
|
38
39
|
builder.dropTable(entity.tableName)
|
|
@@ -40,7 +41,7 @@ export const RemoveEntityModification: ModificationHandlerStatic<RemoveEntityMod
|
|
|
40
41
|
|
|
41
42
|
public getSchemaUpdater(): SchemaUpdater {
|
|
42
43
|
return updateSchema(
|
|
43
|
-
this.formatVersion >= VERSION_ACL_PATCH
|
|
44
|
+
this.options.formatVersion >= VERSION_ACL_PATCH
|
|
44
45
|
? updateAcl(
|
|
45
46
|
updateAclEveryRole(
|
|
46
47
|
({ role }) => ({
|
|
@@ -72,11 +73,11 @@ export const RemoveEntityModification: ModificationHandlerStatic<RemoveEntityMod
|
|
|
72
73
|
),
|
|
73
74
|
)
|
|
74
75
|
: undefined,
|
|
75
|
-
this.formatVersion >= VERSION_REMOVE_REFERENCING_RELATIONS
|
|
76
|
+
this.options.formatVersion >= VERSION_REMOVE_REFERENCING_RELATIONS
|
|
76
77
|
? ({ schema }) => {
|
|
77
78
|
const fieldsToRemove = this.getFieldsToRemove(schema)
|
|
78
79
|
return fieldsToRemove.reduce(
|
|
79
|
-
(schema, [entity, field]) => removeField(entity, field, this.formatVersion)({ schema }),
|
|
80
|
+
(schema, [entity, field]) => removeField(entity, field, this.options.formatVersion)({ schema }),
|
|
80
81
|
schema,
|
|
81
82
|
)
|
|
82
83
|
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
updateModel,
|
|
12
12
|
updateSchema,
|
|
13
13
|
} from '../utils/schemaUpdateUtils'
|
|
14
|
-
import { ModificationHandler, ModificationHandlerStatic } from '../ModificationHandler'
|
|
14
|
+
import { ModificationHandler, ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
15
15
|
import { isIt } from '../../utils/isIt'
|
|
16
16
|
import { VERSION_ACL_PATCH, VERSION_UPDATE_CONSTRAINT_NAME } from '../ModificationVersions'
|
|
17
17
|
import { NamingHelper } from '@contember/schema-utils'
|
|
@@ -27,20 +27,20 @@ export const UpdateEntityNameModification: ModificationHandlerStatic<UpdateEntit
|
|
|
27
27
|
constructor(
|
|
28
28
|
private readonly data: UpdateEntityNameModificationData,
|
|
29
29
|
private readonly schema: Schema,
|
|
30
|
-
private readonly
|
|
30
|
+
private readonly options: ModificationHandlerOptions,
|
|
31
31
|
) {
|
|
32
32
|
this.subModification = data.tableName
|
|
33
33
|
? new UpdateEntityTableNameModification(
|
|
34
34
|
{ entityName: data.entityName, tableName: data.tableName },
|
|
35
35
|
schema,
|
|
36
|
-
this.
|
|
36
|
+
this.options,
|
|
37
37
|
)
|
|
38
38
|
: new NoopModification()
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
public createSql(builder: MigrationBuilder): void {
|
|
42
42
|
const entity = this.schema.model.entities[this.data.entityName]
|
|
43
|
-
if (!entity.view && this.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME) {
|
|
43
|
+
if (!entity.view && this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME) {
|
|
44
44
|
renameConstraintsSqlBuilder(builder, entity, this.getNewConstraintName.bind(this))
|
|
45
45
|
}
|
|
46
46
|
this.subModification.createSql(builder)
|
|
@@ -58,7 +58,7 @@ export const UpdateEntityNameModification: ModificationHandlerStatic<UpdateEntit
|
|
|
58
58
|
return field
|
|
59
59
|
}),
|
|
60
60
|
),
|
|
61
|
-
this.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
61
|
+
this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
62
62
|
? updateEntity(this.data.entityName, renameConstraintSchemaUpdater(this.getNewConstraintName.bind(this)))
|
|
63
63
|
: undefined,
|
|
64
64
|
({ model }) => {
|
|
@@ -76,7 +76,7 @@ export const UpdateEntityNameModification: ModificationHandlerStatic<UpdateEntit
|
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
78
|
),
|
|
79
|
-
this.formatVersion >= VERSION_ACL_PATCH
|
|
79
|
+
this.options.formatVersion >= VERSION_ACL_PATCH
|
|
80
80
|
? updateAcl(
|
|
81
81
|
updateAclEveryRole(
|
|
82
82
|
({ role }) => ({
|
|
@@ -2,15 +2,16 @@ import { acceptFieldVisitor, isInverseRelation, isRelation, NamingHelper } from
|
|
|
2
2
|
import { MigrationBuilder } from '@contember/database-migrations'
|
|
3
3
|
import { Schema } from '@contember/schema'
|
|
4
4
|
import { removeField, SchemaUpdater } from '../utils/schemaUpdateUtils'
|
|
5
|
-
import { ModificationHandlerStatic } from '../ModificationHandler'
|
|
5
|
+
import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
6
6
|
import { isDefined } from '../../utils/isDefined'
|
|
7
7
|
|
|
8
8
|
export const RemoveFieldModification: ModificationHandlerStatic<RemoveFieldModificationData> = class {
|
|
9
9
|
static id = 'removeField'
|
|
10
|
+
|
|
10
11
|
constructor(
|
|
11
12
|
private readonly data: RemoveFieldModificationData,
|
|
12
13
|
private readonly schema: Schema,
|
|
13
|
-
private readonly
|
|
14
|
+
private readonly options: ModificationHandlerOptions,
|
|
14
15
|
) {}
|
|
15
16
|
|
|
16
17
|
public createSql(builder: MigrationBuilder): void {
|
|
@@ -39,7 +40,7 @@ export const RemoveFieldModification: ModificationHandlerStatic<RemoveFieldModif
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
public getSchemaUpdater(): SchemaUpdater {
|
|
42
|
-
return removeField(this.data.entityName, this.data.fieldName, this.formatVersion)
|
|
43
|
+
return removeField(this.data.entityName, this.data.fieldName, this.options.formatVersion)
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
describe() {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
updateModel,
|
|
14
14
|
updateSchema,
|
|
15
15
|
} from '../utils/schemaUpdateUtils'
|
|
16
|
-
import { ModificationHandlerStatic } from '../ModificationHandler'
|
|
16
|
+
import { 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'
|
|
@@ -24,7 +24,7 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
|
|
|
24
24
|
constructor(
|
|
25
25
|
private readonly data: UpdateFieldNameModificationData,
|
|
26
26
|
private readonly schema: Schema,
|
|
27
|
-
private readonly
|
|
27
|
+
private readonly options: ModificationHandlerOptions,
|
|
28
28
|
) {}
|
|
29
29
|
|
|
30
30
|
public createSql(builder: MigrationBuilder): void {
|
|
@@ -32,18 +32,18 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
|
|
|
32
32
|
if (entity.view) {
|
|
33
33
|
return
|
|
34
34
|
}
|
|
35
|
-
if (this.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME) {
|
|
35
|
+
if (this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME) {
|
|
36
36
|
renameConstraintsSqlBuilder(builder, entity, this.getNewConstraintName.bind(this))
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
public getSchemaUpdater(): SchemaUpdater {
|
|
41
41
|
const updateConstraintName =
|
|
42
|
-
this.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
42
|
+
this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
43
43
|
? updateEntity(this.data.entityName, renameConstraintSchemaUpdater(this.getNewConstraintName.bind(this)))
|
|
44
44
|
: undefined
|
|
45
45
|
const updateConstraintFields =
|
|
46
|
-
this.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
46
|
+
this.options.formatVersion >= VERSION_UPDATE_CONSTRAINT_NAME
|
|
47
47
|
? updateEntity(this.data.entityName, ({ entity }) => {
|
|
48
48
|
return {
|
|
49
49
|
...entity,
|
|
@@ -112,7 +112,7 @@ export const UpdateFieldNameModification: ModificationHandlerStatic<UpdateFieldN
|
|
|
112
112
|
}
|
|
113
113
|
})
|
|
114
114
|
const updateAclOp =
|
|
115
|
-
this.formatVersion >= VERSION_ACL_PATCH
|
|
115
|
+
this.options.formatVersion >= VERSION_ACL_PATCH
|
|
116
116
|
? updateAcl(
|
|
117
117
|
updateAclEveryRole(
|
|
118
118
|
updateAclEveryEntity(
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
+
import { Model, Schema } from '@contember/schema'
|
|
3
|
+
import { addField, SchemaUpdater, updateEntity, updateModel, updateSchema } from '../utils/schemaUpdateUtils'
|
|
4
|
+
import { ModificationHandler, ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
5
|
+
import { isInverseRelation, isOwningRelation } from '@contember/schema-utils'
|
|
6
|
+
import { updateRelations } from '../utils/diffUtils'
|
|
7
|
+
import { UpdateFieldNameModification } from '../fields'
|
|
8
|
+
import { createJunctionTableSql } from '../utils/createJunctionTable'
|
|
9
|
+
import { wrapIdentifier } from '@contember/database'
|
|
10
|
+
|
|
11
|
+
export const ConvertOneHasManyToManyHasManyRelationModification: ModificationHandlerStatic<ConvertOneHasManyToManyHasManyRelationModificationData> = class {
|
|
12
|
+
static id = 'convertOneHasManyToManyHasManyRelation'
|
|
13
|
+
private subModification: ModificationHandler<any>
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
private readonly data: ConvertOneHasManyToManyHasManyRelationModificationData,
|
|
17
|
+
private readonly schema: Schema,
|
|
18
|
+
private readonly options: ModificationHandlerOptions,
|
|
19
|
+
) {
|
|
20
|
+
this.subModification = new UpdateFieldNameModification(
|
|
21
|
+
{
|
|
22
|
+
entityName: this.data.entityName,
|
|
23
|
+
fieldName: this.data.fieldName,
|
|
24
|
+
newFieldName: this.data.owningSide.name,
|
|
25
|
+
},
|
|
26
|
+
schema,
|
|
27
|
+
this.options,
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public createSql(builder: MigrationBuilder): void {
|
|
32
|
+
const targetEntity = this.schema.model.entities[this.data.owningSide.target]
|
|
33
|
+
const { relation: oldRelation } = this.getRelation()
|
|
34
|
+
const entity = this.schema.model.entities[this.data.entityName]
|
|
35
|
+
|
|
36
|
+
createJunctionTableSql(builder, this.options.systemSchema, entity, targetEntity, this.data.owningSide)
|
|
37
|
+
const joiningTable = this.data.owningSide.joiningTable
|
|
38
|
+
builder.sql(`
|
|
39
|
+
INSERT INTO ${wrapIdentifier(joiningTable.tableName)} (
|
|
40
|
+
${wrapIdentifier(joiningTable.joiningColumn.columnName)},
|
|
41
|
+
${wrapIdentifier(joiningTable.inverseJoiningColumn.columnName)}
|
|
42
|
+
)
|
|
43
|
+
SELECT ${wrapIdentifier(entity.primaryColumn)}, ${wrapIdentifier(oldRelation.joiningColumn.columnName)}
|
|
44
|
+
FROM ${wrapIdentifier(entity.tableName)}
|
|
45
|
+
WHERE ${wrapIdentifier(oldRelation.joiningColumn.columnName)} IS NOT NULL`)
|
|
46
|
+
|
|
47
|
+
builder.dropColumn(entity.tableName, oldRelation.joiningColumn.columnName)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public getSchemaUpdater(): SchemaUpdater {
|
|
51
|
+
const { entityName } = this.data
|
|
52
|
+
return updateSchema(
|
|
53
|
+
this.subModification.getSchemaUpdater(),
|
|
54
|
+
updateModel(updateEntity(entityName, addField(this.data.owningSide))),
|
|
55
|
+
this.data.inverseSide ? updateModel(updateEntity(this.data.owningSide.target, addField(this.data.inverseSide))) : undefined,
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe() {
|
|
60
|
+
return {
|
|
61
|
+
message: `Converts OneHasMany relation to ManyHasMany on ${this.data.entityName}.${this.data.fieldName}`,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static createModification(data: ConvertOneHasManyToManyHasManyRelationModificationData) {
|
|
66
|
+
return { modification: this.id, ...data }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static createDiff(originalSchema: Schema, updatedSchema: Schema) {
|
|
70
|
+
return updateRelations(originalSchema, updatedSchema, ({ originalRelation, updatedRelation, updatedEntity }) => {
|
|
71
|
+
if (
|
|
72
|
+
isInverseRelation(originalRelation) &&
|
|
73
|
+
isInverseRelation(updatedRelation) &&
|
|
74
|
+
originalRelation.type === Model.RelationType.OneHasMany &&
|
|
75
|
+
updatedRelation.type === Model.RelationType.ManyHasMany
|
|
76
|
+
) {
|
|
77
|
+
const owningOldName = originalRelation.ownedBy
|
|
78
|
+
const owningNewName = updatedRelation.ownedBy
|
|
79
|
+
const owningSide = updatedSchema.model.entities[updatedRelation.target].fields[owningNewName]
|
|
80
|
+
if (owningSide.type !== Model.RelationType.ManyHasMany || !isOwningRelation(owningSide)) {
|
|
81
|
+
throw new Error()
|
|
82
|
+
}
|
|
83
|
+
return ConvertOneHasManyToManyHasManyRelationModification.createModification({
|
|
84
|
+
entityName: updatedRelation.target,
|
|
85
|
+
fieldName: owningOldName,
|
|
86
|
+
owningSide,
|
|
87
|
+
inverseSide: updatedRelation,
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
return undefined
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private getRelation(): { entity: Model.Entity; relation: Model.ManyHasOneRelation } {
|
|
95
|
+
const entity = this.schema.model.entities[this.data.entityName]
|
|
96
|
+
const relation = entity.fields[this.data.fieldName]
|
|
97
|
+
if (relation.type !== Model.RelationType.ManyHasOne) {
|
|
98
|
+
throw new Error()
|
|
99
|
+
}
|
|
100
|
+
return { entity, relation }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface ConvertOneHasManyToManyHasManyRelationModificationData {
|
|
105
|
+
entityName: string
|
|
106
|
+
fieldName: string
|
|
107
|
+
owningSide: Model.ManyHasManyOwningRelation
|
|
108
|
+
inverseSide?: Model.ManyHasManyInverseRelation
|
|
109
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MigrationBuilder } from '@contember/database-migrations'
|
|
2
2
|
import { Model, Schema } from '@contember/schema'
|
|
3
3
|
import { SchemaUpdater, updateEntity, updateField, updateModel, updateSchema } from '../utils/schemaUpdateUtils'
|
|
4
|
-
import { ModificationHandler, ModificationHandlerStatic } from '../ModificationHandler'
|
|
4
|
+
import { ModificationHandler, ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
5
5
|
import { isOwningRelation, NamingHelper } from '@contember/schema-utils'
|
|
6
6
|
import { updateRelations } from '../utils/diffUtils'
|
|
7
7
|
import { UpdateFieldNameModification } from '../fields'
|
|
@@ -11,7 +11,11 @@ export const ConvertOneToManyRelationModification: ModificationHandlerStatic<Con
|
|
|
11
11
|
static id = 'convertOneToManyRelation'
|
|
12
12
|
private subModification: ModificationHandler<any>
|
|
13
13
|
|
|
14
|
-
constructor(
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly data: ConvertOneToManyRelationModificationData,
|
|
16
|
+
private readonly schema: Schema,
|
|
17
|
+
private readonly options: ModificationHandlerOptions,
|
|
18
|
+
) {
|
|
15
19
|
const { relation } = this.getRelation()
|
|
16
20
|
this.subModification = data.newInverseSideFieldName && relation.inversedBy ?
|
|
17
21
|
new UpdateFieldNameModification(
|
|
@@ -21,7 +25,7 @@ export const ConvertOneToManyRelationModification: ModificationHandlerStatic<Con
|
|
|
21
25
|
newFieldName: data.newInverseSideFieldName,
|
|
22
26
|
},
|
|
23
27
|
schema,
|
|
24
|
-
|
|
28
|
+
this.options,
|
|
25
29
|
)
|
|
26
30
|
: new NoopModification()
|
|
27
31
|
}
|
|
@@ -8,20 +8,21 @@ import {
|
|
|
8
8
|
} from '@contember/schema-utils'
|
|
9
9
|
import { MigrationBuilder } from '@contember/database-migrations'
|
|
10
10
|
import { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils'
|
|
11
|
-
import { ModificationHandlerStatic } from '../ModificationHandler'
|
|
12
|
-
import { createEventTrigger, createEventTrxTrigger } from '../utils/sqlUpdateUtils'
|
|
11
|
+
import { ModificationHandlerOptions, ModificationHandlerStatic } from '../ModificationHandler'
|
|
13
12
|
import { isIt } from '../../utils/isIt'
|
|
14
13
|
import { createFields } from '../utils/diffUtils'
|
|
14
|
+
import { getPrimaryColumnType } from '../utils/getPrimaryColumnType'
|
|
15
|
+
import { createJunctionTableSql } from '../utils/createJunctionTable'
|
|
15
16
|
|
|
16
|
-
const getPrimaryType = (entity: Model.Entity): string => {
|
|
17
|
-
const column = entity.fields[entity.primary] as Model.AnyColumn
|
|
18
|
-
return column.columnType
|
|
19
|
-
}
|
|
20
17
|
|
|
21
18
|
export const CreateRelationModification: ModificationHandlerStatic<CreateRelationModificationData> = class {
|
|
22
19
|
static id = 'createRelation'
|
|
23
20
|
|
|
24
|
-
constructor(
|
|
21
|
+
constructor(
|
|
22
|
+
private readonly data: CreateRelationModificationData,
|
|
23
|
+
private readonly schema: Schema,
|
|
24
|
+
private readonly options: ModificationHandlerOptions,
|
|
25
|
+
) {}
|
|
25
26
|
|
|
26
27
|
public createSql(builder: MigrationBuilder): void {
|
|
27
28
|
const entity = this.schema.model.entities[this.data.entityName]
|
|
@@ -32,7 +33,7 @@ export const CreateRelationModification: ModificationHandlerStatic<CreateRelatio
|
|
|
32
33
|
const createOwningSide = (relation: Model.OneHasOneOwningRelation | Model.ManyHasOneRelation) => {
|
|
33
34
|
builder.addColumn(entity.tableName, {
|
|
34
35
|
[relation.joiningColumn.columnName]: {
|
|
35
|
-
type:
|
|
36
|
+
type: getPrimaryColumnType(targetEntity),
|
|
36
37
|
notNull: !relation.nullable,
|
|
37
38
|
},
|
|
38
39
|
})
|
|
@@ -65,34 +66,7 @@ export const CreateRelationModification: ModificationHandlerStatic<CreateRelatio
|
|
|
65
66
|
},
|
|
66
67
|
visitOneHasOneInverse: () => {},
|
|
67
68
|
visitManyHasManyOwning: ({}, relation, {}, _) => {
|
|
68
|
-
|
|
69
|
-
relation.joiningTable.joiningColumn.columnName,
|
|
70
|
-
relation.joiningTable.inverseJoiningColumn.columnName,
|
|
71
|
-
]
|
|
72
|
-
builder.createTable(
|
|
73
|
-
relation.joiningTable.tableName,
|
|
74
|
-
{
|
|
75
|
-
[relation.joiningTable.joiningColumn.columnName]: {
|
|
76
|
-
type: getPrimaryType(entity),
|
|
77
|
-
notNull: true,
|
|
78
|
-
references: `"${entity.tableName}"("${entity.primaryColumn}")`,
|
|
79
|
-
onDelete: 'CASCADE',
|
|
80
|
-
},
|
|
81
|
-
[relation.joiningTable.inverseJoiningColumn.columnName]: {
|
|
82
|
-
type: getPrimaryType(targetEntity),
|
|
83
|
-
notNull: true,
|
|
84
|
-
references: `"${targetEntity.tableName}"("${targetEntity.primaryColumn}")`,
|
|
85
|
-
onDelete: 'CASCADE',
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
constraints: {
|
|
90
|
-
primaryKey: primaryColumns,
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
)
|
|
94
|
-
createEventTrigger(builder, relation.joiningTable.tableName, primaryColumns)
|
|
95
|
-
createEventTrxTrigger(builder, relation.joiningTable.tableName)
|
|
69
|
+
createJunctionTableSql(builder, this.options.systemSchema, entity, targetEntity, relation)
|
|
96
70
|
},
|
|
97
71
|
visitManyHasManyInverse: () => {},
|
|
98
72
|
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createEventTrigger, createEventTrxTrigger } from './sqlUpdateUtils'
|
|
2
|
+
import { MigrationBuilder } from '@contember/database-migrations'
|
|
3
|
+
import { Model } from '@contember/schema'
|
|
4
|
+
import { getPrimaryColumnType } from './getPrimaryColumnType'
|
|
5
|
+
|
|
6
|
+
export const createJunctionTableSql = (
|
|
7
|
+
builder: MigrationBuilder,
|
|
8
|
+
systemSchema: string,
|
|
9
|
+
entity: Model.Entity,
|
|
10
|
+
targetEntity: Model.Entity,
|
|
11
|
+
relation: Model.ManyHasManyOwningRelation,
|
|
12
|
+
) => {
|
|
13
|
+
const primaryColumns = [
|
|
14
|
+
relation.joiningTable.joiningColumn.columnName,
|
|
15
|
+
relation.joiningTable.inverseJoiningColumn.columnName,
|
|
16
|
+
]
|
|
17
|
+
builder.createTable(
|
|
18
|
+
relation.joiningTable.tableName,
|
|
19
|
+
{
|
|
20
|
+
[relation.joiningTable.joiningColumn.columnName]: {
|
|
21
|
+
type: getPrimaryColumnType(entity),
|
|
22
|
+
notNull: true,
|
|
23
|
+
references: `"${entity.tableName}"("${entity.primaryColumn}")`,
|
|
24
|
+
onDelete: 'CASCADE',
|
|
25
|
+
},
|
|
26
|
+
[relation.joiningTable.inverseJoiningColumn.columnName]: {
|
|
27
|
+
type: getPrimaryColumnType(targetEntity),
|
|
28
|
+
notNull: true,
|
|
29
|
+
references: `"${targetEntity.tableName}"("${targetEntity.primaryColumn}")`,
|
|
30
|
+
onDelete: 'CASCADE',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
constraints: {
|
|
35
|
+
primaryKey: primaryColumns,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
)
|
|
39
|
+
createEventTrigger(builder, systemSchema, relation.joiningTable.tableName, primaryColumns)
|
|
40
|
+
createEventTrxTrigger(builder, systemSchema, relation.joiningTable.tableName)
|
|
41
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { MigrationBuilder, Name } from '@contember/database-migrations'
|
|
2
2
|
|
|
3
|
-
export const createEventTrigger = (builder: MigrationBuilder, tableName: Name, primaryColumns: string[]) => {
|
|
3
|
+
export const createEventTrigger = (builder: MigrationBuilder, systemSchema: string, tableName: Name, primaryColumns: string[]) => {
|
|
4
4
|
builder.createTrigger(tableName, 'log_event', {
|
|
5
5
|
when: 'AFTER',
|
|
6
6
|
operation: ['INSERT', 'UPDATE', 'DELETE'],
|
|
7
7
|
level: 'ROW',
|
|
8
8
|
function: {
|
|
9
|
-
schema:
|
|
9
|
+
schema: systemSchema,
|
|
10
10
|
name: 'trigger_event',
|
|
11
11
|
},
|
|
12
12
|
functionParams: primaryColumns,
|
|
13
13
|
})
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const createEventTrxTrigger = (builder: MigrationBuilder, tableName: Name) => {
|
|
16
|
+
export const createEventTrxTrigger = (builder: MigrationBuilder, systemSchema: string, tableName: Name) => {
|
|
17
17
|
builder.createTrigger(tableName, 'log_event_trx', {
|
|
18
18
|
when: 'AFTER',
|
|
19
19
|
operation: ['INSERT', 'UPDATE', 'DELETE'],
|
|
@@ -22,7 +22,7 @@ export const createEventTrxTrigger = (builder: MigrationBuilder, tableName: Name
|
|
|
22
22
|
deferrable: true,
|
|
23
23
|
deferred: true,
|
|
24
24
|
function: {
|
|
25
|
-
schema:
|
|
25
|
+
schema: systemSchema,
|
|
26
26
|
name: 'trigger_event_commit',
|
|
27
27
|
},
|
|
28
28
|
})
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { testMigrations } from '../../src/tests'
|
|
2
|
+
import { SQL } from '../../src/tags'
|
|
3
|
+
import { SchemaDefinition as def } from '@contember/schema-definition'
|
|
4
|
+
|
|
5
|
+
namespace ConvertOHMToMHMSchemaOrig {
|
|
6
|
+
export class Article {
|
|
7
|
+
title = def.stringColumn()
|
|
8
|
+
category = def.manyHasOne(Category, 'articles')
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Category {
|
|
12
|
+
articles = def.oneHasMany(Article, 'category')
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
namespace ConvertOHMToMHMSchemaOrigUpdated {
|
|
17
|
+
export class Article {
|
|
18
|
+
title = def.stringColumn()
|
|
19
|
+
categories = def.manyHasMany(Category, 'articles')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Category {
|
|
23
|
+
articles = def.manyHasManyInverse(Article, 'categories')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
testMigrations('convert one has many to many has many', {
|
|
29
|
+
originalSchema: def.createModel(ConvertOHMToMHMSchemaOrig),
|
|
30
|
+
updatedSchema: def.createModel(ConvertOHMToMHMSchemaOrigUpdated),
|
|
31
|
+
diff: [
|
|
32
|
+
{
|
|
33
|
+
modification: 'convertOneHasManyToManyHasManyRelation',
|
|
34
|
+
entityName: 'Article',
|
|
35
|
+
fieldName: 'category',
|
|
36
|
+
owningSide: {
|
|
37
|
+
type: 'ManyHasMany',
|
|
38
|
+
name: 'categories',
|
|
39
|
+
inversedBy: 'articles',
|
|
40
|
+
target: 'Category',
|
|
41
|
+
joiningTable: {
|
|
42
|
+
tableName: 'article_categories',
|
|
43
|
+
joiningColumn: {
|
|
44
|
+
columnName: 'article_id',
|
|
45
|
+
onDelete: 'cascade',
|
|
46
|
+
},
|
|
47
|
+
inverseJoiningColumn: {
|
|
48
|
+
columnName: 'category_id',
|
|
49
|
+
onDelete: 'cascade',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
inverseSide: {
|
|
54
|
+
name: 'articles',
|
|
55
|
+
ownedBy: 'categories',
|
|
56
|
+
target: 'Article',
|
|
57
|
+
type: 'ManyHasMany',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
sql: SQL`
|
|
62
|
+
CREATE TABLE "article_categories" (
|
|
63
|
+
"article_id" uuid NOT NULL REFERENCES "article"("id") ON DELETE CASCADE,
|
|
64
|
+
"category_id" uuid NOT NULL REFERENCES "category"("id") ON DELETE CASCADE, CONSTRAINT
|
|
65
|
+
"article_categories_pkey" PRIMARY KEY ("article_id", "category_id")
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
CREATE TRIGGER "log_event" AFTER INSERT OR UPDATE OR DELETE
|
|
69
|
+
ON "article_categories" FOR EACH ROW
|
|
70
|
+
EXECUTE PROCEDURE "system"."trigger_event"($pga$article_id$pga$, $pga$category_id$pga$);
|
|
71
|
+
|
|
72
|
+
CREATE CONSTRAINT TRIGGER "log_event_trx" AFTER INSERT OR UPDATE OR DELETE
|
|
73
|
+
ON "article_categories" DEFERRABLE INITIALLY DEFERRED FOR EACH ROW
|
|
74
|
+
EXECUTE PROCEDURE "system"."trigger_event_commit"();
|
|
75
|
+
|
|
76
|
+
INSERT INTO "article_categories" ( "article_id", "category_id" )
|
|
77
|
+
SELECT "id", "category_id" FROM "article" WHERE "category_id" IS NOT NULL;
|
|
78
|
+
|
|
79
|
+
ALTER TABLE "article" DROP "category_id";
|
|
80
|
+
`,
|
|
81
|
+
})
|
package/tests/src/tests.ts
CHANGED
|
@@ -69,7 +69,7 @@ export function testGenerateSql(originalSchema: Model.Schema, diff: Migration.Mo
|
|
|
69
69
|
let schema = { model: originalSchema, acl: emptyAcl, validation: {} }
|
|
70
70
|
const builder = createMigrationBuilder()
|
|
71
71
|
for (let { modification, ...data } of diff) {
|
|
72
|
-
const modificationHandler = modificationFactory.create(modification, data, schema, VERSION_LATEST)
|
|
72
|
+
const modificationHandler = modificationFactory.create(modification, data, schema, { formatVersion: VERSION_LATEST, systemSchema: 'system' })
|
|
73
73
|
modificationHandler.createSql(builder)
|
|
74
74
|
schema = modificationHandler.getSchemaUpdater()({ schema })
|
|
75
75
|
}
|