@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.
- package/README.md +5 -0
- package/dist/authoring.cjs +31 -8
- package/dist/authoring.cjs.map +1 -1
- package/dist/authoring.d.cts +8 -2
- package/dist/authoring.d.ts +8 -2
- package/dist/authoring.js +31 -8
- package/dist/authoring.js.map +1 -1
- package/dist/canonical.cjs +1 -1
- package/dist/canonical.cjs.map +1 -1
- package/dist/canonical.d.cts +1 -1
- package/dist/canonical.d.ts +1 -1
- package/dist/canonical.js +1 -1
- package/dist/canonical.js.map +1 -1
- package/dist/cli.cjs +27 -24
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +31 -28
- package/dist/cli.js.map +1 -1
- package/dist/compiler.cjs +1 -1
- package/dist/compiler.cjs.map +1 -1
- package/dist/compiler.d.cts +4 -4
- package/dist/compiler.d.ts +4 -4
- package/dist/compiler.js +1 -1
- package/dist/compiler.js.map +1 -1
- package/dist/index.cjs +31 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -9
- package/dist/index.d.ts +7 -9
- package/dist/index.js +31 -8
- package/dist/index.js.map +1 -1
- package/dist/ir.cjs +1 -1
- package/dist/ir.cjs.map +1 -1
- package/dist/ir.d.cts +2 -2
- package/dist/ir.d.ts +2 -2
- package/dist/ir.js +1 -1
- package/dist/ir.js.map +1 -1
- package/dist/{naming-CU9ThP_E.d.cts → naming-BMZKFO0W.d.cts} +1 -2
- package/dist/{naming-CPfx7EfF.d.ts → naming-DUk7AcXs.d.ts} +1 -2
- package/dist/predicate-v2.cjs +1 -1
- package/dist/predicate-v2.cjs.map +1 -1
- package/dist/predicate-v2.d.cts +3 -3
- package/dist/predicate-v2.d.ts +3 -3
- package/dist/predicate-v2.js +1 -1
- package/dist/predicate-v2.js.map +1 -1
- package/dist/sdl.cjs +1 -1
- package/dist/sdl.cjs.map +1 -1
- package/dist/sdl.d.cts +2 -2
- package/dist/sdl.d.ts +2 -2
- package/dist/sdl.js +1 -1
- package/dist/sdl.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen-gql/apollo-hooks.cjs +1 -1
- package/src/codegen-gql/server-fns.cjs +1 -1
- package/templates/orm-namespace/graphql/example/queries.ts +1 -1
package/dist/authoring.d.cts
CHANGED
|
@@ -286,7 +286,7 @@ declare const nonNullFirst: (candidates: readonly string[]) => Comparator;
|
|
|
286
286
|
* wins; `ord` is always appended as the final tie-break.
|
|
287
287
|
*
|
|
288
288
|
* ```ts
|
|
289
|
-
* custom(['edits', '
|
|
289
|
+
* custom(['edits', 'vendor'], "CASE WHEN source = 'vendor' AND value IS NOT NULL THEN 0 ELSE 1 END")
|
|
290
290
|
* ```
|
|
291
291
|
*/
|
|
292
292
|
declare const custom: (candidates: readonly string[], orderBy: string) => Comparator;
|
|
@@ -305,6 +305,12 @@ interface ResolvedTableConfig {
|
|
|
305
305
|
default?: Comparator;
|
|
306
306
|
rows?: {
|
|
307
307
|
deletedBy?: readonly string[];
|
|
308
|
+
/**
|
|
309
|
+
* A row exists only while this etl source has its key; edits and other
|
|
310
|
+
* sources only change values. A column resolved from this source alone
|
|
311
|
+
* keeps the synced column's NOT NULL. Exactly one etl source.
|
|
312
|
+
*/
|
|
313
|
+
existsIn?: readonly string[];
|
|
308
314
|
};
|
|
309
315
|
links?: Record<string, SeqLink>;
|
|
310
316
|
/** Reads use `read`; writes are evaluated against the resolved row. */
|
|
@@ -547,7 +553,7 @@ interface ForeignKeyInput {
|
|
|
547
553
|
interface TableConfig {
|
|
548
554
|
displayName?: string;
|
|
549
555
|
description?: string;
|
|
550
|
-
/** Table-level migration rename hint
|
|
556
|
+
/** Table-level migration rename hint. */
|
|
551
557
|
renamedFrom?: string;
|
|
552
558
|
/** Composite primary key: property names (or column names). Mutually exclusive with column-level `.primaryKey()`. */
|
|
553
559
|
primaryKey?: readonly string[];
|
package/dist/authoring.d.ts
CHANGED
|
@@ -286,7 +286,7 @@ declare const nonNullFirst: (candidates: readonly string[]) => Comparator;
|
|
|
286
286
|
* wins; `ord` is always appended as the final tie-break.
|
|
287
287
|
*
|
|
288
288
|
* ```ts
|
|
289
|
-
* custom(['edits', '
|
|
289
|
+
* custom(['edits', 'vendor'], "CASE WHEN source = 'vendor' AND value IS NOT NULL THEN 0 ELSE 1 END")
|
|
290
290
|
* ```
|
|
291
291
|
*/
|
|
292
292
|
declare const custom: (candidates: readonly string[], orderBy: string) => Comparator;
|
|
@@ -305,6 +305,12 @@ interface ResolvedTableConfig {
|
|
|
305
305
|
default?: Comparator;
|
|
306
306
|
rows?: {
|
|
307
307
|
deletedBy?: readonly string[];
|
|
308
|
+
/**
|
|
309
|
+
* A row exists only while this etl source has its key; edits and other
|
|
310
|
+
* sources only change values. A column resolved from this source alone
|
|
311
|
+
* keeps the synced column's NOT NULL. Exactly one etl source.
|
|
312
|
+
*/
|
|
313
|
+
existsIn?: readonly string[];
|
|
308
314
|
};
|
|
309
315
|
links?: Record<string, SeqLink>;
|
|
310
316
|
/** Reads use `read`; writes are evaluated against the resolved row. */
|
|
@@ -547,7 +553,7 @@ interface ForeignKeyInput {
|
|
|
547
553
|
interface TableConfig {
|
|
548
554
|
displayName?: string;
|
|
549
555
|
description?: string;
|
|
550
|
-
/** Table-level migration rename hint
|
|
556
|
+
/** Table-level migration rename hint. */
|
|
551
557
|
renamedFrom?: string;
|
|
552
558
|
/** Composite primary key: property names (or column names). Mutually exclusive with column-level `.primaryKey()`. */
|
|
553
559
|
primaryKey?: readonly string[];
|
package/dist/authoring.js
CHANGED
|
@@ -1695,7 +1695,7 @@ var canonicalTableSchema = z.object({
|
|
|
1695
1695
|
table: identifier2,
|
|
1696
1696
|
displayName: z.string().trim().min(1).max(120).optional(),
|
|
1697
1697
|
description: z.string().max(2e3).optional(),
|
|
1698
|
-
/** Table-level rename hint
|
|
1698
|
+
/** Table-level rename hint. */
|
|
1699
1699
|
renamedFrom: identifier2.optional(),
|
|
1700
1700
|
/** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
|
|
1701
1701
|
source: z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
|
|
@@ -2359,6 +2359,12 @@ function builtinCell({ comparator, candidates }) {
|
|
|
2359
2359
|
}
|
|
2360
2360
|
};
|
|
2361
2361
|
}
|
|
2362
|
+
function existsInCell(candidate) {
|
|
2363
|
+
return {
|
|
2364
|
+
value: candidate.value,
|
|
2365
|
+
parts: { source: literal(candidate.source), at: candidate.at, by: candidate.by, conflicts: "CAST(NULL AS jsonb)" }
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
2362
2368
|
function customCell({ candidates, orderBy, index }) {
|
|
2363
2369
|
const w = ident(`w_${index}`);
|
|
2364
2370
|
const rows = candidates.map((c, ord) => `(${literal(c.source)}, ${c.has}, ${c.value}, ${c.at}, ${c.by}, ${ord})`);
|
|
@@ -2382,26 +2388,29 @@ function buildResolvedQuery({ context, plan }) {
|
|
|
2382
2388
|
const tombstoned2 = RESOLVED_SOURCE_SYSTEM_COLUMNS.tombstoned.columnName;
|
|
2383
2389
|
const sourceByName = new Map(plan.plans.map((source) => [source.name, source]));
|
|
2384
2390
|
const schema = getTableConfig(relation(plan.plans[0].table)).schema;
|
|
2391
|
+
const keySource = plan.existsIn === void 0 ? void 0 : sourceByName.get(plan.existsIn);
|
|
2392
|
+
const keyRef = keySource ? `${alias(keySource.name)}.${ident(physical({ source: keySource, property: plan.pk }))}` : `"k".${ident(pkColumn)}`;
|
|
2385
2393
|
const keyBranches = plan.plans.map((source) => {
|
|
2386
2394
|
const where = source.kind === "prefetch" ? sql.raw(` WHERE NOT ${ident(tombstoned2)}`) : sql.raw("");
|
|
2387
2395
|
const sourcePk = ident(physical({ source, property: plan.pk }));
|
|
2388
2396
|
const selectedPk = sourcePk === ident(pkColumn) ? sourcePk : `${sourcePk} AS ${ident(pkColumn)}`;
|
|
2389
2397
|
return sql`SELECT ${sql.raw(selectedPk)} FROM ${relation(source.table)}${where}`;
|
|
2390
2398
|
});
|
|
2391
|
-
const
|
|
2392
|
-
|
|
2399
|
+
const base2 = keySource ? sql`${relation(keySource.table)} AS ${sql.raw(alias(keySource.name))}` : sql`(${sql.join(keyBranches, sql.raw(" UNION "))}) AS "k"`;
|
|
2400
|
+
const joins = plan.plans.filter((source) => source !== keySource).map(
|
|
2401
|
+
(source) => sql` LEFT JOIN ${relation(source.table)} AS ${sql.raw(alias(source.name))} ON ${sql.raw(`${alias(source.name)}.${ident(physical({ source, property: plan.pk }))} = ${keyRef}`)}`
|
|
2393
2402
|
);
|
|
2394
2403
|
const cells = /* @__PURE__ */ new Map();
|
|
2395
2404
|
plan.rules.forEach((rule, index) => {
|
|
2396
2405
|
const canonical = plan.columns[rule.column].toCanonicalColumn(rule.column);
|
|
2397
2406
|
const pgType = typeof canonical.type === "string" ? PG_TYPE[canonical.type] : `${schema === void 0 ? "" : `${ident(schema)}.`}${ident(canonical.type.enum)}`;
|
|
2398
2407
|
const candidates = rule.candidates.map((name2) => candidateSql({ source: sourceByName.get(name2), column: rule.column, pk: plan.pk, pgType }));
|
|
2399
|
-
cells.set(rule.column, rule.comparator === "custom" ? customCell({ candidates, orderBy: rule.orderBy, index }) : builtinCell({ comparator: rule.comparator, candidates }));
|
|
2408
|
+
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 }) : builtinCell({ comparator: rule.comparator, candidates }));
|
|
2400
2409
|
});
|
|
2401
2410
|
const laterals = [...cells.values()].flatMap((cell) => cell.lateral ? [sql.raw(cell.lateral)] : []);
|
|
2402
|
-
const from = sql.join([
|
|
2411
|
+
const from = sql.join([base2, ...joins, ...laterals], sql.raw(""));
|
|
2403
2412
|
const selected = {
|
|
2404
|
-
[plan.pk]: sql.raw(
|
|
2413
|
+
[plan.pk]: sql.raw(keyRef).as(pkColumn)
|
|
2405
2414
|
};
|
|
2406
2415
|
for (const [property, builder] of Object.entries(plan.columns)) {
|
|
2407
2416
|
if (property === plan.pk) continue;
|
|
@@ -2473,10 +2482,12 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2473
2482
|
for (const source of deletedBy) {
|
|
2474
2483
|
if (plans.find((plan) => plan.name === source)?.kind !== "manual") fail(`rows.deletedBy "${source}" must be the manual source`);
|
|
2475
2484
|
}
|
|
2485
|
+
const existsIn = planExistsIn({ config, plans, fail });
|
|
2486
|
+
const notNullColumns = existsIn ? inheritedNotNullColumns({ existsIn, rules }) : /* @__PURE__ */ new Set();
|
|
2476
2487
|
const partType = { source: t.text, at: t.timestamptz, by: t.text, conflicts: t.jsonb };
|
|
2477
2488
|
const viewColumns = {};
|
|
2478
2489
|
for (const [property, builder] of Object.entries(columns)) {
|
|
2479
|
-
viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk, primaryKey: property === pk });
|
|
2490
|
+
viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk || notNullColumns.has(property), primaryKey: property === pk });
|
|
2480
2491
|
if (property === pk) continue;
|
|
2481
2492
|
const columnName = builder.columnNameFor(property);
|
|
2482
2493
|
for (const part of RESOLVED_VIEW_CELL_PARTS) {
|
|
@@ -2492,7 +2503,7 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2492
2503
|
deletedBy,
|
|
2493
2504
|
policies: writePolicies
|
|
2494
2505
|
};
|
|
2495
|
-
const queryPlan = { columns, pk, plans, rules, deletedBy };
|
|
2506
|
+
const queryPlan = { columns, pk, plans, rules, deletedBy, ...existsIn ? { existsIn: existsIn.name } : {} };
|
|
2496
2507
|
const typedColumns = viewColumns;
|
|
2497
2508
|
const surface = {
|
|
2498
2509
|
...config.description !== void 0 ? { description: config.description } : {},
|
|
@@ -2534,6 +2545,18 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2534
2545
|
}
|
|
2535
2546
|
});
|
|
2536
2547
|
}
|
|
2548
|
+
function planExistsIn({ config, plans, fail }) {
|
|
2549
|
+
const names = config.rows?.existsIn;
|
|
2550
|
+
if (names === void 0) return void 0;
|
|
2551
|
+
if (names.length !== 1) fail("rows.existsIn names exactly one etl source");
|
|
2552
|
+
const source = plans.find((plan) => plan.name === names[0]);
|
|
2553
|
+
if (source?.kind !== "etl") fail(`rows.existsIn "${names[0]}" must be an etl source`);
|
|
2554
|
+
if (config.policies.insert !== void 0 || config.policies.write !== void 0) fail("rows.existsIn allows only an update policy: rows come from the etl source");
|
|
2555
|
+
return source;
|
|
2556
|
+
}
|
|
2557
|
+
function inheritedNotNullColumns({ existsIn, rules }) {
|
|
2558
|
+
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));
|
|
2559
|
+
}
|
|
2537
2560
|
function planRules({ config, plans, dataColumns, fail }) {
|
|
2538
2561
|
const kindOrder = { manual: 0, prefetch: 1, etl: 2 };
|
|
2539
2562
|
const fallback = config.default ?? priority([...plans].sort((a, b) => kindOrder[a.kind] - kindOrder[b.kind]).map((plan) => plan.name));
|