@cadenza.io/service 1.5.2 → 1.6.0
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/index.js +184 -131
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +184 -131
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2261,6 +2261,7 @@ var DatabaseController = class _DatabaseController {
|
|
|
2261
2261
|
return true;
|
|
2262
2262
|
} catch (error) {
|
|
2263
2263
|
if (error.code === "42P04") {
|
|
2264
|
+
console.log("Database already exists");
|
|
2264
2265
|
return true;
|
|
2265
2266
|
}
|
|
2266
2267
|
throw new Error(`Failed to create database: ${error.message}`);
|
|
@@ -2346,157 +2347,168 @@ var DatabaseController = class _DatabaseController {
|
|
|
2346
2347
|
"Validates database schema structure and content"
|
|
2347
2348
|
).then(
|
|
2348
2349
|
CadenzaService.createMetaTask(
|
|
2349
|
-
"
|
|
2350
|
-
this.
|
|
2351
|
-
"
|
|
2350
|
+
"Sort tables by dependencies",
|
|
2351
|
+
this.sortTablesByReferences.bind(this),
|
|
2352
|
+
"Sorts tables by dependencies"
|
|
2352
2353
|
).then(
|
|
2353
2354
|
CadenzaService.createMetaTask(
|
|
2354
|
-
"
|
|
2355
|
-
(
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
if (field.type === "varchar")
|
|
2396
|
-
def += `(${(_b2 = (_a3 = field.constraints) == null ? void 0 : _a3.maxLength) != null ? _b2 : 255})`;
|
|
2397
|
-
if (field.type === "decimal")
|
|
2398
|
-
def += `(${(_d2 = (_c2 = field.constraints) == null ? void 0 : _c2.precision) != null ? _d2 : 10},${(_f = (_e = field.constraints) == null ? void 0 : _e.scale) != null ? _f : 2})`;
|
|
2399
|
-
if (field.primary) def += " PRIMARY KEY";
|
|
2400
|
-
if (field.unique) def += " UNIQUE";
|
|
2401
|
-
if (field.default !== void 0)
|
|
2402
|
-
def += ` DEFAULT ${field.default || "''"}`;
|
|
2403
|
-
if (field.required && !field.nullable) def += " NOT NULL";
|
|
2404
|
-
if (field.nullable) def += " NULL";
|
|
2405
|
-
if (field.generated)
|
|
2406
|
-
def += ` GENERATED ALWAYS AS ${field.generated.toUpperCase()} STORED`;
|
|
2407
|
-
if (field.references)
|
|
2408
|
-
def += ` REFERENCES ${field.references} ON DELETE ${field.onDelete || "NO_ACTION"}`;
|
|
2409
|
-
if (field.encrypted) def += " ENCRYPTED";
|
|
2410
|
-
if ((_g = field.constraints) == null ? void 0 : _g.check) {
|
|
2411
|
-
def += ` CHECK (${field.constraints.check})`;
|
|
2412
|
-
}
|
|
2413
|
-
return def;
|
|
2414
|
-
}).join(", ");
|
|
2415
|
-
let sql = `CREATE TABLE IF NOT EXISTS ${tableName} (${fieldDefs})`;
|
|
2416
|
-
if ((_a2 = table.meta) == null ? void 0 : _a2.appendOnly) {
|
|
2417
|
-
sql += `;
|
|
2418
|
-
CREATE TRIGGER prevent_modification BEFORE UPDATE OR DELETE ON ${tableName} FOR EACH STATEMENT EXECUTE FUNCTION prevent_context_modification();`;
|
|
2419
|
-
}
|
|
2420
|
-
ddl.push(sql);
|
|
2421
|
-
return { ddl, table, tableName, schema, options };
|
|
2422
|
-
}).then(
|
|
2423
|
-
CadenzaService.createMetaTask("Generate index DDL", (ctx) => {
|
|
2355
|
+
"Split schema into tables",
|
|
2356
|
+
this.splitTables.bind(this),
|
|
2357
|
+
"Generates DDL for database schema"
|
|
2358
|
+
).then(
|
|
2359
|
+
CadenzaService.createMetaTask(
|
|
2360
|
+
"Generate tasks",
|
|
2361
|
+
(ctx) => {
|
|
2362
|
+
const { table, tableName, options } = ctx;
|
|
2363
|
+
this.createDatabaseTask(
|
|
2364
|
+
"query",
|
|
2365
|
+
tableName,
|
|
2366
|
+
table,
|
|
2367
|
+
this.queryFunction.bind(this),
|
|
2368
|
+
options
|
|
2369
|
+
);
|
|
2370
|
+
this.createDatabaseTask(
|
|
2371
|
+
"insert",
|
|
2372
|
+
tableName,
|
|
2373
|
+
table,
|
|
2374
|
+
this.insertFunction.bind(this),
|
|
2375
|
+
options
|
|
2376
|
+
);
|
|
2377
|
+
this.createDatabaseTask(
|
|
2378
|
+
"update",
|
|
2379
|
+
tableName,
|
|
2380
|
+
table,
|
|
2381
|
+
this.updateFunction.bind(this),
|
|
2382
|
+
options
|
|
2383
|
+
);
|
|
2384
|
+
this.createDatabaseTask(
|
|
2385
|
+
"delete",
|
|
2386
|
+
tableName,
|
|
2387
|
+
table,
|
|
2388
|
+
this.deleteFunction.bind(this),
|
|
2389
|
+
options
|
|
2390
|
+
);
|
|
2391
|
+
},
|
|
2392
|
+
"Generates auto-tasks for database schema"
|
|
2393
|
+
),
|
|
2394
|
+
CadenzaService.createMetaTask("Generate DDL from table", (ctx) => {
|
|
2395
|
+
var _a2;
|
|
2424
2396
|
const { ddl, table, tableName, schema, options } = ctx;
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2397
|
+
const fieldDefs = Object.entries(table.fields).map((value) => {
|
|
2398
|
+
var _a3, _b2, _c2, _d2, _e, _f, _g;
|
|
2399
|
+
const [fieldName, field] = value;
|
|
2400
|
+
let def = `${fieldName} ${field.type.toUpperCase()}`;
|
|
2401
|
+
if (field.type === "varchar")
|
|
2402
|
+
def += `(${(_b2 = (_a3 = field.constraints) == null ? void 0 : _a3.maxLength) != null ? _b2 : 255})`;
|
|
2403
|
+
if (field.type === "decimal")
|
|
2404
|
+
def += `(${(_d2 = (_c2 = field.constraints) == null ? void 0 : _c2.precision) != null ? _d2 : 10},${(_f = (_e = field.constraints) == null ? void 0 : _e.scale) != null ? _f : 2})`;
|
|
2405
|
+
if (field.primary) def += " PRIMARY KEY";
|
|
2406
|
+
if (field.unique) def += " UNIQUE";
|
|
2407
|
+
if (field.default !== void 0)
|
|
2408
|
+
def += ` DEFAULT ${field.default || "''"}`;
|
|
2409
|
+
if (field.required && !field.nullable) def += " NOT NULL";
|
|
2410
|
+
if (field.nullable) def += " NULL";
|
|
2411
|
+
if (field.generated)
|
|
2412
|
+
def += ` GENERATED ALWAYS AS ${field.generated.toUpperCase()} STORED`;
|
|
2413
|
+
if (field.references)
|
|
2414
|
+
def += ` REFERENCES ${field.references} ON DELETE ${field.onDelete || "NO_ACTION"}`;
|
|
2415
|
+
if (field.encrypted) def += " ENCRYPTED";
|
|
2416
|
+
if ((_g = field.constraints) == null ? void 0 : _g.check) {
|
|
2417
|
+
def += ` CHECK (${field.constraints.check})`;
|
|
2418
|
+
}
|
|
2419
|
+
return def;
|
|
2420
|
+
}).join(", ");
|
|
2421
|
+
let sql = `CREATE TABLE IF NOT EXISTS ${tableName} (${fieldDefs})`;
|
|
2422
|
+
if ((_a2 = table.meta) == null ? void 0 : _a2.appendOnly) {
|
|
2423
|
+
sql += `;
|
|
2424
|
+
CREATE TRIGGER prevent_modification BEFORE UPDATE OR DELETE ON ${tableName} FOR EACH STATEMENT EXECUTE FUNCTION prevent_context_modification();`;
|
|
2431
2425
|
}
|
|
2426
|
+
ddl.push(sql);
|
|
2432
2427
|
return { ddl, table, tableName, schema, options };
|
|
2433
2428
|
}).then(
|
|
2434
|
-
CadenzaService.createMetaTask("Generate
|
|
2429
|
+
CadenzaService.createMetaTask("Generate index DDL", (ctx) => {
|
|
2435
2430
|
const { ddl, table, tableName, schema, options } = ctx;
|
|
2436
|
-
if (table.
|
|
2437
|
-
table.
|
|
2431
|
+
if (table.indexes) {
|
|
2432
|
+
table.indexes.forEach((fields) => {
|
|
2438
2433
|
ddl.push(
|
|
2439
|
-
`
|
|
2434
|
+
`CREATE INDEX idx_${tableName}_${fields.join("_")} ON ${tableName} (${fields.join(", ")});`
|
|
2440
2435
|
);
|
|
2441
2436
|
});
|
|
2442
2437
|
}
|
|
2443
2438
|
return { ddl, table, tableName, schema, options };
|
|
2444
2439
|
}).then(
|
|
2445
|
-
CadenzaService.createMetaTask(
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2440
|
+
CadenzaService.createMetaTask(
|
|
2441
|
+
"Generate unique index DDL",
|
|
2442
|
+
(ctx) => {
|
|
2443
|
+
const { ddl, table, tableName, schema, options } = ctx;
|
|
2444
|
+
if (table.uniqueConstraints) {
|
|
2445
|
+
table.uniqueConstraints.forEach(
|
|
2446
|
+
(fields) => {
|
|
2447
|
+
ddl.push(
|
|
2448
|
+
`ALTER TABLE ${tableName} ADD CONSTRAINT unique_${tableName}_${fields.join("_")} UNIQUE (${fields.join(", ")});`
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2453
2451
|
);
|
|
2454
2452
|
}
|
|
2453
|
+
return { ddl, table, tableName, schema, options };
|
|
2455
2454
|
}
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2455
|
+
).then(
|
|
2456
|
+
CadenzaService.createMetaTask("Generate trigger DDL", (ctx) => {
|
|
2457
|
+
const { ddl, table, tableName, schema, options } = ctx;
|
|
2458
|
+
if (table.triggers) {
|
|
2459
|
+
for (const [triggerName, trigger] of Object.entries(
|
|
2460
|
+
table.triggers
|
|
2461
|
+
)) {
|
|
2463
2462
|
ddl.push(
|
|
2464
|
-
`
|
|
2465
|
-
(row) => `(${row.map((value) => value === void 0 ? "NULL" : value).join(", ")})`
|
|
2466
|
-
).join(", ")};`
|
|
2463
|
+
`CREATE TRIGGER ${triggerName} ${trigger.when} ${trigger.event} ON ${tableName} FOR EACH STATEMENT EXECUTE FUNCTION ${trigger.function};`
|
|
2467
2464
|
);
|
|
2468
2465
|
}
|
|
2469
|
-
return { ddl, table, tableName, schema, options };
|
|
2470
2466
|
}
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
ddl
|
|
2467
|
+
return { ddl, table, tableName, schema, options };
|
|
2468
|
+
}).then(
|
|
2469
|
+
CadenzaService.createMetaTask(
|
|
2470
|
+
"Generate initial data DDL",
|
|
2471
|
+
(ctx) => {
|
|
2472
|
+
const { ddl, table, tableName, schema, options } = ctx;
|
|
2473
|
+
if (table.initialData) {
|
|
2474
|
+
ddl.push(
|
|
2475
|
+
`INSERT INTO ${tableName} (${table.initialData.fields.join(", ")}) VALUES ${table.initialData.data.map(
|
|
2476
|
+
(row) => `(${row.map((value) => value === void 0 ? "NULL" : value).join(", ")})`
|
|
2477
|
+
).join(", ")};`
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
return { ddl, table, tableName, schema, options };
|
|
2477
2481
|
}
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2482
|
+
).then(
|
|
2483
|
+
CadenzaService.createUniqueMetaTask("Join DDL", (ctx) => {
|
|
2484
|
+
const { joinedContexts } = ctx;
|
|
2485
|
+
const ddl = [];
|
|
2486
|
+
for (const joinedContext of joinedContexts) {
|
|
2487
|
+
ddl.push(...joinedContext.ddl);
|
|
2488
|
+
}
|
|
2489
|
+
ddl.flat();
|
|
2490
|
+
return {
|
|
2491
|
+
ddl,
|
|
2492
|
+
schema: joinedContexts[0].schema,
|
|
2493
|
+
options: joinedContexts[0].options
|
|
2494
|
+
};
|
|
2495
|
+
}).then(
|
|
2496
|
+
CadenzaService.createMetaTask(
|
|
2497
|
+
"meta.applyDatabaseChanges",
|
|
2498
|
+
(ctx) => __async(this, null, function* () {
|
|
2499
|
+
const { ddl } = ctx;
|
|
2500
|
+
if (ddl && ddl.length > 0) {
|
|
2501
|
+
for (const sql of ddl) {
|
|
2502
|
+
console.log("Applying SQL", sql);
|
|
2503
|
+
yield this.dbClient.query(sql);
|
|
2504
|
+
}
|
|
2493
2505
|
}
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
"
|
|
2499
|
-
)
|
|
2506
|
+
console.log("DDL applied");
|
|
2507
|
+
return ctx;
|
|
2508
|
+
}),
|
|
2509
|
+
"Applies generated DDL to the database"
|
|
2510
|
+
).emits("meta.database.setup_done")
|
|
2511
|
+
)
|
|
2500
2512
|
)
|
|
2501
2513
|
)
|
|
2502
2514
|
)
|
|
@@ -2559,10 +2571,51 @@ CREATE TRIGGER prevent_modification BEFORE UPDATE OR DELETE ON ${tableName} FOR
|
|
|
2559
2571
|
throw new Error(`Timeout waiting for database to be ready`);
|
|
2560
2572
|
});
|
|
2561
2573
|
}
|
|
2574
|
+
sortTablesByReferences(ctx) {
|
|
2575
|
+
var _a2;
|
|
2576
|
+
const schema = ctx.schema;
|
|
2577
|
+
const graph = /* @__PURE__ */ new Map();
|
|
2578
|
+
const allTables = Object.keys(schema.tables);
|
|
2579
|
+
allTables.forEach((table) => graph.set(table, /* @__PURE__ */ new Set()));
|
|
2580
|
+
for (const [tableName, table] of Object.entries(schema.tables)) {
|
|
2581
|
+
for (const field of Object.values(table.fields)) {
|
|
2582
|
+
if (field.references) {
|
|
2583
|
+
const [refTable] = field.references.split(".");
|
|
2584
|
+
if (allTables.includes(refTable)) {
|
|
2585
|
+
(_a2 = graph.get(refTable)) == null ? void 0 : _a2.add(tableName);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2591
|
+
const tempMark = /* @__PURE__ */ new Set();
|
|
2592
|
+
const sorted = [];
|
|
2593
|
+
function visit(table) {
|
|
2594
|
+
if (tempMark.has(table)) {
|
|
2595
|
+
console.log("Circular reference detected involving table", table);
|
|
2596
|
+
throw new Error(`Circular reference detected involving table ${table}`);
|
|
2597
|
+
}
|
|
2598
|
+
if (visited.has(table)) return;
|
|
2599
|
+
tempMark.add(table);
|
|
2600
|
+
for (const dep of graph.get(table) || []) {
|
|
2601
|
+
visit(dep);
|
|
2602
|
+
}
|
|
2603
|
+
tempMark.delete(table);
|
|
2604
|
+
visited.add(table);
|
|
2605
|
+
sorted.push(table);
|
|
2606
|
+
}
|
|
2607
|
+
for (const table of allTables) {
|
|
2608
|
+
if (!visited.has(table)) {
|
|
2609
|
+
visit(table);
|
|
2610
|
+
}
|
|
2611
|
+
}
|
|
2612
|
+
return __spreadProps(__spreadValues({}, ctx), { sortedTables: sorted });
|
|
2613
|
+
}
|
|
2562
2614
|
splitTables(ctx) {
|
|
2563
2615
|
return __asyncGenerator(this, null, function* () {
|
|
2564
|
-
const { schema, options = {} } = ctx;
|
|
2565
|
-
for (const
|
|
2616
|
+
const { sortedTables, schema, options = {} } = ctx;
|
|
2617
|
+
for (const tableName of sortedTables) {
|
|
2618
|
+
const table = schema.tables[tableName];
|
|
2566
2619
|
yield { ddl: [], table, tableName, schema, options };
|
|
2567
2620
|
}
|
|
2568
2621
|
});
|