@contember/schema-migrations 1.3.6 → 1.4.0-alpha.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.
Files changed (70) hide show
  1. package/dist/src/SchemaDiffer.d.ts.map +1 -1
  2. package/dist/src/SchemaDiffer.js +2 -0
  3. package/dist/src/SchemaDiffer.js.map +1 -1
  4. package/dist/src/modifications/ModificationHandler.d.ts +2 -2
  5. package/dist/src/modifications/ModificationHandler.d.ts.map +1 -1
  6. package/dist/src/modifications/ModificationHandlerFactory.d.ts.map +1 -1
  7. package/dist/src/modifications/ModificationHandlerFactory.js +2 -0
  8. package/dist/src/modifications/ModificationHandlerFactory.js.map +1 -1
  9. package/dist/src/modifications/constraints/CreateUniqueConstraintModification.d.ts.map +1 -1
  10. package/dist/src/modifications/constraints/CreateUniqueConstraintModification.js +8 -1
  11. package/dist/src/modifications/constraints/CreateUniqueConstraintModification.js.map +1 -1
  12. package/dist/src/modifications/constraints/RemoveUniqueConstraintModification.d.ts.map +1 -1
  13. package/dist/src/modifications/constraints/RemoveUniqueConstraintModification.js +2 -2
  14. package/dist/src/modifications/constraints/RemoveUniqueConstraintModification.js.map +1 -1
  15. package/dist/src/modifications/indexes/RemoveIndexModification.js +1 -1
  16. package/dist/src/modifications/indexes/RemoveIndexModification.js.map +1 -1
  17. package/dist/src/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.d.ts +28 -0
  18. package/dist/src/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.d.ts.map +1 -0
  19. package/dist/src/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.js +98 -0
  20. package/dist/src/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.js.map +1 -0
  21. package/dist/src/modifications/relations/ConvertOneToManyRelationModification.d.ts.map +1 -1
  22. package/dist/src/modifications/relations/ConvertOneToManyRelationModification.js +7 -5
  23. package/dist/src/modifications/relations/ConvertOneToManyRelationModification.js.map +1 -1
  24. package/dist/src/modifications/relations/helpers.d.ts +2 -2
  25. package/dist/src/modifications/relations/helpers.d.ts.map +1 -1
  26. package/dist/src/modifications/relations/helpers.js +2 -2
  27. package/dist/src/modifications/relations/helpers.js.map +1 -1
  28. package/dist/src/tsconfig.tsbuildinfo +1 -1
  29. package/dist/tests/cases/integration/convertManyHasOneToOneHasOneRelation.test.d.ts +2 -0
  30. package/dist/tests/cases/integration/convertManyHasOneToOneHasOneRelation.test.d.ts.map +1 -0
  31. package/dist/tests/cases/integration/convertManyHasOneToOneHasOneRelation.test.js +59 -0
  32. package/dist/tests/cases/integration/convertManyHasOneToOneHasOneRelation.test.js.map +1 -0
  33. package/dist/tests/cases/integration/convertOneToManyRelation.test.js +60 -0
  34. package/dist/tests/cases/integration/convertOneToManyRelation.test.js.map +1 -1
  35. package/dist/tests/cases/integration/createAndDropIndex.test.js +10 -0
  36. package/dist/tests/cases/integration/createAndDropIndex.test.js.map +1 -1
  37. package/dist/tests/cases/integration/createRelationInverseSide.test.js +17 -0
  38. package/dist/tests/cases/integration/createRelationInverseSide.test.js.map +1 -1
  39. package/dist/tests/cases/integration/createUnique.test.d.ts +2 -0
  40. package/dist/tests/cases/integration/createUnique.test.d.ts.map +1 -0
  41. package/dist/tests/cases/integration/createUnique.test.js +168 -0
  42. package/dist/tests/cases/integration/createUnique.test.js.map +1 -0
  43. package/dist/tests/cases/integration/removeField.test.js +12 -0
  44. package/dist/tests/cases/integration/removeField.test.js.map +1 -1
  45. package/dist/tests/cases/integration/updateRelationOnDelete.test.js +17 -0
  46. package/dist/tests/cases/integration/updateRelationOnDelete.test.js.map +1 -1
  47. package/dist/tests/src/tests.d.ts +4 -2
  48. package/dist/tests/src/tests.d.ts.map +1 -1
  49. package/dist/tests/src/tests.js +5 -4
  50. package/dist/tests/src/tests.js.map +1 -1
  51. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +7 -6
  53. package/src/SchemaDiffer.ts +2 -0
  54. package/src/modifications/ModificationHandler.ts +2 -2
  55. package/src/modifications/ModificationHandlerFactory.ts +2 -0
  56. package/src/modifications/constraints/CreateUniqueConstraintModification.ts +8 -1
  57. package/src/modifications/constraints/RemoveUniqueConstraintModification.ts +8 -10
  58. package/src/modifications/indexes/RemoveIndexModification.ts +1 -1
  59. package/src/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.ts +145 -0
  60. package/src/modifications/relations/ConvertOneToManyRelationModification.ts +7 -5
  61. package/src/modifications/relations/helpers.ts +4 -4
  62. package/src/tsconfig.json +1 -0
  63. package/tests/cases/integration/convertManyHasOneToOneHasOneRelation.test.ts +48 -0
  64. package/tests/cases/integration/convertOneToManyRelation.test.ts +65 -0
  65. package/tests/cases/integration/createAndDropIndex.test.ts +10 -0
  66. package/tests/cases/integration/createRelationInverseSide.test.ts +17 -0
  67. package/tests/cases/integration/createUnique.test.ts +146 -0
  68. package/tests/cases/integration/removeField.test.ts +12 -0
  69. package/tests/cases/integration/updateRelationOnDelete.test.ts +17 -0
  70. package/tests/src/tests.ts +12 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/schema-migrations",
