@sequenceholdings/orm 2.8.3 → 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/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 +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- 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/index.d.cts
CHANGED
|
@@ -578,6 +578,12 @@ interface SyncedBacking {
|
|
|
578
578
|
*/
|
|
579
579
|
readonly readGuard?: 'crm-serving-v2';
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Atlas reassigns every relation in `orm_<ns>` to this role after apply.
|
|
583
|
+
* Synced views resolve backing access as their owner. Grant this role narrow
|
|
584
|
+
* SELECT before CREATE VIEW, or preserve a separately verified publisher grant.
|
|
585
|
+
*/
|
|
586
|
+
declare const SYNCED_VIEW_EXECUTION_OWNER_ROLE = "orm_exec";
|
|
581
587
|
/**
|
|
582
588
|
* Emit CREATE OR REPLACE VIEW + SELECT-only grants for synced tables that have
|
|
583
589
|
* a registered backing. Synced tables cannot use table-level RLS (they may be
|
|
@@ -586,12 +592,6 @@ interface SyncedBacking {
|
|
|
586
592
|
* Each view lives in `orm_<ns>` alongside regular tables, named identically to
|
|
587
593
|
* the synced table definition so read routing is transparent.
|
|
588
594
|
*/
|
|
589
|
-
/**
|
|
590
|
-
* Atlas reassigns every relation in `orm_<ns>` to this role after apply.
|
|
591
|
-
* Synced views resolve backing access as their owner. Grant this role narrow
|
|
592
|
-
* SELECT before CREATE VIEW, or preserve a separately verified publisher grant.
|
|
593
|
-
*/
|
|
594
|
-
declare const SYNCED_VIEW_EXECUTION_OWNER_ROLE = "orm_exec";
|
|
595
595
|
declare function syncedViewStatements({ definition, backings, readPolicyIrByTable, policyTables, columnNamesByTable, columnTypesByTable, executionOwnerRole, backingPrivileges, viewPrivileges, statementClaimChecks, }: {
|
|
596
596
|
definition: NamespaceDefinition;
|
|
597
597
|
backings: readonly SyncedBacking[];
|
|
@@ -747,9 +747,7 @@ declare function planCommittedMigrationV2({ canonical, previousSnapshot, reprodu
|
|
|
747
747
|
* and types the live view from the SELECT itself. Assert the live catalog in
|
|
748
748
|
* the same transaction so a stale alias/type or an incomplete dependency
|
|
749
749
|
* declaration can never be persisted as a successful schema version.
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Assert live view columns/types/dependencies match the canonical contract.
|
|
750
|
+
*
|
|
753
751
|
* Used by planMigrationV2 and by CASCADE recovery recreates (same transaction).
|
|
754
752
|
*/
|
|
755
753
|
declare function validateViewCatalogStatement({ canonical, view, schema, }: {
|
package/dist/index.d.ts
CHANGED
|
@@ -578,6 +578,12 @@ interface SyncedBacking {
|
|
|
578
578
|
*/
|
|
579
579
|
readonly readGuard?: 'crm-serving-v2';
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Atlas reassigns every relation in `orm_<ns>` to this role after apply.
|
|
583
|
+
* Synced views resolve backing access as their owner. Grant this role narrow
|
|
584
|
+
* SELECT before CREATE VIEW, or preserve a separately verified publisher grant.
|
|
585
|
+
*/
|
|
586
|
+
declare const SYNCED_VIEW_EXECUTION_OWNER_ROLE = "orm_exec";
|
|
581
587
|
/**
|
|
582
588
|
* Emit CREATE OR REPLACE VIEW + SELECT-only grants for synced tables that have
|
|
583
589
|
* a registered backing. Synced tables cannot use table-level RLS (they may be
|
|
@@ -586,12 +592,6 @@ interface SyncedBacking {
|
|
|
586
592
|
* Each view lives in `orm_<ns>` alongside regular tables, named identically to
|
|
587
593
|
* the synced table definition so read routing is transparent.
|
|
588
594
|
*/
|
|
589
|
-
/**
|
|
590
|
-
* Atlas reassigns every relation in `orm_<ns>` to this role after apply.
|
|
591
|
-
* Synced views resolve backing access as their owner. Grant this role narrow
|
|
592
|
-
* SELECT before CREATE VIEW, or preserve a separately verified publisher grant.
|
|
593
|
-
*/
|
|
594
|
-
declare const SYNCED_VIEW_EXECUTION_OWNER_ROLE = "orm_exec";
|
|
595
595
|
declare function syncedViewStatements({ definition, backings, readPolicyIrByTable, policyTables, columnNamesByTable, columnTypesByTable, executionOwnerRole, backingPrivileges, viewPrivileges, statementClaimChecks, }: {
|
|
596
596
|
definition: NamespaceDefinition;
|
|
597
597
|
backings: readonly SyncedBacking[];
|
|
@@ -747,9 +747,7 @@ declare function planCommittedMigrationV2({ canonical, previousSnapshot, reprodu
|
|
|
747
747
|
* and types the live view from the SELECT itself. Assert the live catalog in
|
|
748
748
|
* the same transaction so a stale alias/type or an incomplete dependency
|
|
749
749
|
* declaration can never be persisted as a successful schema version.
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* Assert live view columns/types/dependencies match the canonical contract.
|
|
750
|
+
*
|
|
753
751
|
* Used by planMigrationV2 and by CASCADE recovery recreates (same transaction).
|
|
754
752
|
*/
|
|
755
753
|
declare function validateViewCatalogStatement({ canonical, view, schema, }: {
|
package/dist/index.js
CHANGED
|
@@ -1759,7 +1759,7 @@ var canonicalTableSchema = z.object({
|
|
|
1759
1759
|
table: identifier2,
|
|
1760
1760
|
displayName: z.string().trim().min(1).max(120).optional(),
|
|
1761
1761
|
description: z.string().max(2e3).optional(),
|
|
1762
|
-
/** Table-level rename hint
|
|
1762
|
+
/** Table-level rename hint. */
|
|
1763
1763
|
renamedFrom: identifier2.optional(),
|
|
1764
1764
|
/** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
|
|
1765
1765
|
source: z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
|
|
@@ -2423,6 +2423,12 @@ function builtinCell({ comparator, candidates }) {
|
|
|
2423
2423
|
}
|
|
2424
2424
|
};
|
|
2425
2425
|
}
|
|
2426
|
+
function existsInCell(candidate) {
|
|
2427
|
+
return {
|
|
2428
|
+
value: candidate.value,
|
|
2429
|
+
parts: { source: literal(candidate.source), at: candidate.at, by: candidate.by, conflicts: "CAST(NULL AS jsonb)" }
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2426
2432
|
function customCell({ candidates, orderBy, index: index3 }) {
|
|
2427
2433
|
const w = ident(`w_${index3}`);
|
|
2428
2434
|
const rows = candidates.map((c, ord) => `(${literal(c.source)}, ${c.has}, ${c.value}, ${c.at}, ${c.by}, ${ord})`);
|
|
@@ -2446,26 +2452,29 @@ function buildResolvedQuery({ context, plan }) {
|
|
|
2446
2452
|
const tombstoned2 = RESOLVED_SOURCE_SYSTEM_COLUMNS.tombstoned.columnName;
|
|
2447
2453
|
const sourceByName = new Map(plan.plans.map((source) => [source.name, source]));
|
|
2448
2454
|
const schema = getTableConfig(relation(plan.plans[0].table)).schema;
|
|
2455
|
+
const keySource = plan.existsIn === void 0 ? void 0 : sourceByName.get(plan.existsIn);
|
|
2456
|
+
const keyRef = keySource ? `${alias(keySource.name)}.${ident(physical({ source: keySource, property: plan.pk }))}` : `"k".${ident(pkColumn)}`;
|
|
2449
2457
|
const keyBranches = plan.plans.map((source) => {
|
|
2450
2458
|
const where = source.kind === "prefetch" ? sql.raw(` WHERE NOT ${ident(tombstoned2)}`) : sql.raw("");
|
|
2451
2459
|
const sourcePk = ident(physical({ source, property: plan.pk }));
|
|
2452
2460
|
const selectedPk = sourcePk === ident(pkColumn) ? sourcePk : `${sourcePk} AS ${ident(pkColumn)}`;
|
|
2453
2461
|
return sql`SELECT ${sql.raw(selectedPk)} FROM ${relation(source.table)}${where}`;
|
|
2454
2462
|
});
|
|
2455
|
-
const
|
|
2456
|
-
|
|
2463
|
+
const base2 = keySource ? sql`${relation(keySource.table)} AS ${sql.raw(alias(keySource.name))}` : sql`(${sql.join(keyBranches, sql.raw(" UNION "))}) AS "k"`;
|
|
2464
|
+
const joins = plan.plans.filter((source) => source !== keySource).map(
|
|
2465
|
+
(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}`)}`
|
|
2457
2466
|
);
|
|
2458
2467
|
const cells = /* @__PURE__ */ new Map();
|
|
2459
2468
|
plan.rules.forEach((rule, index3) => {
|
|
2460
2469
|
const canonical = plan.columns[rule.column].toCanonicalColumn(rule.column);
|
|
2461
2470
|
const pgType = typeof canonical.type === "string" ? PG_TYPE[canonical.type] : `${schema === void 0 ? "" : `${ident(schema)}.`}${ident(canonical.type.enum)}`;
|
|
2462
2471
|
const candidates = rule.candidates.map((name2) => candidateSql({ source: sourceByName.get(name2), column: rule.column, pk: plan.pk, pgType }));
|
|
2463
|
-
cells.set(rule.column, rule.comparator === "custom" ? customCell({ candidates, orderBy: rule.orderBy, index: index3 }) : builtinCell({ comparator: rule.comparator, candidates }));
|
|
2472
|
+
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 }));
|
|
2464
2473
|
});
|
|
2465
2474
|
const laterals = [...cells.values()].flatMap((cell) => cell.lateral ? [sql.raw(cell.lateral)] : []);
|
|
2466
|
-
const from = sql.join([
|
|
2475
|
+
const from = sql.join([base2, ...joins, ...laterals], sql.raw(""));
|
|
2467
2476
|
const selected = {
|
|
2468
|
-
[plan.pk]: sql.raw(
|
|
2477
|
+
[plan.pk]: sql.raw(keyRef).as(pkColumn)
|
|
2469
2478
|
};
|
|
2470
2479
|
for (const [property, builder] of Object.entries(plan.columns)) {
|
|
2471
2480
|
if (property === plan.pk) continue;
|
|
@@ -2537,10 +2546,12 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2537
2546
|
for (const source of deletedBy) {
|
|
2538
2547
|
if (plans.find((plan) => plan.name === source)?.kind !== "manual") fail3(`rows.deletedBy "${source}" must be the manual source`);
|
|
2539
2548
|
}
|
|
2549
|
+
const existsIn = planExistsIn({ config, plans, fail: fail3 });
|
|
2550
|
+
const notNullColumns = existsIn ? inheritedNotNullColumns({ existsIn, rules }) : /* @__PURE__ */ new Set();
|
|
2540
2551
|
const partType = { source: t.text, at: t.timestamptz, by: t.text, conflicts: t.jsonb };
|
|
2541
2552
|
const viewColumns = {};
|
|
2542
2553
|
for (const [property, builder] of Object.entries(columns)) {
|
|
2543
|
-
viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk, primaryKey: property === pk });
|
|
2554
|
+
viewColumns[property] = cloneColumn({ builder, property, notNull: property === pk || notNullColumns.has(property), primaryKey: property === pk });
|
|
2544
2555
|
if (property === pk) continue;
|
|
2545
2556
|
const columnName = builder.columnNameFor(property);
|
|
2546
2557
|
for (const part of RESOLVED_VIEW_CELL_PARTS) {
|
|
@@ -2556,7 +2567,7 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2556
2567
|
deletedBy,
|
|
2557
2568
|
policies: writePolicies
|
|
2558
2569
|
};
|
|
2559
|
-
const queryPlan = { columns, pk, plans, rules, deletedBy };
|
|
2570
|
+
const queryPlan = { columns, pk, plans, rules, deletedBy, ...existsIn ? { existsIn: existsIn.name } : {} };
|
|
2560
2571
|
const typedColumns = viewColumns;
|
|
2561
2572
|
const surface = {
|
|
2562
2573
|
...config.description !== void 0 ? { description: config.description } : {},
|
|
@@ -2598,6 +2609,18 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2598
2609
|
}
|
|
2599
2610
|
});
|
|
2600
2611
|
}
|
|
2612
|
+
function planExistsIn({ config, plans, fail: fail3 }) {
|
|
2613
|
+
const names = config.rows?.existsIn;
|
|
2614
|
+
if (names === void 0) return void 0;
|
|
2615
|
+
if (names.length !== 1) fail3("rows.existsIn names exactly one etl source");
|
|
2616
|
+
const source = plans.find((plan) => plan.name === names[0]);
|
|
2617
|
+
if (source?.kind !== "etl") fail3(`rows.existsIn "${names[0]}" must be an etl source`);
|
|
2618
|
+
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");
|
|
2619
|
+
return source;
|
|
2620
|
+
}
|
|
2621
|
+
function inheritedNotNullColumns({ existsIn, rules }) {
|
|
2622
|
+
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));
|
|
2623
|
+
}
|
|
2601
2624
|
function planRules({ config, plans, dataColumns, fail: fail3 }) {
|
|
2602
2625
|
const kindOrder = { manual: 0, prefetch: 1, etl: 2 };
|
|
2603
2626
|
const fallback = config.default ?? priority([...plans].sort((a, b) => kindOrder[a.kind] - kindOrder[b.kind]).map((plan) => plan.name));
|