@sequenceholdings/orm 2.8.2 → 2.8.4

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 (53) hide show
  1. package/README.md +5 -0
  2. package/dist/authoring.cjs +31 -8
  3. package/dist/authoring.cjs.map +1 -1
  4. package/dist/authoring.d.cts +8 -2
  5. package/dist/authoring.d.ts +8 -2
  6. package/dist/authoring.js +31 -8
  7. package/dist/authoring.js.map +1 -1
  8. package/dist/canonical.cjs +1 -1
  9. package/dist/canonical.cjs.map +1 -1
  10. package/dist/canonical.d.cts +1 -1
  11. package/dist/canonical.d.ts +1 -1
  12. package/dist/canonical.js +1 -1
  13. package/dist/canonical.js.map +1 -1
  14. package/dist/cli.cjs +27 -24
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.js +31 -28
  17. package/dist/cli.js.map +1 -1
  18. package/dist/compiler.cjs +1 -1
  19. package/dist/compiler.cjs.map +1 -1
  20. package/dist/compiler.d.cts +4 -4
  21. package/dist/compiler.d.ts +4 -4
  22. package/dist/compiler.js +1 -1
  23. package/dist/compiler.js.map +1 -1
  24. package/dist/index.cjs +31 -8
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +7 -9
  27. package/dist/index.d.ts +7 -9
  28. package/dist/index.js +31 -8
  29. package/dist/index.js.map +1 -1
  30. package/dist/ir.cjs +1 -1
  31. package/dist/ir.cjs.map +1 -1
  32. package/dist/ir.d.cts +2 -2
  33. package/dist/ir.d.ts +2 -2
  34. package/dist/ir.js +1 -1
  35. package/dist/ir.js.map +1 -1
  36. package/dist/{naming-CU9ThP_E.d.cts → naming-BMZKFO0W.d.cts} +1 -2
  37. package/dist/{naming-CPfx7EfF.d.ts → naming-DUk7AcXs.d.ts} +1 -2
  38. package/dist/predicate-v2.cjs +1 -1
  39. package/dist/predicate-v2.cjs.map +1 -1
  40. package/dist/predicate-v2.d.cts +3 -3
  41. package/dist/predicate-v2.d.ts +3 -3
  42. package/dist/predicate-v2.js +1 -1
  43. package/dist/predicate-v2.js.map +1 -1
  44. package/dist/sdl.cjs +1 -1
  45. package/dist/sdl.cjs.map +1 -1
  46. package/dist/sdl.d.cts +2 -2
  47. package/dist/sdl.d.ts +2 -2
  48. package/dist/sdl.js +1 -1
  49. package/dist/sdl.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/codegen-gql/apollo-hooks.cjs +1 -1
  52. package/src/codegen-gql/server-fns.cjs +1 -1
  53. package/templates/orm-namespace/graphql/example/queries.ts +1 -1
