@contember/migrations-client 2.1.0-rc.3 → 2.2.0-alpha.10

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 (137) hide show
  1. package/dist/development/index.cjs +4 -0
  2. package/dist/development/index.cjs.map +1 -1
  3. package/dist/development/index.js +4 -0
  4. package/dist/development/index.js.map +1 -1
  5. package/dist/development/src/JsLoader.cjs.map +1 -1
  6. package/dist/development/src/JsLoader.js.map +1 -1
  7. package/dist/development/src/JsonLoader.cjs.map +1 -1
  8. package/dist/development/src/JsonLoader.js.map +1 -1
  9. package/dist/development/src/MigrationCreator.cjs +3 -3
  10. package/dist/development/src/MigrationCreator.cjs.map +1 -1
  11. package/dist/development/src/MigrationCreator.js +3 -3
  12. package/dist/development/src/MigrationCreator.js.map +1 -1
  13. package/dist/development/src/MigrationExecuteHelper.cjs +14 -5
  14. package/dist/development/src/MigrationExecuteHelper.cjs.map +1 -1
  15. package/dist/development/src/MigrationExecuteHelper.js +14 -5
  16. package/dist/development/src/MigrationExecuteHelper.js.map +1 -1
  17. package/dist/development/src/MigrationFile.cjs.map +1 -1
  18. package/dist/development/src/MigrationFile.js.map +1 -1
  19. package/dist/development/src/MigrationFilesManager.cjs +11 -11
  20. package/dist/development/src/MigrationFilesManager.cjs.map +1 -1
  21. package/dist/development/src/MigrationFilesManager.js.map +1 -1
  22. package/dist/development/src/MigrationParser.cjs.map +1 -1
  23. package/dist/development/src/MigrationParser.js.map +1 -1
  24. package/dist/development/src/MigrationsResolver.cjs.map +1 -1
  25. package/dist/development/src/MigrationsResolver.js.map +1 -1
  26. package/dist/development/src/SchemaStateManager.cjs +82 -0
  27. package/dist/development/src/SchemaStateManager.cjs.map +1 -0
  28. package/dist/development/src/SchemaStateManager.js +64 -0
  29. package/dist/development/src/SchemaStateManager.js.map +1 -0
  30. package/dist/development/src/SchemaVersionBuilder.cjs +28 -4
  31. package/dist/development/src/SchemaVersionBuilder.cjs.map +1 -1
  32. package/dist/development/src/SchemaVersionBuilder.js +28 -4
  33. package/dist/development/src/SchemaVersionBuilder.js.map +1 -1
  34. package/dist/development/src/SnapshotManager.cjs +46 -0
  35. package/dist/development/src/SnapshotManager.cjs.map +1 -0
  36. package/dist/development/src/SnapshotManager.js +29 -0
  37. package/dist/development/src/SnapshotManager.js.map +1 -0
  38. package/dist/development/src/SystemClient.cjs +29 -4
  39. package/dist/development/src/SystemClient.cjs.map +1 -1
  40. package/dist/development/src/SystemClient.js +29 -4
  41. package/dist/development/src/SystemClient.js.map +1 -1
  42. package/dist/development/src/migrations.cjs.map +1 -1
  43. package/dist/development/src/migrations.js.map +1 -1
  44. package/dist/production/index.cjs +4 -0
  45. package/dist/production/index.cjs.map +1 -1
  46. package/dist/production/index.js +4 -0
  47. package/dist/production/index.js.map +1 -1
  48. package/dist/production/src/JsLoader.cjs.map +1 -1
  49. package/dist/production/src/JsLoader.js.map +1 -1
  50. package/dist/production/src/JsonLoader.cjs.map +1 -1
  51. package/dist/production/src/JsonLoader.js.map +1 -1
  52. package/dist/production/src/MigrationCreator.cjs +3 -3
  53. package/dist/production/src/MigrationCreator.cjs.map +1 -1
  54. package/dist/production/src/MigrationCreator.js +3 -3
  55. package/dist/production/src/MigrationCreator.js.map +1 -1
  56. package/dist/production/src/MigrationExecuteHelper.cjs +14 -5
  57. package/dist/production/src/MigrationExecuteHelper.cjs.map +1 -1
  58. package/dist/production/src/MigrationExecuteHelper.js +14 -5
  59. package/dist/production/src/MigrationExecuteHelper.js.map +1 -1
  60. package/dist/production/src/MigrationFile.cjs.map +1 -1
  61. package/dist/production/src/MigrationFile.js.map +1 -1
  62. package/dist/production/src/MigrationFilesManager.cjs +11 -11
  63. package/dist/production/src/MigrationFilesManager.cjs.map +1 -1
  64. package/dist/production/src/MigrationFilesManager.js.map +1 -1
  65. package/dist/production/src/MigrationParser.cjs.map +1 -1
  66. package/dist/production/src/MigrationParser.js.map +1 -1
  67. package/dist/production/src/MigrationsResolver.cjs.map +1 -1
  68. package/dist/production/src/MigrationsResolver.js.map +1 -1
  69. package/dist/production/src/SchemaStateManager.cjs +82 -0
  70. package/dist/production/src/SchemaStateManager.cjs.map +1 -0
  71. package/dist/production/src/SchemaStateManager.js +64 -0
  72. package/dist/production/src/SchemaStateManager.js.map +1 -0
  73. package/dist/production/src/SchemaVersionBuilder.cjs +28 -4
  74. package/dist/production/src/SchemaVersionBuilder.cjs.map +1 -1
  75. package/dist/production/src/SchemaVersionBuilder.js +28 -4
  76. package/dist/production/src/SchemaVersionBuilder.js.map +1 -1
  77. package/dist/production/src/SnapshotManager.cjs +46 -0
  78. package/dist/production/src/SnapshotManager.cjs.map +1 -0
  79. package/dist/production/src/SnapshotManager.js +29 -0
  80. package/dist/production/src/SnapshotManager.js.map +1 -0
  81. package/dist/production/src/SystemClient.cjs +29 -4
  82. package/dist/production/src/SystemClient.cjs.map +1 -1
  83. package/dist/production/src/SystemClient.js +29 -4
  84. package/dist/production/src/SystemClient.js.map +1 -1
  85. package/dist/production/src/migrations.cjs.map +1 -1
  86. package/dist/production/src/migrations.js.map +1 -1
  87. package/dist/types/JsLoader.d.ts +3 -3
  88. package/dist/types/JsLoader.d.ts.map +1 -1
  89. package/dist/types/JsonLoader.d.ts +4 -4
  90. package/dist/types/JsonLoader.d.ts.map +1 -1
  91. package/dist/types/MigrationCreator.d.ts +4 -2
  92. package/dist/types/MigrationCreator.d.ts.map +1 -1
  93. package/dist/types/MigrationExecuteHelper.d.ts +6 -4
  94. package/dist/types/MigrationExecuteHelper.d.ts.map +1 -1
  95. package/dist/types/MigrationFile.d.ts +2 -2
  96. package/dist/types/MigrationFile.d.ts.map +1 -1
  97. package/dist/types/MigrationFileLoader.d.ts +1 -1
  98. package/dist/types/MigrationFileLoader.d.ts.map +1 -1
  99. package/dist/types/MigrationFilesManager.d.ts +2 -2
  100. package/dist/types/MigrationFilesManager.d.ts.map +1 -1
  101. package/dist/types/MigrationParser.d.ts +2 -2
  102. package/dist/types/MigrationParser.d.ts.map +1 -1
  103. package/dist/types/MigrationsResolver.d.ts +2 -2
  104. package/dist/types/MigrationsResolver.d.ts.map +1 -1
  105. package/dist/types/SchemaStateManager.d.ts +19 -0
  106. package/dist/types/SchemaStateManager.d.ts.map +1 -0
  107. package/dist/types/SchemaVersionBuilder.d.ts +10 -2
  108. package/dist/types/SchemaVersionBuilder.d.ts.map +1 -1
  109. package/dist/types/SnapshotManager.d.ts +31 -0
  110. package/dist/types/SnapshotManager.d.ts.map +1 -0
  111. package/dist/types/SystemClient.d.ts +11 -3
  112. package/dist/types/SystemClient.d.ts.map +1 -1
  113. package/dist/types/index.d.ts +14 -12
  114. package/dist/types/index.d.ts.map +1 -1
  115. package/dist/types/migrations.d.ts +1 -1
  116. package/dist/types/migrations.d.ts.map +1 -1
  117. package/dist/types/tsconfig.tsbuildinfo +1 -1
  118. package/package.json +6 -6
  119. package/src/JsLoader.ts +3 -3
  120. package/src/JsonLoader.ts +3 -3
  121. package/src/MigrationCreator.ts +8 -5
  122. package/src/MigrationExecuteHelper.ts +19 -8
  123. package/src/MigrationFile.ts +2 -2
  124. package/src/MigrationFileLoader.ts +1 -1
  125. package/src/MigrationFilesManager.ts +2 -2
  126. package/src/MigrationParser.ts +2 -2
  127. package/src/MigrationsResolver.ts +2 -2
  128. package/src/SchemaStateManager.ts +75 -0
  129. package/src/SchemaVersionBuilder.ts +35 -10
  130. package/src/SnapshotManager.ts +52 -0
  131. package/src/SystemClient.ts +41 -4
  132. package/src/index.ts +14 -12
  133. package/src/migrations.ts +1 -1
  134. package/tests/cases/unit/MigrationCreator.test.ts +50 -0
  135. package/tests/cases/unit/SchemaStateManager.test.ts +96 -0
  136. package/tests/cases/unit/SchemaVersionBuilder.test.ts +125 -0
  137. package/tests/cases/unit/SnapshotManager.test.ts +64 -0
