@contember/schema-migrations 1.3.0-alpha.8 → 1.3.0-beta.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.
- package/dist/src/SchemaDiffer.d.ts +1 -1
- package/dist/src/SchemaDiffer.d.ts.map +1 -1
- package/dist/src/SchemaDiffer.js +8 -1
- package/dist/src/SchemaDiffer.js.map +1 -1
- package/dist/src/modifications/ModificationHandler.d.ts +1 -1
- package/dist/src/modifications/ModificationHandler.d.ts.map +1 -1
- package/dist/src/modifications/ModificationHandlerFactory.js +1 -2
- package/dist/src/modifications/ModificationHandlerFactory.js.map +1 -1
- package/dist/src/modifications/columns/CreateColumnModification.d.ts +2 -2
- package/dist/src/modifications/columns/CreateColumnModification.d.ts.map +1 -1
- package/dist/src/modifications/columns/CreateColumnModification.js +14 -24
- package/dist/src/modifications/columns/CreateColumnModification.js.map +1 -1
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.d.ts +5 -3
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.d.ts.map +1 -1
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js +16 -1
- package/dist/src/modifications/columns/UpdateColumnDefinitionModification.js.map +1 -1
- package/dist/src/modifications/columns/columnUtils.d.ts +14 -0
- package/dist/src/modifications/columns/columnUtils.d.ts.map +1 -0
- package/dist/src/modifications/columns/columnUtils.js +29 -0
- package/dist/src/modifications/columns/columnUtils.js.map +1 -0
- package/dist/src/modifications/constraints/RemoveUniqueConstraintModification.d.ts +1 -1
- package/dist/src/modifications/constraints/RemoveUniqueConstraintModification.d.ts.map +1 -1
- package/dist/src/modifications/indexes/RemoveIndexModification.d.ts +1 -1
- package/dist/src/modifications/indexes/RemoveIndexModification.d.ts.map +1 -1
- package/dist/src/modifications/relations/CreateRelationModification.d.ts +1 -1
- package/dist/src/modifications/relations/CreateRelationModification.d.ts.map +1 -1
- package/dist/src/modifications/relations/normalization.d.ts +2 -2
- package/dist/src/modifications/relations/normalization.d.ts.map +1 -1
- package/dist/src/modifications/settings/UpdateSettingsModification.d.ts +1 -1
- package/dist/src/modifications/settings/UpdateSettingsModification.d.ts.map +1 -1
- package/dist/src/modifications/upgrade/RemoveIndexNamesModification.d.ts +1 -1
- package/dist/src/modifications/upgrade/RemoveIndexNamesModification.d.ts.map +1 -1
- package/dist/src/modifications/utils/schemaUpdateUtils.d.ts +10 -10
- package/dist/src/modifications/utils/schemaUpdateUtils.d.ts.map +1 -1
- package/dist/src/modifications/utils/viewDependencies.d.ts +1 -1
- package/dist/src/modifications/utils/viewDependencies.d.ts.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/utils/PartialEntity.d.ts +1 -1
- package/dist/src/utils/PartialEntity.d.ts.map +1 -1
- package/dist/tests/cases/integration/createColumn.test.js +0 -2
- package/dist/tests/cases/integration/createColumn.test.js.map +1 -1
- package/dist/tests/cases/integration/updateColumnDefinition.test.js +38 -0
- package/dist/tests/cases/integration/updateColumnDefinition.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/SchemaDiffer.ts +10 -11
- package/src/modifications/columns/CreateColumnModification.ts +19 -27
- package/src/modifications/columns/UpdateColumnDefinitionModification.ts +21 -2
- package/src/modifications/columns/columnUtils.ts +35 -0
- package/tests/cases/integration/createColumn.test.ts +0 -2
- package/tests/cases/integration/updateColumnDefinition.test.ts +32 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/schema-migrations",
|
|
3
|
-
"version": "1.3.0-
|
|
3
|
+
"version": "1.3.0-beta.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -9,20 +9,20 @@
|
|
|
9
9
|
"default": "./dist/src/index.js"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
|
-
"test": "vitest"
|
|
12
|
+
"test": "vitest --dir ./tests/cases"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@contember/database-migrations": "
|
|
16
|
-
"@contember/engine-common": "
|
|
17
|
-
"@contember/schema": "
|
|
18
|
-
"@contember/schema-utils": "
|
|
15
|
+
"@contember/database-migrations": "1.3.0-beta.2",
|
|
16
|
+
"@contember/engine-common": "1.3.0-beta.2",
|
|
17
|
+
"@contember/schema": "1.3.0-beta.2",
|
|
18
|
+
"@contember/schema-utils": "1.3.0-beta.2",
|
|
19
19
|
"fast-deep-equal": "^3.1.3",
|
|
20
20
|
"rfc6902": "^5.0.1"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@contember/schema-definition": "
|
|
23
|
+
"@contember/schema-definition": "1.3.0-beta.2"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"pg": "^8.9.0"
|
|
27
27
|
}
|
|
28
|
-
}
|
|
28
|
+
}
|
package/src/SchemaDiffer.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { Schema } from '@contember/schema'
|
|
2
|
-
import {
|
|
3
|
-
deepCompare,
|
|
4
|
-
isInverseRelation,
|
|
5
|
-
isOwningRelation,
|
|
6
|
-
isRelation,
|
|
7
|
-
SchemaValidator,
|
|
8
|
-
ValidationError,
|
|
9
|
-
} from '@contember/schema-utils'
|
|
2
|
+
import { compareArraysIgnoreOrder, deepCompare, isInverseRelation, isOwningRelation, isRelation, SchemaValidator, ValidationError } from '@contember/schema-utils'
|
|
10
3
|
import { SchemaMigrator } from './SchemaMigrator'
|
|
11
4
|
import { Migration } from './Migration'
|
|
12
5
|
import { ImplementationException } from './exceptions'
|
|
@@ -34,11 +27,11 @@ import {
|
|
|
34
27
|
UpdateAclSchemaDiffer,
|
|
35
28
|
UpdateColumnDefinitionDiffer,
|
|
36
29
|
UpdateColumnNameDiffer,
|
|
30
|
+
UpdateEntityOrderByDiffer,
|
|
37
31
|
UpdateEntityTableNameDiffer,
|
|
38
32
|
UpdateEnumDiffer,
|
|
39
33
|
UpdateRelationOnDeleteDiffer,
|
|
40
34
|
UpdateRelationOrderByDiffer,
|
|
41
|
-
UpdateEntityOrderByDiffer,
|
|
42
35
|
UpdateValidationSchemaDiffer,
|
|
43
36
|
VERSION_LATEST,
|
|
44
37
|
} from './modifications'
|
|
@@ -124,9 +117,15 @@ export class SchemaDiffer {
|
|
|
124
117
|
diffs.push(...differDiffs)
|
|
125
118
|
}
|
|
126
119
|
|
|
127
|
-
|
|
128
120
|
if (!skipRecreateValidation) {
|
|
129
|
-
const errors = deepCompare(updatedSchema, appliedDiffsSchema, []
|
|
121
|
+
const errors = deepCompare(updatedSchema, appliedDiffsSchema, [], path => {
|
|
122
|
+
if (path[0] === 'model' && path[1] === 'entities' && (path[3] === 'unique' || path[3] === 'index')) {
|
|
123
|
+
return (a, b) => {
|
|
124
|
+
return compareArraysIgnoreOrder(a, b, path)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return null
|
|
128
|
+
})
|
|
130
129
|
if (errors.length === 0) {
|
|
131
130
|
return diffs
|
|
132
131
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Model, Schema } from '@contember/schema'
|
|
1
|
+
import { MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
+
import { JSONValue, Model, Schema } from '@contember/schema'
|
|
3
3
|
import { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils'
|
|
4
4
|
import { createModificationType, Differ, ModificationHandler } from '../ModificationHandler'
|
|
5
|
-
import {
|
|
6
|
-
import { getColumnName, isColumn } from '@contember/schema-utils'
|
|
7
|
-
import { ImplementationException } from '../../exceptions'
|
|
5
|
+
import { isColumn } from '@contember/schema-utils'
|
|
8
6
|
import { createFields } from '../utils/diffUtils'
|
|
9
7
|
import { getColumnSqlType } from '../utils/columnUtils'
|
|
8
|
+
import { fillSeed } from './columnUtils'
|
|
10
9
|
|
|
11
10
|
export class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {
|
|
12
11
|
constructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}
|
|
@@ -18,34 +17,27 @@ export class CreateColumnModificationHandler implements ModificationHandler<Crea
|
|
|
18
17
|
}
|
|
19
18
|
const column = this.data.field
|
|
20
19
|
const hasSeed = this.data.fillValue !== undefined || this.data.copyValue !== undefined
|
|
20
|
+
const columnType = getColumnSqlType(column)
|
|
21
21
|
builder.addColumn(entity.tableName, {
|
|
22
22
|
[column.columnName]: {
|
|
23
|
-
type:
|
|
23
|
+
type: columnType,
|
|
24
24
|
notNull: !column.nullable && !hasSeed,
|
|
25
25
|
sequenceGenerated: column.sequence,
|
|
26
26
|
},
|
|
27
27
|
})
|
|
28
|
-
if (hasSeed) {
|
|
29
|
-
if (this.data.fillValue !== undefined) {
|
|
30
|
-
builder.sql(`UPDATE ${wrapIdentifier(entity.tableName)}
|
|
31
|
-
SET ${wrapIdentifier(column.columnName)} = ${escapeValue(this.data.fillValue)}`)
|
|
32
|
-
} else if (this.data.copyValue !== undefined) {
|
|
33
|
-
const copyFrom = getColumnName(this.schema.model, entity, this.data.copyValue)
|
|
34
|
-
builder.sql(`UPDATE ${wrapIdentifier(entity.tableName)}
|
|
35
|
-
SET ${wrapIdentifier(column.columnName)} = ${wrapIdentifier(copyFrom)}::${getColumnSqlType(column)}`)
|
|
36
|
-
} else {
|
|
37
|
-
throw new ImplementationException()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// event applier defers constraint check, we need to fire them before ALTER
|
|
41
|
-
builder.sql(`SET CONSTRAINTS ALL IMMEDIATE`)
|
|
42
|
-
builder.sql(`SET CONSTRAINTS ALL DEFERRED`)
|
|
43
28
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
29
|
+
if (hasSeed) {
|
|
30
|
+
fillSeed({
|
|
31
|
+
builder,
|
|
32
|
+
type: 'creating',
|
|
33
|
+
model: this.schema.model,
|
|
34
|
+
entity,
|
|
35
|
+
columnName: column.columnName,
|
|
36
|
+
nullable: column.nullable,
|
|
37
|
+
columnType,
|
|
38
|
+
copyValue: this.data.copyValue,
|
|
39
|
+
fillValue: this.data.fillValue,
|
|
40
|
+
})
|
|
49
41
|
}
|
|
50
42
|
}
|
|
51
43
|
|
|
@@ -67,7 +59,7 @@ export class CreateColumnModificationHandler implements ModificationHandler<Crea
|
|
|
67
59
|
export interface CreateColumnModificationData {
|
|
68
60
|
entityName: string
|
|
69
61
|
field: Model.AnyColumn
|
|
70
|
-
fillValue?:
|
|
62
|
+
fillValue?: JSONValue
|
|
71
63
|
copyValue?: string
|
|
72
64
|
}
|
|
73
65
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { escapeValue, MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
-
import { Model, Schema } from '@contember/schema'
|
|
2
|
+
import { JSONValue, Model, Schema } from '@contember/schema'
|
|
3
3
|
import { SchemaUpdater, updateEntity, updateField, updateModel } from '../utils/schemaUpdateUtils'
|
|
4
4
|
import { createModificationType, Differ, ModificationHandler } from '../ModificationHandler'
|
|
5
5
|
import deepEqual from 'fast-deep-equal'
|
|
6
6
|
import { updateColumns } from '../utils/diffUtils'
|
|
7
7
|
import { wrapIdentifier } from '../../utils/dbHelpers'
|
|
8
8
|
import { getColumnSqlType } from '../utils/columnUtils'
|
|
9
|
+
import { fillSeed } from './columnUtils'
|
|
9
10
|
|
|
10
11
|
export class UpdateColumnDefinitionModificationHandler implements ModificationHandler<UpdateColumnDefinitionModificationData> {
|
|
11
12
|
constructor(private readonly data: UpdateColumnDefinitionModificationData, private readonly schema: Schema) {}
|
|
@@ -24,9 +25,11 @@ export class UpdateColumnDefinitionModificationHandler implements ModificationHa
|
|
|
24
25
|
|
|
25
26
|
const usingCast = `${wrapIdentifier(oldColumn.columnName)}::${columnType}`
|
|
26
27
|
|
|
28
|
+
const hasSeed = this.data.fillValue !== undefined || this.data.copyValue !== undefined
|
|
29
|
+
|
|
27
30
|
builder.alterColumn(entity.tableName, oldColumn.columnName, {
|
|
28
31
|
type: hasNewSequence || hasNewType ? columnType : undefined,
|
|
29
|
-
notNull: oldColumn.nullable !== newColumn.nullable ? !newColumn.nullable : undefined,
|
|
32
|
+
notNull: oldColumn.nullable !== newColumn.nullable && (!hasSeed || newColumn.nullable) ? !newColumn.nullable : undefined,
|
|
30
33
|
using: hasNewSequence
|
|
31
34
|
? `COALESCE(${usingCast}, nextval(PG_GET_SERIAL_SEQUENCE(${escapeValue(entity.tableName)}, ${escapeValue(oldColumn.columnName)})))`
|
|
32
35
|
: hasNewType
|
|
@@ -35,6 +38,20 @@ export class UpdateColumnDefinitionModificationHandler implements ModificationHa
|
|
|
35
38
|
sequenceGenerated: oldColumn.sequence && !newColumn.sequence ? false : (!oldColumn.sequence ? newColumn.sequence : undefined),
|
|
36
39
|
})
|
|
37
40
|
|
|
41
|
+
if (hasSeed) {
|
|
42
|
+
fillSeed({
|
|
43
|
+
builder,
|
|
44
|
+
type: 'updating',
|
|
45
|
+
model: this.schema.model,
|
|
46
|
+
entity,
|
|
47
|
+
columnName: oldColumn.columnName,
|
|
48
|
+
nullable: newColumn.nullable,
|
|
49
|
+
columnType,
|
|
50
|
+
copyValue: this.data.copyValue,
|
|
51
|
+
fillValue: this.data.fillValue,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
38
55
|
const seqAlter = []
|
|
39
56
|
if (oldColumn.sequence && newColumn.sequence) {
|
|
40
57
|
if (oldColumn.sequence.precedence !== newColumn.sequence.precedence) {
|
|
@@ -95,6 +112,8 @@ export interface UpdateColumnDefinitionModificationData {
|
|
|
95
112
|
entityName: string
|
|
96
113
|
fieldName: string
|
|
97
114
|
definition: ColumnDefinitionAlter
|
|
115
|
+
fillValue?: JSONValue
|
|
116
|
+
copyValue?: string
|
|
98
117
|
}
|
|
99
118
|
|
|
100
119
|
export const updateColumnDefinitionModification = createModificationType({
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { wrapIdentifier } from '../../utils/dbHelpers'
|
|
2
|
+
import { ImplementationException } from '../../exceptions'
|
|
3
|
+
import { JSONValue, Model } from '@contember/schema'
|
|
4
|
+
import { escapeValue, MigrationBuilder } from '@contember/database-migrations'
|
|
5
|
+
import { getColumnName } from '@contember/schema-utils'
|
|
6
|
+
|
|
7
|
+
export const fillSeed = ({ builder, fillValue, copyValue, entity, columnName, nullable, model, columnType, type }: {
|
|
8
|
+
model: Model.Schema
|
|
9
|
+
entity: Model.Entity
|
|
10
|
+
columnName: string
|
|
11
|
+
columnType: string
|
|
12
|
+
nullable: boolean
|
|
13
|
+
builder: MigrationBuilder
|
|
14
|
+
fillValue?: JSONValue
|
|
15
|
+
copyValue?: string
|
|
16
|
+
type: 'creating' | 'updating'
|
|
17
|
+
}) => {
|
|
18
|
+
const where = type === 'updating' ? ` WHERE ${wrapIdentifier(columnName)} IS NULL` : ''
|
|
19
|
+
if (fillValue !== undefined) {
|
|
20
|
+
builder.sql(`UPDATE ${wrapIdentifier(entity.tableName)}
|
|
21
|
+
SET ${wrapIdentifier(columnName)} = ${escapeValue(fillValue)}${where}`)
|
|
22
|
+
} else if (copyValue !== undefined) {
|
|
23
|
+
const copyFrom = getColumnName(model, entity, copyValue)
|
|
24
|
+
builder.sql(`UPDATE ${wrapIdentifier(entity.tableName)}
|
|
25
|
+
SET ${wrapIdentifier(columnName)} = ${wrapIdentifier(copyFrom)}::${columnType}${where}`)
|
|
26
|
+
} else {
|
|
27
|
+
throw new ImplementationException()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!nullable) {
|
|
31
|
+
builder.alterColumn(entity.tableName, columnName, {
|
|
32
|
+
notNull: true,
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -32,7 +32,6 @@ testMigrations('create a column with default value', {
|
|
|
32
32
|
],
|
|
33
33
|
sql: SQL`ALTER TABLE "author" ADD "name" text;
|
|
34
34
|
UPDATE "author" SET "name" = $pga$unnamed author$pga$;
|
|
35
|
-
SET CONSTRAINTS ALL IMMEDIATE; SET CONSTRAINTS ALL DEFERRED;
|
|
36
35
|
ALTER TABLE "author" ALTER "name" SET NOT NULL;`,
|
|
37
36
|
})
|
|
38
37
|
|
|
@@ -65,6 +64,5 @@ testMigrations('create a column with copy value', {
|
|
|
65
64
|
noDiff: true,
|
|
66
65
|
sql: SQL`ALTER TABLE "author" ADD "name" text;
|
|
67
66
|
UPDATE "author" SET "name" = "email"::text;
|
|
68
|
-
SET CONSTRAINTS ALL IMMEDIATE; SET CONSTRAINTS ALL DEFERRED;
|
|
69
67
|
ALTER TABLE "author" ALTER "name" SET NOT NULL;`,
|
|
70
68
|
})
|
|
@@ -168,3 +168,35 @@ ALTER TABLE "author"
|
|
|
168
168
|
CREATE VIEW "author_meta_x" AS SELECT * FROM author;
|
|
169
169
|
CREATE VIEW "author_meta_y" AS SELECT * FROM author_meta_x;`,
|
|
170
170
|
})
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
namespace NotNullOrig {
|
|
174
|
+
export class Author {
|
|
175
|
+
name = def.stringColumn()
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
namespace NotNullUpdated {
|
|
179
|
+
export class Author {
|
|
180
|
+
name = def.stringColumn().notNull()
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
testMigrations('set not null and fill', {
|
|
184
|
+
originalSchema: createSchema(NotNullOrig).model,
|
|
185
|
+
updatedSchema: createSchema(NotNullUpdated).model,
|
|
186
|
+
noDiff: true,
|
|
187
|
+
diff: [
|
|
188
|
+
updateColumnDefinitionModification.createModification({
|
|
189
|
+
entityName: 'Author',
|
|
190
|
+
fieldName: 'name',
|
|
191
|
+
definition: {
|
|
192
|
+
type: Model.ColumnType.String,
|
|
193
|
+
columnType: 'text',
|
|
194
|
+
nullable: false,
|
|
195
|
+
},
|
|
196
|
+
fillValue: 'unnamed',
|
|
197
|
+
}),
|
|
198
|
+
],
|
|
199
|
+
sql: SQL`
|
|
200
|
+
UPDATE "author" SET "name" = $pga$unnamed$pga$ WHERE "name" IS NULL;
|
|
201
|
+
ALTER TABLE "author" ALTER "name" SET NOT NULL;`,
|
|
202
|
+
})
|