@contember/engine-system-api 1.3.3 → 1.3.5
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/migrations/2023-10-19-173000-fix-unique.d.ts +4 -0
- package/dist/src/migrations/2023-10-19-173000-fix-unique.d.ts.map +1 -0
- package/dist/src/migrations/2023-10-19-173000-fix-unique.js +45 -0
- package/dist/src/migrations/2023-10-19-173000-fix-unique.js.map +1 -0
- package/dist/src/migrations/runner.d.ts.map +1 -1
- package/dist/src/migrations/runner.js +2 -0
- package/dist/src/migrations/runner.js.map +1 -1
- package/dist/src/model/metadata/ResolvedDatabaseMetadata.d.ts +1 -0
- package/dist/src/model/metadata/ResolvedDatabaseMetadata.d.ts.map +1 -1
- package/dist/src/model/metadata/ResolvedDatabaseMetadata.js +9 -2
- package/dist/src/model/metadata/ResolvedDatabaseMetadata.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/cases/migrations/2023-10-19-173000-fix-unique.test.d.ts +2 -0
- package/dist/tests/cases/migrations/2023-10-19-173000-fix-unique.test.d.ts.map +1 -0
- package/dist/tests/cases/migrations/2023-10-19-173000-fix-unique.test.js +73 -0
- package/dist/tests/cases/migrations/2023-10-19-173000-fix-unique.test.js.map +1 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/migrations/2023-10-19-173000-fix-unique.ts +49 -0
- package/src/migrations/runner.ts +2 -0
- package/src/model/metadata/ResolvedDatabaseMetadata.ts +10 -2
- package/tests/cases/migrations/2023-10-19-173000-fix-unique.test.ts +66 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-system-api",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"typings": "dist/src/index.d.ts",
|
|
@@ -13,22 +13,22 @@
|
|
|
13
13
|
"test": "vitest --dir ./tests/cases"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@contember/authorization": "1.3.
|
|
17
|
-
"@contember/database": "1.3.
|
|
18
|
-
"@contember/database-migrations": "1.3.
|
|
19
|
-
"@contember/dic": "1.3.
|
|
20
|
-
"@contember/graphql-utils": "1.3.
|
|
21
|
-
"@contember/logger": "1.3.
|
|
22
|
-
"@contember/queryable": "1.3.
|
|
23
|
-
"@contember/schema": "1.3.
|
|
24
|
-
"@contember/schema-migrations": "1.3.
|
|
25
|
-
"@contember/schema-utils": "1.3.
|
|
16
|
+
"@contember/authorization": "1.3.5",
|
|
17
|
+
"@contember/database": "1.3.5",
|
|
18
|
+
"@contember/database-migrations": "1.3.5",
|
|
19
|
+
"@contember/dic": "1.3.5",
|
|
20
|
+
"@contember/graphql-utils": "1.3.5",
|
|
21
|
+
"@contember/logger": "1.3.5",
|
|
22
|
+
"@contember/queryable": "1.3.5",
|
|
23
|
+
"@contember/schema": "1.3.5",
|
|
24
|
+
"@contember/schema-migrations": "1.3.5",
|
|
25
|
+
"@contember/schema-utils": "1.3.5",
|
|
26
26
|
"@graphql-tools/utils": "^8.6.13",
|
|
27
27
|
"graphql-tag": "^2.12.5"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@contember/engine-api-tester": "1.3.
|
|
31
|
-
"@contember/schema-definition": "1.3.
|
|
30
|
+
"@contember/engine-api-tester": "1.3.5",
|
|
31
|
+
"@contember/schema-definition": "1.3.5",
|
|
32
32
|
"@graphql-codegen/cli": "^2.6.2",
|
|
33
33
|
"@graphql-codegen/typescript": "^2.5.1",
|
|
34
34
|
"@graphql-codegen/typescript-operations": "^2.4.2",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MigrationArgs, MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
+
import { wrapIdentifier } from '@contember/database'
|
|
3
|
+
import { SystemMigrationArgs } from './types'
|
|
4
|
+
import { acceptEveryFieldVisitor, SchemaDatabaseMetadata } from '@contember/schema-utils'
|
|
5
|
+
import { getUniqueConstraintColumns } from '@contember/schema-migrations'
|
|
6
|
+
|
|
7
|
+
export default async function (builder: MigrationBuilder, args: MigrationArgs<SystemMigrationArgs>) {
|
|
8
|
+
const schema = await args.schemaResolver(args.connection)
|
|
9
|
+
const stages = (await args.connection.query<{schema: string}>('SELECT schema FROM stage')).rows
|
|
10
|
+
const metadataByStage: Record<string, SchemaDatabaseMetadata> = {}
|
|
11
|
+
|
|
12
|
+
for (const entity of Object.values(schema.model.entities)) {
|
|
13
|
+
if (entity.view) {
|
|
14
|
+
continue
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const expectedUnique: string[][] = []
|
|
18
|
+
|
|
19
|
+
for (const uniq of entity.unique) {
|
|
20
|
+
const columns = getUniqueConstraintColumns({
|
|
21
|
+
entity,
|
|
22
|
+
fields: uniq.fields,
|
|
23
|
+
model: schema.model,
|
|
24
|
+
})
|
|
25
|
+
expectedUnique.push(columns)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
for (const stage of stages) {
|
|
30
|
+
const databaseMetadata = metadataByStage[stage.schema] ??= await args.databaseMetadataResolver(args.connection, stage.schema)
|
|
31
|
+
|
|
32
|
+
const existingUniqueConstraints = databaseMetadata.getAllUniqueConstraints().filter(it => it.tableName === entity.tableName)
|
|
33
|
+
for (const constraint of existingUniqueConstraints) {
|
|
34
|
+
if (constraint.columnNames.length === 1 || expectedUnique.some(it => stringArrayEquals(it, constraint.columnNames))) {
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
builder.sql(`ALTER TABLE ${wrapIdentifier(stage.schema)}.${wrapIdentifier(entity.tableName)} DROP CONSTRAINT ${wrapIdentifier(constraint.constraintName)}`)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const stringArrayEquals = (colA: string[], colB: string[]) => {
|
|
43
|
+
if (colA.length !== colB.length) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
const a = [...colA].sort()
|
|
47
|
+
const b = [...colB].sort()
|
|
48
|
+
return a.every((it, index) => it === b[index])
|
|
49
|
+
}
|
package/src/migrations/runner.ts
CHANGED
|
@@ -18,6 +18,7 @@ import _20220208140500dropdeadcode from './2022-02-08-140500-drop-deadcode'
|
|
|
18
18
|
import _20220208144400dynamicstageschema from './2022-02-08-144400-dynamic-stage-schema'
|
|
19
19
|
import _20221003110000tableondelete from './2022-10-03-110000-table-on-delete'
|
|
20
20
|
import _20230911174000fixondelete from './2023-09-11-174000-fix-on-delete'
|
|
21
|
+
import _20231019173000fixunique from './2023-10-19-173000-fix-unique'
|
|
21
22
|
import snapshot from './snapshot'
|
|
22
23
|
|
|
23
24
|
import { Client, Connection, createDatabaseIfNotExists, DatabaseConfig } from '@contember/database'
|
|
@@ -48,6 +49,7 @@ const migrations = {
|
|
|
48
49
|
'2022-02-08-144400-dynamic-stage-schema': _20220208144400dynamicstageschema,
|
|
49
50
|
'2022-10-03-110000-table-on-delete': _20221003110000tableondelete,
|
|
50
51
|
'2023-09-11-174000-fix-on-delete': _20230911174000fixondelete,
|
|
52
|
+
'2023-10-19-173000-fix-unique': _20231019173000fixunique,
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
|
|
@@ -9,8 +9,12 @@ import {
|
|
|
9
9
|
} from '@contember/schema-utils'
|
|
10
10
|
|
|
11
11
|
const stringArrayEquals = (colA: string[], colB: string[]) => {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
if (colA.length !== colB.length) {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
const a = [...colA].sort()
|
|
16
|
+
const b = [...colB].sort()
|
|
17
|
+
return a.every((it, index) => it === b[index])
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export class ResolvedDatabaseMetadata implements SchemaDatabaseMetadata {
|
|
@@ -21,6 +25,10 @@ export class ResolvedDatabaseMetadata implements SchemaDatabaseMetadata {
|
|
|
21
25
|
) {
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
getAllUniqueConstraints(): UniqueConstraintMetadata[] {
|
|
29
|
+
return this.uniqueConstraints
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
getUniqueConstraint(tableName: string, constraintName: string): UniqueConstraintMetadata | null {
|
|
25
33
|
return this.uniqueConstraints.find(it => it.tableName === tableName && it.constraintName === constraintName) ?? null
|
|
26
34
|
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import migration from '../../../src/migrations/2023-10-19-173000-fix-unique'
|
|
2
|
+
import { createMigrationBuilder } from '@contember/database-migrations'
|
|
3
|
+
import { assert, test } from 'vitest'
|
|
4
|
+
import { c, createSchema } from '@contember/schema-definition'
|
|
5
|
+
import { dummySchemaDatabaseMetadata } from '@contember/schema-utils'
|
|
6
|
+
import { createConnectionMock } from '@contember/database-tester'
|
|
7
|
+
|
|
8
|
+
namespace UniqueModel {
|
|
9
|
+
|
|
10
|
+
@c.Unique('colA', 'colB')
|
|
11
|
+
@c.Unique('manyHasOneBar', 'colB')
|
|
12
|
+
export class Foo {
|
|
13
|
+
hasOneBar = c.oneHasOne(Bar)
|
|
14
|
+
manyHasOneBar = c.manyHasOne(Bar)
|
|
15
|
+
singleColUnique = c.stringColumn().unique()
|
|
16
|
+
|
|
17
|
+
colA = c.stringColumn()
|
|
18
|
+
colB = c.stringColumn()
|
|
19
|
+
colC = c.stringColumn()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Bar {
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
test('unique fix test', async () => {
|
|
28
|
+
const builder = createMigrationBuilder()
|
|
29
|
+
const connection = createConnectionMock([{
|
|
30
|
+
sql: 'select schema from stage',
|
|
31
|
+
response: { rows: [{ schema: 'stage_live' }] },
|
|
32
|
+
}])
|
|
33
|
+
await migration(builder, {
|
|
34
|
+
connection: connection,
|
|
35
|
+
databaseMetadataResolver: () => Promise.resolve({
|
|
36
|
+
...dummySchemaDatabaseMetadata,
|
|
37
|
+
getAllUniqueConstraints: () => [
|
|
38
|
+
{ constraintName: 'valid1', tableName: 'foo', columnNames: ['col_a', 'col_b'] },
|
|
39
|
+
{ constraintName: 'valid2', tableName: 'foo', columnNames: ['col_b', 'many_has_one_bar_id'] },
|
|
40
|
+
{ constraintName: 'valid3', tableName: 'foo', columnNames: ['single_col_unique'] },
|
|
41
|
+
{ constraintName: 'valid4', tableName: 'foo', columnNames: ['has_one_bar_id'] },
|
|
42
|
+
|
|
43
|
+
{ constraintName: 'invalid1', tableName: 'foo', columnNames: ['col_a', 'col_c'] },
|
|
44
|
+
{ constraintName: 'invalid2', tableName: 'foo', columnNames: ['col_c', 'many_has_one_bar_id'] },
|
|
45
|
+
|
|
46
|
+
],
|
|
47
|
+
}),
|
|
48
|
+
schemaResolver: () => Promise.resolve(createSchema(UniqueModel)),
|
|
49
|
+
project: {
|
|
50
|
+
slug: 'test',
|
|
51
|
+
stages: [
|
|
52
|
+
{
|
|
53
|
+
slug: 'prod',
|
|
54
|
+
name: 'prod',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
assert.equal(
|
|
60
|
+
builder.getSql(),
|
|
61
|
+
`ALTER TABLE "stage_live"."foo" DROP CONSTRAINT "invalid1";
|
|
62
|
+
ALTER TABLE "stage_live"."foo" DROP CONSTRAINT "invalid2";
|
|
63
|
+
`,
|
|
64
|
+
)
|
|
65
|
+
})
|
|
66
|
+
|