package/dist/index.cjs CHANGED
@@ -1761,7 +1761,7 @@ var canonicalTableSchema = zod.z.object({
1761
1761
  table: identifier2,
1762
1762
  displayName: zod.z.string().trim().min(1).max(120).optional(),
1763
1763
  description: zod.z.string().max(2e3).optional(),
1764
- /** Table-level rename hint (new in v2). */
1764
+ /** Table-level rename hint. */
1765
1765
  renamedFrom: identifier2.optional(),
1766
1766
  /** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
1767
1767
  source: zod.z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
@@ -2425,6 +2425,12 @@ function builtinCell({ comparator, candidates }) {
2425
2425
  }
2426
2426
  };
2427
2427
  }
2428
+ function existsInCell(candidate) {
2429
+ return {
2430
+ value: candidate.value,
2431
+ parts: { source: literal(candidate.source), at: candidate.at, by: candidate.by, conflicts: "CAST(NULL AS jsonb)" }
2432
+ };
2433
+ }
2428
2434
  function customCell({ candidates, orderBy, index: index3 }) {
2429
2435
  const w = ident(`w_${index3}`);
2430
2436
  const rows = candidates.map((c, ord) => `(${literal(c.source)}, ${c.has}, ${c.value}, ${c.at}, ${c.by}, ${ord})`);
@@ -2448,26 +2454,29 @@ function buildResolvedQuery({ context, plan }) {
2448
2454
  const tombstoned2 = RESOLVED_SOURCE_SYSTEM_COLUMNS.tombstoned.columnName;
2449
2455
  const sourceByName = new Map(plan.plans.map((source) => [source.name, source]));
2450
2456
  const schema = pgCore.getTableConfig(relation(plan.plans[0].table)).schema;
2457
+ const keySource = plan.existsIn === void 0 ? void 0 : sourceByName.get(plan.existsIn);
2458
+ const keyRef = keySource ? `${alias(keySource.name)}.${ident(physical({ source: keySource, property: plan.pk }))}` : `"k".${ident(pkColumn)}`;
2451
2459
  const keyBranches = plan.plans.map((source) => {
2452
2460
  const where = source.kind === "prefetch" ? drizzleOrm.sql.raw(` WHERE NOT ${ident(tombstoned2)}`) : drizzleOrm.sql.raw("");
2453
2461
  const sourcePk = ident(physical({ source, property: plan.pk }));
2454
2462
  const selectedPk = sourcePk === ident(pkColumn) ? sourcePk : `${sourcePk} AS ${ident(pkColumn)}`;
2455
2463
  return drizzleOrm.sql`SELECT ${drizzleOrm.sql.raw(selectedPk)} FROM ${relation(source.table)}${where}`;
2456
2464
  });
2457
- const joins = plan.plans.map(
2458
- (source) => drizzleOrm.sql` LEFT JOIN ${relation(source.table)} AS ${drizzleOrm.sql.raw(alias(source.name))} ON ${drizzleOrm.sql.raw(`${alias(source.name)}.${ident(physical({ source, property: plan.pk }))} = "k".${ident(pkColumn)}`)}`
2465
+ const base2 = keySource ? drizzleOrm.sql`${relation(keySource.table)} AS ${drizzleOrm.sql.raw(alias(keySource.name))}` : drizzleOrm.sql`(${drizzleOrm.sql.join(keyBranches, drizzleOrm.sql.raw(" UNION "))}) AS "k"`;
2466
+ const joins = plan.plans.filter((source) => source !== keySource).map(
2467
+ (source) => drizzleOrm.sql` LEFT JOIN ${relation(source.table)} AS ${drizzleOrm.sql.raw(alias(source.name))} ON ${drizzleOrm.sql.raw(`${alias(source.name)}.${ident(physical({ source, property: plan.pk }))} = ${keyRef}`)}`
2459
2468
  );
2460
2469
  const cells = /* @__PURE__ */ new Map();
2461
2470
  plan.rules.forEach((rule, index3) => {
2462
2471
  const canonical = plan.columns[rule.column].toCanonicalColumn(rule.column);
2463
2472
  const pgType = typeof canonical.type === "string" ? PG_TYPE[canonical.type] : `${schema === void 0 ? "" : `${ident(schema)}.`}${ident(canonical.type.enum)}`;
2464
2473
  const candidates = rule.candidates.map((name2) => candidateSql({ source: sourceByName.get(name2), column: rule.column, pk: plan.pk, pgType }));
2465
- cells.set(rule.column, rule.comparator === "custom" ? customCell({ candidates, orderBy: rule.orderBy, index: index3 }) : builtinCell({ comparator: rule.comparator, candidates }));
2474
+ cells.set(rule.column, keySource && rule.candidates.length === 1 && rule.candidates[0] === keySource.name ? existsInCell(candidates[0]) : rule.comparator === "custom" ? customCell({ candidates, orderBy: rule.orderBy, index: index3 }) : builtinCell({ comparator: rule.comparator, candidates }));
2466
2475
  });
2467
2476
  const laterals = [...cells.values()].flatMap((cell) => cell.lateral ? [drizzleOrm.sql.raw(cell.lateral)] : []);
2468
- const from = drizzleOrm.sql.join([drizzleOrm.sql`(${drizzleOrm.sql.join(keyBranches, drizzleOrm.sql.raw(" UNION "))}) AS "k"`, ...joins, ...laterals], drizzleOrm.sql.raw(""));
2477
+ const from = drizzleOrm.sql.join([base2, ...joins, ...laterals], drizzleOrm.sql.raw(""));
2469
2478
  const selected = {
2470
- [plan.pk]: drizzleOrm.sql.raw(`"k".${ident(pkColumn)}`).as(pkColumn)
2479
+ [plan.pk]: drizzleOrm.sql.raw(keyRef).as(pkColumn)
2471
2480
  };
2472
2481
  for (const [property, builder] of Object.entries(plan.columns)) {
2473
2482
  if (property === plan.pk) continue;
@@ -2539,10 +2548,12 @@ function defineResolvedTable(name2, columns, config) {
2539
2548
  for (const source of deletedBy) {
2540
2549
  if (plans.find((plan) => plan.name === source)?.kind !== "manual") fail3(`rows.deletedBy "${source}" must be the manual source`);
2541
2550
  }
2551
+ const existsIn = planExistsIn({ config, plans, fail: fail3 });
2552
+ const notNullColumns = existsIn ? inheritedNotNullColumns({ existsIn, rules }) : /* @__PURE__ */ new Set();
2542
2553
  const partType = { source: t.text, at: t.timestamptz, by: t.text, conflicts: t.jsonb };
2543
2554
  const viewColumns = {};
2544
2555
  for (const [property, builder] of Object.entries(columns)) {
2545
- viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk, primaryKey: property === pk });
2556
+ viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk || notNullColumns.has(property), primaryKey: property === pk });
2546
2557
  if (property === pk) continue;
2547
2558
  const columnName = builder.columnNameFor(property);
2548
2559
  for (const part of RESOLVED_VIEW_CELL_PARTS) {
@@ -2558,7 +2569,7 @@ function defineResolvedTable(name2, columns, config) {
2558
2569
  deletedBy,
2559
2570
  policies: writePolicies
2560
2571
  };
2561
- const queryPlan = { columns, pk, plans, rules, deletedBy };
2572
+ const queryPlan = { columns, pk, plans, rules, deletedBy, ...existsIn ? { existsIn: existsIn.name } : {} };
2562
2573
  const typedColumns = viewColumns;
2563
2574
  const surface = {
2564
2575
  ...config.description !== void 0 ? { description: config.description } : {},
@@ -2600,6 +2611,18 @@ function defineResolvedTable(name2, columns, config) {
2600
2611
  }
2601
2612
  });
2602
2613
  }
