@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/engine-system-api",
3
- "version": "1.3.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.3",
17
- "@contember/database": "1.3.3",
18
- "@contember/database-migrations": "1.3.3",
19
- "@contember/dic": "1.3.3",
20
- "@contember/graphql-utils": "1.3.3",
21
- "@contember/logger": "1.3.3",
22
- "@contember/queryable": "1.3.3",
23
- "@contember/schema": "1.3.3",
24
- "@contember/schema-migrations": "1.3.3",
25
- "@contember/schema-utils": "1.3.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.3",
31
- "@contember/schema-definition": "1.3.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
+ }
@@ -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
- return colA.length === colB.length
13
- && colA.every((it, index) => it === colB[index])
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
+