@objectstack/metadata 0.8.2 → 0.9.1
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/CHANGELOG.md +10 -0
- package/README.md +250 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/migration/executor.d.ts +9 -0
- package/dist/migration/executor.d.ts.map +1 -0
- package/dist/migration/executor.js +49 -0
- package/dist/migration/index.d.ts +2 -0
- package/dist/migration/index.d.ts.map +1 -0
- package/dist/migration/index.js +1 -0
- package/package.json +4 -4
- package/src/index.ts +1 -0
- package/src/migration/executor.ts +52 -0
- package/src/migration/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @objectstack/metadata
|
|
2
2
|
|
|
3
|
+
## 0.9.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Patch release for maintenance and stability improvements. All packages updated with unified versioning.
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @objectstack/spec@0.9.1
|
|
10
|
+
- @objectstack/core@0.9.1
|
|
11
|
+
- @objectstack/types@0.9.1
|
|
12
|
+
|
|
3
13
|
## 0.8.2
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -196,6 +196,256 @@ The metadata package is designed as a Layer 3 package in the ObjectStack archite
|
|
|
196
196
|
└── @objectstack/objectql (registry persistence)
|
|
197
197
|
```
|
|
198
198
|
|
|
199
|
+
## Common Workflows
|
|
200
|
+
|
|
201
|
+
### Development Workflow with File Watching
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
205
|
+
|
|
206
|
+
const manager = new MetadataManager({
|
|
207
|
+
rootDir: './metadata',
|
|
208
|
+
watch: true, // Enable file watching
|
|
209
|
+
cache: { enabled: true, ttl: 3600 }
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// Watch for changes and reload
|
|
213
|
+
manager.watch('object', async (event) => {
|
|
214
|
+
if (event.type === 'modified' || event.type === 'added') {
|
|
215
|
+
console.log(`Reloading object: ${event.name}`);
|
|
216
|
+
const updated = await manager.load('object', event.name);
|
|
217
|
+
|
|
218
|
+
// Notify the system to reload
|
|
219
|
+
await objectQL.reloadObject(event.name, updated);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Hot module replacement for development
|
|
224
|
+
console.log('Watching metadata files for changes...');
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Metadata Migration Workflow
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
231
|
+
|
|
232
|
+
async function migrateMetadata() {
|
|
233
|
+
const manager = new MetadataManager({
|
|
234
|
+
rootDir: './metadata'
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// 1. Load all existing objects
|
|
238
|
+
const objects = await manager.loadMany('object');
|
|
239
|
+
|
|
240
|
+
// 2. Transform metadata (e.g., rename field)
|
|
241
|
+
const transformed = objects.map(obj => ({
|
|
242
|
+
...obj,
|
|
243
|
+
fields: Object.entries(obj.fields).reduce((acc, [key, field]) => {
|
|
244
|
+
// Rename 'description' to 'notes'
|
|
245
|
+
const newKey = key === 'description' ? 'notes' : key;
|
|
246
|
+
acc[newKey] = field;
|
|
247
|
+
return acc;
|
|
248
|
+
}, {})
|
|
249
|
+
}));
|
|
250
|
+
|
|
251
|
+
// 3. Save with backup
|
|
252
|
+
for (const obj of transformed) {
|
|
253
|
+
await manager.save('object', obj.name, obj, {
|
|
254
|
+
format: 'typescript',
|
|
255
|
+
backup: true, // Create .bak file
|
|
256
|
+
prettify: true
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log(`Migrated ${objects.length} objects`);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Multi-Format Support Workflow
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
268
|
+
|
|
269
|
+
const manager = new MetadataManager({
|
|
270
|
+
rootDir: './metadata',
|
|
271
|
+
formats: ['typescript', 'json', 'yaml']
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Load from any format - manager auto-detects
|
|
275
|
+
const customer = await manager.load('object', 'customer');
|
|
276
|
+
// Tries: customer.object.ts, customer.object.json, customer.object.yaml
|
|
277
|
+
|
|
278
|
+
// Save in preferred format
|
|
279
|
+
await manager.save('object', 'customer', customer, {
|
|
280
|
+
format: 'typescript' // Convert to TypeScript
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Generate documentation from metadata
|
|
284
|
+
const allObjects = await manager.loadMany('object');
|
|
285
|
+
const docs = allObjects.map(obj => `
|
|
286
|
+
## ${obj.label}
|
|
287
|
+
|
|
288
|
+
**Name:** ${obj.name}
|
|
289
|
+
|
|
290
|
+
**Fields:**
|
|
291
|
+
${Object.entries(obj.fields).map(([name, field]) =>
|
|
292
|
+
`- **${field.label}** (\`${name}\`): ${field.type}`
|
|
293
|
+
).join('\n')}
|
|
294
|
+
`).join('\n\n');
|
|
295
|
+
|
|
296
|
+
fs.writeFileSync('docs/objects.md', docs);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Validation and Testing Workflow
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
303
|
+
import { ObjectSchema } from '@objectstack/spec/data';
|
|
304
|
+
|
|
305
|
+
async function validateAllMetadata() {
|
|
306
|
+
const manager = new MetadataManager({
|
|
307
|
+
rootDir: './metadata'
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const objects = await manager.loadMany('object');
|
|
311
|
+
const errors = [];
|
|
312
|
+
|
|
313
|
+
for (const obj of objects) {
|
|
314
|
+
const result = ObjectSchema.safeParse(obj);
|
|
315
|
+
|
|
316
|
+
if (!result.success) {
|
|
317
|
+
errors.push({
|
|
318
|
+
name: obj.name,
|
|
319
|
+
issues: result.error.issues
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (errors.length > 0) {
|
|
325
|
+
console.error('Validation errors found:');
|
|
326
|
+
errors.forEach(({ name, issues }) => {
|
|
327
|
+
console.error(`\n${name}:`);
|
|
328
|
+
issues.forEach(issue => {
|
|
329
|
+
console.error(` - ${issue.path.join('.')}: ${issue.message}`);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
console.log(`✅ All ${objects.length} objects validated successfully`);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Metadata Versioning Workflow
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
343
|
+
import { execSync } from 'child_process';
|
|
344
|
+
|
|
345
|
+
async function versionMetadata() {
|
|
346
|
+
const manager = new MetadataManager({
|
|
347
|
+
rootDir: './metadata'
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const objects = await manager.loadMany('object');
|
|
351
|
+
|
|
352
|
+
// Get git user name safely
|
|
353
|
+
let modifiedBy = 'unknown';
|
|
354
|
+
try {
|
|
355
|
+
modifiedBy = execSync('git config user.name', { encoding: 'utf-8' }).trim();
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.warn('Could not get git user name, using "unknown"');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Add version metadata
|
|
361
|
+
const versioned = objects.map(obj => ({
|
|
362
|
+
...obj,
|
|
363
|
+
metadata: {
|
|
364
|
+
...obj.metadata,
|
|
365
|
+
version: '2.0.0',
|
|
366
|
+
lastModified: new Date().toISOString(),
|
|
367
|
+
modifiedBy
|
|
368
|
+
}
|
|
369
|
+
}));
|
|
370
|
+
|
|
371
|
+
// Save versioned metadata
|
|
372
|
+
for (const obj of versioned) {
|
|
373
|
+
await manager.save('object', obj.name, obj, {
|
|
374
|
+
format: 'typescript',
|
|
375
|
+
prettify: true
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Commit to version control (if git is available)
|
|
380
|
+
try {
|
|
381
|
+
execSync('git add metadata/', { stdio: 'inherit' });
|
|
382
|
+
execSync('git commit -m "Version bump to 2.0.0"', { stdio: 'inherit' });
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.warn('Git commit failed, changes are staged but not committed');
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Import/Export Workflow
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import { MetadataManager } from '@objectstack/metadata';
|
|
393
|
+
|
|
394
|
+
async function exportToJSON() {
|
|
395
|
+
const manager = new MetadataManager({
|
|
396
|
+
rootDir: './metadata'
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// Load all metadata
|
|
400
|
+
const [objects, views, apps] = await Promise.all([
|
|
401
|
+
manager.loadMany('object'),
|
|
402
|
+
manager.loadMany('view'),
|
|
403
|
+
manager.loadMany('app')
|
|
404
|
+
]);
|
|
405
|
+
|
|
406
|
+
// Create unified export
|
|
407
|
+
const exportData = {
|
|
408
|
+
version: '1.0.0',
|
|
409
|
+
exported: new Date().toISOString(),
|
|
410
|
+
objects,
|
|
411
|
+
views,
|
|
412
|
+
apps
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// Save as single JSON file
|
|
416
|
+
fs.writeFileSync(
|
|
417
|
+
'export/metadata-export.json',
|
|
418
|
+
JSON.stringify(exportData, null, 2)
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
console.log('Export complete!');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
async function importFromJSON(filePath: string) {
|
|
425
|
+
const manager = new MetadataManager({
|
|
426
|
+
rootDir: './metadata'
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
const importData = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
430
|
+
|
|
431
|
+
// Import objects
|
|
432
|
+
for (const obj of importData.objects) {
|
|
433
|
+
await manager.save('object', obj.name, obj, {
|
|
434
|
+
format: 'typescript'
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Import views
|
|
439
|
+
for (const view of importData.views) {
|
|
440
|
+
await manager.save('view', view.name, view, {
|
|
441
|
+
format: 'typescript'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
console.log('Import complete!');
|
|
446
|
+
}
|
|
447
|
+
```
|
|
448
|
+
|
|
199
449
|
## License
|
|
200
450
|
|
|
201
451
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { FilesystemLoader } from './loaders/filesystem-loader.js';
|
|
|
10
10
|
export { type MetadataSerializer, type SerializeOptions } from './serializers/serializer-interface.js';
|
|
11
11
|
export { JSONSerializer } from './serializers/json-serializer.js';
|
|
12
12
|
export { YAMLSerializer } from './serializers/yaml-serializer.js';
|
|
13
|
+
export * as Migration from './migration/index.js';
|
|
13
14
|
export { TypeScriptSerializer } from './serializers/typescript-serializer.js';
|
|
14
15
|
export type { MetadataFormat, MetadataStats, MetadataLoadOptions, MetadataSaveOptions, MetadataExportOptions, MetadataImportOptions, MetadataLoadResult, MetadataSaveResult, MetadataWatchEvent, MetadataCollectionInfo, MetadataLoaderContract, MetadataManagerConfig, } from '@objectstack/spec/system';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGlE,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACvG,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAG9E,YAAY,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAG5E,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAGlE,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACvG,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAG9E,YAAY,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,4 +10,5 @@ export { MetadataPlugin } from './plugin.js';
|
|
|
10
10
|
export { FilesystemLoader } from './loaders/filesystem-loader.js';
|
|
11
11
|
export { JSONSerializer } from './serializers/json-serializer.js';
|
|
12
12
|
export { YAMLSerializer } from './serializers/yaml-serializer.js';
|
|
13
|
+
export * as Migration from './migration/index.js';
|
|
13
14
|
export { TypeScriptSerializer } from './serializers/typescript-serializer.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { System } from '@objectstack/spec';
|
|
2
|
+
import { ISchemaDriver } from '@objectstack/spec/contracts';
|
|
3
|
+
export declare class MigrationExecutor {
|
|
4
|
+
private driver;
|
|
5
|
+
constructor(driver: ISchemaDriver);
|
|
6
|
+
executeChangeSet(changeSet: System.ChangeSet): Promise<void>;
|
|
7
|
+
private executeOperation;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/migration/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,qBAAa,iBAAiB;IAChB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAEnC,gBAAgB,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;YAapD,gBAAgB;CAgC/B"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class MigrationExecutor {
|
|
2
|
+
constructor(driver) {
|
|
3
|
+
this.driver = driver;
|
|
4
|
+
}
|
|
5
|
+
async executeChangeSet(changeSet) {
|
|
6
|
+
console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);
|
|
7
|
+
for (const op of changeSet.operations) {
|
|
8
|
+
try {
|
|
9
|
+
await this.executeOperation(op);
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
console.error(`Failed to execute operation ${op.type}:`, e);
|
|
13
|
+
throw e;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async executeOperation(op) {
|
|
18
|
+
switch (op.type) {
|
|
19
|
+
case 'create_object':
|
|
20
|
+
console.log(` > Create Object: ${op.object.name}`);
|
|
21
|
+
await this.driver.createCollection(op.object.name, op.object);
|
|
22
|
+
break;
|
|
23
|
+
case 'add_field':
|
|
24
|
+
console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);
|
|
25
|
+
await this.driver.addColumn(op.objectName, op.fieldName, op.field);
|
|
26
|
+
break;
|
|
27
|
+
case 'remove_field':
|
|
28
|
+
console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);
|
|
29
|
+
await this.driver.dropColumn(op.objectName, op.fieldName);
|
|
30
|
+
break;
|
|
31
|
+
case 'delete_object':
|
|
32
|
+
console.log(` > Delete Object: ${op.objectName}`);
|
|
33
|
+
await this.driver.dropCollection(op.objectName);
|
|
34
|
+
break;
|
|
35
|
+
case 'execute_sql':
|
|
36
|
+
console.log(` > Execute SQL`);
|
|
37
|
+
await this.driver.executeRaw(op.sql);
|
|
38
|
+
break;
|
|
39
|
+
case 'modify_field':
|
|
40
|
+
console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);
|
|
41
|
+
break;
|
|
42
|
+
case 'rename_object':
|
|
43
|
+
console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unknown operation type`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migration/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './executor.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/metadata",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Metadata loading, saving, and persistence for ObjectStack",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"js-yaml": "^4.1.0",
|
|
17
17
|
"chokidar": "^3.5.3",
|
|
18
18
|
"zod": "^4.3.6",
|
|
19
|
-
"@objectstack/core": "0.
|
|
20
|
-
"@objectstack/spec": "0.
|
|
21
|
-
"@objectstack/types": "0.
|
|
19
|
+
"@objectstack/core": "0.9.1",
|
|
20
|
+
"@objectstack/spec": "0.9.1",
|
|
21
|
+
"@objectstack/types": "0.9.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/js-yaml": "^4.0.9",
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { FilesystemLoader } from './loaders/filesystem-loader.js';
|
|
|
18
18
|
export { type MetadataSerializer, type SerializeOptions } from './serializers/serializer-interface.js';
|
|
19
19
|
export { JSONSerializer } from './serializers/json-serializer.js';
|
|
20
20
|
export { YAMLSerializer } from './serializers/yaml-serializer.js';
|
|
21
|
+
export * as Migration from './migration/index.js';
|
|
21
22
|
export { TypeScriptSerializer } from './serializers/typescript-serializer.js';
|
|
22
23
|
|
|
23
24
|
// Re-export types from spec
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { System } from '@objectstack/spec';
|
|
2
|
+
import { ISchemaDriver } from '@objectstack/spec/contracts';
|
|
3
|
+
|
|
4
|
+
export class MigrationExecutor {
|
|
5
|
+
constructor(private driver: ISchemaDriver) {}
|
|
6
|
+
|
|
7
|
+
async executeChangeSet(changeSet: System.ChangeSet): Promise<void> {
|
|
8
|
+
console.log(`Executing ChangeSet: ${changeSet.name} (${changeSet.id})`);
|
|
9
|
+
|
|
10
|
+
for (const op of changeSet.operations) {
|
|
11
|
+
try {
|
|
12
|
+
await this.executeOperation(op);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error(`Failed to execute operation ${op.type}:`, e);
|
|
15
|
+
throw e;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private async executeOperation(op: System.MigrationOperation): Promise<void> {
|
|
21
|
+
switch (op.type) {
|
|
22
|
+
case 'create_object':
|
|
23
|
+
console.log(` > Create Object: ${op.object.name}`);
|
|
24
|
+
await this.driver.createCollection(op.object.name, op.object);
|
|
25
|
+
break;
|
|
26
|
+
case 'add_field':
|
|
27
|
+
console.log(` > Add Field: ${op.objectName}.${op.fieldName}`);
|
|
28
|
+
await this.driver.addColumn(op.objectName, op.fieldName, op.field);
|
|
29
|
+
break;
|
|
30
|
+
case 'remove_field':
|
|
31
|
+
console.log(` > Remove Field: ${op.objectName}.${op.fieldName}`);
|
|
32
|
+
await this.driver.dropColumn(op.objectName, op.fieldName);
|
|
33
|
+
break;
|
|
34
|
+
case 'delete_object':
|
|
35
|
+
console.log(` > Delete Object: ${op.objectName}`);
|
|
36
|
+
await this.driver.dropCollection(op.objectName);
|
|
37
|
+
break;
|
|
38
|
+
case 'execute_sql':
|
|
39
|
+
console.log(` > Execute SQL`);
|
|
40
|
+
await this.driver.executeRaw(op.sql);
|
|
41
|
+
break;
|
|
42
|
+
case 'modify_field':
|
|
43
|
+
console.warn(` ! Modify Field: ${op.objectName}.${op.fieldName} (Not fully implemented)`);
|
|
44
|
+
break;
|
|
45
|
+
case 'rename_object':
|
|
46
|
+
console.warn(` ! Rename Object: ${op.oldName} -> ${op.newName} (Not fully implemented)`);
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
throw new Error(`Unknown operation type`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './executor.js';
|