2614
+ function planExistsIn({ config, plans, fail: fail3 }) {
2615
+ const names = config.rows?.existsIn;
2616
+ if (names === void 0) return void 0;
2617
+ if (names.length !== 1) fail3("rows.existsIn names exactly one etl source");
2618
+ const source = plans.find((plan) => plan.name === names[0]);
2619
+ if (source?.kind !== "etl") fail3(`rows.existsIn "${names[0]}" must be an etl source`);
2620
+ if (config.policies.insert !== void 0 || config.policies.write !== void 0) fail3("rows.existsIn allows only an update policy: rows come from the etl source");
2621
+ return source;
2622
+ }
2623
+ function inheritedNotNullColumns({ existsIn, rules }) {
2624
+ return new Set(rules.filter((rule) => rule.candidates.length === 1 && rule.candidates[0] === existsIn.name).map((rule) => rule.column).filter((column) => existsIn.table.columns[column]?.toCanonicalColumn(column).nullable === false));
2625
+ }
2603
2626
  function planRules({ config, plans, dataColumns, fail: fail3 }) {
2604
2627
  const kindOrder = { manual: 0, prefetch: 1, etl: 2 };
2605
2628
  const fallback = config.default ?? priority([...plans].sort((a, b) => kindOrder[a.kind] - kindOrder[b.kind]).map((plan) => plan.name));