@sequenceholdings/orm 0.1.1 → 0.1.3
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 +12 -2
- package/dist/authoring.cjs +1801 -0
- package/dist/authoring.cjs.map +1 -0
- package/dist/authoring.d.cts +539 -0
- package/dist/authoring.d.ts +539 -0
- package/dist/authoring.js +1759 -0
- package/dist/authoring.js.map +1 -0
- package/dist/canonical.cjs +552 -0
- package/dist/canonical.cjs.map +1 -0
- package/dist/canonical.d.cts +603 -0
- package/dist/canonical.d.ts +603 -0
- package/dist/canonical.js +532 -0
- package/dist/canonical.js.map +1 -0
- package/dist/cli.cjs +7843 -1815
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +8 -1
- package/dist/cli.d.ts +8 -1
- package/dist/cli.js +7854 -1828
- package/dist/cli.js.map +1 -1
- package/dist/client.cjs +120 -0
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +74 -2
- package/dist/client.d.ts +74 -2
- package/dist/client.js +116 -1
- package/dist/client.js.map +1 -1
- package/dist/compiler.cjs +3453 -0
- package/dist/compiler.cjs.map +1 -0
- package/dist/compiler.d.cts +389 -0
- package/dist/compiler.d.ts +389 -0
- package/dist/compiler.js +3396 -0
- package/dist/compiler.js.map +1 -0
- package/dist/drizzle.cjs +14 -0
- package/dist/drizzle.cjs.map +1 -0
- package/dist/drizzle.d.cts +1 -0
- package/dist/drizzle.d.ts +1 -0
- package/dist/drizzle.js +3 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/dynamic-input.cjs +391 -0
- package/dist/dynamic-input.cjs.map +1 -0
- package/dist/dynamic-input.d.cts +111 -0
- package/dist/dynamic-input.d.ts +111 -0
- package/dist/dynamic-input.js +380 -0
- package/dist/dynamic-input.js.map +1 -0
- package/dist/index.cjs +3727 -344
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +236 -59
- package/dist/index.d.ts +236 -59
- package/dist/index.js +3757 -482
- package/dist/index.js.map +1 -1
- package/dist/ir.cjs +642 -0
- package/dist/ir.cjs.map +1 -0
- package/dist/ir.d.cts +1119 -0
- package/dist/ir.d.ts +1119 -0
- package/dist/ir.js +623 -0
- package/dist/ir.js.map +1 -0
- package/dist/naming-CTvWSRTf.d.ts +79 -0
- package/dist/naming-DRyinU4u.d.cts +79 -0
- package/dist/predicate-v2.cjs +1093 -0
- package/dist/predicate-v2.cjs.map +1 -0
- package/dist/predicate-v2.d.cts +139 -0
- package/dist/predicate-v2.d.ts +139 -0
- package/dist/predicate-v2.js +1083 -0
- package/dist/predicate-v2.js.map +1 -0
- package/dist/sdl.cjs +1122 -0
- package/dist/sdl.cjs.map +1 -0
- package/dist/sdl.d.cts +94 -0
- package/dist/sdl.d.ts +94 -0
- package/dist/sdl.js +1098 -0
- package/dist/sdl.js.map +1 -0
- package/package.json +51 -3
- package/src/codegen-gql/apollo-hooks.cjs +98 -0
- package/src/codegen-gql/server-fns.cjs +101 -0
- package/templates/README.md +13 -0
- package/templates/orm-namespace/CLAUDE.md +82 -0
- package/templates/orm-namespace/codegen.ts +22 -0
- package/templates/orm-namespace/gitignore +5 -0
- package/templates/orm-namespace/graphql/example/queries.ts +56 -0
- package/templates/orm-namespace/package.json +24 -0
- package/templates/orm-namespace/schema/tables.ts +71 -0
- package/templates/orm-namespace/sequence.config.ts +32 -0
- package/templates/orm-namespace/tsconfig.json +15 -0
package/dist/drizzle.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var drizzleOrm = require('drizzle-orm');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.keys(drizzleOrm).forEach(function (k) {
|
|
8
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return drizzleOrm[k]; }
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=drizzle.cjs.map
|
|
14
|
+
//# sourceMappingURL=drizzle.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"drizzle.cjs","sourcesContent":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'drizzle-orm';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'drizzle-orm';
|
package/dist/drizzle.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"drizzle.js","sourcesContent":[]}
|
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/compiler-gql/dynamic-input.ts
|
|
4
|
+
var CONST_TRUE = { kind: "and", operands: [] };
|
|
5
|
+
var ORDER_DIRECTIONS = {
|
|
6
|
+
ASC: { direction: "asc" },
|
|
7
|
+
DESC: { direction: "desc" },
|
|
8
|
+
ASC_NULLS_FIRST: { direction: "asc", nulls: "first" },
|
|
9
|
+
ASC_NULLS_LAST: { direction: "asc", nulls: "last" },
|
|
10
|
+
DESC_NULLS_FIRST: { direction: "desc", nulls: "first" },
|
|
11
|
+
DESC_NULLS_LAST: { direction: "desc", nulls: "last" }
|
|
12
|
+
};
|
|
13
|
+
var BOOLEXP_OPS = {
|
|
14
|
+
_eq: "eq",
|
|
15
|
+
_neq: "neq",
|
|
16
|
+
_gt: "gt",
|
|
17
|
+
_gte: "gte",
|
|
18
|
+
_lt: "lt",
|
|
19
|
+
_lte: "lte",
|
|
20
|
+
_in: "in",
|
|
21
|
+
_nin: "nin",
|
|
22
|
+
_like: "like",
|
|
23
|
+
_ilike: "ilike",
|
|
24
|
+
_isNull: "isNull",
|
|
25
|
+
_contains: "contains",
|
|
26
|
+
_hasKey: "hasKey"
|
|
27
|
+
};
|
|
28
|
+
function allowedOps(type) {
|
|
29
|
+
if (typeof type !== "string") return ["eq", "neq", "in", "nin", "isNull"];
|
|
30
|
+
switch (type) {
|
|
31
|
+
case "text":
|
|
32
|
+
return ["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin", "like", "ilike", "isNull"];
|
|
33
|
+
case "uuid":
|
|
34
|
+
return ["eq", "neq", "in", "nin", "isNull"];
|
|
35
|
+
case "integer":
|
|
36
|
+
case "bigint":
|
|
37
|
+
case "numeric":
|
|
38
|
+
case "double":
|
|
39
|
+
case "timestamptz":
|
|
40
|
+
case "date":
|
|
41
|
+
return ["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin", "isNull"];
|
|
42
|
+
case "boolean":
|
|
43
|
+
return ["eq", "neq", "isNull"];
|
|
44
|
+
case "jsonb":
|
|
45
|
+
return ["eq", "neq", "contains", "hasKey", "isNull"];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var CMP_OP_TO_BOOLEXP_KEY = Object.fromEntries(
|
|
49
|
+
Object.entries(BOOLEXP_OPS).map(([key, op]) => [op, key])
|
|
50
|
+
);
|
|
51
|
+
function allowedBoolExpOperators(type) {
|
|
52
|
+
return allowedOps(type).map((op) => CMP_OP_TO_BOOLEXP_KEY[op] ?? `_${op}`);
|
|
53
|
+
}
|
|
54
|
+
var ORDER_BY_DIRECTIONS = Object.keys(ORDER_DIRECTIONS);
|
|
55
|
+
function isPlainObject(value) {
|
|
56
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
57
|
+
}
|
|
58
|
+
function scalarMatches(type, value) {
|
|
59
|
+
if (typeof type !== "string") return typeof value === "string" && type.values.includes(value);
|
|
60
|
+
switch (type) {
|
|
61
|
+
case "text":
|
|
62
|
+
case "uuid":
|
|
63
|
+
case "timestamptz":
|
|
64
|
+
case "date":
|
|
65
|
+
return typeof value === "string";
|
|
66
|
+
case "integer":
|
|
67
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
68
|
+
case "double":
|
|
69
|
+
return typeof value === "number";
|
|
70
|
+
// bigint/numeric exceed JS number precision — the JSON wire form may be a string.
|
|
71
|
+
case "bigint":
|
|
72
|
+
case "numeric":
|
|
73
|
+
return typeof value === "number" || typeof value === "string";
|
|
74
|
+
case "boolean":
|
|
75
|
+
return typeof value === "boolean";
|
|
76
|
+
case "jsonb":
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
var IssueCollector = class {
|
|
81
|
+
issues = [];
|
|
82
|
+
add(code, path, message) {
|
|
83
|
+
this.issues.push({ code, path, message });
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
function finish(collector, value) {
|
|
87
|
+
return collector.issues.length > 0 ? { ok: false, issues: collector.issues } : { ok: true, value };
|
|
88
|
+
}
|
|
89
|
+
function validateBoolExpInput({ table, tables, value, maxDepth, maxNodes }) {
|
|
90
|
+
const collector = new IssueCollector();
|
|
91
|
+
const depthCap = maxDepth ?? table.dynamicFilterMaxDepth;
|
|
92
|
+
const nodeCap = maxNodes ?? table.dynamicFilterMaxNodes;
|
|
93
|
+
let nodes = 0;
|
|
94
|
+
let capped = false;
|
|
95
|
+
const consumeNode = (path) => {
|
|
96
|
+
nodes += 1;
|
|
97
|
+
if (nodes <= nodeCap) return true;
|
|
98
|
+
if (!capped) {
|
|
99
|
+
capped = true;
|
|
100
|
+
collector.add("too-many-nodes", path, `filter tree exceeds the node cap of ${nodeCap}`);
|
|
101
|
+
}
|
|
102
|
+
return false;
|
|
103
|
+
};
|
|
104
|
+
const walk = (input, meta, depth, path) => {
|
|
105
|
+
if (capped) return CONST_TRUE;
|
|
106
|
+
if (depth > depthCap) {
|
|
107
|
+
collector.add("too-deep", path, `filter tree exceeds the depth cap of ${depthCap}`);
|
|
108
|
+
return CONST_TRUE;
|
|
109
|
+
}
|
|
110
|
+
if (!isPlainObject(input)) {
|
|
111
|
+
collector.add("invalid-shape", path, "a boolean expression must be an object");
|
|
112
|
+
return CONST_TRUE;
|
|
113
|
+
}
|
|
114
|
+
const operands = [];
|
|
115
|
+
for (const [key, entry] of Object.entries(input)) {
|
|
116
|
+
if (entry === void 0 || entry === null) continue;
|
|
117
|
+
if (!consumeNode(path)) return CONST_TRUE;
|
|
118
|
+
if (key === "_and" || key === "_or") {
|
|
119
|
+
const items = Array.isArray(entry) ? entry : [entry];
|
|
120
|
+
const children = items.map((item, index) => walk(item, meta, depth + 1, `${path}.${key}[${index}]`));
|
|
121
|
+
if (children.length > 0) operands.push({ kind: key === "_and" ? "and" : "or", operands: children });
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (key === "_not") {
|
|
125
|
+
operands.push({ kind: "not", operand: walk(entry, meta, depth + 1, `${path}._not`) });
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const column = meta.columns.find((c) => c.name === key);
|
|
129
|
+
if (column) {
|
|
130
|
+
if (!meta.filterable.includes(key)) {
|
|
131
|
+
collector.add("column-not-allowed", `${path}.${key}`, `column '${key}' is not filterable on '${meta.table}'`);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!isPlainObject(entry)) {
|
|
135
|
+
collector.add("invalid-shape", `${path}.${key}`, `comparison on '${key}' must be an object like { _eq: \u2026 }`);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
for (const [opKey, opValue] of Object.entries(entry)) {
|
|
139
|
+
if (opValue === void 0) continue;
|
|
140
|
+
if (!consumeNode(`${path}.${key}`)) return CONST_TRUE;
|
|
141
|
+
const op = BOOLEXP_OPS[opKey];
|
|
142
|
+
if (!op || !allowedOps(column.type).includes(op)) {
|
|
143
|
+
collector.add("unknown-operator", `${path}.${key}.${opKey}`, `operator '${opKey}' is not allowed on '${meta.table}.${key}'`);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const issue = checkOperatorValue(op, column.type, opValue);
|
|
147
|
+
if (issue) {
|
|
148
|
+
collector.add("invalid-value", `${path}.${key}.${opKey}`, issue);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
operands.push({ kind: "cmp", op, column: key, value: opValue });
|
|
152
|
+
}
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const link = meta.links.find((l) => l.name === key);
|
|
156
|
+
if (link) {
|
|
157
|
+
const target = tables[link.target];
|
|
158
|
+
if (!target) {
|
|
159
|
+
collector.add("unknown-link", `${path}.${key}`, `link target '${link.target}' is not in the artifact`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
operands.push({ kind: "exists", link: key, target: link.target, where: walk(entry, target, depth + 1, `${path}.${key}`) });
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
collector.add(
|
|
166
|
+
"unknown-column",
|
|
167
|
+
`${path}.${key}`,
|
|
168
|
+
`unknown field '${key}' in a filter on '${meta.table}' (declared columns and links only)`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (operands.length === 0) return CONST_TRUE;
|
|
172
|
+
return operands.length === 1 ? operands[0] : { kind: "and", operands };
|
|
173
|
+
};
|
|
174
|
+
const normalized = walk(value, table, 1, "$");
|
|
175
|
+
return finish(collector, normalized);
|
|
176
|
+
}
|
|
177
|
+
function checkOperatorValue(op, type, value) {
|
|
178
|
+
if (op === "isNull") return typeof value === "boolean" ? void 0 : "_isNull takes a boolean";
|
|
179
|
+
if (op === "hasKey") return typeof value === "string" ? void 0 : "_hasKey takes a string key";
|
|
180
|
+
if (op === "contains") return void 0;
|
|
181
|
+
if (op === "in" || op === "nin") {
|
|
182
|
+
if (!Array.isArray(value)) return `${op === "in" ? "_in" : "_nin"} takes an array`;
|
|
183
|
+
return value.every((item) => scalarMatches(type, item)) ? void 0 : "array items do not match the column type";
|
|
184
|
+
}
|
|
185
|
+
if (op === "like" || op === "ilike") return typeof value === "string" ? void 0 : "pattern must be a string";
|
|
186
|
+
return scalarMatches(type, value) ? void 0 : "value does not match the column type";
|
|
187
|
+
}
|
|
188
|
+
function validateOrderByInput({
|
|
189
|
+
table,
|
|
190
|
+
tables,
|
|
191
|
+
value
|
|
192
|
+
}) {
|
|
193
|
+
const collector = new IssueCollector();
|
|
194
|
+
const normalized = [];
|
|
195
|
+
const items = Array.isArray(value) ? value : [value];
|
|
196
|
+
items.forEach((item, index) => {
|
|
197
|
+
const path = `$[${index}]`;
|
|
198
|
+
if (!isPlainObject(item)) {
|
|
199
|
+
collector.add("invalid-shape", path, "orderBy entries must be objects");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
for (const [key, direction] of Object.entries(item)) {
|
|
203
|
+
if (direction === void 0 || direction === null) continue;
|
|
204
|
+
if (table.orderable.includes(key)) {
|
|
205
|
+
const resolved = typeof direction === "string" ? ORDER_DIRECTIONS[direction] : void 0;
|
|
206
|
+
if (!resolved) {
|
|
207
|
+
collector.add("invalid-value", `${path}.${key}`, `unknown order direction '${String(direction)}'`);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
normalized.push({ column: key, ...resolved });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const link = table.links.find((l) => l.name === key);
|
|
214
|
+
if (link && link.kind !== "toMany") {
|
|
215
|
+
const target = tables[link.target];
|
|
216
|
+
if (!target || !isPlainObject(direction) || Object.keys(direction).length !== 1) {
|
|
217
|
+
collector.add("invalid-shape", `${path}.${key}`, `orderBy through '${key}' needs exactly one target column`);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const [targetColumn, targetDirection] = Object.entries(direction)[0];
|
|
221
|
+
const resolved = typeof targetDirection === "string" ? ORDER_DIRECTIONS[targetDirection] : void 0;
|
|
222
|
+
if (!target.orderable.includes(targetColumn)) {
|
|
223
|
+
collector.add("unknown-column", `${path}.${key}.${targetColumn}`, `'${targetColumn}' is not orderable on '${link.target}'`);
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (!resolved) {
|
|
227
|
+
collector.add("invalid-value", `${path}.${key}.${targetColumn}`, `unknown order direction '${String(targetDirection)}'`);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
normalized.push({ column: targetColumn, link: key, ...resolved });
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
collector.add("unknown-column", `${path}.${key}`, `'${key}' is not orderable on '${table.table}' (columns and to-one links only)`);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
return finish(collector, normalized);
|
|
237
|
+
}
|
|
238
|
+
function validateSelectColumns({ table, value }) {
|
|
239
|
+
const collector = new IssueCollector();
|
|
240
|
+
const items = Array.isArray(value) ? value : [value];
|
|
241
|
+
const normalized = [];
|
|
242
|
+
items.forEach((item, index) => {
|
|
243
|
+
if (typeof item !== "string" || !table.filterable.includes(item)) {
|
|
244
|
+
collector.add("unknown-column", `$[${index}]`, `'${String(item)}' is not a selectable column of '${table.table}'`);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
normalized.push(item);
|
|
248
|
+
});
|
|
249
|
+
return finish(collector, normalized);
|
|
250
|
+
}
|
|
251
|
+
function validateInsertInput({
|
|
252
|
+
table,
|
|
253
|
+
value,
|
|
254
|
+
list,
|
|
255
|
+
maxRows
|
|
256
|
+
}) {
|
|
257
|
+
const collector = new IssueCollector();
|
|
258
|
+
const rowCap = maxRows ?? 1e3;
|
|
259
|
+
const rows = list ? value : [value];
|
|
260
|
+
if (!Array.isArray(rows)) {
|
|
261
|
+
collector.add("invalid-shape", "$", "objects must be an array of rows");
|
|
262
|
+
return { ok: false, issues: collector.issues };
|
|
263
|
+
}
|
|
264
|
+
if (rows.length > rowCap) {
|
|
265
|
+
collector.add("too-many-rows", "$", `insert exceeds the row cap of ${rowCap}`);
|
|
266
|
+
return { ok: false, issues: collector.issues };
|
|
267
|
+
}
|
|
268
|
+
const normalized = [];
|
|
269
|
+
rows.forEach((row, index) => {
|
|
270
|
+
const path = list ? `$[${index}]` : "$";
|
|
271
|
+
if (!isPlainObject(row)) {
|
|
272
|
+
collector.add("invalid-shape", path, "insert rows must be objects");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const out = {};
|
|
276
|
+
for (const [key, entry] of Object.entries(row)) {
|
|
277
|
+
if (entry === void 0) continue;
|
|
278
|
+
if (table.links.some((l) => l.name === key)) {
|
|
279
|
+
collector.add("nested-insert", `${path}.${key}`, `nested inserts are not supported \u2014 '${key}' is a link (a { data: \u2026 } shape was rejected)`);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const column = table.columns.find((c) => c.name === key);
|
|
283
|
+
if (!column || !table.insertable.includes(key)) {
|
|
284
|
+
const reason = column ? "not insertable (pinned by the write policy or deprecated)" : "not a declared column";
|
|
285
|
+
collector.add(column ? "column-not-allowed" : "unknown-column", `${path}.${key}`, `'${key}' is ${reason} on '${table.table}'`);
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (entry === null) {
|
|
289
|
+
if (!column.nullable) {
|
|
290
|
+
collector.add("invalid-value", `${path}.${key}`, `'${key}' is not nullable`);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
} else if (!scalarMatches(column.type, entry)) {
|
|
294
|
+
collector.add("invalid-value", `${path}.${key}`, `value for '${key}' does not match its column type`);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
out[key] = entry;
|
|
298
|
+
}
|
|
299
|
+
normalized.push(out);
|
|
300
|
+
});
|
|
301
|
+
return finish(collector, normalized);
|
|
302
|
+
}
|
|
303
|
+
function validateColumnMap({
|
|
304
|
+
table,
|
|
305
|
+
value,
|
|
306
|
+
whitelist,
|
|
307
|
+
argName,
|
|
308
|
+
typeCheck
|
|
309
|
+
}) {
|
|
310
|
+
const collector = new IssueCollector();
|
|
311
|
+
if (!isPlainObject(value)) {
|
|
312
|
+
collector.add("invalid-shape", "$", `${argName} must be an object`);
|
|
313
|
+
return { ok: false, issues: collector.issues };
|
|
314
|
+
}
|
|
315
|
+
const out = {};
|
|
316
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
317
|
+
if (entry === void 0) continue;
|
|
318
|
+
if (!whitelist.includes(key)) {
|
|
319
|
+
const known = table.columns.some((c) => c.name === key);
|
|
320
|
+
collector.add(known ? "column-not-allowed" : "unknown-column", `$.${key}`, `'${key}' is not allowed in ${argName} on '${table.table}'`);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const column = table.columns.find((c) => c.name === key);
|
|
324
|
+
if (column && entry === null && !column.nullable) {
|
|
325
|
+
collector.add("invalid-value", `$.${key}`, `'${key}' is not nullable`);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (typeCheck && column && entry !== null && !scalarMatches(column.type, entry)) {
|
|
329
|
+
collector.add("invalid-value", `$.${key}`, `value for '${key}' does not match its column type`);
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
out[key] = entry;
|
|
333
|
+
}
|
|
334
|
+
return finish(collector, out);
|
|
335
|
+
}
|
|
336
|
+
function validateSetInput({ table, value }) {
|
|
337
|
+
return validateColumnMap({ table, value, whitelist: table.settable, argName: "_set", typeCheck: true });
|
|
338
|
+
}
|
|
339
|
+
function validateAppendInput({ table, value }) {
|
|
340
|
+
return validateColumnMap({ table, value, whitelist: table.appendable, argName: "_append", typeCheck: false });
|
|
341
|
+
}
|
|
342
|
+
function validateOnConflictInput({
|
|
343
|
+
table,
|
|
344
|
+
value
|
|
345
|
+
}) {
|
|
346
|
+
const collector = new IssueCollector();
|
|
347
|
+
if (!isPlainObject(value)) {
|
|
348
|
+
collector.add("invalid-shape", "$", "onConflict must be an object");
|
|
349
|
+
return { ok: false, issues: collector.issues };
|
|
350
|
+
}
|
|
351
|
+
for (const key of Object.keys(value)) {
|
|
352
|
+
if (key !== "constraint" && key !== "updateColumns") {
|
|
353
|
+
collector.add("invalid-shape", `$.${key}`, `unknown onConflict key '${key}' (constraint, updateColumns)`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const constraint = value["constraint"];
|
|
357
|
+
if (typeof constraint !== "string" || !table.constraints.some((c) => c.name === constraint)) {
|
|
358
|
+
collector.add(
|
|
359
|
+
"unknown-constraint",
|
|
360
|
+
"$.constraint",
|
|
361
|
+
`'${String(constraint)}' is not a declared constraint of '${table.table}'`
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
const updateColumns = [];
|
|
365
|
+
const rawColumns = value["updateColumns"] ?? [];
|
|
366
|
+
if (!Array.isArray(rawColumns)) {
|
|
367
|
+
collector.add("invalid-shape", "$.updateColumns", "updateColumns must be an array");
|
|
368
|
+
} else {
|
|
369
|
+
rawColumns.forEach((item, index) => {
|
|
370
|
+
if (typeof item !== "string" || !table.settable.includes(item)) {
|
|
371
|
+
collector.add("column-not-allowed", `$.updateColumns[${index}]`, `'${String(item)}' is not updatable on '${table.table}'`);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
updateColumns.push(item);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
return finish(collector, { constraint, updateColumns });
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
exports.ORDER_BY_DIRECTIONS = ORDER_BY_DIRECTIONS;
|
|
381
|
+
exports.allowedBoolExpOperators = allowedBoolExpOperators;
|
|
382
|
+
exports.allowedOps = allowedOps;
|
|
383
|
+
exports.validateAppendInput = validateAppendInput;
|
|
384
|
+
exports.validateBoolExpInput = validateBoolExpInput;
|
|
385
|
+
exports.validateInsertInput = validateInsertInput;
|
|
386
|
+
exports.validateOnConflictInput = validateOnConflictInput;
|
|
387
|
+
exports.validateOrderByInput = validateOrderByInput;
|
|
388
|
+
exports.validateSelectColumns = validateSelectColumns;
|
|
389
|
+
exports.validateSetInput = validateSetInput;
|
|
390
|
+
//# sourceMappingURL=dynamic-input.cjs.map
|
|
391
|
+
//# sourceMappingURL=dynamic-input.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compiler-gql/dynamic-input.ts"],"names":[],"mappings":"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","file":"dynamic-input.cjs","sourcesContent":["/**\n * §4f dynamic-input validators — PURE, data-only functions the data plane\n * imports to check client-supplied values for dynamic slots (BoolExp /\n * OrderBy / SelectColumn / InsertInput / SetInput / AppendInput / OnConflict)\n * against the artifact's per-table whitelist metadata (TableMetaIr).\n *\n * No drizzle imports, no IO. Each validator returns a normalized tree or\n * typed issues; the executor's runtime lowering step consumes the normalized\n * form and ANDs the result with the baked policy predicate — the policy is\n * non-negotiable regardless of what the client sends.\n */\nimport type { CmpOp, TableMetaIr } from '../ir/index.js'\n\nexport interface DynamicInputIssue {\n code:\n | 'invalid-shape'\n | 'unknown-column'\n | 'unknown-link'\n | 'unknown-operator'\n | 'invalid-value'\n | 'column-not-allowed'\n | 'nested-insert'\n | 'unknown-constraint'\n | 'too-deep'\n | 'too-many-nodes'\n | 'too-many-rows'\n path: string\n message: string\n}\n\nexport type DynamicInputResult<T> = { ok: true; value: T } | { ok: false; issues: DynamicInputIssue[] }\n\nexport type NormalizedBoolExp =\n | { kind: 'and' | 'or'; operands: NormalizedBoolExp[] }\n | { kind: 'not'; operand: NormalizedBoolExp }\n | { kind: 'cmp'; op: CmpOp; column: string; value: unknown }\n | { kind: 'exists'; link: string; target: string; where: NormalizedBoolExp }\n\nexport interface NormalizedOrderBy {\n column: string\n link?: string\n direction: 'asc' | 'desc'\n nulls?: 'first' | 'last'\n}\n\nexport type NormalizedRow = Record<string, unknown>\n\nexport interface NormalizedOnConflict {\n constraint: string\n updateColumns: string[]\n}\n\nconst CONST_TRUE: NormalizedBoolExp = { kind: 'and', operands: [] }\n\nconst ORDER_DIRECTIONS: Readonly<Record<string, { direction: 'asc' | 'desc'; nulls?: 'first' | 'last' }>> = {\n ASC: { direction: 'asc' },\n DESC: { direction: 'desc' },\n ASC_NULLS_FIRST: { direction: 'asc', nulls: 'first' },\n ASC_NULLS_LAST: { direction: 'asc', nulls: 'last' },\n DESC_NULLS_FIRST: { direction: 'desc', nulls: 'first' },\n DESC_NULLS_LAST: { direction: 'desc', nulls: 'last' },\n}\n\nconst BOOLEXP_OPS: Readonly<Record<string, CmpOp>> = {\n _eq: 'eq',\n _neq: 'neq',\n _gt: 'gt',\n _gte: 'gte',\n _lt: 'lt',\n _lte: 'lte',\n _in: 'in',\n _nin: 'nin',\n _like: 'like',\n _ilike: 'ilike',\n _isNull: 'isNull',\n _contains: 'contains',\n _hasKey: 'hasKey',\n}\n\nexport type ScalarKind = TableMetaIr['columns'][number]['type']\n\n/** Operators each column type accepts — anything else is rejected, never lowered. */\nexport function allowedOps(type: ScalarKind): readonly CmpOp[] {\n if (typeof type !== 'string') return ['eq', 'neq', 'in', 'nin', 'isNull']\n switch (type) {\n case 'text':\n return ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'like', 'ilike', 'isNull']\n case 'uuid':\n return ['eq', 'neq', 'in', 'nin', 'isNull']\n case 'integer':\n case 'bigint':\n case 'numeric':\n case 'double':\n case 'timestamptz':\n case 'date':\n return ['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'nin', 'isNull']\n case 'boolean':\n return ['eq', 'neq', 'isNull']\n case 'jsonb':\n return ['eq', 'neq', 'contains', 'hasKey', 'isNull']\n }\n}\n\n/** `eq` → `_eq` — the reverse of BOOLEXP_OPS, built once. */\nconst CMP_OP_TO_BOOLEXP_KEY: Readonly<Record<string, string>> = Object.fromEntries(\n Object.entries(BOOLEXP_OPS).map(([key, op]) => [op, key]),\n)\n\n/**\n * The comparison keys a client may put on this column inside a `BoolExp` —\n * `['_eq', '_neq', '_in', '_nin', '_isNull']` for a uuid.\n *\n * This is `allowedOps` in the wire spelling, and it is deliberately the same\n * function the validator consults. The generated SDL is NOT a substitute: it\n * renders a wider comparison type per scalar family (a uuid gets `_gt`, a\n * boolean gets `_in`, jsonb gets `_nin`), so a form built from the SDL offers\n * operators the executor answers with BAD_USER_INPUT.\n */\nexport function allowedBoolExpOperators(type: ScalarKind): readonly string[] {\n return allowedOps(type).map((op) => CMP_OP_TO_BOOLEXP_KEY[op] ?? `_${op}`)\n}\n\n/** Every `OrderBy` enum value the executor accepts, in SDL order. */\nexport const ORDER_BY_DIRECTIONS: readonly string[] = Object.keys(ORDER_DIRECTIONS)\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction scalarMatches(type: ScalarKind, value: unknown): boolean {\n if (typeof type !== 'string') return typeof value === 'string' && type.values.includes(value)\n switch (type) {\n case 'text':\n case 'uuid':\n case 'timestamptz':\n case 'date':\n return typeof value === 'string'\n case 'integer':\n return typeof value === 'number' && Number.isInteger(value)\n case 'double':\n return typeof value === 'number'\n // bigint/numeric exceed JS number precision — the JSON wire form may be a string.\n case 'bigint':\n case 'numeric':\n return typeof value === 'number' || typeof value === 'string'\n case 'boolean':\n return typeof value === 'boolean'\n case 'jsonb':\n return true\n }\n}\n\nclass IssueCollector {\n readonly issues: DynamicInputIssue[] = []\n\n add(code: DynamicInputIssue['code'], path: string, message: string): void {\n this.issues.push({ code, path, message })\n }\n}\n\nfunction finish<T>(collector: IssueCollector, value: T): DynamicInputResult<T> {\n return collector.issues.length > 0 ? { ok: false, issues: collector.issues } : { ok: true, value }\n}\n\nexport interface BoolExpInput {\n table: TableMetaIr\n /** Artifact tables record — relationship predicates resolve targets here. */\n tables: Record<string, TableMetaIr>\n value: unknown\n maxDepth?: number\n maxNodes?: number\n}\n\nexport function validateBoolExpInput({ table, tables, value, maxDepth, maxNodes }: BoolExpInput): DynamicInputResult<NormalizedBoolExp> {\n const collector = new IssueCollector()\n const depthCap = maxDepth ?? table.dynamicFilterMaxDepth\n const nodeCap = maxNodes ?? table.dynamicFilterMaxNodes\n let nodes = 0\n let capped = false\n\n /** Every crossing reports exactly once; a capped result is ALWAYS ok:false — a silently truncated `_or` branch would widen results. */\n const consumeNode = (path: string): boolean => {\n nodes += 1\n if (nodes <= nodeCap) return true\n if (!capped) {\n capped = true\n collector.add('too-many-nodes', path, `filter tree exceeds the node cap of ${nodeCap}`)\n }\n return false\n }\n\n const walk = (input: unknown, meta: TableMetaIr, depth: number, path: string): NormalizedBoolExp => {\n if (capped) return CONST_TRUE\n if (depth > depthCap) {\n collector.add('too-deep', path, `filter tree exceeds the depth cap of ${depthCap}`)\n return CONST_TRUE\n }\n if (!isPlainObject(input)) {\n collector.add('invalid-shape', path, 'a boolean expression must be an object')\n return CONST_TRUE\n }\n\n const operands: NormalizedBoolExp[] = []\n for (const [key, entry] of Object.entries(input)) {\n if (entry === undefined || entry === null) continue\n if (!consumeNode(path)) return CONST_TRUE\n\n if (key === '_and' || key === '_or') {\n const items = Array.isArray(entry) ? entry : [entry]\n const children = items.map((item, index) => walk(item, meta, depth + 1, `${path}.${key}[${index}]`))\n if (children.length > 0) operands.push({ kind: key === '_and' ? 'and' : 'or', operands: children })\n continue\n }\n if (key === '_not') {\n operands.push({ kind: 'not', operand: walk(entry, meta, depth + 1, `${path}._not`) })\n continue\n }\n\n const column = meta.columns.find((c) => c.name === key)\n if (column) {\n if (!meta.filterable.includes(key)) {\n collector.add('column-not-allowed', `${path}.${key}`, `column '${key}' is not filterable on '${meta.table}'`)\n continue\n }\n if (!isPlainObject(entry)) {\n collector.add('invalid-shape', `${path}.${key}`, `comparison on '${key}' must be an object like { _eq: … }`)\n continue\n }\n for (const [opKey, opValue] of Object.entries(entry)) {\n if (opValue === undefined) continue\n if (!consumeNode(`${path}.${key}`)) return CONST_TRUE\n const op = BOOLEXP_OPS[opKey]\n if (!op || !allowedOps(column.type).includes(op)) {\n collector.add('unknown-operator', `${path}.${key}.${opKey}`, `operator '${opKey}' is not allowed on '${meta.table}.${key}'`)\n continue\n }\n const issue = checkOperatorValue(op, column.type, opValue)\n if (issue) {\n collector.add('invalid-value', `${path}.${key}.${opKey}`, issue)\n continue\n }\n operands.push({ kind: 'cmp', op, column: key, value: opValue })\n }\n continue\n }\n\n const link = meta.links.find((l) => l.name === key)\n if (link) {\n const target = tables[link.target]\n if (!target) {\n collector.add('unknown-link', `${path}.${key}`, `link target '${link.target}' is not in the artifact`)\n continue\n }\n operands.push({ kind: 'exists', link: key, target: link.target, where: walk(entry, target, depth + 1, `${path}.${key}`) })\n continue\n }\n\n // Aggregation predicates are deliberately NOT accepted from dynamic\n // input in v2.0 — only document-authored filters may use them.\n collector.add(\n 'unknown-column',\n `${path}.${key}`,\n `unknown field '${key}' in a filter on '${meta.table}' (declared columns and links only)`,\n )\n }\n if (operands.length === 0) return CONST_TRUE\n return operands.length === 1 ? (operands[0] as NormalizedBoolExp) : { kind: 'and', operands }\n }\n\n const normalized = walk(value, table, 1, '$')\n return finish(collector, normalized)\n}\n\nfunction checkOperatorValue(op: CmpOp, type: ScalarKind, value: unknown): string | undefined {\n if (op === 'isNull') return typeof value === 'boolean' ? undefined : '_isNull takes a boolean'\n if (op === 'hasKey') return typeof value === 'string' ? undefined : '_hasKey takes a string key'\n if (op === 'contains') return undefined // jsonb containment takes arbitrary JSON\n if (op === 'in' || op === 'nin') {\n if (!Array.isArray(value)) return `${op === 'in' ? '_in' : '_nin'} takes an array`\n return value.every((item) => scalarMatches(type, item)) ? undefined : 'array items do not match the column type'\n }\n if (op === 'like' || op === 'ilike') return typeof value === 'string' ? undefined : 'pattern must be a string'\n return scalarMatches(type, value) ? undefined : 'value does not match the column type'\n}\n\nexport function validateOrderByInput({\n table,\n tables,\n value,\n}: {\n table: TableMetaIr\n tables: Record<string, TableMetaIr>\n value: unknown\n}): DynamicInputResult<NormalizedOrderBy[]> {\n const collector = new IssueCollector()\n const normalized: NormalizedOrderBy[] = []\n const items = Array.isArray(value) ? value : [value]\n\n items.forEach((item, index) => {\n const path = `$[${index}]`\n if (!isPlainObject(item)) {\n collector.add('invalid-shape', path, 'orderBy entries must be objects')\n return\n }\n for (const [key, direction] of Object.entries(item)) {\n if (direction === undefined || direction === null) continue\n if (table.orderable.includes(key)) {\n const resolved = typeof direction === 'string' ? ORDER_DIRECTIONS[direction] : undefined\n if (!resolved) {\n collector.add('invalid-value', `${path}.${key}`, `unknown order direction '${String(direction)}'`)\n continue\n }\n normalized.push({ column: key, ...resolved })\n continue\n }\n const link = table.links.find((l) => l.name === key)\n if (link && link.kind !== 'toMany') {\n const target = tables[link.target]\n if (!target || !isPlainObject(direction) || Object.keys(direction).length !== 1) {\n collector.add('invalid-shape', `${path}.${key}`, `orderBy through '${key}' needs exactly one target column`)\n continue\n }\n const [targetColumn, targetDirection] = Object.entries(direction)[0] as [string, unknown]\n const resolved = typeof targetDirection === 'string' ? ORDER_DIRECTIONS[targetDirection] : undefined\n if (!target.orderable.includes(targetColumn)) {\n collector.add('unknown-column', `${path}.${key}.${targetColumn}`, `'${targetColumn}' is not orderable on '${link.target}'`)\n continue\n }\n if (!resolved) {\n collector.add('invalid-value', `${path}.${key}.${targetColumn}`, `unknown order direction '${String(targetDirection)}'`)\n continue\n }\n normalized.push({ column: targetColumn, link: key, ...resolved })\n continue\n }\n collector.add('unknown-column', `${path}.${key}`, `'${key}' is not orderable on '${table.table}' (columns and to-one links only)`)\n }\n })\n\n return finish(collector, normalized)\n}\n\nexport function validateSelectColumns({ table, value }: { table: TableMetaIr; value: unknown }): DynamicInputResult<string[]> {\n const collector = new IssueCollector()\n const items = Array.isArray(value) ? value : [value]\n const normalized: string[] = []\n items.forEach((item, index) => {\n if (typeof item !== 'string' || !table.filterable.includes(item)) {\n collector.add('unknown-column', `$[${index}]`, `'${String(item)}' is not a selectable column of '${table.table}'`)\n return\n }\n normalized.push(item)\n })\n return finish(collector, normalized)\n}\n\nexport function validateInsertInput({\n table,\n value,\n list,\n maxRows,\n}: {\n table: TableMetaIr\n value: unknown\n /** true for `$objects: [FooInsertInput!]`, false for `$object: FooInsertInput`. */\n list: boolean\n maxRows?: number\n}): DynamicInputResult<NormalizedRow[]> {\n const collector = new IssueCollector()\n const rowCap = maxRows ?? 1000\n const rows = list ? value : [value]\n if (!Array.isArray(rows)) {\n collector.add('invalid-shape', '$', 'objects must be an array of rows')\n return { ok: false, issues: collector.issues }\n }\n if (rows.length > rowCap) {\n collector.add('too-many-rows', '$', `insert exceeds the row cap of ${rowCap}`)\n return { ok: false, issues: collector.issues }\n }\n\n const normalized: NormalizedRow[] = []\n rows.forEach((row, index) => {\n const path = list ? `$[${index}]` : '$'\n if (!isPlainObject(row)) {\n collector.add('invalid-shape', path, 'insert rows must be objects')\n return\n }\n const out: NormalizedRow = {}\n for (const [key, entry] of Object.entries(row)) {\n if (entry === undefined) continue\n if (table.links.some((l) => l.name === key)) {\n collector.add('nested-insert', `${path}.${key}`, `nested inserts are not supported — '${key}' is a link (a { data: … } shape was rejected)`)\n continue\n }\n const column = table.columns.find((c) => c.name === key)\n if (!column || !table.insertable.includes(key)) {\n const reason = column ? 'not insertable (pinned by the write policy or deprecated)' : 'not a declared column'\n collector.add(column ? 'column-not-allowed' : 'unknown-column', `${path}.${key}`, `'${key}' is ${reason} on '${table.table}'`)\n continue\n }\n if (entry === null) {\n if (!column.nullable) {\n collector.add('invalid-value', `${path}.${key}`, `'${key}' is not nullable`)\n continue\n }\n } else if (!scalarMatches(column.type, entry)) {\n collector.add('invalid-value', `${path}.${key}`, `value for '${key}' does not match its column type`)\n continue\n }\n out[key] = entry\n }\n normalized.push(out)\n })\n\n return finish(collector, normalized)\n}\n\nfunction validateColumnMap({\n table,\n value,\n whitelist,\n argName,\n typeCheck,\n}: {\n table: TableMetaIr\n value: unknown\n whitelist: readonly string[]\n argName: string\n typeCheck: boolean\n}): DynamicInputResult<NormalizedRow> {\n const collector = new IssueCollector()\n if (!isPlainObject(value)) {\n collector.add('invalid-shape', '$', `${argName} must be an object`)\n return { ok: false, issues: collector.issues }\n }\n const out: NormalizedRow = {}\n for (const [key, entry] of Object.entries(value)) {\n if (entry === undefined) continue\n if (!whitelist.includes(key)) {\n const known = table.columns.some((c) => c.name === key)\n collector.add(known ? 'column-not-allowed' : 'unknown-column', `$.${key}`, `'${key}' is not allowed in ${argName} on '${table.table}'`)\n continue\n }\n const column = table.columns.find((c) => c.name === key)\n if (column && entry === null && !column.nullable) {\n collector.add('invalid-value', `$.${key}`, `'${key}' is not nullable`)\n continue\n }\n if (typeCheck && column && entry !== null && !scalarMatches(column.type, entry)) {\n collector.add('invalid-value', `$.${key}`, `value for '${key}' does not match its column type`)\n continue\n }\n out[key] = entry\n }\n return finish(collector, out)\n}\n\nexport function validateSetInput({ table, value }: { table: TableMetaIr; value: unknown }): DynamicInputResult<NormalizedRow> {\n return validateColumnMap({ table, value, whitelist: table.settable, argName: '_set', typeCheck: true })\n}\n\n/** _append targets jsonb columns; values are arbitrary JSON (no scalar check). */\nexport function validateAppendInput({ table, value }: { table: TableMetaIr; value: unknown }): DynamicInputResult<NormalizedRow> {\n return validateColumnMap({ table, value, whitelist: table.appendable, argName: '_append', typeCheck: false })\n}\n\nexport function validateOnConflictInput({\n table,\n value,\n}: {\n table: TableMetaIr\n value: unknown\n}): DynamicInputResult<NormalizedOnConflict> {\n const collector = new IssueCollector()\n if (!isPlainObject(value)) {\n collector.add('invalid-shape', '$', 'onConflict must be an object')\n return { ok: false, issues: collector.issues }\n }\n for (const key of Object.keys(value)) {\n if (key !== 'constraint' && key !== 'updateColumns') {\n collector.add('invalid-shape', `$.${key}`, `unknown onConflict key '${key}' (constraint, updateColumns)`)\n }\n }\n\n const constraint = value['constraint']\n if (typeof constraint !== 'string' || !table.constraints.some((c) => c.name === constraint)) {\n collector.add(\n 'unknown-constraint',\n '$.constraint',\n `'${String(constraint)}' is not a declared constraint of '${table.table}'`,\n )\n }\n\n const updateColumns: string[] = []\n const rawColumns = value['updateColumns'] ?? []\n if (!Array.isArray(rawColumns)) {\n collector.add('invalid-shape', '$.updateColumns', 'updateColumns must be an array')\n } else {\n rawColumns.forEach((item, index) => {\n if (typeof item !== 'string' || !table.settable.includes(item)) {\n collector.add('column-not-allowed', `$.updateColumns[${index}]`, `'${String(item)}' is not updatable on '${table.table}'`)\n return\n }\n updateColumns.push(item)\n })\n }\n\n return finish(collector, { constraint: constraint as string, updateColumns })\n}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { CmpOp, TableMetaIr } from './ir.cjs';
|
|
2
|
+
import 'zod';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* §4f dynamic-input validators — PURE, data-only functions the data plane
|
|
6
|
+
* imports to check client-supplied values for dynamic slots (BoolExp /
|
|
7
|
+
* OrderBy / SelectColumn / InsertInput / SetInput / AppendInput / OnConflict)
|
|
8
|
+
* against the artifact's per-table whitelist metadata (TableMetaIr).
|
|
9
|
+
*
|
|
10
|
+
* No drizzle imports, no IO. Each validator returns a normalized tree or
|
|
11
|
+
* typed issues; the executor's runtime lowering step consumes the normalized
|
|
12
|
+
* form and ANDs the result with the baked policy predicate — the policy is
|
|
13
|
+
* non-negotiable regardless of what the client sends.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
interface DynamicInputIssue {
|
|
17
|
+
code: 'invalid-shape' | 'unknown-column' | 'unknown-link' | 'unknown-operator' | 'invalid-value' | 'column-not-allowed' | 'nested-insert' | 'unknown-constraint' | 'too-deep' | 'too-many-nodes' | 'too-many-rows';
|
|
18
|
+
path: string;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
type DynamicInputResult<T> = {
|
|
22
|
+
ok: true;
|
|
23
|
+
value: T;
|
|
24
|
+
} | {
|
|
25
|
+
ok: false;
|
|
26
|
+
issues: DynamicInputIssue[];
|
|
27
|
+
};
|
|
28
|
+
type NormalizedBoolExp = {
|
|
29
|
+
kind: 'and' | 'or';
|
|
30
|
+
operands: NormalizedBoolExp[];
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'not';
|
|
33
|
+
operand: NormalizedBoolExp;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'cmp';
|
|
36
|
+
op: CmpOp;
|
|
37
|
+
column: string;
|
|
38
|
+
value: unknown;
|
|
39
|
+
} | {
|
|
40
|
+
kind: 'exists';
|
|
41
|
+
link: string;
|
|
42
|
+
target: string;
|
|
43
|
+
where: NormalizedBoolExp;
|
|
44
|
+
};
|
|
45
|
+
interface NormalizedOrderBy {
|
|
46
|
+
column: string;
|
|
47
|
+
link?: string;
|
|
48
|
+
direction: 'asc' | 'desc';
|
|
49
|
+
nulls?: 'first' | 'last';
|
|
50
|
+
}
|
|
51
|
+
type NormalizedRow = Record<string, unknown>;
|
|
52
|
+
interface NormalizedOnConflict {
|
|
53
|
+
constraint: string;
|
|
54
|
+
updateColumns: string[];
|
|
55
|
+
}
|
|
56
|
+
type ScalarKind = TableMetaIr['columns'][number]['type'];
|
|
57
|
+
/** Operators each column type accepts — anything else is rejected, never lowered. */
|
|
58
|
+
declare function allowedOps(type: ScalarKind): readonly CmpOp[];
|
|
59
|
+
/**
|
|
60
|
+
* The comparison keys a client may put on this column inside a `BoolExp` —
|
|
61
|
+
* `['_eq', '_neq', '_in', '_nin', '_isNull']` for a uuid.
|
|
62
|
+
*
|
|
63
|
+
* This is `allowedOps` in the wire spelling, and it is deliberately the same
|
|
64
|
+
* function the validator consults. The generated SDL is NOT a substitute: it
|
|
65
|
+
* renders a wider comparison type per scalar family (a uuid gets `_gt`, a
|
|
66
|
+
* boolean gets `_in`, jsonb gets `_nin`), so a form built from the SDL offers
|
|
67
|
+
* operators the executor answers with BAD_USER_INPUT.
|
|
68
|
+
*/
|
|
69
|
+
declare function allowedBoolExpOperators(type: ScalarKind): readonly string[];
|
|
70
|
+
/** Every `OrderBy` enum value the executor accepts, in SDL order. */
|
|
71
|
+
declare const ORDER_BY_DIRECTIONS: readonly string[];
|
|
72
|
+
interface BoolExpInput {
|
|
73
|
+
table: TableMetaIr;
|
|
74
|
+
/** Artifact tables record — relationship predicates resolve targets here. */
|
|
75
|
+
tables: Record<string, TableMetaIr>;
|
|
76
|
+
value: unknown;
|
|
77
|
+
maxDepth?: number;
|
|
78
|
+
maxNodes?: number;
|
|
79
|
+
}
|
|
80
|
+
declare function validateBoolExpInput({ table, tables, value, maxDepth, maxNodes }: BoolExpInput): DynamicInputResult<NormalizedBoolExp>;
|
|
81
|
+
declare function validateOrderByInput({ table, tables, value, }: {
|
|
82
|
+
table: TableMetaIr;
|
|
83
|
+
tables: Record<string, TableMetaIr>;
|
|
84
|
+
value: unknown;
|
|
85
|
+
}): DynamicInputResult<NormalizedOrderBy[]>;
|
|
86
|
+
declare function validateSelectColumns({ table, value }: {
|
|
87
|
+
table: TableMetaIr;
|
|
88
|
+
value: unknown;
|
|
89
|
+
}): DynamicInputResult<string[]>;
|
|
90
|
+
declare function validateInsertInput({ table, value, list, maxRows, }: {
|
|
91
|
+
table: TableMetaIr;
|
|
92
|
+
value: unknown;
|
|
93
|
+
/** true for `$objects: [FooInsertInput!]`, false for `$object: FooInsertInput`. */
|
|
94
|
+
list: boolean;
|
|
95
|
+
maxRows?: number;
|
|
96
|
+
}): DynamicInputResult<NormalizedRow[]>;
|
|
97
|
+
declare function validateSetInput({ table, value }: {
|
|
98
|
+
table: TableMetaIr;
|
|
99
|
+
value: unknown;
|
|
100
|
+
}): DynamicInputResult<NormalizedRow>;
|
|
101
|
+
/** _append targets jsonb columns; values are arbitrary JSON (no scalar check). */
|
|
102
|
+
declare function validateAppendInput({ table, value }: {
|
|
103
|
+
table: TableMetaIr;
|
|
104
|
+
value: unknown;
|
|
105
|
+
}): DynamicInputResult<NormalizedRow>;
|
|
106
|
+
declare function validateOnConflictInput({ table, value, }: {
|
|
107
|
+
table: TableMetaIr;
|
|
108
|
+
value: unknown;
|
|
109
|
+
}): DynamicInputResult<NormalizedOnConflict>;
|
|
110
|
+
|
|
111
|
+
export { type BoolExpInput, type DynamicInputIssue, type DynamicInputResult, type NormalizedBoolExp, type NormalizedOnConflict, type NormalizedOrderBy, type NormalizedRow, ORDER_BY_DIRECTIONS, type ScalarKind, allowedBoolExpOperators, allowedOps, validateAppendInput, validateBoolExpInput, validateInsertInput, validateOnConflictInput, validateOrderByInput, validateSelectColumns, validateSetInput };
|