@@ -0,0 +1,125 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
2
+ import * as fs from 'node:fs/promises'
3
+ import * as os from 'node:os'
4
+ import * as path from 'node:path'
5
+ import {
6
+ JsonLoader,
7
+ MigrationFilesManager,
8
+ MigrationParser,
9
+ MigrationsResolver,
10
+ SchemaStateManager,
11
+ SchemaVersionBuilder,
12
+ } from '../../../src/index.js'
13
+ import { Migration, ModificationHandlerFactory, SchemaMigrator } from '@contember/schema-migrations'
14
+ import { emptySchema } from '@contember/schema-utils'
15
+ import { Schema } from '@contember/schema'
16
+
17
+ const schemaMigrator = new SchemaMigrator(new ModificationHandlerFactory(ModificationHandlerFactory.defaultFactoryMap))
18
+
19
+ // No migrations on disk — buildSchemaAdvanced reduces to the initial (empty) schema, isolating the state-merge behavior.
20
+ const emptyResolver = { getSchemaMigrations: async () => [] } as unknown as MigrationsResolver
21
+
22
+ const stateAcl: Schema['acl'] = { roles: { admin: { variables: {}, stages: '*', entities: {} } } }
23
+
24
+ describe('SchemaVersionBuilder schema state merge', () => {
25
+ let baseDir: string
26
+ let stateDir: string
27
+ let stateManager: SchemaStateManager
28
+
29
+ beforeEach(async () => {
30
+ baseDir = await fs.mkdtemp(path.join(os.tmpdir(), 'contember-svb-'))
31
+ stateDir = path.join(baseDir, 'state')
32
+ stateManager = new SchemaStateManager(stateDir)
33
+ })
34
+
35
+ afterEach(async () => {
36
+ await fs.rm(baseDir, { recursive: true, force: true })
37
+ })
38
+
39
+ test('buildSchema does not merge state when state mode is off', async () => {
40
+ const builder = new SchemaVersionBuilder(emptyResolver, schemaMigrator, stateManager)
41
+
42
+ const schema = await builder.buildSchema()
43
+
44
+ expect(schema.acl).toStrictEqual(emptySchema.acl)
45
+ })
46
+
47
+ test('buildSchema merges state from disk when state mode is on', async () => {
48
+ await stateManager.extractState({ ...emptySchema, acl: stateAcl })
49
+ const builder = new SchemaVersionBuilder(emptyResolver, schemaMigrator, stateManager)
50
+
51
+ const schema = await builder.buildSchema()
52
+
53
+ expect(schema.acl).toStrictEqual(stateAcl)
54
+ })
55
+
56
+ test('buildSchema with a target version skips the state merge', async () => {
57
+ await stateManager.extractState({ ...emptySchema, acl: stateAcl })
58
+ const builder = new SchemaVersionBuilder(emptyResolver, schemaMigrator, stateManager)
59
+
60
+ // The merge is guarded by `!targetVersion`, so requesting a historical version must not pull in current state.
61
+ const schema = await builder.buildSchema('2024-01-01-000000')
62
+
63
+ expect(schema.acl).toStrictEqual(emptySchema.acl)
64
+ })
65
+ })
66
+
67
+ class CountingSchemaMigrator extends SchemaMigrator {
68
+ public appliedMigrations = 0
69
+
70
+ constructor() {
71
+ super(new ModificationHandlerFactory(ModificationHandlerFactory.defaultFactoryMap))
72
+ }
73
+
74
+ public override applyModifications(schema: Schema, diff: readonly Migration.Modification[], formatVersion: number): Schema {
75
+ this.appliedMigrations++
76
+ return super.applyModifications(schema, diff, formatVersion)
77
+ }
78
+ }
79
+
80
+ describe('SchemaVersionBuilder buildSchemaUntil', () => {
81
+ let migrationsDir: string
82
+ let filesManager: MigrationFilesManager
83
+ let migrator: CountingSchemaMigrator
84
+ let builder: SchemaVersionBuilder
85
+
86
+ const createEnumMigration = (version: string, enumName: string) =>
87
+ filesManager.createFile(
88
+ JSON.stringify({ formatVersion: 6, modifications: [{ modification: 'createEnum', enumName, values: ['a'] }] }),
89
+ `${version}-${enumName}`,
90
+ )
91
+ const enumNames = (schema: Schema) => Object.keys(schema.model.enums)
92
+
93
+ beforeEach(async () => {
94
+ migrationsDir = await fs.mkdtemp(path.join(os.tmpdir(), 'contember-svb-until-'))
95
+ filesManager = new MigrationFilesManager(migrationsDir, { json: new JsonLoader(new MigrationParser()) })
96
+ migrator = new CountingSchemaMigrator()
97
+ builder = new SchemaVersionBuilder(new MigrationsResolver(filesManager), migrator, new SchemaStateManager(path.join(migrationsDir, 'state')))
98
+ await createEnumMigration('2024-01-01-000000', 'first')
99
+ await createEnumMigration('2024-01-02-000000', 'second')
100
+ await createEnumMigration('2024-01-03-000000', 'third')
101
+ })
102
+
103
+ afterEach(async () => {
104
+ await fs.rm(migrationsDir, { recursive: true, force: true })
105
+ })
106
+
107
+ test('continues from the previous build for an ascending target', async () => {
108
+ expect(enumNames(await builder.buildSchemaUntil('2024-01-02-000000'))).toStrictEqual(['first'])
109
+ expect(enumNames(await builder.buildSchemaUntil('2024-01-04-000000'))).toStrictEqual(['first', 'second', 'third'])
110
+ expect(migrator.appliedMigrations).toBe(3)
111
+ })
112
+
113
+ test('rebuilds from scratch for a descending target', async () => {
114
+ await builder.buildSchemaUntil('2024-01-04-000000')
115
+
116
+ expect(enumNames(await builder.buildSchemaUntil('2024-01-02-000000'))).toStrictEqual(['first'])
117
+ })
118
+
119
+ test('rebuilds from scratch when the migration files change', async () => {
120
+ await builder.buildSchemaUntil('2024-01-03-000000')
121
+ await createEnumMigration('2024-01-01-120000', 'inserted')
122
+
123
+ expect(enumNames(await builder.buildSchemaUntil('2024-01-04-000000'))).toStrictEqual(['first', 'inserted', 'second', 'third'])
124
+ })
125
+ })
@@ -0,0 +1,64 @@
1
+ import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
2
+ import * as fs from 'node:fs/promises'
3
+ import * as os from 'node:os'
4
+ import * as path from 'node:path'
5
+ import { SnapshotFile, SnapshotManager } from '../../../src/index.js'
6
+
7
+ const sampleSnapshot: SnapshotFile = {
8
+ version: '2024-01-02-120000',
9
+ stateMode: true,
10
+ snapshot: {
11
+ formatVersion: 6,
12
+ modifications: [{ modification: 'createEntity', entity: { name: 'Foo' } } as any],
13
+ },
14
+ covers: [
15
+ { version: '2024-01-01-120000', name: '2024-01-01-120000-init', type: 'schema', checksum: 'abc' },
16
+ { version: '2024-01-02-120000', name: '2024-01-02-120000-seed', type: 'content', checksum: null },
17
+ ],
18
+ contentMigrations: ['2024-01-02-120000'],
19
+ }
20
+
21
+ describe('SnapshotManager', () => {
22
+ let baseDir: string
23
+ let snapshotPath: string
24
+ let manager: SnapshotManager
25
+
26
+ beforeEach(async () => {
27
+ baseDir = await fs.mkdtemp(path.join(os.tmpdir(), 'contember-snapshot-'))
28
+ snapshotPath = path.join(baseDir, 'snapshot.json')
29
+ manager = new SnapshotManager(snapshotPath)
30
+ })
31
+
32
+ afterEach(async () => {
33
+ await fs.rm(baseDir, { recursive: true, force: true })
34
+ })
35
+
36
+ test('exists is false when the snapshot file is absent', async () => {
37
+ expect(await manager.exists()).toBe(false)
38
+ })
39
+
40
+ test('exists is false when the path is a directory', async () => {
41
+ await fs.mkdir(snapshotPath)
42
+ expect(await manager.exists()).toBe(false)
43
+ })
44
+
45
+ test('write then read round-trips the snapshot', async () => {
46
+ await manager.write(sampleSnapshot)
47
+
48
+ expect(await manager.exists()).toBe(true)
49
+ expect(await manager.read()).toStrictEqual(sampleSnapshot)
50
+ })
51
+
52
+ test('write produces tab-indented JSON with a trailing newline', async () => {
53
+ await manager.write(sampleSnapshot)
54
+
55
+ const content = await fs.readFile(snapshotPath, 'utf8')
56
+ expect(content.endsWith('}\n')).toBe(true)
57
+ expect(content).toContain('\n\t"version"')
58
+ })
59
+
60
+ test('read throws a descriptive error for malformed JSON', async () => {
61
+ await fs.writeFile(snapshotPath, '{ not json')
62
+ await expect(manager.read()).rejects.toThrow(/Failed to read snapshot file/)
63
+ })
64
+ })