@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 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
- "Split schema into tables",
2350
- this.splitTables.bind(this),
2351
- "Generates DDL for database schema"
2350
+ "Sort tables by dependencies",
2351
+ this.sortTablesByReferences.bind(this),
2352
+ "Sorts tables by dependencies"
2352
2353
  ).then(
2353
2354
  CadenzaService.createMetaTask(
2354
- "Generate tasks",
2355
- (ctx) => {
2356
- const { table, tableName, options } = ctx;
2357
- this.createDatabaseTask(
2358
- "query",
2359
- tableName,
2360
- table,
2361
- this.queryFunction.bind(this),
2362
- options
2363
- );
2364
- this.createDatabaseTask(
2365
- "insert",
2366
- tableName,
2367
- table,
2368
- this.insertFunction.bind(this),
2369
- options
2370
- );
2371
- this.createDatabaseTask(
2372
- "update",
2373
- tableName,
2374
- table,
2375
- this.updateFunction.bind(this),
2376
- options
2377
- );
2378
- this.createDatabaseTask(
2379
- "delete",
2380
- tableName,
2381
- table,
2382
- this.deleteFunction.bind(this),
2383
- options
2384
- );
2385
- },
2386
- "Generates auto-tasks for database schema"
2387
- ),
2388
- CadenzaService.createMetaTask("Generate DDL from table", (ctx) => {
2389
- var _a2;
2390
- const { ddl, table, tableName, schema, options } = ctx;
2391
- const fieldDefs = Object.entries(table.fields).map((value) => {
2392
- var _a3, _b2, _c2, _d2, _e, _f, _g;
2393
- const [fieldName, field] = value;
2394
- let def = `${fieldName} ${field.type.toUpperCase()}`;
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
- if (table.indexes) {
2426
- table.indexes.forEach((fields) => {
2427
- ddl.push(
2428
- `CREATE INDEX idx_${tableName}_${fields.join("_")} ON ${tableName} (${fields.join(", ")});`
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 unique index DDL", (ctx) => {
2429
+ CadenzaService.createMetaTask("Generate index DDL", (ctx) => {
2435
2430
  const { ddl, table, tableName, schema, options } = ctx;
2436
- if (table.uniqueConstraints) {
2437
- table.uniqueConstraints.forEach((fields) => {
2431
+ if (table.indexes) {
2432
+ table.indexes.forEach((fields) => {
2438
2433
  ddl.push(
2439
- `ALTER TABLE ${tableName} ADD CONSTRAINT unique_${tableName}_${fields.join("_")} UNIQUE (${fields.join(", ")});`
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("Generate trigger DDL", (ctx) => {
2446
- const { ddl, table, tableName, schema, options } = ctx;
2447
- if (table.triggers) {
2448
- for (const [triggerName, trigger] of Object.entries(
2449
- table.triggers
2450
- )) {
2451
- ddl.push(
2452
- `CREATE TRIGGER ${triggerName} ${trigger.when} ${trigger.event} ON ${tableName} FOR EACH STATEMENT EXECUTE FUNCTION ${trigger.function};`
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
- return { ddl, table, tableName, schema, options };
2457
- }).then(
2458
- CadenzaService.createMetaTask(
2459
- "Generate initial data DDL",
2460
- (ctx) => {
2461
- const { ddl, table, tableName, schema, options } = ctx;
2462
- if (table.initialData) {
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
- `INSERT INTO ${tableName} (${table.initialData.fields.join(", ")}) VALUES ${table.initialData.data.map(
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
- ).then(
2472
- CadenzaService.createUniqueMetaTask("Join DDL", (ctx) => {
2473
- const { joinedContexts } = ctx;
2474
- const ddl = [];
2475
- for (const joinedContext of joinedContexts) {
2476
- ddl.push(...joinedContext.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
- ddl.flat();
2479
- return {
2480
- ddl,
2481
- schema: joinedContexts[0].schema,
2482
- options: joinedContexts[0].options
2483
- };
2484
- }).then(
2485
- CadenzaService.createMetaTask(
2486
- "meta.applyDatabaseChanges",
2487
- (ctx) => __async(this, null, function* () {
2488
- const { ddl } = ctx;
2489
- if (ddl && ddl.length > 0) {
2490
- for (const sql of ddl) {
2491
- console.log("Applying SQL", sql);
2492
- yield this.dbClient.query(sql);
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
- console.log("DDL applied");
2496
- return ctx;
2497
- }),
2498
- "Applies generated DDL to the database"
2499
- ).emits("meta.database.setup_done")
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 [tableName, table] of Object.entries(schema.tables)) {
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
  });