@sequenceholdings/orm 2.3.0 → 2.5.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/authoring.cjs +53 -7
- package/dist/authoring.cjs.map +1 -1
- package/dist/authoring.d.cts +11 -7
- package/dist/authoring.d.ts +11 -7
- package/dist/authoring.js +53 -7
- package/dist/authoring.js.map +1 -1
- package/dist/canonical.cjs +48 -2
- package/dist/canonical.cjs.map +1 -1
- package/dist/canonical.d.cts +72 -72
- package/dist/canonical.d.ts +72 -72
- package/dist/canonical.js +48 -2
- package/dist/canonical.js.map +1 -1
- package/dist/cli.cjs +337 -86
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +337 -86
- package/dist/cli.js.map +1 -1
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/compiler.cjs +493 -52
- package/dist/compiler.cjs.map +1 -1
- package/dist/compiler.d.cts +22 -7
- package/dist/compiler.d.ts +22 -7
- package/dist/compiler.js +493 -53
- package/dist/compiler.js.map +1 -1
- package/dist/{constants-C6EG6Wq7.d.cts → constants-Dou1RkTo.d.cts} +7 -2
- package/dist/{constants-C6EG6Wq7.d.ts → constants-Dou1RkTo.d.ts} +7 -2
- package/dist/dynamic-input.d.cts +1 -1
- package/dist/dynamic-input.d.ts +1 -1
- package/dist/index.cjs +329 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -58
- package/dist/index.d.ts +66 -58
- package/dist/index.js +329 -131
- package/dist/index.js.map +1 -1
- package/dist/ir.cjs +50 -3
- package/dist/ir.cjs.map +1 -1
- package/dist/ir.d.cts +71 -71
- package/dist/ir.d.ts +71 -71
- package/dist/ir.js +50 -3
- package/dist/ir.js.map +1 -1
- package/dist/predicate-v2.cjs +145 -22
- package/dist/predicate-v2.cjs.map +1 -1
- package/dist/predicate-v2.d.cts +41 -4
- package/dist/predicate-v2.d.ts +41 -4
- package/dist/predicate-v2.js +145 -22
- package/dist/predicate-v2.js.map +1 -1
- package/dist/sdl.cjs +53 -3
- package/dist/sdl.cjs.map +1 -1
- package/dist/sdl.d.cts +3 -1
- package/dist/sdl.d.ts +3 -1
- package/dist/sdl.js +53 -3
- package/dist/sdl.js.map +1 -1
- package/package.json +1 -1
- package/dist/{definition-DjfC7Lll.d.cts → definition-B99BsOAO.d.cts} +4 -4
- package/dist/{definition-DjfC7Lll.d.ts → definition-B99BsOAO.d.ts} +4 -4
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { realpath, stat, readdir, readFile, mkdir, writeFile } from 'fs/promises
|
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
8
|
import { join, sep, extname } from 'path';
|
|
9
9
|
import { generateDrizzleJson, upPgSnapshot, generateMigration, pushSchema } from 'drizzle-kit/api';
|
|
10
|
+
import { PgParser } from '@supabase/pg-parser';
|
|
10
11
|
import { load } from 'js-yaml';
|
|
11
12
|
import { capabilityPinsSchema, customRolesBlockSchema, validateCapabilityPins } from '@sequenceholdings/custom-roles-manifest';
|
|
12
13
|
export { capabilityPinsSchema, customRolesBlockSchema, customRolesDeclared, parseCapabilityPin, validateCapabilityPins } from '@sequenceholdings/custom-roles-manifest';
|
|
@@ -155,20 +156,24 @@ var t = {
|
|
|
155
156
|
};
|
|
156
157
|
|
|
157
158
|
// src/constants.ts
|
|
158
|
-
var NAMESPACE_PATTERN = /^[a-z][a-z0-9_]{0,40}$/;
|
|
159
|
+
var NAMESPACE_PATTERN = /^(?!(?:events|native_sources)$)[a-z][a-z0-9_]{0,40}$/;
|
|
159
160
|
var ORM_DATA_TOKEN_HEADER = "x-sequence-data-token";
|
|
160
161
|
var ORM_SERVICE_DATA_TOKEN_HEADER = "x-sequence-data-token-service";
|
|
161
162
|
var IDENTIFIER_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
162
163
|
var COLUMN_IDENTIFIER_PATTERN = /^_?[a-z][a-z0-9_]*$/;
|
|
163
164
|
var MAX_IDENTIFIER_LENGTH = 63;
|
|
164
165
|
var CAPABILITY_KEY_PATTERN = /^(?:org\/|app\/[a-z][a-z0-9-]{0,63}\/)?[a-z0-9-]{1,64}$/;
|
|
166
|
+
var MAX_PERSISTED_READ_ROWS = 50001;
|
|
165
167
|
var CLAIM_KEY_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
166
168
|
var QUALIFIED_TABLE_PATTERN = /^[a-z][a-z0-9_]{0,62}\.[a-z][a-z0-9_]{0,62}$/;
|
|
167
169
|
var SYNCED_SOURCE_PATTERN = QUALIFIED_TABLE_PATTERN;
|
|
168
170
|
var ORM_SCHEMA_PREFIX = "orm_";
|
|
169
171
|
var CONSUMER_ROLE_SUFFIX = "_consumer";
|
|
170
|
-
var ormSchemaName = (namespace) =>
|
|
171
|
-
|
|
172
|
+
var ormSchemaName = (namespace) => {
|
|
173
|
+
if (!NAMESPACE_PATTERN.test(namespace)) throw new Error(`invalid or reserved ORM namespace '${namespace}'`);
|
|
174
|
+
return `${ORM_SCHEMA_PREFIX}${namespace}`;
|
|
175
|
+
};
|
|
176
|
+
var consumerRoleName = (namespace) => `${ormSchemaName(namespace)}${CONSUMER_ROLE_SUFFIX}`;
|
|
172
177
|
var DEFINITION_FILE_EXTENSIONS = [".yml", ".yaml"];
|
|
173
178
|
var NAMESPACE_CONFIG_FILENAMES = /* @__PURE__ */ new Set(["namespace.yaml", "namespace.yml"]);
|
|
174
179
|
var HASH_DOMAIN = "sequence-orm-definitions\0";
|
|
@@ -397,10 +402,10 @@ function defineSyncedTable(name2, columnsOrConfig, maybeConfig) {
|
|
|
397
402
|
if (builder.isPrimaryKey) columnLevelPk.push(propertyName);
|
|
398
403
|
}
|
|
399
404
|
if (entries.length > 0) {
|
|
400
|
-
const hasConfigPk = config.primaryKey !== void 0
|
|
405
|
+
const hasConfigPk = config.primaryKey !== void 0;
|
|
401
406
|
if (columnLevelPk.length === 0 && !hasConfigPk) {
|
|
402
407
|
throw new OrmDefinitionError(
|
|
403
|
-
`synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey()
|
|
408
|
+
`synced table "${name2}" declares columns but no primary key \u2014 use .primaryKey(), config.primaryKey, or explicit primaryKey: [] for an unkeyed read-only source`,
|
|
404
409
|
file
|
|
405
410
|
);
|
|
406
411
|
}
|
|
@@ -1253,10 +1258,10 @@ function validateResolvedView({ view, tables, views = [] }) {
|
|
|
1253
1258
|
const resolved = view.resolved;
|
|
1254
1259
|
if (!resolved) return [];
|
|
1255
1260
|
const errors = [];
|
|
1256
|
-
const
|
|
1261
|
+
const fail2 = (message) => errors.push(`resolved table '${view.view}': ${message}`);
|
|
1257
1262
|
const pkColumn = view.primaryKey?.length === 1 ? view.columns.find((c) => c.columnName === view.primaryKey?.[0]) : void 0;
|
|
1258
1263
|
if (!pkColumn) {
|
|
1259
|
-
|
|
1264
|
+
fail2("requires exactly one primary-key column");
|
|
1260
1265
|
return errors;
|
|
1261
1266
|
}
|
|
1262
1267
|
const systemNames = new Set(Object.values(RESOLVED_VIEW_SYSTEM_COLUMNS).map((c) => c.name));
|
|
@@ -1266,92 +1271,93 @@ function validateResolvedView({ view, tables, views = [] }) {
|
|
|
1266
1271
|
pkColumn,
|
|
1267
1272
|
dataColumns: new Map(view.columns.filter((c) => !systemNames.has(c.name) && c.cell === void 0).map((c) => [c.name, c])),
|
|
1268
1273
|
sourceByName: /* @__PURE__ */ new Map(),
|
|
1269
|
-
fail
|
|
1274
|
+
fail: fail2
|
|
1270
1275
|
};
|
|
1271
|
-
if (resolved.sources.filter((source) => source.kind === "manual").length !== 1)
|
|
1276
|
+
if (resolved.sources.filter((source) => source.kind === "manual").length !== 1) fail2("requires exactly one manual source");
|
|
1272
1277
|
const tableByName = new Map(tables.map((table) => [table.table, table]));
|
|
1273
1278
|
for (const source of resolved.sources) {
|
|
1274
|
-
if (scope.sourceByName.has(source.name))
|
|
1279
|
+
if (scope.sourceByName.has(source.name)) fail2(`duplicate source '${source.name}'`);
|
|
1275
1280
|
scope.sourceByName.set(source.name, source);
|
|
1276
1281
|
const table = tableByName.get(source.table);
|
|
1277
|
-
if (!table)
|
|
1282
|
+
if (!table) fail2(`source '${source.name}' references unknown table '${source.table}'`);
|
|
1278
1283
|
else validateSource({ scope, source, table });
|
|
1279
1284
|
}
|
|
1280
1285
|
validateRules(scope);
|
|
1281
1286
|
validateViewCells(scope);
|
|
1282
1287
|
if (resolved.materialized) validateMaterialized({ scope, tableByName, views });
|
|
1283
1288
|
for (const name2 of resolved.deletedBy) {
|
|
1284
|
-
if (scope.sourceByName.get(name2)?.kind !== "manual")
|
|
1289
|
+
if (scope.sourceByName.get(name2)?.kind !== "manual") fail2(`deletedBy '${name2}' must be the manual source`);
|
|
1285
1290
|
}
|
|
1286
1291
|
return errors;
|
|
1287
1292
|
}
|
|
1288
1293
|
function validateSource({ scope, source, table }) {
|
|
1289
|
-
const { fail } = scope;
|
|
1290
|
-
if (source.kind === "etl" && table.source === void 0)
|
|
1294
|
+
const { fail: fail2 } = scope;
|
|
1295
|
+
if (source.kind === "etl" && table.source === void 0) fail2(`etl source '${source.name}' must reference a synced table`);
|
|
1296
|
+
if (source.kind === "etl" && table.primaryKey?.length === 0) fail2(`etl source '${source.name}' cannot use an unkeyed synced table for resolved row identity`);
|
|
1291
1297
|
if (source.kind !== "etl" && (table.internal !== true || table.cellMetadata !== true)) {
|
|
1292
|
-
|
|
1298
|
+
fail2(`${source.kind} source '${source.name}' must reference an internal table with cell metadata`);
|
|
1293
1299
|
}
|
|
1294
1300
|
const hasRev = table.columns.some((column) => column.cell?.part === "rev");
|
|
1295
|
-
if (source.kind === "manual" && !hasRev)
|
|
1296
|
-
if (source.kind === "prefetch" && hasRev)
|
|
1301
|
+
if (source.kind === "manual" && !hasRev) fail2(`manual source '${source.name}' must carry '__rev' cell columns`);
|
|
1302
|
+
if (source.kind === "prefetch" && hasRev) fail2(`prefetch source '${source.name}' must not carry '__rev' cell columns`);
|
|
1297
1303
|
const byName = new Map(table.columns.map((c) => [c.name, c]));
|
|
1298
1304
|
validateSourceColumns({ scope, source, byName });
|
|
1299
1305
|
if (source.kind === "etl") {
|
|
1300
1306
|
const updatedAt = source.updatedAt === void 0 ? void 0 : byName.get(source.updatedAt);
|
|
1301
1307
|
if (source.updatedAt !== void 0 && updatedAt?.type !== "timestamptz" && updatedAt?.type !== "date") {
|
|
1302
|
-
|
|
1308
|
+
fail2(`etl source '${source.name}' updatedAt must name a timestamptz/date column on '${source.table}'`);
|
|
1303
1309
|
}
|
|
1304
1310
|
}
|
|
1305
1311
|
validatePrefetchFields({ scope, source });
|
|
1306
1312
|
}
|
|
1307
1313
|
function validatePrefetchFields({ scope, source }) {
|
|
1308
|
-
const { fail, pkColumn } = scope;
|
|
1314
|
+
const { fail: fail2, pkColumn } = scope;
|
|
1309
1315
|
if (source.kind !== "prefetch") {
|
|
1310
1316
|
if (source.key || source.fetch || source.function || source.prefetchDefaults || source.writeback) {
|
|
1311
|
-
|
|
1317
|
+
fail2(`only prefetch sources may declare key/fetch/function/prefetchDefaults/writeback ('${source.name}')`);
|
|
1312
1318
|
}
|
|
1313
1319
|
return;
|
|
1314
1320
|
}
|
|
1315
1321
|
if (!source.key || !source.fetch || !source.function || !source.prefetchDefaults) {
|
|
1316
|
-
|
|
1322
|
+
fail2(`prefetch source '${source.name}' requires key, fetch, function and prefetchDefaults`);
|
|
1317
1323
|
} else if (source.key !== pkColumn.name && !source.columns.includes(source.key)) {
|
|
1318
|
-
|
|
1324
|
+
fail2(`prefetch source '${source.name}' key '${source.key}' must be the primary key or one of its columns`);
|
|
1319
1325
|
}
|
|
1320
1326
|
for (const column of source.writeback?.columns ?? []) {
|
|
1321
|
-
if (!source.columns.includes(column))
|
|
1327
|
+
if (!source.columns.includes(column)) fail2(`prefetch source '${source.name}' writes back '${column}', which it does not supply`);
|
|
1322
1328
|
}
|
|
1323
1329
|
}
|
|
1324
1330
|
function validateSourceColumns({ scope, source, byName }) {
|
|
1325
|
-
const { fail, pkColumn, dataColumns } = scope;
|
|
1331
|
+
const { fail: fail2, pkColumn, dataColumns } = scope;
|
|
1326
1332
|
for (const column of [pkColumn.name, ...source.columns]) {
|
|
1327
1333
|
const own = column === pkColumn.name ? pkColumn : dataColumns.get(column);
|
|
1328
1334
|
const theirs = byName.get(column);
|
|
1329
|
-
if (!own)
|
|
1330
|
-
else if (!theirs)
|
|
1331
|
-
else if (JSON.stringify(theirs.type) !== JSON.stringify(own.type))
|
|
1335
|
+
if (!own) fail2(`source '${source.name}' supplies unknown column '${column}'`);
|
|
1336
|
+
else if (!theirs) fail2(`source '${source.name}' table '${source.table}' has no column '${column}'`);
|
|
1337
|
+
else if (JSON.stringify(theirs.type) !== JSON.stringify(own.type)) fail2(`column '${column}' has a different type on source '${source.name}'`);
|
|
1332
1338
|
}
|
|
1333
1339
|
}
|
|
1334
|
-
function validateRules({ resolved, pkColumn, dataColumns, sourceByName, fail }) {
|
|
1340
|
+
function validateRules({ resolved, pkColumn, dataColumns, sourceByName, fail: fail2 }) {
|
|
1335
1341
|
const ruled = /* @__PURE__ */ new Set();
|
|
1336
1342
|
for (const rule of resolved.resolve) {
|
|
1337
1343
|
if (!dataColumns.has(rule.column) || rule.column === pkColumn.name) {
|
|
1338
|
-
|
|
1344
|
+
fail2(`resolve rule targets unknown column '${rule.column}'`);
|
|
1339
1345
|
continue;
|
|
1340
1346
|
}
|
|
1341
|
-
if (ruled.has(rule.column))
|
|
1347
|
+
if (ruled.has(rule.column)) fail2(`column '${rule.column}' has more than one resolve rule`);
|
|
1342
1348
|
ruled.add(rule.column);
|
|
1343
1349
|
if (rule.comparator === "custom" !== (rule.orderBy !== void 0)) {
|
|
1344
|
-
|
|
1350
|
+
fail2(`column '${rule.column}': orderBy is required for custom comparators and only allowed there`);
|
|
1345
1351
|
}
|
|
1346
|
-
if (new Set(rule.candidates).size !== rule.candidates.length)
|
|
1352
|
+
if (new Set(rule.candidates).size !== rule.candidates.length) fail2(`column '${rule.column}' repeats a candidate`);
|
|
1347
1353
|
for (const candidate of rule.candidates) {
|
|
1348
1354
|
const source = sourceByName.get(candidate);
|
|
1349
|
-
if (!source)
|
|
1350
|
-
else if (!source.columns.includes(rule.column))
|
|
1355
|
+
if (!source) fail2(`column '${rule.column}' names unknown candidate source '${candidate}'`);
|
|
1356
|
+
else if (!source.columns.includes(rule.column)) fail2(`column '${rule.column}' candidate '${candidate}' does not supply it`);
|
|
1351
1357
|
}
|
|
1352
1358
|
}
|
|
1353
1359
|
for (const column of dataColumns.keys()) {
|
|
1354
|
-
if (column !== pkColumn.name && !ruled.has(column))
|
|
1360
|
+
if (column !== pkColumn.name && !ruled.has(column)) fail2(`column '${column}' has no resolve rule`);
|
|
1355
1361
|
}
|
|
1356
1362
|
}
|
|
1357
1363
|
var VIEW_CELL_TYPES = {
|
|
@@ -1360,7 +1366,7 @@ var VIEW_CELL_TYPES = {
|
|
|
1360
1366
|
by: "text",
|
|
1361
1367
|
conflicts: "jsonb"
|
|
1362
1368
|
};
|
|
1363
|
-
function validateViewCells({ view, dataColumns, pkColumn, fail }) {
|
|
1369
|
+
function validateViewCells({ view, dataColumns, pkColumn, fail: fail2 }) {
|
|
1364
1370
|
const expected = /* @__PURE__ */ new Map();
|
|
1365
1371
|
for (const column of dataColumns.values()) {
|
|
1366
1372
|
if (column.name === pkColumn.name) continue;
|
|
@@ -1372,34 +1378,34 @@ function validateViewCells({ view, dataColumns, pkColumn, fail }) {
|
|
|
1372
1378
|
if (!column.cell) continue;
|
|
1373
1379
|
const want = expected.get(column.name);
|
|
1374
1380
|
if (!want || want.part !== column.cell.part || want.columnName !== column.columnName || cellColumnName(column.cell.of, column.cell.part) !== column.name) {
|
|
1375
|
-
|
|
1381
|
+
fail2(`unexpected cell column '${column.name}'`);
|
|
1376
1382
|
continue;
|
|
1377
1383
|
}
|
|
1378
|
-
if (column.type !== VIEW_CELL_TYPES[column.cell.part])
|
|
1384
|
+
if (column.type !== VIEW_CELL_TYPES[column.cell.part]) fail2(`cell column '${column.name}' must be ${VIEW_CELL_TYPES[column.cell.part]}`);
|
|
1379
1385
|
expected.delete(column.name);
|
|
1380
1386
|
}
|
|
1381
|
-
for (const name2 of expected.keys())
|
|
1387
|
+
for (const name2 of expected.keys()) fail2(`missing cell column '${name2}'`);
|
|
1382
1388
|
}
|
|
1383
1389
|
var columnSignature = (columns) => JSON.stringify(columns.map((column) => [column.name, column.columnName, column.type]));
|
|
1384
1390
|
function validateMaterialized({ scope, tableByName, views }) {
|
|
1385
|
-
const { view, resolved, fail } = scope;
|
|
1391
|
+
const { view, resolved, fail: fail2 } = scope;
|
|
1386
1392
|
const { table: tableName, compute: computeName } = resolved.materialized;
|
|
1387
1393
|
const table = tableByName.get(tableName);
|
|
1388
1394
|
if (!table || table.internal !== true || table.materializes !== view.view) {
|
|
1389
|
-
|
|
1395
|
+
fail2(`materialized table '${tableName}' must be an internal table that materializes '${view.view}'`);
|
|
1390
1396
|
} else {
|
|
1391
|
-
if (columnSignature(table.columns) !== columnSignature(view.columns))
|
|
1392
|
-
if (JSON.stringify(table.primaryKey ?? []) !== JSON.stringify(view.primaryKey ?? []))
|
|
1397
|
+
if (columnSignature(table.columns) !== columnSignature(view.columns)) fail2(`materialized table '${tableName}' must have exactly the view's columns`);
|
|
1398
|
+
if (JSON.stringify(table.primaryKey ?? []) !== JSON.stringify(view.primaryKey ?? [])) fail2(`materialized table '${tableName}' must share the view's primary key`);
|
|
1393
1399
|
}
|
|
1394
1400
|
const compute = views.find((candidate) => candidate.view === computeName);
|
|
1395
|
-
if (!compute || compute.internal !== true)
|
|
1396
|
-
else if (columnSignature(compute.columns) !== columnSignature(view.columns))
|
|
1401
|
+
if (!compute || compute.internal !== true) fail2(`compute view '${computeName}' must be an internal view`);
|
|
1402
|
+
else if (columnSignature(compute.columns) !== columnSignature(view.columns)) fail2(`compute view '${computeName}' must have exactly the view's columns`);
|
|
1397
1403
|
for (const source of resolved.sources) {
|
|
1398
1404
|
if (source.kind !== "etl") continue;
|
|
1399
1405
|
const read = tableByName.get(source.table)?.policies?.read;
|
|
1400
1406
|
const unconditional = typeof read === "string" ? read.trim() === "true" : read !== void 0 && read.default.trim() === "true" && read.variants.length === 0;
|
|
1401
1407
|
if (!unconditional) {
|
|
1402
|
-
|
|
1408
|
+
fail2(`etl source '${source.name}' must have read policy 'true' to be materialized (the copy is shared by every caller)`);
|
|
1403
1409
|
}
|
|
1404
1410
|
}
|
|
1405
1411
|
}
|
|
@@ -1736,7 +1742,7 @@ var canonicalTableSchema = z.object({
|
|
|
1736
1742
|
/** Synced/reflected read-only tables (`source: schema.table`) — v1 semantics. */
|
|
1737
1743
|
source: z.string().regex(QUALIFIED_TABLE_PATTERN).optional(),
|
|
1738
1744
|
columns: z.array(canonicalColumnSchema).default([]),
|
|
1739
|
-
primaryKey: z.array(columnIdentifier).
|
|
1745
|
+
primaryKey: z.array(columnIdentifier).max(8).optional(),
|
|
1740
1746
|
links: z.array(canonicalLinkSchema).default([]),
|
|
1741
1747
|
indexes: z.array(canonicalIndexSchema).default([]),
|
|
1742
1748
|
/** Omitted by old definitions, preserving their existing content hashes. */
|
|
@@ -1772,6 +1778,29 @@ var canonicalTableSchema = z.object({
|
|
|
1772
1778
|
* data plane. Omitted otherwise.
|
|
1773
1779
|
*/
|
|
1774
1780
|
materializes: identifier2.optional()
|
|
1781
|
+
}).superRefine((table, ctx) => {
|
|
1782
|
+
if (table.primaryKey?.length !== 0) return;
|
|
1783
|
+
const fail2 = (message, path = ["primaryKey"]) => ctx.addIssue({ code: "custom", path, message: `unkeyed table '${table.table}' ${message}` });
|
|
1784
|
+
if (table.source === void 0 || table.columns.length === 0) {
|
|
1785
|
+
fail2("requires a typed synced source");
|
|
1786
|
+
}
|
|
1787
|
+
if ([table.policies.write, table.policies.insert, table.policies.update].some((policy) => policy !== void 0)) {
|
|
1788
|
+
fail2("is read-only and cannot declare write policies", ["policies"]);
|
|
1789
|
+
}
|
|
1790
|
+
const ownedCollections = [table.indexes, table.actions, table.checks, table.foreignKeys, table.cowMutations];
|
|
1791
|
+
const ownedMetadata = [table.cellMetadata, table.internal, table.materializes, table.renamedFrom];
|
|
1792
|
+
if (ownedCollections.some((items) => items !== void 0 && items.length > 0) || ownedMetadata.some((value) => value !== void 0)) {
|
|
1793
|
+
fail2("cannot declare owned storage, constraints or identity operations");
|
|
1794
|
+
}
|
|
1795
|
+
for (const [index3, column] of table.columns.entries()) {
|
|
1796
|
+
const ownedColumnMetadata = [column.default, column.defaultFn, column.onUpdateFn, column.renamedFrom, column.cast, column.cell];
|
|
1797
|
+
if (column.unique || ownedColumnMetadata.some((value) => value !== void 0)) {
|
|
1798
|
+
fail2("cannot declare column uniqueness, mutation defaults or migration metadata", ["columns", index3]);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
for (const [index3, link] of table.links.entries()) {
|
|
1802
|
+
if (link.enforce || link.kind === "toMany") fail2("cannot provide an identity for this link", ["links", index3]);
|
|
1803
|
+
}
|
|
1775
1804
|
});
|
|
1776
1805
|
var MAX_VIEW_QUERY = 1e5;
|
|
1777
1806
|
var MAX_RESOLVED_VIEW_QUERY = 5e6;
|
|
@@ -1828,6 +1857,26 @@ var canonicalViewSchema = z.object({
|
|
|
1828
1857
|
}
|
|
1829
1858
|
}
|
|
1830
1859
|
});
|
|
1860
|
+
function validateUnkeyedLinkIdentities({ definition, ctx }) {
|
|
1861
|
+
const tables = new Map(definition.tables.map((table) => [table.table, table]));
|
|
1862
|
+
const relations = [
|
|
1863
|
+
...definition.tables.map((table, index3) => ({ kind: "tables", index: index3, links: table.links })),
|
|
1864
|
+
...(definition.views ?? []).map((view, index3) => ({ kind: "views", index: index3, links: view.links }))
|
|
1865
|
+
];
|
|
1866
|
+
for (const relation of relations) {
|
|
1867
|
+
for (const [linkIndex, link] of relation.links.entries()) {
|
|
1868
|
+
if (link.kind !== "toOne" || link.namespace !== void 0 && link.namespace !== definition.namespace) continue;
|
|
1869
|
+
const target = link.target === void 0 ? void 0 : tables.get(link.target);
|
|
1870
|
+
if (target?.source !== void 0 && target.primaryKey?.length === 0) {
|
|
1871
|
+
ctx.addIssue({
|
|
1872
|
+
code: "custom",
|
|
1873
|
+
path: [relation.kind, relation.index, "links", linkIndex],
|
|
1874
|
+
message: `link '${link.name}' cannot use unkeyed table '${target.table}' as a to-one identity`
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1831
1880
|
var CELL_PART_TYPES = {
|
|
1832
1881
|
at: "timestamptz",
|
|
1833
1882
|
by: "text",
|
|
@@ -1841,49 +1890,49 @@ function trackedCellColumns(table) {
|
|
|
1841
1890
|
}
|
|
1842
1891
|
var SUFFIXES = Object.values(CELL_PART_SUFFIX);
|
|
1843
1892
|
function validateCellMetadata(table, index3, ctx) {
|
|
1844
|
-
const
|
|
1893
|
+
const fail2 = (message, path = ["tables", index3]) => ctx.addIssue({ code: "custom", path, message });
|
|
1845
1894
|
const cells = table.columns.flatMap((column, position) => column.cell ? [{ column, position, cell: column.cell }] : []);
|
|
1846
1895
|
if (table.materializes !== void 0) return;
|
|
1847
1896
|
if (table.cellMetadata !== true) {
|
|
1848
|
-
for (const { position } of cells)
|
|
1897
|
+
for (const { position } of cells) fail2(`cell-metadata columns require cellMetadata on table '${table.table}'`, ["tables", index3, "columns", position]);
|
|
1849
1898
|
return;
|
|
1850
1899
|
}
|
|
1851
1900
|
if (table.source !== void 0) {
|
|
1852
|
-
|
|
1901
|
+
fail2(`synced table '${table.table}' cannot track cell metadata`);
|
|
1853
1902
|
return;
|
|
1854
1903
|
}
|
|
1855
1904
|
const tracked = trackedCellColumns(table);
|
|
1856
1905
|
const byName = new Map(tracked.map((column) => [column.name, column]));
|
|
1857
1906
|
const withRev = cells.some(({ cell }) => cell.part === "rev");
|
|
1858
|
-
if (withRev && table.internal !== true)
|
|
1907
|
+
if (withRev && table.internal !== true) fail2(`only a resolved table's internal sources carry '__rev' cell columns ('${table.table}')`);
|
|
1859
1908
|
const seen = /* @__PURE__ */ new Set();
|
|
1860
1909
|
for (const { column, position, cell } of cells) {
|
|
1861
1910
|
const path = ["tables", index3, "columns", position];
|
|
1862
1911
|
const owner = byName.get(cell.of);
|
|
1863
1912
|
if (!owner) {
|
|
1864
|
-
|
|
1913
|
+
fail2(`cell column '${column.name}' belongs to '${cell.of}', which is not a tracked column`, path);
|
|
1865
1914
|
continue;
|
|
1866
1915
|
}
|
|
1867
|
-
if (cell.part !== "at" && cell.part !== "by" && cell.part !== "rev")
|
|
1916
|
+
if (cell.part !== "at" && cell.part !== "by" && cell.part !== "rev") fail2(`a table cell column must be part at/by/rev, not '${cell.part}'`, path);
|
|
1868
1917
|
if (column.name !== cellColumnName(owner.name, cell.part) || column.columnName !== cellColumnName(owner.columnName, cell.part)) {
|
|
1869
|
-
|
|
1918
|
+
fail2(`cell column for '${owner.name}' ${cell.part} must be named '${cellColumnName(owner.name, cell.part)}' / '${cellColumnName(owner.columnName, cell.part)}'`, path);
|
|
1870
1919
|
}
|
|
1871
1920
|
if (column.type !== CELL_PART_TYPES[cell.part] || !column.nullable || column.unique || column.default !== void 0 || column.defaultFn !== void 0) {
|
|
1872
|
-
|
|
1921
|
+
fail2(`cell column '${column.name}' must be a nullable, default-less ${CELL_PART_TYPES[cell.part]}`, path);
|
|
1873
1922
|
}
|
|
1874
1923
|
const key = `${cell.of}:${cell.part}`;
|
|
1875
|
-
if (seen.has(key))
|
|
1924
|
+
if (seen.has(key)) fail2(`duplicate cell column '${column.name}'`, path);
|
|
1876
1925
|
seen.add(key);
|
|
1877
1926
|
}
|
|
1878
1927
|
for (const column of tracked) {
|
|
1879
1928
|
if (column.columnName.length > MAX_TRACKED_COLUMN_NAME) {
|
|
1880
|
-
|
|
1929
|
+
fail2(`column '${column.columnName}' is too long to track cell metadata (max ${MAX_TRACKED_COLUMN_NAME} characters)`);
|
|
1881
1930
|
}
|
|
1882
1931
|
if (SUFFIXES.some((suffix) => column.columnName.endsWith(suffix))) {
|
|
1883
|
-
|
|
1932
|
+
fail2(`column '${column.columnName}' ends in a reserved cell-metadata suffix (${SUFFIXES.join(", ")})`);
|
|
1884
1933
|
}
|
|
1885
1934
|
for (const part of withRev ? ["at", "by", "rev"] : ["at", "by"]) {
|
|
1886
|
-
if (!seen.has(`${column.name}:${part}`))
|
|
1935
|
+
if (!seen.has(`${column.name}:${part}`)) fail2(`tracked column '${column.name}' is missing its '${cellColumnName(column.columnName, part)}' cell column`);
|
|
1887
1936
|
}
|
|
1888
1937
|
}
|
|
1889
1938
|
}
|
|
@@ -1891,7 +1940,7 @@ var exportGateSchema = z.union([z.literal(true), z.object({ capability: z.string
|
|
|
1891
1940
|
var relationExportSchema = z.object({ read: exportGateSchema, write: exportGateSchema.optional() }).strict();
|
|
1892
1941
|
var localDefinitionSchema = z.object({
|
|
1893
1942
|
definition_format: z.literal(CANONICAL_FORMAT),
|
|
1894
|
-
namespace: identifier2.max(41),
|
|
1943
|
+
namespace: identifier2.max(41).regex(NAMESPACE_PATTERN, "invalid or reserved ORM namespace"),
|
|
1895
1944
|
description: z.string().max(2e3).optional(),
|
|
1896
1945
|
enums: z.array(canonicalEnumSchema).default([]),
|
|
1897
1946
|
tables: z.array(canonicalTableSchema).min(0).max(500),
|
|
@@ -1925,6 +1974,7 @@ var localDefinitionSchema = z.object({
|
|
|
1925
1974
|
}
|
|
1926
1975
|
}
|
|
1927
1976
|
const fkTables = new Map(definition.tables.map((table) => [table.table, table]));
|
|
1977
|
+
validateUnkeyedLinkIdentities({ definition, ctx });
|
|
1928
1978
|
const relations = /* @__PURE__ */ new Set([...fkTables.keys(), ...(definition.views ?? []).map((view) => view.view)]);
|
|
1929
1979
|
for (const name2 of Object.keys(definition.exports ?? {})) {
|
|
1930
1980
|
if (!relations.has(name2)) ctx.addIssue({ code: "custom", path: ["exports", name2], message: `export '${name2}' is not a local object` });
|
|
@@ -1950,38 +2000,38 @@ var localDefinitionSchema = z.object({
|
|
|
1950
2000
|
}
|
|
1951
2001
|
}
|
|
1952
2002
|
for (const [index3, check] of (table.checks ?? []).entries()) {
|
|
1953
|
-
const
|
|
1954
|
-
if (table.source)
|
|
1955
|
-
if (names.has(check.name))
|
|
2003
|
+
const fail2 = (message) => ctx.addIssue({ code: "custom", path: ["tables", tableIndex, "checks", index3], message });
|
|
2004
|
+
if (table.source) fail2("synced tables cannot declare checks");
|
|
2005
|
+
if (names.has(check.name)) fail2(`duplicate constraint '${check.name}'`);
|
|
1956
2006
|
names.add(check.name);
|
|
1957
2007
|
try {
|
|
1958
2008
|
compileCheckExpression(check.expression, table.columns);
|
|
1959
2009
|
} catch (error) {
|
|
1960
|
-
|
|
2010
|
+
fail2(error instanceof Error ? error.message : String(error));
|
|
1961
2011
|
}
|
|
1962
2012
|
}
|
|
1963
2013
|
for (const [index3, fk] of (table.foreignKeys ?? []).entries()) {
|
|
1964
|
-
const
|
|
1965
|
-
if (names.has(fk.name))
|
|
2014
|
+
const fail2 = (message) => ctx.addIssue({ code: "custom", path: ["tables", tableIndex, "foreignKeys", index3], message });
|
|
2015
|
+
if (names.has(fk.name)) fail2(`duplicate foreign key '${fk.name}'`);
|
|
1966
2016
|
names.add(fk.name);
|
|
1967
2017
|
const target = fkTables.get(fk.target);
|
|
1968
2018
|
if (table.source || !target || target.source) {
|
|
1969
|
-
|
|
2019
|
+
fail2("foreign keys must connect owned tables in the same namespace");
|
|
1970
2020
|
continue;
|
|
1971
2021
|
}
|
|
1972
|
-
if (fk.columns.length !== fk.references.length)
|
|
1973
|
-
if (new Set(fk.columns).size !== fk.columns.length || new Set(fk.references).size !== fk.references.length)
|
|
2022
|
+
if (fk.columns.length !== fk.references.length) fail2("foreign key columns and references must have the same number of columns");
|
|
2023
|
+
if (new Set(fk.columns).size !== fk.columns.length || new Set(fk.references).size !== fk.references.length) fail2("foreign key columns must not repeat");
|
|
1974
2024
|
for (const [position, name2] of fk.columns.entries()) {
|
|
1975
2025
|
const sourceColumn = table.columns.find((column) => column.columnName === name2);
|
|
1976
2026
|
const targetColumn = target.columns.find((column) => column.columnName === fk.references[position]);
|
|
1977
|
-
if (!sourceColumn || !targetColumn)
|
|
1978
|
-
else if (JSON.stringify(sourceColumn.type) !== JSON.stringify(targetColumn.type))
|
|
2027
|
+
if (!sourceColumn || !targetColumn) fail2("foreign key references an unknown column");
|
|
2028
|
+
else if (JSON.stringify(sourceColumn.type) !== JSON.stringify(targetColumn.type)) fail2("foreign key column types must match");
|
|
1979
2029
|
}
|
|
1980
2030
|
if (fk.onDelete === "set null" || fk.onUpdate === "set null") {
|
|
1981
|
-
if (fk.columns.some((name2) => table.columns.find((column) => column.columnName === name2)?.nullable === false || table.primaryKey?.includes(name2)))
|
|
2031
|
+
if (fk.columns.some((name2) => table.columns.find((column) => column.columnName === name2)?.nullable === false || table.primaryKey?.includes(name2))) fail2("SET NULL requires nullable source columns");
|
|
1982
2032
|
}
|
|
1983
2033
|
const uniqueKeys = [target.primaryKey ?? [], ...target.indexes.filter((index4) => index4.unique).map((index4) => index4.columns), ...target.columns.filter((column) => column.unique).map((column) => [column.columnName])];
|
|
1984
|
-
if (!uniqueKeys.some((key) => key.length === fk.references.length && key.every((column) => fk.references.includes(column))))
|
|
2034
|
+
if (!uniqueKeys.some((key) => key.length === fk.references.length && key.every((column) => fk.references.includes(column)))) fail2("foreign key target columns must form a unique key");
|
|
1985
2035
|
}
|
|
1986
2036
|
}
|
|
1987
2037
|
for (const [viewIndex, view] of (definition.views ?? []).entries()) {
|
|
@@ -2169,8 +2219,8 @@ function cloneColumn({ builder, property, notNull, primaryKey: primaryKey2 }) {
|
|
|
2169
2219
|
return clone;
|
|
2170
2220
|
}
|
|
2171
2221
|
function planSource(input) {
|
|
2172
|
-
const { sourceName, input: source, fail } = input;
|
|
2173
|
-
if (!IDENTIFIER_PATTERN.test(sourceName))
|
|
2222
|
+
const { sourceName, input: source, fail: fail2 } = input;
|
|
2223
|
+
if (!IDENTIFIER_PATTERN.test(sourceName)) fail2(`source name "${sourceName}" must match ${IDENTIFIER_PATTERN}`);
|
|
2174
2224
|
switch (source.kind) {
|
|
2175
2225
|
case "manual":
|
|
2176
2226
|
return {
|
|
@@ -2206,30 +2256,31 @@ function internalTable(input, supplied, system, options = {}) {
|
|
|
2206
2256
|
internal: true
|
|
2207
2257
|
});
|
|
2208
2258
|
}
|
|
2209
|
-
function assertColumns(input,
|
|
2210
|
-
for (const column of
|
|
2259
|
+
function assertColumns(input, list2, what) {
|
|
2260
|
+
for (const column of list2) if (!input.dataColumns.includes(column)) input.fail(`${what} names unknown column "${column}"`);
|
|
2211
2261
|
}
|
|
2212
2262
|
function planEtl(input, source) {
|
|
2213
|
-
const { sourceName, pk, dataColumns, fail } = input;
|
|
2263
|
+
const { sourceName, pk, dataColumns, fail: fail2 } = input;
|
|
2214
2264
|
const table = typeof source.table === "function" ? source.table() : source.table;
|
|
2215
|
-
if (!isSeqTable(table) || table.source === void 0)
|
|
2265
|
+
if (!isSeqTable(table) || table.source === void 0) fail2(`etl source "${sourceName}" must reference a defineSyncedTable`);
|
|
2216
2266
|
const synced = table;
|
|
2217
|
-
if (
|
|
2267
|
+
if (synced.config.primaryKey?.length === 0) fail2(`etl source "${sourceName}" cannot use an unkeyed synced table for resolved row identity`);
|
|
2268
|
+
if (!(pk in synced.columns)) fail2(`etl source "${sourceName}" table "${synced.tableName}" has no "${pk}" column`);
|
|
2218
2269
|
const supplied = source.columns ? [...source.columns] : dataColumns.filter((column) => column in synced.columns);
|
|
2219
2270
|
assertColumns(input, supplied, `etl source "${sourceName}"`);
|
|
2220
2271
|
if (source.updatedAt !== void 0 && !(source.updatedAt in synced.columns)) {
|
|
2221
|
-
|
|
2272
|
+
fail2(`etl source "${sourceName}" updatedAt "${source.updatedAt}" is not a column of "${synced.tableName}"`);
|
|
2222
2273
|
}
|
|
2223
2274
|
return { name: sourceName, kind: "etl", table: synced, columns: supplied, ...source.updatedAt ? { updatedAt: source.updatedAt } : {} };
|
|
2224
2275
|
}
|
|
2225
2276
|
function planPrefetch(input, source) {
|
|
2226
|
-
const { sourceName, pk, fail } = input;
|
|
2277
|
+
const { sourceName, pk, fail: fail2 } = input;
|
|
2227
2278
|
assertColumns(input, source.columns, `prefetch source "${sourceName}"`);
|
|
2228
2279
|
if (source.key !== pk && !source.columns.includes(source.key)) {
|
|
2229
|
-
|
|
2280
|
+
fail2(`prefetch source "${sourceName}" key "${source.key}" must be the primary key or one of its columns`);
|
|
2230
2281
|
}
|
|
2231
2282
|
for (const column of source.writeback?.columns ?? []) {
|
|
2232
|
-
if (!source.columns.includes(column))
|
|
2283
|
+
if (!source.columns.includes(column)) fail2(`prefetch source "${sourceName}" writes back "${column}", which it does not supply`);
|
|
2233
2284
|
}
|
|
2234
2285
|
const writeback = source.writeback;
|
|
2235
2286
|
return {
|
|
@@ -2435,34 +2486,34 @@ var SYSTEM_VIEW_COLUMNS = {
|
|
|
2435
2486
|
};
|
|
2436
2487
|
function defineResolvedTable(name2, columns, config) {
|
|
2437
2488
|
const file = activeAuthoringContext()?.currentFile;
|
|
2438
|
-
const
|
|
2489
|
+
const fail2 = (message) => {
|
|
2439
2490
|
throw new OrmDefinitionError(`resolved table "${name2}": ${message}`, file);
|
|
2440
2491
|
};
|
|
2441
|
-
if (!IDENTIFIER_PATTERN.test(name2))
|
|
2492
|
+
if (!IDENTIFIER_PATTERN.test(name2)) fail2(`name must match ${IDENTIFIER_PATTERN}`);
|
|
2442
2493
|
for (const property of Object.keys(columns)) {
|
|
2443
2494
|
if (RESERVED_RESOLVED_COLUMN_NAMES.has(property) || RESERVED_RESOLVED_COLUMN_NAMES.has(columns[property].columnNameFor(property))) {
|
|
2444
|
-
|
|
2495
|
+
fail2(`column "${property}" collides with a reserved system column`);
|
|
2445
2496
|
}
|
|
2446
2497
|
}
|
|
2447
2498
|
for (const property of Object.keys(columns)) {
|
|
2448
2499
|
if (columns[property].columnNameFor(property).length > MAX_TRACKED_COLUMN_NAME) {
|
|
2449
|
-
|
|
2500
|
+
fail2(`column "${property}" is too long for a resolved table (max ${MAX_TRACKED_COLUMN_NAME} characters, room for cell parts)`);
|
|
2450
2501
|
}
|
|
2451
2502
|
}
|
|
2452
2503
|
const pkEntries = Object.entries(columns).filter(([, builder]) => builder.isPrimaryKey);
|
|
2453
|
-
if (pkEntries.length !== 1)
|
|
2504
|
+
if (pkEntries.length !== 1) fail2("declare exactly one .primaryKey() column");
|
|
2454
2505
|
const [pk, pkBuilder] = pkEntries[0];
|
|
2455
2506
|
const dataColumns = Object.keys(columns).filter((property) => property !== pk);
|
|
2456
|
-
if (dataColumns.length === 0)
|
|
2507
|
+
if (dataColumns.length === 0) fail2("declare at least one non-key column");
|
|
2457
2508
|
const sourceEntries = Object.entries(config.sources);
|
|
2458
|
-
if (sourceEntries.filter(([, source]) => source.kind === "manual").length !== 1)
|
|
2509
|
+
if (sourceEntries.filter(([, source]) => source.kind === "manual").length !== 1) fail2("declare exactly one manualSource()");
|
|
2459
2510
|
const plans = sourceEntries.map(
|
|
2460
|
-
([sourceName, input]) => planSource({ viewName: name2, sourceName, input, columns, pk, pkBuilder, dataColumns, fail })
|
|
2511
|
+
([sourceName, input]) => planSource({ viewName: name2, sourceName, input, columns, pk, pkBuilder, dataColumns, fail: fail2 })
|
|
2461
2512
|
);
|
|
2462
|
-
const rules = planRules({ config, plans, dataColumns, fail });
|
|
2513
|
+
const rules = planRules({ config, plans, dataColumns, fail: fail2 });
|
|
2463
2514
|
const deletedBy = [...config.rows?.deletedBy ?? []];
|
|
2464
2515
|
for (const source of deletedBy) {
|
|
2465
|
-
if (plans.find((plan) => plan.name === source)?.kind !== "manual")
|
|
2516
|
+
if (plans.find((plan) => plan.name === source)?.kind !== "manual") fail2(`rows.deletedBy "${source}" must be the manual source`);
|
|
2466
2517
|
}
|
|
2467
2518
|
const partType = { source: t.text, at: t.timestamptz, by: t.text, conflicts: t.jsonb };
|
|
2468
2519
|
const viewColumns = {};
|
|
@@ -2525,11 +2576,11 @@ function defineResolvedTable(name2, columns, config) {
|
|
|
2525
2576
|
}
|
|
2526
2577
|
});
|
|
2527
2578
|
}
|
|
2528
|
-
function planRules({ config, plans, dataColumns, fail }) {
|
|
2579
|
+
function planRules({ config, plans, dataColumns, fail: fail2 }) {
|
|
2529
2580
|
const kindOrder = { manual: 0, prefetch: 1, etl: 2 };
|
|
2530
2581
|
const fallback = config.default ?? priority([...plans].sort((a, b) => kindOrder[a.kind] - kindOrder[b.kind]).map((plan) => plan.name));
|
|
2531
2582
|
for (const column of Object.keys(config.resolve ?? {})) {
|
|
2532
|
-
if (!dataColumns.includes(column))
|
|
2583
|
+
if (!dataColumns.includes(column)) fail2(`resolve names unknown column "${column}"`);
|
|
2533
2584
|
}
|
|
2534
2585
|
return dataColumns.map((column) => {
|
|
2535
2586
|
const explicit = config.resolve?.[column];
|
|
@@ -2537,11 +2588,11 @@ function planRules({ config, plans, dataColumns, fail }) {
|
|
|
2537
2588
|
const candidates = explicit ? [...explicit.candidates] : comparator.candidates.filter((name2) => plans.find((plan) => plan.name === name2)?.columns.includes(column));
|
|
2538
2589
|
for (const candidate of candidates) {
|
|
2539
2590
|
const plan = plans.find((entry) => entry.name === candidate);
|
|
2540
|
-
if (!plan)
|
|
2541
|
-
else if (!plan.columns.includes(column))
|
|
2591
|
+
if (!plan) fail2(`column "${column}" names unknown source "${candidate}"`);
|
|
2592
|
+
else if (!plan.columns.includes(column)) fail2(`column "${column}" candidate "${candidate}" does not supply it`);
|
|
2542
2593
|
}
|
|
2543
|
-
if (candidates.length === 0)
|
|
2544
|
-
if (comparator.kind === "custom") assertSafeOrderBy({ orderBy: comparator.orderBy ?? "", column, fail });
|
|
2594
|
+
if (candidates.length === 0) fail2(`column "${column}" has no candidate source`);
|
|
2595
|
+
if (comparator.kind === "custom") assertSafeOrderBy({ orderBy: comparator.orderBy ?? "", column, fail: fail2 });
|
|
2545
2596
|
return {
|
|
2546
2597
|
column,
|
|
2547
2598
|
comparator: comparator.kind,
|
|
@@ -2592,18 +2643,18 @@ var ORDER_BY_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
2592
2643
|
]);
|
|
2593
2644
|
var ALLOWED_FUNCTIONS = new Set(VIEW_QUERY_FUNCTION_ALLOWLIST);
|
|
2594
2645
|
var ORDER_BY_TOKEN = /\s+|'(?:[^']|'')*'|\d+(?:\.\d+)?|[a-z_][a-z0-9_]*|::|<=|>=|<>|!=|[-+*/%<>=(),|]/giy;
|
|
2595
|
-
function assertSafeOrderBy({ orderBy, column, fail }) {
|
|
2646
|
+
function assertSafeOrderBy({ orderBy, column, fail: fail2 }) {
|
|
2596
2647
|
ORDER_BY_TOKEN.lastIndex = 0;
|
|
2597
2648
|
let consumed = 0;
|
|
2598
2649
|
for (let match = ORDER_BY_TOKEN.exec(orderBy); match; match = ORDER_BY_TOKEN.exec(orderBy)) {
|
|
2599
2650
|
consumed = ORDER_BY_TOKEN.lastIndex;
|
|
2600
2651
|
const token = match[0].toLowerCase();
|
|
2601
2652
|
if (/^[a-z_]/.test(token) && !ORDER_BY_KEYWORDS.has(token) && !ALLOWED_FUNCTIONS.has(token)) {
|
|
2602
|
-
|
|
2653
|
+
fail2(`column "${column}" custom orderBy uses "${match[0]}" \u2014 only value, updated_at, source, actor, ord, SQL keywords and allowlisted functions`);
|
|
2603
2654
|
}
|
|
2604
2655
|
}
|
|
2605
2656
|
if (consumed !== orderBy.length || orderBy.trim() === "") {
|
|
2606
|
-
|
|
2657
|
+
fail2(`column "${column}" custom orderBy contains an unsupported character near "${orderBy.slice(consumed, consumed + 10)}"`);
|
|
2607
2658
|
}
|
|
2608
2659
|
}
|
|
2609
2660
|
function stableJson(value) {
|
|
@@ -3131,17 +3182,17 @@ function buildCanonicalLink({
|
|
|
3131
3182
|
}) {
|
|
3132
3183
|
const ownerKind = relationKind(relation);
|
|
3133
3184
|
const ownerName = relationName(relation);
|
|
3134
|
-
const
|
|
3185
|
+
const fail2 = (message) => {
|
|
3135
3186
|
throw new OrmDefinitionError(`${ownerKind} "${ownerName}": link "${linkName}" ${message}`, relation.file);
|
|
3136
3187
|
};
|
|
3137
3188
|
if (link.enforce && link.linkKind !== "toOne") {
|
|
3138
|
-
return
|
|
3189
|
+
return fail2("sets enforce: true, which is only supported on toOne links");
|
|
3139
3190
|
}
|
|
3140
3191
|
if ((link.onDelete !== void 0 || link.onUpdate !== void 0) && !link.enforce) {
|
|
3141
|
-
return
|
|
3192
|
+
return fail2("sets a referential action without enforce: true");
|
|
3142
3193
|
}
|
|
3143
3194
|
if (link.linkKind === "toPlatformUser") {
|
|
3144
|
-
if (link.target !== void 0) return
|
|
3195
|
+
if (link.target !== void 0) return fail2("is toPlatformUser and must not declare a target table");
|
|
3145
3196
|
return {
|
|
3146
3197
|
name: linkName,
|
|
3147
3198
|
kind: "toPlatformUser",
|
|
@@ -3152,7 +3203,7 @@ function buildCanonicalLink({
|
|
|
3152
3203
|
};
|
|
3153
3204
|
}
|
|
3154
3205
|
if (typeof link.target === "object" && link.target?.kind === "seq-external-object") {
|
|
3155
|
-
if (link.enforce) return
|
|
3206
|
+
if (link.enforce) return fail2("cannot enforce a cross-namespace physical foreign key; use an ORM link without enforce");
|
|
3156
3207
|
return {
|
|
3157
3208
|
name: linkName,
|
|
3158
3209
|
kind: link.linkKind,
|
|
@@ -3164,13 +3215,13 @@ function buildCanonicalLink({
|
|
|
3164
3215
|
...link.description !== void 0 ? { description: link.description } : {}
|
|
3165
3216
|
};
|
|
3166
3217
|
}
|
|
3167
|
-
const target = resolveRelationRef({ ref: link.target, fail });
|
|
3218
|
+
const target = resolveRelationRef({ ref: link.target, fail: fail2 });
|
|
3168
3219
|
const targetName = relationName(target);
|
|
3169
3220
|
if (!relationsByName.has(targetName)) {
|
|
3170
|
-
return
|
|
3221
|
+
return fail2(`targets ${relationKind(target)} "${targetName}" which is not part of this namespace`);
|
|
3171
3222
|
}
|
|
3172
3223
|
if (link.enforce && (!isSeqTable(relation) || !isSeqTable(target))) {
|
|
3173
|
-
return
|
|
3224
|
+
return fail2("cannot enforce a PostgreSQL foreign key involving a view");
|
|
3174
3225
|
}
|
|
3175
3226
|
const owningSide = link.linkKind === "toOne" ? relation : target;
|
|
3176
3227
|
const referencedSide = link.linkKind === "toOne" ? target : relation;
|
|
@@ -3186,19 +3237,19 @@ function buildCanonicalLink({
|
|
|
3186
3237
|
...link.description !== void 0 ? { description: link.description } : {}
|
|
3187
3238
|
};
|
|
3188
3239
|
}
|
|
3189
|
-
function resolveRelationRef({ ref, fail }) {
|
|
3190
|
-
if (ref === void 0) return
|
|
3240
|
+
function resolveRelationRef({ ref, fail: fail2 }) {
|
|
3241
|
+
if (ref === void 0) return fail2("declares no target relation");
|
|
3191
3242
|
if (typeof ref !== "function") return ref;
|
|
3192
3243
|
let resolved;
|
|
3193
3244
|
try {
|
|
3194
3245
|
resolved = ref();
|
|
3195
3246
|
} catch (error) {
|
|
3196
|
-
return
|
|
3247
|
+
return fail2(
|
|
3197
3248
|
`target thunk threw (${error instanceof Error ? error.message : String(error)}) \u2014 lazy refs resolve at serialize time; make sure the target module ran`
|
|
3198
3249
|
);
|
|
3199
3250
|
}
|
|
3200
3251
|
if (!isSeqTable(resolved) && !isSeqView(resolved)) {
|
|
3201
|
-
return
|
|
3252
|
+
return fail2("target thunk did not return a relation defined with defineTable/defineView");
|
|
3202
3253
|
}
|
|
3203
3254
|
return resolved;
|
|
3204
3255
|
}
|
|
@@ -3301,9 +3352,9 @@ function extractOrmSyncedTableContract({
|
|
|
3301
3352
|
);
|
|
3302
3353
|
}
|
|
3303
3354
|
const primaryKey2 = table.primaryKey;
|
|
3304
|
-
if (primaryKey2 === void 0
|
|
3355
|
+
if (primaryKey2 === void 0) {
|
|
3305
3356
|
throw new OrmDefinitionError(
|
|
3306
|
-
`synced table "${table.table}" has no primary key \u2014
|
|
3357
|
+
`synced table "${table.table}" has no primary key contract \u2014 declare a key or explicit primaryKey: []`
|
|
3307
3358
|
);
|
|
3308
3359
|
}
|
|
3309
3360
|
const pkSet = new Set(primaryKey2);
|
|
@@ -4108,9 +4159,9 @@ function buildActionParamsSchema(action) {
|
|
|
4108
4159
|
for (const [name2, param] of entries) {
|
|
4109
4160
|
shape[name2] = param.optional ? PARAM_SCHEMAS[param.type].nullish() : PARAM_SCHEMAS[param.type];
|
|
4110
4161
|
}
|
|
4111
|
-
return z.strictObject(shape).superRefine((
|
|
4162
|
+
return z.strictObject(shape).superRefine((obj2, ctx) => {
|
|
4112
4163
|
for (const [name2, param] of entries) {
|
|
4113
|
-
if (!param.optional && param.type === "jsonb" &&
|
|
4164
|
+
if (!param.optional && param.type === "jsonb" && obj2[name2] === void 0) {
|
|
4114
4165
|
ctx.addIssue({ code: "custom", message: "Required", path: [name2] });
|
|
4115
4166
|
}
|
|
4116
4167
|
}
|
|
@@ -4768,6 +4819,17 @@ function syncedViewStatements({
|
|
|
4768
4819
|
const viewName = `${schema}.${quoteIdentifier(table.table)}`;
|
|
4769
4820
|
const physical2 = splitPhysicalRelation(backing.physicalRelation);
|
|
4770
4821
|
const physicalTarget = `${quoteIdentifier(physical2.schema)}.${quoteIdentifier(physical2.table)}`;
|
|
4822
|
+
const declaredColumns = Object.keys(table.columns ?? {});
|
|
4823
|
+
const projection = declaredColumns.length > 0 ? declaredColumns.map(quoteIdentifier).join(", ") : "*";
|
|
4824
|
+
if (backing.selectColumns) {
|
|
4825
|
+
if (declaredColumns.length === 0) {
|
|
4826
|
+
throw new OrmDefinitionError(`synced backing for "${table.table}" requires declared columns`);
|
|
4827
|
+
}
|
|
4828
|
+
const approved = new Set(backing.selectColumns);
|
|
4829
|
+
if (declaredColumns.some((column) => !approved.has(column))) {
|
|
4830
|
+
throw new OrmDefinitionError(`synced backing for "${table.table}" projects outside its approved column ceiling`);
|
|
4831
|
+
}
|
|
4832
|
+
}
|
|
4771
4833
|
const columnTypes = mergeSyncedViewColumnTypes({
|
|
4772
4834
|
table,
|
|
4773
4835
|
canonicalColumnTypes: columnTypesByTable?.get(table.table),
|
|
@@ -4776,23 +4838,26 @@ function syncedViewStatements({
|
|
|
4776
4838
|
});
|
|
4777
4839
|
const readPolicyIr = readPolicyIrByTable?.get(table.table);
|
|
4778
4840
|
const readPolicy = table.policies?.read;
|
|
4779
|
-
const
|
|
4841
|
+
const policyClause = readPolicyIr ? ` WHERE ${compilePredIrToSql(readPolicyIr, {
|
|
4780
4842
|
namespace: definition.namespace,
|
|
4781
4843
|
columnTypes,
|
|
4782
4844
|
columnNames: columnNamesByTable?.get(table.table)
|
|
4783
4845
|
})}` : readPolicy ? ` WHERE ${compilePredicate(readPolicy.ast, narrowToV1ColumnTypes(columnTypes))}` : " WHERE false";
|
|
4784
4846
|
if (backingPrivileges === "grant") {
|
|
4847
|
+
const selectPrivilege = backing.selectColumns ? `SELECT (${backing.selectColumns.map(quoteIdentifier).join(", ")})` : "SELECT";
|
|
4848
|
+
const hasSelectPrivilege = backing.selectColumns ? backing.selectColumns.map((column) => `pg_catalog.has_column_privilege(${quoteLiteral(executionOwnerRole)}, ${quoteLiteral(physicalTarget)}, ${quoteLiteral(column)}, 'SELECT')`).join("\n AND ") : `pg_catalog.has_table_privilege(${quoteLiteral(executionOwnerRole)}, ${quoteLiteral(physicalTarget)}, 'SELECT')`;
|
|
4785
4849
|
statements.push(`GRANT USAGE ON SCHEMA ${quoteIdentifier(physical2.schema)} TO ${owner}`);
|
|
4786
|
-
statements.push(`GRANT
|
|
4850
|
+
statements.push(`GRANT ${selectPrivilege} ON ${physicalTarget} TO ${owner}`);
|
|
4787
4851
|
statements.push(`DO ${quoteLiteral(`BEGIN
|
|
4788
4852
|
IF NOT (pg_catalog.has_schema_privilege(${quoteLiteral(executionOwnerRole)}, ${quoteLiteral(physical2.schema)}, 'USAGE')
|
|
4789
|
-
AND
|
|
4853
|
+
AND ${hasSelectPrivilege}) THEN
|
|
4790
4854
|
RAISE EXCEPTION 'Synced backing owner lacks effective USAGE/SELECT; repair managed serving reader access before ORM apply' USING ERRCODE = '42501';
|
|
4791
4855
|
END IF;
|
|
4792
4856
|
END`)}`);
|
|
4793
4857
|
}
|
|
4858
|
+
const whereClause = backing.readGuard ? ` WHERE (SELECT orm_native_sources.require_read_guard(${quoteLiteral(backing.readGuard)})) AND (${policyClause.slice(" WHERE ".length)})` : policyClause;
|
|
4794
4859
|
statements.push(
|
|
4795
|
-
`CREATE OR REPLACE VIEW ${viewName} AS SELECT
|
|
4860
|
+
`CREATE OR REPLACE VIEW ${viewName} AS SELECT ${projection} FROM ${physicalTarget}${whereClause}`
|
|
4796
4861
|
);
|
|
4797
4862
|
statements.push(`GRANT SELECT ON ${viewName} TO ${role}`);
|
|
4798
4863
|
}
|
|
@@ -5063,10 +5128,142 @@ function snapshotTableNames(snapshot, schema) {
|
|
|
5063
5128
|
return Object.values(tables).filter((entry) => entry.schema === schema).map((entry) => entry.name);
|
|
5064
5129
|
}
|
|
5065
5130
|
|
|
5131
|
+
// src/sql/ast.ts
|
|
5132
|
+
function obj(value) {
|
|
5133
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("unsupported SQL node");
|
|
5134
|
+
return value;
|
|
5135
|
+
}
|
|
5136
|
+
function list(value) {
|
|
5137
|
+
return value === void 0 ? [] : Array.isArray(value) ? value : fail("expected SQL list");
|
|
5138
|
+
}
|
|
5139
|
+
function str(value) {
|
|
5140
|
+
return typeof value === "string" ? value : fail("expected SQL name");
|
|
5141
|
+
}
|
|
5142
|
+
function fail(message) {
|
|
5143
|
+
throw new Error(message);
|
|
5144
|
+
}
|
|
5145
|
+
function strings(value) {
|
|
5146
|
+
return list(value).map((v) => str(obj(obj(v).String).sval));
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
// src/canonical/view-query.ts
|
|
5150
|
+
var parser;
|
|
5151
|
+
var functions = new Set(VIEW_QUERY_FUNCTION_ALLOWLIST);
|
|
5152
|
+
var scalarTypes = /* @__PURE__ */ new Set([
|
|
5153
|
+
"bool",
|
|
5154
|
+
"boolean",
|
|
5155
|
+
"int2",
|
|
5156
|
+
"int4",
|
|
5157
|
+
"int8",
|
|
5158
|
+
"integer",
|
|
5159
|
+
"bigint",
|
|
5160
|
+
"smallint",
|
|
5161
|
+
"numeric",
|
|
5162
|
+
"decimal",
|
|
5163
|
+
"float4",
|
|
5164
|
+
"float8",
|
|
5165
|
+
"real",
|
|
5166
|
+
"text",
|
|
5167
|
+
"varchar",
|
|
5168
|
+
"bpchar",
|
|
5169
|
+
"uuid",
|
|
5170
|
+
"date",
|
|
5171
|
+
"timestamp",
|
|
5172
|
+
"timestamptz",
|
|
5173
|
+
"time",
|
|
5174
|
+
"timetz",
|
|
5175
|
+
"interval",
|
|
5176
|
+
"json",
|
|
5177
|
+
"jsonb",
|
|
5178
|
+
"bytea"
|
|
5179
|
+
]);
|
|
5180
|
+
var sqlValues = /* @__PURE__ */ new Set([
|
|
5181
|
+
"SVFOP_CURRENT_DATE",
|
|
5182
|
+
"SVFOP_CURRENT_TIME",
|
|
5183
|
+
"SVFOP_CURRENT_TIME_N",
|
|
5184
|
+
"SVFOP_CURRENT_TIMESTAMP",
|
|
5185
|
+
"SVFOP_CURRENT_TIMESTAMP_N",
|
|
5186
|
+
"SVFOP_LOCALTIME",
|
|
5187
|
+
"SVFOP_LOCALTIME_N",
|
|
5188
|
+
"SVFOP_LOCALTIMESTAMP",
|
|
5189
|
+
"SVFOP_LOCALTIMESTAMP_N",
|
|
5190
|
+
"SVFOP_CURRENT_ROLE",
|
|
5191
|
+
"SVFOP_CURRENT_USER",
|
|
5192
|
+
"SVFOP_USER",
|
|
5193
|
+
"SVFOP_SESSION_USER",
|
|
5194
|
+
"SVFOP_CURRENT_CATALOG",
|
|
5195
|
+
"SVFOP_CURRENT_SCHEMA"
|
|
5196
|
+
]);
|
|
5197
|
+
async function validateManagedViewQueries({ canonical }) {
|
|
5198
|
+
for (const definition of [canonical, ...canonical.imports ?? []]) {
|
|
5199
|
+
for (const view of definition.views ?? []) {
|
|
5200
|
+
const fail2 = (message) => {
|
|
5201
|
+
throw new OrmDefinitionError(`managed view '${definition.namespace}/${view.view}': ${message}`);
|
|
5202
|
+
};
|
|
5203
|
+
parser ??= new PgParser({ version: 17 });
|
|
5204
|
+
const parsed = await parser.parse(view.query);
|
|
5205
|
+
if (parsed.error || !parsed.tree) fail2("invalid SELECT query");
|
|
5206
|
+
const statements = list(obj(parsed.tree).stmts);
|
|
5207
|
+
if (statements.length !== 1 || !obj(obj(statements[0]).stmt).SelectStmt) fail2("one SELECT query is required");
|
|
5208
|
+
validateTree({ tree: parsed.tree, schema: ormSchemaName(definition.namespace), enums: definition.enums.map((entry) => entry.name), fail: fail2 });
|
|
5209
|
+
}
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
function pgCatalogName(parts) {
|
|
5213
|
+
if (parts.length === 1) return parts[0];
|
|
5214
|
+
if (parts.length === 2 && parts[0] === "pg_catalog") return parts[1];
|
|
5215
|
+
return void 0;
|
|
5216
|
+
}
|
|
5217
|
+
function reviewedFunctionName({ parts, format }) {
|
|
5218
|
+
return format === "COERCE_SQL_SYNTAX" && parts.length === 2 && parts[0] === "pg_catalog" && parts[1] === "position" ? "strpos" : pgCatalogName(parts);
|
|
5219
|
+
}
|
|
5220
|
+
function validateTree({ tree, ...scope }) {
|
|
5221
|
+
const pending = [tree];
|
|
5222
|
+
while (pending.length) {
|
|
5223
|
+
const value = pending.pop();
|
|
5224
|
+
if (Array.isArray(value)) {
|
|
5225
|
+
pending.push(...value);
|
|
5226
|
+
continue;
|
|
5227
|
+
}
|
|
5228
|
+
if (!value || typeof value !== "object") continue;
|
|
5229
|
+
const node = obj(value);
|
|
5230
|
+
for (const [kind, child] of Object.entries(node)) {
|
|
5231
|
+
validateNode({ kind, child, scope });
|
|
5232
|
+
pending.push(child);
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
function validateNode({ kind, child, scope }) {
|
|
5237
|
+
const { fail: fail2 } = scope;
|
|
5238
|
+
if (kind.endsWith("Stmt") && kind !== "SelectStmt") fail2("only SELECT statements are permitted");
|
|
5239
|
+
if (kind === "FuncCall") {
|
|
5240
|
+
const call = obj(child);
|
|
5241
|
+
const parts = strings(call.funcname);
|
|
5242
|
+
const name2 = reviewedFunctionName({ parts, format: call.funcformat });
|
|
5243
|
+
if (!name2 || !functions.has(name2)) fail2(`only explicitly allowlisted pg_catalog functions are permitted (found '${parts.join(".")}')`);
|
|
5244
|
+
}
|
|
5245
|
+
if (kind === "typeName" || kind === "TypeName") validateType({ node: obj(child), ...scope });
|
|
5246
|
+
if (kind === "A_Expr" && pgCatalogName(strings(obj(child).name)) === void 0) fail2("only pg_catalog operators are permitted");
|
|
5247
|
+
if (kind === "SortBy" && list(obj(child).useOp).length && pgCatalogName(strings(obj(child).useOp)) === void 0) fail2("only pg_catalog sort operators are permitted");
|
|
5248
|
+
if (kind === "SQLValueFunction" && !sqlValues.has(String(obj(child).op))) fail2("unsupported SQL value expression");
|
|
5249
|
+
if (kind === "ParamRef") fail2("view queries cannot contain parameters");
|
|
5250
|
+
if (kind === "A_Indirection" && list(obj(child).indirection).some((entry) => !obj(entry).A_Indices)) {
|
|
5251
|
+
fail2("composite field notation is not permitted in managed views");
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
function validateType({ node, schema, enums, fail: fail2 }) {
|
|
5255
|
+
const parts = strings(node.names);
|
|
5256
|
+
const builtin = pgCatalogName(parts);
|
|
5257
|
+
const managedEnum = parts.length === 1 && enums.includes(parts[0]) || parts.length === 2 && parts[0] === schema && enums.includes(parts[1]);
|
|
5258
|
+
if (node.setof || node.pct_type || !managedEnum && (!builtin || !scalarTypes.has(builtin))) {
|
|
5259
|
+
fail2(`casts may only use supported pg_catalog scalar types or declared enums (found '${parts.join(".")}')`);
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
|
|
5066
5263
|
// src/engine/materialized-refresh.ts
|
|
5067
5264
|
function materializedRefreshFunctions(canonical) {
|
|
5068
5265
|
const schema = ormSchemaName(canonical.namespace);
|
|
5069
|
-
const
|
|
5266
|
+
const functions2 = /* @__PURE__ */ new Map();
|
|
5070
5267
|
for (const view of canonical.views ?? []) {
|
|
5071
5268
|
const materialized = view.resolved?.materialized;
|
|
5072
5269
|
if (!materialized) continue;
|
|
@@ -5075,7 +5272,7 @@ function materializedRefreshFunctions(canonical) {
|
|
|
5075
5272
|
if (!table || pk.length === 0) {
|
|
5076
5273
|
throw new OrmDefinitionError(`materialized resolved table '${view.view}' needs its table and primary key`);
|
|
5077
5274
|
}
|
|
5078
|
-
|
|
5275
|
+
functions2.set(view.view, refreshFunctionSql({
|
|
5079
5276
|
schema,
|
|
5080
5277
|
name: view.view,
|
|
5081
5278
|
table: materialized.table,
|
|
@@ -5084,13 +5281,13 @@ function materializedRefreshFunctions(canonical) {
|
|
|
5084
5281
|
pk
|
|
5085
5282
|
}));
|
|
5086
5283
|
}
|
|
5087
|
-
return
|
|
5284
|
+
return functions2;
|
|
5088
5285
|
}
|
|
5089
5286
|
function refreshFunctionSql({ schema, name: name2, table, compute, columns, pk }) {
|
|
5090
5287
|
const fn = `${quoteIdentifier(schema)}.${quoteIdentifier(materializedRefreshFunctionName(name2))}`;
|
|
5091
5288
|
const target = `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
|
|
5092
5289
|
const source = `${quoteIdentifier(schema)}.${quoteIdentifier(compute)}`;
|
|
5093
|
-
const
|
|
5290
|
+
const list2 = columns.map(quoteIdentifier).join(", ");
|
|
5094
5291
|
const others = columns.filter((column) => !pk.includes(column));
|
|
5095
5292
|
const keys = pk.map(quoteIdentifier).join(", ");
|
|
5096
5293
|
const matches = pk.map((column) => `c.${quoteIdentifier(column)} = m.${quoteIdentifier(column)}`).join(" AND ");
|
|
@@ -5116,8 +5313,8 @@ BEGIN
|
|
|
5116
5313
|
PERFORM set_config('request.jwt.claims', ${quoteLiteral(MATERIALIZE_CLAIMS_JSON)}, true);
|
|
5117
5314
|
RETURN QUERY
|
|
5118
5315
|
WITH up AS (
|
|
5119
|
-
INSERT INTO ${target} AS m (${
|
|
5120
|
-
SELECT ${
|
|
5316
|
+
INSERT INTO ${target} AS m (${list2})
|
|
5317
|
+
SELECT ${list2} FROM ${source}
|
|
5121
5318
|
ON CONFLICT (${keys}) ${onConflict}
|
|
5122
5319
|
RETURNING 1
|
|
5123
5320
|
), gone AS (
|
|
@@ -5728,6 +5925,7 @@ async function planWithViewRecreation({
|
|
|
5728
5925
|
previousSnapshot,
|
|
5729
5926
|
viewRecreation
|
|
5730
5927
|
}) {
|
|
5928
|
+
await validateManagedViewQueries({ canonical });
|
|
5731
5929
|
const schema = ormSchemaName(canonical.namespace);
|
|
5732
5930
|
const previous = previousSnapshot ? normalizeSnapshot(previousSnapshot) : emptySnapshot(canonical.namespace);
|
|
5733
5931
|
assertValidViewDependencies(canonical);
|
|
@@ -6426,7 +6624,7 @@ var limitIrSchema = z.object({
|
|
|
6426
6624
|
variable: z.string().optional(),
|
|
6427
6625
|
value: z.number().int().positive().optional(),
|
|
6428
6626
|
default: z.number().int().positive(),
|
|
6429
|
-
max: z.number().int().positive()
|
|
6627
|
+
max: z.number().int().positive().max(MAX_PERSISTED_READ_ROWS)
|
|
6430
6628
|
});
|
|
6431
6629
|
var selectionIrSchema = z.lazy(
|
|
6432
6630
|
() => z.object({
|
|
@@ -8042,6 +8240,6 @@ function resumeArguments({
|
|
|
8042
8240
|
return [literal2.sql];
|
|
8043
8241
|
}
|
|
8044
8242
|
|
|
8045
|
-
export { ACTION_REQUIRES_DENIED_SQLSTATE, ACTION_VALIDATES_FAILED_SQLSTATE, AUDIT_ACTIONS, CANONICAL_FORMAT, CAPABILITIES_CLAIM_KEY, CAPABILITY_KEY_PATTERN, CELLS_FIELD, CELL_PARTS, CELL_PART_SUFFIX, CLAIMS_CONTRACT, CLAIMS_SETTING, CLAIM_KEY_PATTERN, CMP_OPS, COLUMN_BRAND, COLUMN_DEFAULT_FNS, COLUMN_IDENTIFIER_PATTERN, COLUMN_TYPES2 as COLUMN_TYPES, COMPARE_OPS, COMPOSED_IR_VERSION, CONSUMER_ROLE_SUFFIX, ColumnBuilder, DATE_BUCKETS, DEFINITION_FILE_EXTENSIONS, ENUM_BRAND, EXTERNAL_POLICY_CLAIM_KEYS, GUARDED_IR_VERSION, HASH_DOMAIN, IDENTIFIER_PATTERN, IDENTIFIER_RE, IMPORT_CONFLICT_MODES, INPUT_REF_KINDS, IR_VERSION, IrVersionError, LEGACY_IR_VERSION, LINK_BRAND, MATERIALIZE_ACTOR, MATERIALIZE_CLAIMS_JSON, MAX_DEFINITION_FILE_BYTES, MAX_GENERATED_SDL_BYTES, MAX_IDENTIFIER_LENGTH, MAX_TRACKED_COLUMN_NAME, MIGRATIONS_DIRNAME, NAMESPACE_CONFIG_BRAND, NAMESPACE_CONFIG_FILE, NAMESPACE_CONFIG_FILENAMES, NAMESPACE_PATTERN, ORM_DATA_TOKEN_HEADER, ORM_MIGRATION_EXPORT_FILE, ORM_MIGRATION_EXPORT_MAX_BYTES, ORM_REGISTRATION_MAX_BYTES, ORM_SCHEMA_PREFIX, ORM_SERVICE_DATA_TOKEN_HEADER, ORM_TO_PIPELINE_TYPE, OrmDefinitionError, PredicateParseError, QUALIFIED_TABLE_PATTERN, RESERVED_COLUMN_NAMES, RESERVED_TABLE_NAMES, ROLES_CLAIM_KEY, RUNTIME_SQL_IR_VERSION, SCHEMA_DIR, SQL_IR_VERSION, STATEMENT_KINDS, SYNCED_CONTRACT_HASH_DOMAIN, SYNCED_SOURCE_PATTERN, SYNCED_VIEW_EXECUTION_OWNER_ROLE, TABLE_BRAND, VIEW_BRAND, actionFunctionName, actionFunctionStatements, actionParamArg, actionParamOrder, actionParamSchema, actionPrepareChecks, actionSchema, actionWriteTargets, actionsInterfaceName, activeAuthoringContext, applyMigrationHints, applyMigrationHintsV2, beginAuthoringContext, buildActionParamsSchema, buildDrizzleEntities, buildDrizzleEntitiesV2, buildNamespaceDefinition, buildRebaseJournalEntry, canonicalActionSchema, canonicalColumnSchema, canonicalDefinitionSchema, canonicalEnumSchema, canonicalIndexSchema, canonicalLinkSchema, canonicalPoliciesSchema, canonicalRelations, canonicalTableSchema, canonicalViewSchema, canonicalizeDefinition, capabilityExpression, castParts, cellColumnName, checksumOf, claimExpression, classifyDestructive, columnSchema, columnTypeSchema2 as columnTypeSchema, compileActionRequires, compileActionStatements, compileNamespace, compilePredIrToSql, compilePredicate, compiledArtifactSchema, compiledOperationSchema, computeCanonicalHash, computeDefinitionHash, computeSyncedContractHash, consumerRoleName, convertV1DefinitionToCanonical, createOrmMigrationExport, custom, declaredCapabilityKeys, defineEnum, defineNamespace, defineOperation, defineResolvedTable, defineSyncedTable, defineTable, defineView, deriveColumnName, diffCommand, diffStatements, emptyJournal, emptySnapshot, endAuthoringContext, etlSource, extractNamedParams, extractOrmSyncedTableContract, generateNamespaceTypes, generateSnapshot, generateSnapshotV2, highest, identifierSchema, importSpecSchema, indexByHash, isColumnBuilder, isEnumRef, isExternalPolicyClaimKey, isFunctionDefault, isOwnedStatement, isOwnedStatementV2, isQualifiedReference, isSeqLink, isSeqNamespaceConfig, isSeqTable, isSeqView, latest, limitIrSchema, loadCommittedMigrations, loadCommittedTipMigration, loadNamespaceDefinition, loadNamespaceFromDir, lowest, managedFn, manualSource, materializeLockKey, materializedRefreshFunctionName, migrationName, namespaceConfigSchema, namespaceSchema, nonNullFirst, normalizeCanonical, normalizeIr, normalizeSnapshot, objectRef, ontologyContractSchema, orderIrSchema, ormMigrationExportSchema, ormSchemaName, overlayWinsUnion, overrideRowMutation, parseCanonicalDefinition, parseDefinitionSources, parseOrmMigrationExport, parsePredicate, parseTableFile, parsedPredicateSchema, pendingKitStatements, pendingKitStatementsV2, planCommittedMigrationV2, planMigration, planMigrationV2, planTableImport, policyExpressionSchema, policyVariantSchema, predIrSchema, predicateOperands, prefetchPlanIrSchema, prefetchSource, priority, quoteIdentifier, quoteLiteral, readMigrationSql, readMigrationWorkspace, readOntologyContract, readSnapshot, rebaseViolations, referencedCapabilities, referencedColumns, renderMigrationSql, renderOrmMigrationExport, requiredArtifactIrVersion, resolvedMetaIrSchema, resolvedSourceIrSchema, revertOverlayMutation, rewriteSyncedSourceRelationsInViewQuery, roleExpression, rootIrSchema, securityStatements, selectionIrSchema, serializeNamespace, sqlTypeName, stableJson, syncedBackingRevokeStatements, syncedContractSurface, syncedTables, syncedViewDropStatements, syncedViewStatements, t, tableFileSchema, tableMetaIrSchema, tableReferenceSchema, toMany, toOne, toPlatformUser, typesInterfaceName, validateNamespaceCatalog, validateViewCatalogStatement, valueIrSchema, variableDefaultIrSchema, variableIrSchema, verifyRebaseIsNoop, walkPredicate, writeMigration };
|
|
8243
|
+
export { ACTION_REQUIRES_DENIED_SQLSTATE, ACTION_VALIDATES_FAILED_SQLSTATE, AUDIT_ACTIONS, CANONICAL_FORMAT, CAPABILITIES_CLAIM_KEY, CAPABILITY_KEY_PATTERN, CELLS_FIELD, CELL_PARTS, CELL_PART_SUFFIX, CLAIMS_CONTRACT, CLAIMS_SETTING, CLAIM_KEY_PATTERN, CMP_OPS, COLUMN_BRAND, COLUMN_DEFAULT_FNS, COLUMN_IDENTIFIER_PATTERN, COLUMN_TYPES2 as COLUMN_TYPES, COMPARE_OPS, COMPOSED_IR_VERSION, CONSUMER_ROLE_SUFFIX, ColumnBuilder, DATE_BUCKETS, DEFINITION_FILE_EXTENSIONS, ENUM_BRAND, EXTERNAL_POLICY_CLAIM_KEYS, GUARDED_IR_VERSION, HASH_DOMAIN, IDENTIFIER_PATTERN, IDENTIFIER_RE, IMPORT_CONFLICT_MODES, INPUT_REF_KINDS, IR_VERSION, IrVersionError, LEGACY_IR_VERSION, LINK_BRAND, MATERIALIZE_ACTOR, MATERIALIZE_CLAIMS_JSON, MAX_DEFINITION_FILE_BYTES, MAX_GENERATED_SDL_BYTES, MAX_IDENTIFIER_LENGTH, MAX_PERSISTED_READ_ROWS, MAX_TRACKED_COLUMN_NAME, MIGRATIONS_DIRNAME, NAMESPACE_CONFIG_BRAND, NAMESPACE_CONFIG_FILE, NAMESPACE_CONFIG_FILENAMES, NAMESPACE_PATTERN, ORM_DATA_TOKEN_HEADER, ORM_MIGRATION_EXPORT_FILE, ORM_MIGRATION_EXPORT_MAX_BYTES, ORM_REGISTRATION_MAX_BYTES, ORM_SCHEMA_PREFIX, ORM_SERVICE_DATA_TOKEN_HEADER, ORM_TO_PIPELINE_TYPE, OrmDefinitionError, PredicateParseError, QUALIFIED_TABLE_PATTERN, RESERVED_COLUMN_NAMES, RESERVED_TABLE_NAMES, ROLES_CLAIM_KEY, RUNTIME_SQL_IR_VERSION, SCHEMA_DIR, SQL_IR_VERSION, STATEMENT_KINDS, SYNCED_CONTRACT_HASH_DOMAIN, SYNCED_SOURCE_PATTERN, SYNCED_VIEW_EXECUTION_OWNER_ROLE, TABLE_BRAND, VIEW_BRAND, actionFunctionName, actionFunctionStatements, actionParamArg, actionParamOrder, actionParamSchema, actionPrepareChecks, actionSchema, actionWriteTargets, actionsInterfaceName, activeAuthoringContext, applyMigrationHints, applyMigrationHintsV2, beginAuthoringContext, buildActionParamsSchema, buildDrizzleEntities, buildDrizzleEntitiesV2, buildNamespaceDefinition, buildRebaseJournalEntry, canonicalActionSchema, canonicalColumnSchema, canonicalDefinitionSchema, canonicalEnumSchema, canonicalIndexSchema, canonicalLinkSchema, canonicalPoliciesSchema, canonicalRelations, canonicalTableSchema, canonicalViewSchema, canonicalizeDefinition, capabilityExpression, castParts, cellColumnName, checksumOf, claimExpression, classifyDestructive, columnSchema, columnTypeSchema2 as columnTypeSchema, compileActionRequires, compileActionStatements, compileNamespace, compilePredIrToSql, compilePredicate, compiledArtifactSchema, compiledOperationSchema, computeCanonicalHash, computeDefinitionHash, computeSyncedContractHash, consumerRoleName, convertV1DefinitionToCanonical, createOrmMigrationExport, custom, declaredCapabilityKeys, defineEnum, defineNamespace, defineOperation, defineResolvedTable, defineSyncedTable, defineTable, defineView, deriveColumnName, diffCommand, diffStatements, emptyJournal, emptySnapshot, endAuthoringContext, etlSource, extractNamedParams, extractOrmSyncedTableContract, generateNamespaceTypes, generateSnapshot, generateSnapshotV2, highest, identifierSchema, importSpecSchema, indexByHash, isColumnBuilder, isEnumRef, isExternalPolicyClaimKey, isFunctionDefault, isOwnedStatement, isOwnedStatementV2, isQualifiedReference, isSeqLink, isSeqNamespaceConfig, isSeqTable, isSeqView, latest, limitIrSchema, loadCommittedMigrations, loadCommittedTipMigration, loadNamespaceDefinition, loadNamespaceFromDir, lowest, managedFn, manualSource, materializeLockKey, materializedRefreshFunctionName, migrationName, namespaceConfigSchema, namespaceSchema, nonNullFirst, normalizeCanonical, normalizeIr, normalizeSnapshot, objectRef, ontologyContractSchema, orderIrSchema, ormMigrationExportSchema, ormSchemaName, overlayWinsUnion, overrideRowMutation, parseCanonicalDefinition, parseDefinitionSources, parseOrmMigrationExport, parsePredicate, parseTableFile, parsedPredicateSchema, pendingKitStatements, pendingKitStatementsV2, planCommittedMigrationV2, planMigration, planMigrationV2, planTableImport, policyExpressionSchema, policyVariantSchema, predIrSchema, predicateOperands, prefetchPlanIrSchema, prefetchSource, priority, quoteIdentifier, quoteLiteral, readMigrationSql, readMigrationWorkspace, readOntologyContract, readSnapshot, rebaseViolations, referencedCapabilities, referencedColumns, renderMigrationSql, renderOrmMigrationExport, requiredArtifactIrVersion, resolvedMetaIrSchema, resolvedSourceIrSchema, revertOverlayMutation, rewriteSyncedSourceRelationsInViewQuery, roleExpression, rootIrSchema, securityStatements, selectionIrSchema, serializeNamespace, sqlTypeName, stableJson, syncedBackingRevokeStatements, syncedContractSurface, syncedTables, syncedViewDropStatements, syncedViewStatements, t, tableFileSchema, tableMetaIrSchema, tableReferenceSchema, toMany, toOne, toPlatformUser, typesInterfaceName, validateNamespaceCatalog, validateViewCatalogStatement, valueIrSchema, variableDefaultIrSchema, variableIrSchema, verifyRebaseIsNoop, walkPredicate, writeMigration };
|
|
8046
8244
|
//# sourceMappingURL=index.js.map
|
|
8047
8245
|
//# sourceMappingURL=index.js.map
|