@contember/engine-system-api 1.3.2 → 1.3.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/migrations/2023-09-11-174000-fix-on-delete.d.ts +4 -0
- package/dist/src/migrations/2023-09-11-174000-fix-on-delete.d.ts.map +1 -0
- package/dist/src/migrations/2023-09-11-174000-fix-on-delete.js +70 -0
- package/dist/src/migrations/2023-09-11-174000-fix-on-delete.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/SchemaDatabaseMetadataResolver.d.ts.map +1 -1
- package/dist/src/model/metadata/SchemaDatabaseMetadataResolver.js +14 -8
- package/dist/src/model/metadata/SchemaDatabaseMetadataResolver.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/migrations/2023-09-11-174000-fix-on-delete.ts +77 -0
- package/src/migrations/runner.ts +2 -0
- package/src/model/metadata/SchemaDatabaseMetadataResolver.ts +5 -1
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.3",
|
|
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.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",
|
|
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.3",
|
|
31
|
+
"@contember/schema-definition": "1.3.3",
|
|
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,77 @@
|
|
|
1
|
+
import { MigrationArgs, MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
+
import { wrapIdentifier } from '@contember/database'
|
|
3
|
+
import { SystemMigrationArgs } from './types'
|
|
4
|
+
import { acceptFieldVisitor, ForeignKeyDeleteAction, SchemaDatabaseMetadata } from '@contember/schema-utils'
|
|
5
|
+
import { Model } from '@contember/schema'
|
|
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
|
+
for (const field of Object.values(entity.fields)) {
|
|
14
|
+
const result = acceptFieldVisitor<null | {
|
|
15
|
+
relation: Model.OneHasOneOwningRelation | Model.ManyHasOneRelation
|
|
16
|
+
targetEntity: Model.Entity
|
|
17
|
+
}>(schema.model, entity, field, {
|
|
18
|
+
visitManyHasOne: ({ entity, relation, targetEntity }) => {
|
|
19
|
+
return { relation, entity, targetEntity }
|
|
20
|
+
},
|
|
21
|
+
visitOneHasOneOwning: ({ entity, relation, targetEntity }) => {
|
|
22
|
+
return { relation, entity, targetEntity }
|
|
23
|
+
},
|
|
24
|
+
visitOneHasOneInverse: () => null,
|
|
25
|
+
visitManyHasManyInverse: () => null,
|
|
26
|
+
visitManyHasManyOwning: () => null,
|
|
27
|
+
visitOneHasMany: () => null,
|
|
28
|
+
visitColumn: () => null,
|
|
29
|
+
})
|
|
30
|
+
if (!result) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
const { targetEntity, relation } = result
|
|
34
|
+
if (entity.view || targetEntity.view) {
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
for (const stage of stages) {
|
|
38
|
+
const databaseMetadata = metadataByStage[stage.schema] ??= await args.databaseMetadataResolver(args.connection, stage.schema)
|
|
39
|
+
|
|
40
|
+
const fkNames = databaseMetadata.getForeignKeyConstraintNames({
|
|
41
|
+
fromTable: entity.tableName,
|
|
42
|
+
fromColumn: relation.joiningColumn.columnName,
|
|
43
|
+
toTable: targetEntity.tableName,
|
|
44
|
+
toColumn: targetEntity.primaryColumn,
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (fkNames.every(it => {
|
|
48
|
+
const constraint = databaseMetadata.getForeignKeyConstraint(entity.tableName, it)
|
|
49
|
+
const dbConstraintFlag = ({
|
|
50
|
+
[Model.OnDelete.setNull]: ForeignKeyDeleteAction.setnull,
|
|
51
|
+
[Model.OnDelete.cascade]: ForeignKeyDeleteAction.cascade,
|
|
52
|
+
[Model.OnDelete.restrict]: ForeignKeyDeleteAction.restrict,
|
|
53
|
+
} as const)[relation.joiningColumn.onDelete]
|
|
54
|
+
|
|
55
|
+
return constraint && constraint.deleteAction === dbConstraintFlag
|
|
56
|
+
})) {
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
for (const name of fkNames) {
|
|
61
|
+
builder.sql(`ALTER TABLE ${wrapIdentifier(stage.schema)}.${wrapIdentifier(entity.tableName)} DROP CONSTRAINT ${wrapIdentifier(name)}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const onDelete = ({
|
|
65
|
+
[Model.OnDelete.setNull]: 'SET NULL',
|
|
66
|
+
[Model.OnDelete.cascade]: 'CASCADE',
|
|
67
|
+
[Model.OnDelete.restrict]: 'RESTRICT',
|
|
68
|
+
} as const)[relation.joiningColumn.onDelete]
|
|
69
|
+
|
|
70
|
+
builder.sql(`ALTER TABLE ${wrapIdentifier(stage.schema)}.${wrapIdentifier(entity.tableName)}
|
|
71
|
+
ADD FOREIGN KEY (${wrapIdentifier(relation.joiningColumn.columnName)})
|
|
72
|
+
REFERENCES ${wrapIdentifier(stage.schema)}.${wrapIdentifier(targetEntity.tableName)} (${wrapIdentifier(targetEntity.primaryColumn)}) ON DELETE ${onDelete} DEFERRABLE INITIALLY IMMEDIATE
|
|
73
|
+
`)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/migrations/runner.ts
CHANGED
|
@@ -17,6 +17,7 @@ import _20220208132600fnsearchpath from './2022-02-08-132600-fn-search-path'
|
|
|
17
17
|
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
|
+
import _20230911174000fixondelete from './2023-09-11-174000-fix-on-delete'
|
|
20
21
|
import snapshot from './snapshot'
|
|
21
22
|
|
|
22
23
|
import { Client, Connection, createDatabaseIfNotExists, DatabaseConfig } from '@contember/database'
|
|
@@ -46,6 +47,7 @@ const migrations = {
|
|
|
46
47
|
'2022-02-08-140500-drop-deadcode': _20220208140500dropdeadcode,
|
|
47
48
|
'2022-02-08-144400-dynamic-stage-schema': _20220208144400dynamicstageschema,
|
|
48
49
|
'2022-10-03-110000-table-on-delete': _20221003110000tableondelete,
|
|
50
|
+
'2023-09-11-174000-fix-on-delete': _20230911174000fixondelete,
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
IndexMetadata,
|
|
4
4
|
SchemaDatabaseMetadata,
|
|
5
5
|
UniqueConstraintMetadata,
|
|
6
|
+
ForeignKeyDeleteAction,
|
|
6
7
|
} from '@contember/schema-utils'
|
|
7
8
|
import { DatabaseContext } from '../database'
|
|
8
9
|
import { Connection } from '@contember/database'
|
|
@@ -21,6 +22,7 @@ export class SchemaDatabaseMetadataResolver {
|
|
|
21
22
|
toColumn: it.target_columns[0],
|
|
22
23
|
fromTable: it.table_name,
|
|
23
24
|
toTable: it.target_table,
|
|
25
|
+
deleteAction: it.delete_action ?? ForeignKeyDeleteAction.noaction,
|
|
24
26
|
}))
|
|
25
27
|
const uniqueConstraints = constraintRows
|
|
26
28
|
.filter((it): it is UniqueConstraintsRow => it.type === ConstraintTypes.unique)
|
|
@@ -54,7 +56,8 @@ export class SchemaDatabaseMetadataResolver {
|
|
|
54
56
|
JSONB_AGG(DISTINCT pg_attribute_target.attname)
|
|
55
57
|
FILTER ( WHERE pg_attribute_target.attname IS NOT NULL) AS target_columns,
|
|
56
58
|
BOOL_OR(condeferrable),
|
|
57
|
-
BOOL_OR(condeferred)
|
|
59
|
+
BOOL_OR(condeferred),
|
|
60
|
+
MAX(confdeltype) AS delete_action
|
|
58
61
|
FROM pg_constraint
|
|
59
62
|
JOIN pg_class
|
|
60
63
|
ON pg_constraint.conrelid = pg_class.oid
|
|
@@ -116,6 +119,7 @@ type ForeignKeyConstraintsRow = {
|
|
|
116
119
|
type: ConstraintTypes.foreignKey
|
|
117
120
|
deferrable: boolean
|
|
118
121
|
deferred: boolean
|
|
122
|
+
delete_action: ForeignKeyDeleteAction | null
|
|
119
123
|
}
|
|
120
124
|
type UniqueConstraintsRow = {
|
|
121
125
|
constraint_name: string
|