@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.
- package/dist/development/index.cjs +4 -0
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +4 -0
- package/dist/development/index.js.map +1 -1
- package/dist/development/src/JsLoader.cjs.map +1 -1
- package/dist/development/src/JsLoader.js.map +1 -1
- package/dist/development/src/JsonLoader.cjs.map +1 -1
- package/dist/development/src/JsonLoader.js.map +1 -1
- package/dist/development/src/MigrationCreator.cjs +3 -3
- package/dist/development/src/MigrationCreator.cjs.map +1 -1
- package/dist/development/src/MigrationCreator.js +3 -3
- package/dist/development/src/MigrationCreator.js.map +1 -1
- package/dist/development/src/MigrationExecuteHelper.cjs +14 -5
- package/dist/development/src/MigrationExecuteHelper.cjs.map +1 -1
- package/dist/development/src/MigrationExecuteHelper.js +14 -5
- package/dist/development/src/MigrationExecuteHelper.js.map +1 -1
- package/dist/development/src/MigrationFile.cjs.map +1 -1
- package/dist/development/src/MigrationFile.js.map +1 -1
- package/dist/development/src/MigrationFilesManager.cjs +11 -11
- package/dist/development/src/MigrationFilesManager.cjs.map +1 -1
- package/dist/development/src/MigrationFilesManager.js.map +1 -1
- package/dist/development/src/MigrationParser.cjs.map +1 -1
- package/dist/development/src/MigrationParser.js.map +1 -1
- package/dist/development/src/MigrationsResolver.cjs.map +1 -1
- package/dist/development/src/MigrationsResolver.js.map +1 -1
- package/dist/development/src/SchemaStateManager.cjs +82 -0
- package/dist/development/src/SchemaStateManager.cjs.map +1 -0
- package/dist/development/src/SchemaStateManager.js +64 -0
- package/dist/development/src/SchemaStateManager.js.map +1 -0
- package/dist/development/src/SchemaVersionBuilder.cjs +28 -4
- package/dist/development/src/SchemaVersionBuilder.cjs.map +1 -1
- package/dist/development/src/SchemaVersionBuilder.js +28 -4
- package/dist/development/src/SchemaVersionBuilder.js.map +1 -1
- package/dist/development/src/SnapshotManager.cjs +46 -0
- package/dist/development/src/SnapshotManager.cjs.map +1 -0
- package/dist/development/src/SnapshotManager.js +29 -0
- package/dist/development/src/SnapshotManager.js.map +1 -0
- package/dist/development/src/SystemClient.cjs +29 -4
- package/dist/development/src/SystemClient.cjs.map +1 -1
- package/dist/development/src/SystemClient.js +29 -4
- package/dist/development/src/SystemClient.js.map +1 -1
- package/dist/development/src/migrations.cjs.map +1 -1
- package/dist/development/src/migrations.js.map +1 -1
- package/dist/production/index.cjs +4 -0
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.js +4 -0
- package/dist/production/index.js.map +1 -1
- package/dist/production/src/JsLoader.cjs.map +1 -1
- package/dist/production/src/JsLoader.js.map +1 -1
- package/dist/production/src/JsonLoader.cjs.map +1 -1
- package/dist/production/src/JsonLoader.js.map +1 -1
- package/dist/production/src/MigrationCreator.cjs +3 -3
- package/dist/production/src/MigrationCreator.cjs.map +1 -1
- package/dist/production/src/MigrationCreator.js +3 -3
- package/dist/production/src/MigrationCreator.js.map +1 -1
- package/dist/production/src/MigrationExecuteHelper.cjs +14 -5
- package/dist/production/src/MigrationExecuteHelper.cjs.map +1 -1
- package/dist/production/src/MigrationExecuteHelper.js +14 -5
- package/dist/production/src/MigrationExecuteHelper.js.map +1 -1
- package/dist/production/src/MigrationFile.cjs.map +1 -1
- package/dist/production/src/MigrationFile.js.map +1 -1
- package/dist/production/src/MigrationFilesManager.cjs +11 -11
- package/dist/production/src/MigrationFilesManager.cjs.map +1 -1
- package/dist/production/src/MigrationFilesManager.js.map +1 -1
- package/dist/production/src/MigrationParser.cjs.map +1 -1
- package/dist/production/src/MigrationParser.js.map +1 -1
- package/dist/production/src/MigrationsResolver.cjs.map +1 -1
- package/dist/production/src/MigrationsResolver.js.map +1 -1
- package/dist/production/src/SchemaStateManager.cjs +82 -0
- package/dist/production/src/SchemaStateManager.cjs.map +1 -0
- package/dist/production/src/SchemaStateManager.js +64 -0
- package/dist/production/src/SchemaStateManager.js.map +1 -0
- package/dist/production/src/SchemaVersionBuilder.cjs +28 -4
- package/dist/production/src/SchemaVersionBuilder.cjs.map +1 -1
- package/dist/production/src/SchemaVersionBuilder.js +28 -4
- package/dist/production/src/SchemaVersionBuilder.js.map +1 -1
- package/dist/production/src/SnapshotManager.cjs +46 -0
- package/dist/production/src/SnapshotManager.cjs.map +1 -0
- package/dist/production/src/SnapshotManager.js +29 -0
- package/dist/production/src/SnapshotManager.js.map +1 -0
- package/dist/production/src/SystemClient.cjs +29 -4
- package/dist/production/src/SystemClient.cjs.map +1 -1
- package/dist/production/src/SystemClient.js +29 -4
- package/dist/production/src/SystemClient.js.map +1 -1
- package/dist/production/src/migrations.cjs.map +1 -1
- package/dist/production/src/migrations.js.map +1 -1
- package/dist/types/JsLoader.d.ts +3 -3
- package/dist/types/JsLoader.d.ts.map +1 -1
- package/dist/types/JsonLoader.d.ts +4 -4
- package/dist/types/JsonLoader.d.ts.map +1 -1
- package/dist/types/MigrationCreator.d.ts +4 -2
- package/dist/types/MigrationCreator.d.ts.map +1 -1
- package/dist/types/MigrationExecuteHelper.d.ts +6 -4
- package/dist/types/MigrationExecuteHelper.d.ts.map +1 -1
- package/dist/types/MigrationFile.d.ts +2 -2
- package/dist/types/MigrationFile.d.ts.map +1 -1
- package/dist/types/MigrationFileLoader.d.ts +1 -1
- package/dist/types/MigrationFileLoader.d.ts.map +1 -1
- package/dist/types/MigrationFilesManager.d.ts +2 -2
- package/dist/types/MigrationFilesManager.d.ts.map +1 -1
- package/dist/types/MigrationParser.d.ts +2 -2
- package/dist/types/MigrationParser.d.ts.map +1 -1
- package/dist/types/MigrationsResolver.d.ts +2 -2
- package/dist/types/MigrationsResolver.d.ts.map +1 -1
- package/dist/types/SchemaStateManager.d.ts +19 -0
- package/dist/types/SchemaStateManager.d.ts.map +1 -0
- package/dist/types/SchemaVersionBuilder.d.ts +10 -2
- package/dist/types/SchemaVersionBuilder.d.ts.map +1 -1
- package/dist/types/SnapshotManager.d.ts +31 -0
- package/dist/types/SnapshotManager.d.ts.map +1 -0
- package/dist/types/SystemClient.d.ts +11 -3
- package/dist/types/SystemClient.d.ts.map +1 -1
- package/dist/types/index.d.ts +14 -12
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/migrations.d.ts +1 -1
- package/dist/types/migrations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/JsLoader.ts +3 -3
- package/src/JsonLoader.ts +3 -3
- package/src/MigrationCreator.ts +8 -5
- package/src/MigrationExecuteHelper.ts +19 -8
- package/src/MigrationFile.ts +2 -2
- package/src/MigrationFileLoader.ts +1 -1
- package/src/MigrationFilesManager.ts +2 -2
- package/src/MigrationParser.ts +2 -2
- package/src/MigrationsResolver.ts +2 -2
- package/src/SchemaStateManager.ts +75 -0
- package/src/SchemaVersionBuilder.ts +35 -10
- package/src/SnapshotManager.ts +52 -0
- package/src/SystemClient.ts +41 -4
- package/src/index.ts +14 -12
- package/src/migrations.ts +1 -1
- package/tests/cases/unit/MigrationCreator.test.ts +50 -0
- package/tests/cases/unit/SchemaStateManager.test.ts +96 -0
- package/tests/cases/unit/SchemaVersionBuilder.test.ts +125 -0
- 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
|
+
})
|