3
- "version": "1.3.6",
3
+ "version": "1.4.0-alpha.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/src/index.js",
6
6
  "typings": "dist/src/index.d.ts",
@@ -12,15 +12,16 @@
12
12
  "test": "vitest --dir ./tests/cases"
13
13
  },
14
14
  "dependencies": {
15
- "@contember/database-migrations": "1.3.6",
16
- "@contember/engine-common": "1.3.6",
17
- "@contember/schema": "1.3.6",
18
- "@contember/schema-utils": "1.3.6",
15
+ "@contember/database": "1.4.0-alpha.2",
16
+ "@contember/database-migrations": "1.4.0-alpha.2",
17
+ "@contember/engine-common": "1.4.0-alpha.2",
18
+ "@contember/schema": "1.4.0-alpha.2",
19
+ "@contember/schema-utils": "1.4.0-alpha.2",
19
20
  "fast-deep-equal": "^3.1.3",
20
21
  "rfc6902": "^5.0.1"
21
22
  },
22
23
  "devDependencies": {
23
- "@contember/schema-definition": "1.3.6"
24
+ "@contember/schema-definition": "1.4.0-alpha.2"
24
25
  },
25
26
  "peerDependencies": {
26
27
  "pg": "^8.9.0"
@@ -43,6 +43,7 @@ import { CreateTargetDiffer } from './modifications/actions/CreateTargetModifica
43
43
  import { RemoveTargetDiffer } from './modifications/actions/RemoveTargetModification'
44
44
  import { UpdateSettingsDiffer } from './modifications/settings'
45
45
  import { RemoveIndexNamesDiffer } from './modifications/upgrade/RemoveIndexNamesModification'
46
+ import { ConvertOneHasManyToOneHasOneRelationDiffer } from './modifications/relations/ConvertOneHasManyToOneHasOneRelationModification'
46
47
 
47
48
  type DiffOptions = { skipRecreateValidation?: boolean; skipInitialSchemaValidation?: boolean }
48
49
 
@@ -69,6 +70,7 @@ export class SchemaDiffer {
69
70
  new UpdateSettingsDiffer(),
70
71
  new ConvertOneToManyRelationDiffer(),
71
72
  new ConvertOneHasManyToManyHasManyRelationDiffer(),
73
+ new ConvertOneHasManyToOneHasOneRelationDiffer(),
72
74
  new RemoveUniqueConstraintDiffer(),
73
75
  new RemoveIndexDiffer(),
74
76
  new RemoveViewDiffer(),
@@ -2,7 +2,7 @@ import { MigrationBuilder } from '@contember/database-migrations'
2
2
  import { SchemaUpdater } from './utils/schemaUpdateUtils'
3
3
  import { Schema } from '@contember/schema'
4
4
  import { Migration } from '../Migration'
5
- import { SchemaDatabaseMetadata } from '@contember/schema-utils'
5
+ import { DatabaseMetadata } from '@contember/database'
6
6
 
7
7
  export interface ModificationDescription {
8
8
  message: string
@@ -23,7 +23,7 @@ export interface ModificationHandler<Data> {
23
23
 
24
24
  export interface ModificationHandlerCreateSqlOptions {
25
25
  systemSchema: string
26
- databaseMetadata: SchemaDatabaseMetadata
26
+ databaseMetadata: DatabaseMetadata
27
27
  invalidateDatabaseMetadata: () => void
28
28
  }
29
29
 
@@ -36,6 +36,7 @@ import { removeTargetModification } from './actions/RemoveTargetModification'
36
36
  import { updateTargetModification } from './actions/UpdateTargetModification'
37
37
  import { updateEntityOrderByModification } from './entities/UpdateEntityOrderByModification'
38
38
  import { removeIndexNamesModification } from './upgrade/RemoveIndexNamesModification'
39
+ import { convertOneHasManyToOneHasOneRelationModification } from './relations/ConvertOneHasManyToOneHasOneRelationModification'
39
40
 
40
41
 
41
42
  class ModificationHandlerFactory {
@@ -86,6 +87,7 @@ namespace ModificationHandlerFactory {
86
87
  updateValidationSchemaModification,
87
88
  patchValidationSchemaModification,
88
89
  convertOneToManyRelationModification,
90
+ convertOneHasManyToOneHasOneRelationModification,
89
91
  toggleEventLogModification,
90
92
  toggleJunctionEventLogModification,
91
93
  convertOneHasManyToManyHasManyRelationModification,
@@ -30,7 +30,14 @@ export class CreateUniqueConstraintModificationHandler implements ModificationHa
30
30
  const tableNameId = wrapIdentifier(entity.tableName)
31
31
  const columnNameIds = columns.map(wrapIdentifier)
32
32
 
33
- builder.sql(`ALTER TABLE ${tableNameId} ADD UNIQUE (${columnNameIds.join(', ')})`)
33
+ let checkModifier = ''
34
+ if (this.data.unique.timing === 'deferred') {
35
+ checkModifier = ' INITIALLY DEFERRED'
36
+ } else if (this.data.unique.timing === 'deferrable') {
37
+ checkModifier = ' DEFERRABLE'
38
+ }
39
+
40
+ builder.sql(`ALTER TABLE ${tableNameId} ADD UNIQUE (${columnNameIds.join(', ')})${checkModifier}`)
34
41
 
35
42
  invalidateDatabaseMetadata()
36
43
  }
@@ -29,7 +29,7 @@ export class RemoveUniqueConstraintModificationHandler implements ModificationHa
29
29
  model: this.schema.model,
30
30
  })
31
31
 
32
- const constraintNames = databaseMetadata.getUniqueConstraintNames({ tableName: entity.tableName, columnNames: columns })
32
+ const constraintNames = databaseMetadata.uniqueConstraints.filter({ tableName: entity.tableName, columnNames: columns }).getNames()
33
33
 
34
34
  for (const name of constraintNames) {
35
35
  builder.sql(`ALTER TABLE ${wrapIdentifier(entity.tableName)} DROP CONSTRAINT ${wrapIdentifier(name)}`)
@@ -91,15 +91,13 @@ export class RemoveUniqueConstraintDiffer implements Differ {
91
91
  createDiff(originalSchema: Schema, updatedSchema: Schema) {
92
92
  return Object.values(originalSchema.model.entities).flatMap(entity =>
93
93
  entity.unique
94
- .filter(
95
- it => {
96
- const updatedEntity = updatedSchema.model.entities[entity.name]
97
- if (!updatedEntity) {
98
- return false
99
- }
100
- return !updatedEntity.unique.find(uniq => deepEqual(uniq.fields, it.fields))
101
- },
102
- )
94
+ .filter(it => {
95
+ const updatedEntity = updatedSchema.model.entities[entity.name]
96
+ if (!updatedEntity) {
97
+ return false
98
+ }
99
+ return !updatedEntity.unique.find(uniq => deepEqual(uniq.fields, it.fields) && it.timing === uniq.timing)
100
+ })
103
101
  .map(unique =>
104
102
  removeUniqueConstraintModification.createModification({
105
103
  entityName: entity.name,
@@ -27,7 +27,7 @@ export class RemoveIndexModificationHandler implements ModificationHandler<Remov
27
27
  model: this.schema.model,
28
28
  })
29
29
 
30
- const indexNames = databaseMetadata.getIndexNames({ tableName: entity.tableName, columnNames: columns })
30
+ const indexNames = databaseMetadata.indexes.filter({ tableName: entity.tableName, columnNames: columns }).getNames()
31
31
 
32
32
  for (const name of indexNames) {
33
33
  builder.sql(`DROP INDEX ${wrapIdentifier(name)}`)
@@ -0,0 +1,145 @@
1
+ import { MigrationBuilder } from '@contember/database-migrations'
2
+ import { Model, Schema } from '@contember/schema'
3
+ import { SchemaUpdater, updateEntity, updateField, updateModel, updateSchema } from '../utils/schemaUpdateUtils'
4
+ import {
5
+ createModificationType,
6
+ Differ,
7
+ ModificationHandler,
8
+ ModificationHandlerCreateSqlOptions,
9
+ ModificationHandlerOptions,
10
+ } from '../ModificationHandler'
11
+ import { isOwningRelation } from '@contember/schema-utils'
12
+ import { updateRelations } from '../utils/diffUtils'
13
+ import { NoopModification } from '../NoopModification'
14
+ import { updateFieldNameModification } from '../fields'
15
+ import { wrapIdentifier } from '../../utils/dbHelpers'
16
+
17
+ export class ConvertOneHasManyToOneHasOneRelationModificationHandler implements ModificationHandler<ConvertOneHasManyToOneHasOneRelationModificationData> {
18
+ private subModification: ModificationHandler<any>
19
+
20
+ constructor(
21
+ private readonly data: ConvertOneHasManyToOneHasOneRelationModificationData,
22
+ private readonly schema: Schema,
23
+ private readonly options: ModificationHandlerOptions,
24
+ ) {
25
+ const { relation } = this.getRelation()
26
+ this.subModification = data.newInverseSideFieldName && relation.inversedBy ?
27
+ updateFieldNameModification.createHandler(
28
+ {
29
+ entityName: relation.target,
30
+ fieldName: relation.inversedBy,
31
+ newFieldName: data.newInverseSideFieldName,
32
+ },
33
+ schema,
34
+ this.options,
35
+ )
36
+ : new NoopModification()
37
+ }
38
+
39
+ public createSql(builder: MigrationBuilder, options: ModificationHandlerCreateSqlOptions): void {
40
+ const { entity, relation } = this.getRelation()
41
+ const columnName = relation.joiningColumn.columnName
42
+
43
+ const tableNameId = wrapIdentifier(entity.tableName)
44
+ const columnNameId = wrapIdentifier(columnName)
45
+
46
+ const uniqueConstraintNames = options.databaseMetadata.indexes.filter({
47
+ tableName: entity.tableName,
48
+ columnNames: [columnName],
49
+ }).getNames()
50
+
51
+ for (const name of uniqueConstraintNames) {
52
+ builder.sql(`DROP INDEX ${wrapIdentifier(name)}`)
53
+ }
54
+ builder.sql(`ALTER TABLE ${tableNameId} ADD UNIQUE (${columnNameId})`)
55
+
56
+ options.invalidateDatabaseMetadata()
57
+
58
+ this.subModification.createSql(builder, options)
59
+ }
60
+
61
+ public getSchemaUpdater(): SchemaUpdater {
62
+ const { relation } = this.getRelation()
63
+ const { entityName, fieldName } = this.data
64
+ const inverseFieldName = this.data.newInverseSideFieldName ?? relation.inversedBy
65
+ return updateSchema(
66
+ updateModel(
67
+ updateEntity(
68
+ entityName,
69
+ updateField<Model.ManyHasOneRelation, Model.OneHasOneOwningRelation>(
70
+ fieldName,
71
+ ({ field: { type, ...field } }) => ({
72
+ type: Model.RelationType.OneHasOne,
73
+ ...field,
74
+ }),
75
+ ),
76
+ ),
77
+ ),
78
+ this.subModification.getSchemaUpdater(),
79
+ inverseFieldName ?
80
+ updateModel(
81
+ updateEntity(
82
+ relation.target,
83
+ updateField<Model.OneHasManyRelation, Model.OneHasOneInverseRelation>(
84
+ inverseFieldName,
85
+ ({ field: { type, ...field } }) => ({
86
+ type: Model.RelationType.OneHasOne,
87
+ nullable: true,
88
+ ...field,
89
+ }),
90
+ ),
91
+ ),
92
+ ) : undefined,
93
+ )
94
+ }
95
+
96
+ describe() {
97
+ return {
98
+ message: `Converts ManyHasOne relation to OneHasOne on ${this.data.entityName}.${this.data.fieldName}`,
99
+ failureWarning: 'Make sure no conflicting rows exists, otherwise this may fail in runtime.',
100
+ }
101
+ }
102
+
103
+ private getRelation() {
104
+ const entity = this.schema.model.entities[this.data.entityName]
105
+ const relation = entity.fields[this.data.fieldName]
106
+ if (relation.type !== Model.RelationType.ManyHasOne) {
107
+ throw new Error()
108
+ }
109
+ return { entity, relation }
110
+ }
111
+ }
112
+
113
+ export interface ConvertOneHasManyToOneHasOneRelationModificationData {
114
+ entityName: string
115
+ fieldName: string
116
+ newInverseSideFieldName?: string
117
+ }
118
+
119
+ export const convertOneHasManyToOneHasOneRelationModification = createModificationType({
120
+ id: 'convertOneHasManyToOneHasOneRelation',
121
+ handler: ConvertOneHasManyToOneHasOneRelationModificationHandler,
122
+ })
123
+
124
+ export class ConvertOneHasManyToOneHasOneRelationDiffer implements Differ {
125
+ createDiff(originalSchema: Schema, updatedSchema: Schema) {
126
+ return updateRelations(originalSchema, updatedSchema, ({ originalRelation, updatedRelation, updatedEntity }) => {
127
+ if (
128
+ isOwningRelation(originalRelation) &&
129
+ isOwningRelation(updatedRelation) &&
130
+ originalRelation.type === Model.RelationType.ManyHasOne &&
131
+ updatedRelation.type === Model.RelationType.OneHasOne
132
+ ) {
133
+ const isInverseSideRenamed = originalRelation.inversedBy && updatedRelation.inversedBy && originalRelation.inversedBy !== updatedRelation.inversedBy
134
+ return convertOneHasManyToOneHasOneRelationModification.createModification({
135
+ entityName: updatedEntity.name,
136
+ fieldName: updatedRelation.name,
137
+ ...(isInverseSideRenamed ? {
138
+ newInverseSideFieldName: updatedRelation.inversedBy,
139
+ } : {}),
140
+ })
141
+ }
142
+ return undefined
143
+ })
144
+ }
145
+ }
@@ -44,10 +44,11 @@ export class ConvertOneToManyRelationModificationHandler implements Modification
44
44
  const columnNameId = wrapIdentifier(columnName)
45
45
  builder.sql(`CREATE INDEX ON ${tableNameId} (${columnNameId})`)
46
46
 
47
- const uniqueConstraintNames = options.databaseMetadata.getUniqueConstraintNames({
47
+ const uniqueConstraintNames = options.databaseMetadata.uniqueConstraints.filter({
48
48
  tableName: entity.tableName,
49
- columnNames: [relation.joiningColumn.columnName],
50
- })
49
+ columnNames: [columnName],
50
+ }).getNames()
51
+
51
52
  for (const name of uniqueConstraintNames) {
52
53
  builder.sql(`ALTER TABLE ${wrapIdentifier(entity.tableName)} DROP CONSTRAINT ${wrapIdentifier(name)}`)
53
54
  }
@@ -60,6 +61,7 @@ export class ConvertOneToManyRelationModificationHandler implements Modification
60
61
  const { relation } = this.getRelation()
61
62
  const { entityName, fieldName } = this.data
62
63
 
64
+ const inverseFieldName = this.data.newInverseSideFieldName ?? relation.inversedBy
63
65
  return updateSchema(
64
66
  updateModel(
65
67
  updateEntity(
@@ -74,12 +76,12 @@ export class ConvertOneToManyRelationModificationHandler implements Modification
74
76
  ),
75
77
  ),
76
78
  this.subModification.getSchemaUpdater(),
77
- this.data.newInverseSideFieldName ?
79
+ inverseFieldName ?
78
80
  updateModel(
79
81
  updateEntity(
80
82
  relation.target,
81
83
  updateField<Model.OneHasOneInverseRelation, Model.OneHasManyRelation>(
82
- this.data.newInverseSideFieldName,
84
+ inverseFieldName,
83
85
  ({ field: { type, nullable, ...field } }) => ({
84
86
  type: Model.RelationType.OneHasMany,
85
87
  ...field,
@@ -1,7 +1,7 @@
1
1
  import { MigrationBuilder } from '@contember/database-migrations'
2
2
  import { Model } from '@contember/schema'
3
3
  import { wrapIdentifier } from '../../utils/dbHelpers'
4
- import { SchemaDatabaseMetadata } from '@contember/schema-utils'
4
+ import { DatabaseMetadata } from '@contember/database'
5
5
 
6
6
  export const addForeignKeyConstraint = ({ builder, entity, relation, targetEntity, recreate = false, databaseMetadata, invalidateDatabaseMetadata }: {
7
7
  recreate?: boolean
@@ -9,18 +9,18 @@ export const addForeignKeyConstraint = ({ builder, entity, relation, targetEntit
9
9
  entity: Model.Entity
10
10
  targetEntity: Model.Entity
11
11
  relation: Model.OneHasOneOwningRelation | Model.ManyHasOneRelation
12
- databaseMetadata: SchemaDatabaseMetadata
12
+ databaseMetadata: DatabaseMetadata
13
13
  invalidateDatabaseMetadata: () => void
14
14
  }) => {
15
15
  if (recreate) {
16
- const fkNames = databaseMetadata.getForeignKeyConstraintNames(
16
+ const fkNames = databaseMetadata.foreignKeys.filter(
17
17
  {
18
18
  fromTable: entity.tableName,
19
19
  fromColumn: relation.joiningColumn.columnName,
20
20
  toTable: targetEntity.tableName,
21
21
  toColumn: targetEntity.primaryColumn,
22
22
  },
23
- )
23
+ ).getNames()
24
24
  for (const name of fkNames) {
25
25
  builder.sql(`ALTER TABLE ${wrapIdentifier(entity.tableName)} DROP CONSTRAINT ${wrapIdentifier(name)}`)
26
26
  }
package/src/tsconfig.json CHANGED
@@ -7,6 +7,7 @@
7
7
  },
8
8
  "references": [
9
9
  { "path": "../../database-migrations/src" },
10
+ { "path": "../../database/src" },
10
11
  { "path": "../../engine-common/src" },
11
12
  { "path": "../../schema/src" },
12
13
  { "path": "../../schema-utils/src" }
@@ -0,0 +1,48 @@
1
+ import { testMigrations } from '../../src/tests'
2
+ import { SQL } from '../../src/tags'
3
+ import { createSchema, SchemaDefinition as def } from '@contember/schema-definition'
4
+ import { createDatabaseMetadata } from '@contember/database'
5
+
6
+ namespace ConvertMHOtoOHOSchemaOrig {
7
+ export class Article {
8
+ title = def.stringColumn()
9
+ reviews = def.oneHasMany(ArticleReview, 'article')
10
+ }
11
+
12
+ export class ArticleReview {
13
+ article = def.manyHasOne(Article, 'reviews')
14
+ }
15
+ }
16
+
17
+ namespace ConvertMHOtoOHOSchemaUpdated {
18
+ export class Article {
19
+ title = def.stringColumn()
20
+ review = def.oneHasOneInverse(ArticleReview, 'article')
21
+ }
22
+
23
+ export class ArticleReview {
24
+ article = def.oneHasOne(Article, 'review')
25
+ }
26
+ }
27
+
28
+
29
+ testMigrations('convert one has many to one has one', {
30
+ original: createSchema(ConvertMHOtoOHOSchemaOrig),
31
+ updated: createSchema(ConvertMHOtoOHOSchemaUpdated),
32
+ diff: [{
33
+ entityName: 'ArticleReview',
34
+ fieldName: 'article',
35
+ modification: 'convertOneHasManyToOneHasOneRelation',
36
+ newInverseSideFieldName: 'review',
37
+ }],
38
+ sql: SQL`DROP INDEX "article_review_article_id_idx"; ALTER TABLE "article_review" ADD UNIQUE ("article_id");`,
39
+ databaseMetadata: createDatabaseMetadata({
40
+ foreignKeys: [],
41
+ indexes: [{
42
+ indexName: 'article_review_article_id_idx',
43
+ columnNames: ['article_id'],
44
+ tableName: 'article_review',
45
+ }],
46
+ uniqueConstraints: [],
47
+ }),
48
+ })
@@ -2,6 +2,7 @@ import { testMigrations } from '../../src/tests'
2
2
  import { SchemaBuilder } from '@contember/schema-definition'
3
3
  import { Model } from '@contember/schema'
4
4
  import { SQL } from '../../src/tags'
5
+ import { createDatabaseMetadata } from '@contember/database'
5
6
 
6
7
  testMigrations('convert one has one to many has one relation without inverse side', {
7
8
  original: {
@@ -31,6 +32,17 @@ testMigrations('convert one has one to many has one relation without inverse sid
31
32
  CREATE INDEX ON "post" ("image_id");
32
33
  ALTER TABLE "post" DROP CONSTRAINT "uniq_post_image_id";
33
34
  `,
35
+ databaseMetadata: createDatabaseMetadata({
36
+ foreignKeys: [],
37
+ indexes: [],
38
+ uniqueConstraints: [{
39
+ constraintName: 'uniq_post_image_id',
40
+ columnNames: ['image_id'],
41
+ tableName: 'post',
42
+ deferred: false,
43
+ deferrable: false,
44
+ }],
45
+ }),
34
46
  })
35
47
 
36
48
 
@@ -63,5 +75,58 @@ testMigrations('convert one has one to many has one relation with inverse side',
63
75
  CREATE INDEX ON "post" ("image_id");
64
76
  ALTER TABLE "post" DROP CONSTRAINT "uniq_post_image_id";
65
77
  `,
78
+ databaseMetadata: createDatabaseMetadata({
79
+ foreignKeys: [],
80
+ indexes: [],
81
+ uniqueConstraints: [{
82
+ constraintName: 'uniq_post_image_id',
83
+ columnNames: ['image_id'],
84
+ tableName: 'post',
85
+ deferred: false,
86
+ deferrable: false,
87
+ }],
88
+ }),
89
+ })
90
+
91
+ testMigrations('convert one has one to many has one relation with inverse side, but not renamed', {
92
+ original: {
93
+ model: new SchemaBuilder()
94
+ .entity('Post', entity =>
95
+ entity.oneHasOne('image', rel => rel.target('Image').inversedBy('posts')),
96
+ )
97
+ .entity('Image', e => e.column('url', c => c.type(Model.ColumnType.String)))
98
+ .buildSchema(),
99
+ },
100
+ updated: {
101
+ model: new SchemaBuilder()
102
+ .entity('Post', entity =>
103
+ entity.manyHasOne('image', rel => rel.target('Image').inversedBy('posts')),
104
+ )
105
+ .entity('Image', e => e.column('url', c => c.type(Model.ColumnType.String)))
106
+ .buildSchema(),
107
+ },
108
+ diff: [
109
+ {
110
+ modification: 'convertOneToManyRelation',
111
+ entityName: 'Post',
112
+ fieldName: 'image',
113
+ },
114
+ ],
115
+ sql: SQL`
116
+ CREATE INDEX ON "post" ("image_id");
117
+ ALTER TABLE "post"
118
+ DROP CONSTRAINT "uniq_post_image_id";
119
+ `,
120
+ databaseMetadata: createDatabaseMetadata({
121
+ foreignKeys: [],
122
+ indexes: [],
123
+ uniqueConstraints: [{
124
+ constraintName: 'uniq_post_image_id',
125
+ columnNames: ['image_id'],
126
+ tableName: 'post',
127
+ deferred: false,
128
+ deferrable: false,
129
+ }],
130
+ }),
66
131
  })
67
132
 
@@ -1,6 +1,7 @@
1
1
  import { testMigrations } from '../../src/tests'
2
2
  import { SQL } from '../../src/tags'
3
3
  import { createSchema, SchemaDefinition as def } from '@contember/schema-definition'
4
+ import { createDatabaseMetadata } from '@contember/database'
4
5
 
5
6
  namespace SchemaWithoutIndex {
6
7
  export class Article {
@@ -41,4 +42,13 @@ testMigrations('drop index', {
41
42
  },
42
43
  ],
43
44
  sql: SQL`DROP INDEX "idx_article_title";`,
45
+ databaseMetadata: createDatabaseMetadata({
46
+ foreignKeys: [],
47
+ indexes: [{
48
+ tableName: 'article',
49
+ columnNames: ['title'],
50
+ indexName: 'idx_article_title',
51
+ }],
52
+ uniqueConstraints: [],
53
+ }),
44
54
  })
@@ -2,6 +2,7 @@ import { testMigrations } from '../../src/tests'
2
2
  import { Model } from '@contember/schema'
3
3
  import { SQL } from '../../src/tags'
4
4
  import { SchemaBuilder } from '@contember/schema-definition'
5
+ import { createDatabaseMetadata, ForeignKeyDeleteAction } from '@contember/database'
5
6
 
6
7
  testMigrations('create inverse side relation (post with locales)', {
7
8
  original: {
@@ -65,4 +66,20 @@ testMigrations('create inverse side relation together with changing onDelete beh
65
66
  },
66
67
  ],
67
68
  sql: SQL`ALTER TABLE "post_locale" DROP CONSTRAINT "fk_post_locale_post_id_post_id"; ALTER TABLE "post_locale" ADD FOREIGN KEY ("post_id") REFERENCES "post"("id") ON DELETE CASCADE DEFERRABLE INITIALLY IMMEDIATE;`,
69
+ databaseMetadata: createDatabaseMetadata({
70
+ foreignKeys: [
71
+ {
72
+ constraintName: 'fk_post_locale_post_id_post_id',
73
+ deleteAction: ForeignKeyDeleteAction.cascade,
74
+ fromColumn: 'post_id',
75
+ fromTable: 'post_locale',
76
+ toColumn: 'id',
77
+ toTable: 'post',
78
+ deferred: false,
79
+ deferrable: false,
80
+ },
81
+ ],
82
+ indexes: [],
83
+ uniqueConstraints: [],
84
+ }),
68
85
  })