@zenstackhq/runtime 3.0.0-beta.8 → 3.0.0-beta.9

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.
@@ -1,3478 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
- var __export = (target, all) => {
10
- for (var name in all)
11
- __defProp(target, name, { get: all[name], enumerable: true });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
- }
19
- return to;
20
- };
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/plugins/policy/index.ts
32
- var policy_exports = {};
33
- __export(policy_exports, {
34
- PolicyPlugin: () => PolicyPlugin,
35
- RejectedByPolicyError: () => RejectedByPolicyError,
36
- RejectedByPolicyReason: () => RejectedByPolicyReason
37
- });
38
- module.exports = __toCommonJS(policy_exports);
39
-
40
- // src/client/client-impl.ts
41
- var import_common_helpers12 = require("@zenstackhq/common-helpers");
42
- var import_kysely13 = require("kysely");
43
-
44
- // src/client/crud/operations/aggregate.ts
45
- var import_kysely5 = require("kysely");
46
- var import_ts_pattern7 = require("ts-pattern");
47
-
48
- // src/client/query-utils.ts
49
- var import_common_helpers = require("@zenstackhq/common-helpers");
50
- var import_ts_pattern = require("ts-pattern");
51
-
52
- // src/schema/expression.ts
53
- var ExpressionUtils = {
54
- literal: /* @__PURE__ */ __name((value) => {
55
- return {
56
- kind: "literal",
57
- value
58
- };
59
- }, "literal"),
60
- array: /* @__PURE__ */ __name((items) => {
61
- return {
62
- kind: "array",
63
- items
64
- };
65
- }, "array"),
66
- call: /* @__PURE__ */ __name((functionName, args) => {
67
- return {
68
- kind: "call",
69
- function: functionName,
70
- args
71
- };
72
- }, "call"),
73
- binary: /* @__PURE__ */ __name((left, op, right) => {
74
- return {
75
- kind: "binary",
76
- op,
77
- left,
78
- right
79
- };
80
- }, "binary"),
81
- unary: /* @__PURE__ */ __name((op, operand) => {
82
- return {
83
- kind: "unary",
84
- op,
85
- operand
86
- };
87
- }, "unary"),
88
- field: /* @__PURE__ */ __name((field) => {
89
- return {
90
- kind: "field",
91
- field
92
- };
93
- }, "field"),
94
- member: /* @__PURE__ */ __name((receiver, members) => {
95
- return {
96
- kind: "member",
97
- receiver,
98
- members
99
- };
100
- }, "member"),
101
- _this: /* @__PURE__ */ __name(() => {
102
- return {
103
- kind: "this"
104
- };
105
- }, "_this"),
106
- _null: /* @__PURE__ */ __name(() => {
107
- return {
108
- kind: "null"
109
- };
110
- }, "_null"),
111
- and: /* @__PURE__ */ __name((expr2, ...expressions) => {
112
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "&&", exp), expr2);
113
- }, "and"),
114
- or: /* @__PURE__ */ __name((expr2, ...expressions) => {
115
- return expressions.reduce((acc, exp) => ExpressionUtils.binary(acc, "||", exp), expr2);
116
- }, "or"),
117
- not: /* @__PURE__ */ __name((expr2) => {
118
- return ExpressionUtils.unary("!", expr2);
119
- }, "not"),
120
- is: /* @__PURE__ */ __name((value, kind) => {
121
- return !!value && typeof value === "object" && "kind" in value && value.kind === kind;
122
- }, "is"),
123
- isLiteral: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "literal"), "isLiteral"),
124
- isArray: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "array"), "isArray"),
125
- isCall: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "call"), "isCall"),
126
- isNull: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "null"), "isNull"),
127
- isThis: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "this"), "isThis"),
128
- isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
129
- isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
130
- isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
131
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember"),
132
- getLiteralValue: /* @__PURE__ */ __name((expr2) => {
133
- return ExpressionUtils.isLiteral(expr2) ? expr2.value : void 0;
134
- }, "getLiteralValue")
135
- };
136
-
137
- // src/client/errors.ts
138
- var ZenStackError = class extends Error {
139
- static {
140
- __name(this, "ZenStackError");
141
- }
142
- };
143
- var QueryError = class extends ZenStackError {
144
- static {
145
- __name(this, "QueryError");
146
- }
147
- constructor(message, cause) {
148
- super(message, {
149
- cause
150
- });
151
- }
152
- };
153
- var InternalError = class extends ZenStackError {
154
- static {
155
- __name(this, "InternalError");
156
- }
157
- };
158
-
159
- // src/client/query-utils.ts
160
- function getModel(schema, model) {
161
- return Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase());
162
- }
163
- __name(getModel, "getModel");
164
- function getTypeDef(schema, type) {
165
- return schema.typeDefs?.[type];
166
- }
167
- __name(getTypeDef, "getTypeDef");
168
- function requireModel(schema, model) {
169
- const modelDef = getModel(schema, model);
170
- if (!modelDef) {
171
- throw new QueryError(`Model "${model}" not found in schema`);
172
- }
173
- return modelDef;
174
- }
175
- __name(requireModel, "requireModel");
176
- function getField(schema, model, field) {
177
- const modelDef = getModel(schema, model);
178
- return modelDef?.fields[field];
179
- }
180
- __name(getField, "getField");
181
- function requireField(schema, modelOrType, field) {
182
- const modelDef = getModel(schema, modelOrType);
183
- if (modelDef) {
184
- if (!modelDef.fields[field]) {
185
- throw new QueryError(`Field "${field}" not found in model "${modelOrType}"`);
186
- } else {
187
- return modelDef.fields[field];
188
- }
189
- }
190
- const typeDef = getTypeDef(schema, modelOrType);
191
- if (typeDef) {
192
- if (!typeDef.fields[field]) {
193
- throw new QueryError(`Field "${field}" not found in type "${modelOrType}"`);
194
- } else {
195
- return typeDef.fields[field];
196
- }
197
- }
198
- throw new QueryError(`Model or type "${modelOrType}" not found in schema`);
199
- }
200
- __name(requireField, "requireField");
201
- function requireIdFields(schema, model) {
202
- const modelDef = requireModel(schema, model);
203
- const result = modelDef?.idFields;
204
- if (!result) {
205
- throw new InternalError(`Model "${model}" does not have ID field(s)`);
206
- }
207
- return result;
208
- }
209
- __name(requireIdFields, "requireIdFields");
210
- function getRelationForeignKeyFieldPairs(schema, model, relationField) {
211
- const fieldDef = requireField(schema, model, relationField);
212
- if (!fieldDef?.relation) {
213
- throw new InternalError(`Field "${relationField}" is not a relation`);
214
- }
215
- if (fieldDef.relation.fields) {
216
- if (!fieldDef.relation.references) {
217
- throw new InternalError(`Relation references not defined for field "${relationField}"`);
218
- }
219
- return {
220
- keyPairs: fieldDef.relation.fields.map((f, i) => ({
221
- fk: f,
222
- pk: fieldDef.relation.references[i]
223
- })),
224
- ownedByModel: true
225
- };
226
- } else {
227
- if (!fieldDef.relation.opposite) {
228
- throw new InternalError(`Opposite relation not defined for field "${relationField}"`);
229
- }
230
- const oppositeField = requireField(schema, fieldDef.type, fieldDef.relation.opposite);
231
- if (!oppositeField.relation) {
232
- throw new InternalError(`Field "${fieldDef.relation.opposite}" is not a relation`);
233
- }
234
- if (!oppositeField.relation.fields) {
235
- throw new InternalError(`Relation fields not defined for field "${relationField}"`);
236
- }
237
- if (!oppositeField.relation.references) {
238
- throw new InternalError(`Relation references not defined for field "${relationField}"`);
239
- }
240
- return {
241
- keyPairs: oppositeField.relation.fields.map((f, i) => ({
242
- fk: f,
243
- pk: oppositeField.relation.references[i]
244
- })),
245
- ownedByModel: false
246
- };
247
- }
248
- }
249
- __name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
250
- function isRelationField(schema, model, field) {
251
- const fieldDef = getField(schema, model, field);
252
- return !!fieldDef?.relation;
253
- }
254
- __name(isRelationField, "isRelationField");
255
- function isInheritedField(schema, model, field) {
256
- const fieldDef = getField(schema, model, field);
257
- return !!fieldDef?.originModel;
258
- }
259
- __name(isInheritedField, "isInheritedField");
260
- function getUniqueFields(schema, model) {
261
- const modelDef = requireModel(schema, model);
262
- const result = [];
263
- for (const [key, value] of Object.entries(modelDef.uniqueFields)) {
264
- if (typeof value !== "object") {
265
- throw new InternalError(`Invalid unique field definition for "${key}"`);
266
- }
267
- if (typeof value.type === "string") {
268
- result.push({
269
- name: key,
270
- def: requireField(schema, model, key)
271
- });
272
- } else {
273
- result.push({
274
- name: key,
275
- defs: Object.fromEntries(Object.keys(value).map((k) => [
276
- k,
277
- requireField(schema, model, k)
278
- ]))
279
- });
280
- }
281
- }
282
- return result;
283
- }
284
- __name(getUniqueFields, "getUniqueFields");
285
- function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComputedField = true) {
286
- const fieldDef = requireField(schema, model, field);
287
- if (!fieldDef.computed) {
288
- return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
289
- } else {
290
- if (!inlineComputedField) {
291
- return eb.ref(modelAlias ? `${modelAlias}.${field}` : field);
292
- }
293
- let computer;
294
- if ("computedFields" in options) {
295
- const computedFields = options.computedFields;
296
- computer = computedFields?.[model]?.[field];
297
- }
298
- if (!computer) {
299
- throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
300
- }
301
- return computer(eb, {
302
- modelAlias
303
- });
304
- }
305
- }
306
- __name(buildFieldRef, "buildFieldRef");
307
- function isEnum(schema, type) {
308
- return !!schema.enums?.[type];
309
- }
310
- __name(isEnum, "isEnum");
311
- function buildJoinPairs(schema, model, modelAlias, relationField, relationModelAlias) {
312
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(schema, model, relationField);
313
- return keyPairs.map(({ fk, pk }) => {
314
- if (ownedByModel) {
315
- return [
316
- `${relationModelAlias}.${pk}`,
317
- `${modelAlias}.${fk}`
318
- ];
319
- } else {
320
- return [
321
- `${relationModelAlias}.${fk}`,
322
- `${modelAlias}.${pk}`
323
- ];
324
- }
325
- });
326
- }
327
- __name(buildJoinPairs, "buildJoinPairs");
328
- function makeDefaultOrderBy(schema, model) {
329
- const idFields = requireIdFields(schema, model);
330
- return idFields.map((f) => ({
331
- [f]: "asc"
332
- }));
333
- }
334
- __name(makeDefaultOrderBy, "makeDefaultOrderBy");
335
- function getManyToManyRelation(schema, model, field) {
336
- const fieldDef = requireField(schema, model, field);
337
- if (!fieldDef.array || !fieldDef.relation?.opposite) {
338
- return void 0;
339
- }
340
- const oppositeFieldDef = requireField(schema, fieldDef.type, fieldDef.relation.opposite);
341
- if (oppositeFieldDef.array) {
342
- const sortedModelNames = [
343
- model,
344
- fieldDef.type
345
- ].sort();
346
- let orderedFK;
347
- if (model !== fieldDef.type) {
348
- orderedFK = sortedModelNames[0] === model ? [
349
- "A",
350
- "B"
351
- ] : [
352
- "B",
353
- "A"
354
- ];
355
- } else {
356
- const sortedFieldNames = [
357
- field,
358
- oppositeFieldDef.name
359
- ].sort();
360
- orderedFK = sortedFieldNames[0] === field ? [
361
- "A",
362
- "B"
363
- ] : [
364
- "B",
365
- "A"
366
- ];
367
- }
368
- const modelIdFields = requireIdFields(schema, model);
369
- (0, import_common_helpers.invariant)(modelIdFields.length === 1, "Only single-field ID is supported for many-to-many relation");
370
- const otherIdFields = requireIdFields(schema, fieldDef.type);
371
- (0, import_common_helpers.invariant)(otherIdFields.length === 1, "Only single-field ID is supported for many-to-many relation");
372
- return {
373
- parentFkName: orderedFK[0],
374
- parentPKName: modelIdFields[0],
375
- otherModel: fieldDef.type,
376
- otherField: fieldDef.relation.opposite,
377
- otherFkName: orderedFK[1],
378
- otherPKName: otherIdFields[0],
379
- joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
380
- };
381
- } else {
382
- return void 0;
383
- }
384
- }
385
- __name(getManyToManyRelation, "getManyToManyRelation");
386
- function flattenCompoundUniqueFilters(schema, model, filter) {
387
- if (typeof filter !== "object" || !filter) {
388
- return filter;
389
- }
390
- const uniqueFields = getUniqueFields(schema, model);
391
- const compoundUniques = uniqueFields.filter((u) => "defs" in u);
392
- if (compoundUniques.length === 0) {
393
- return filter;
394
- }
395
- const result = {};
396
- for (const [key, value] of Object.entries(filter)) {
397
- if (compoundUniques.some(({ name }) => name === key)) {
398
- Object.assign(result, value);
399
- } else {
400
- result[key] = value;
401
- }
402
- }
403
- return result;
404
- }
405
- __name(flattenCompoundUniqueFilters, "flattenCompoundUniqueFilters");
406
- function ensureArray(value) {
407
- if (Array.isArray(value)) {
408
- return value;
409
- } else {
410
- return [
411
- value
412
- ];
413
- }
414
- }
415
- __name(ensureArray, "ensureArray");
416
- function getDelegateDescendantModels(schema, model, collected = /* @__PURE__ */ new Set()) {
417
- const subModels = Object.values(schema.models).filter((m) => m.baseModel === model);
418
- subModels.forEach((def) => {
419
- if (!collected.has(def)) {
420
- collected.add(def);
421
- getDelegateDescendantModels(schema, def.name, collected);
422
- }
423
- });
424
- return [
425
- ...collected
426
- ];
427
- }
428
- __name(getDelegateDescendantModels, "getDelegateDescendantModels");
429
- function aggregate(eb, expr2, op) {
430
- return (0, import_ts_pattern.match)(op).with("_count", () => eb.fn.count(expr2)).with("_sum", () => eb.fn.sum(expr2)).with("_avg", () => eb.fn.avg(expr2)).with("_min", () => eb.fn.min(expr2)).with("_max", () => eb.fn.max(expr2)).exhaustive();
431
- }
432
- __name(aggregate, "aggregate");
433
-
434
- // src/client/crud/operations/base.ts
435
- var import_cuid2 = require("@paralleldrive/cuid2");
436
- var import_common_helpers6 = require("@zenstackhq/common-helpers");
437
- var import_kysely4 = require("kysely");
438
- var import_nanoid = require("nanoid");
439
- var import_ts_pattern6 = require("ts-pattern");
440
- var import_ulid = require("ulid");
441
- var uuid = __toESM(require("uuid"), 1);
442
-
443
- // src/utils/clone.ts
444
- var import_common_helpers2 = require("@zenstackhq/common-helpers");
445
-
446
- // src/utils/enumerate.ts
447
- function enumerate(x) {
448
- if (x === null || x === void 0) {
449
- return [];
450
- } else if (Array.isArray(x)) {
451
- return x;
452
- } else {
453
- return [
454
- x
455
- ];
456
- }
457
- }
458
- __name(enumerate, "enumerate");
459
-
460
- // src/client/constants.ts
461
- var DELEGATE_JOINED_FIELD_PREFIX = "$delegate$";
462
- var LOGICAL_COMBINATORS = [
463
- "AND",
464
- "OR",
465
- "NOT"
466
- ];
467
- var AGGREGATE_OPERATORS = [
468
- "_count",
469
- "_sum",
470
- "_avg",
471
- "_min",
472
- "_max"
473
- ];
474
-
475
- // src/client/contract.ts
476
- var CRUD = [
477
- "create",
478
- "read",
479
- "update",
480
- "delete"
481
- ];
482
- var CRUD_EXT = [
483
- ...CRUD,
484
- "post-update"
485
- ];
486
-
487
- // src/client/crud/dialects/index.ts
488
- var import_ts_pattern5 = require("ts-pattern");
489
-
490
- // src/client/crud/dialects/postgresql.ts
491
- var import_common_helpers4 = require("@zenstackhq/common-helpers");
492
- var import_decimal = __toESM(require("decimal.js"), 1);
493
- var import_kysely2 = require("kysely");
494
- var import_ts_pattern3 = require("ts-pattern");
495
-
496
- // src/client/crud/dialects/base-dialect.ts
497
- var import_common_helpers3 = require("@zenstackhq/common-helpers");
498
- var import_kysely = require("kysely");
499
- var import_ts_pattern2 = require("ts-pattern");
500
- var BaseCrudDialect = class {
501
- static {
502
- __name(this, "BaseCrudDialect");
503
- }
504
- schema;
505
- options;
506
- constructor(schema, options) {
507
- this.schema = schema;
508
- this.options = options;
509
- }
510
- transformPrimitive(value, _type, _forArrayField) {
511
- return value;
512
- }
513
- transformOutput(value, _type) {
514
- return value;
515
- }
516
- // #region common query builders
517
- buildSelectModel(eb, model, modelAlias) {
518
- const modelDef = requireModel(this.schema, model);
519
- let result = eb.selectFrom(model === modelAlias ? model : `${model} as ${modelAlias}`);
520
- let joinBase = modelDef.baseModel;
521
- while (joinBase) {
522
- result = this.buildDelegateJoin(model, modelAlias, joinBase, result);
523
- joinBase = requireModel(this.schema, joinBase).baseModel;
524
- }
525
- return result;
526
- }
527
- buildFilterSortTake(model, args, query, modelAlias) {
528
- let result = query;
529
- if (args.where) {
530
- result = result.where((eb) => this.buildFilter(eb, model, modelAlias, args?.where));
531
- }
532
- let negateOrderBy = false;
533
- const skip = args.skip;
534
- let take = args.take;
535
- if (take !== void 0 && take < 0) {
536
- negateOrderBy = true;
537
- take = -take;
538
- }
539
- result = this.buildSkipTake(result, skip, take);
540
- result = this.buildOrderBy(result, model, modelAlias, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
541
- if ("distinct" in args && args.distinct) {
542
- const distinct = ensureArray(args.distinct);
543
- if (this.supportsDistinctOn) {
544
- result = result.distinctOn(distinct.map((f) => import_kysely.sql.ref(`${modelAlias}.${f}`)));
545
- } else {
546
- throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
547
- }
548
- }
549
- if (args.cursor) {
550
- result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
551
- }
552
- return result;
553
- }
554
- buildFilter(eb, model, modelAlias, where) {
555
- if (where === true || where === void 0) {
556
- return this.true(eb);
557
- }
558
- if (where === false) {
559
- return this.false(eb);
560
- }
561
- let result = this.true(eb);
562
- const _where = flattenCompoundUniqueFilters(this.schema, model, where);
563
- for (const [key, payload] of Object.entries(_where)) {
564
- if (payload === void 0) {
565
- continue;
566
- }
567
- if (key.startsWith("$")) {
568
- continue;
569
- }
570
- if (this.isLogicalCombinator(key)) {
571
- result = this.and(eb, result, this.buildCompositeFilter(eb, model, modelAlias, key, payload));
572
- continue;
573
- }
574
- const fieldDef = requireField(this.schema, model, key);
575
- if (fieldDef.relation) {
576
- result = this.and(eb, result, this.buildRelationFilter(eb, model, modelAlias, key, fieldDef, payload));
577
- } else {
578
- const fieldRef = this.fieldRef(fieldDef.originModel ?? model, key, eb, fieldDef.originModel ?? modelAlias);
579
- if (fieldDef.array) {
580
- result = this.and(eb, result, this.buildArrayFilter(eb, fieldRef, fieldDef, payload));
581
- } else {
582
- result = this.and(eb, result, this.buildPrimitiveFilter(eb, fieldRef, fieldDef, payload));
583
- }
584
- }
585
- }
586
- if ("$expr" in _where && typeof _where["$expr"] === "function") {
587
- result = this.and(eb, result, _where["$expr"](eb));
588
- }
589
- return result;
590
- }
591
- buildCursorFilter(model, query, cursor, orderBy, negateOrderBy, modelAlias) {
592
- const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);
593
- const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries(obj));
594
- const eb = (0, import_kysely.expressionBuilder)();
595
- const subQueryAlias = `${model}$cursor$sub`;
596
- const cursorFilter = this.buildFilter(eb, model, subQueryAlias, cursor);
597
- let result = query;
598
- const filters = [];
599
- for (let i = orderByItems.length - 1; i >= 0; i--) {
600
- const andFilters = [];
601
- for (let j = 0; j <= i; j++) {
602
- const [field, order] = orderByItems[j];
603
- const _order = negateOrderBy ? order === "asc" ? "desc" : "asc" : order;
604
- const op = j === i ? _order === "asc" ? ">=" : "<=" : "=";
605
- andFilters.push(eb(eb.ref(`${modelAlias}.${field}`), op, this.buildSelectModel(eb, model, subQueryAlias).select(`${subQueryAlias}.${field}`).where(cursorFilter)));
606
- }
607
- filters.push(eb.and(andFilters));
608
- }
609
- result = result.where((eb2) => eb2.or(filters));
610
- return result;
611
- }
612
- isLogicalCombinator(key) {
613
- return LOGICAL_COMBINATORS.includes(key);
614
- }
615
- buildCompositeFilter(eb, model, modelAlias, key, payload) {
616
- return (0, import_ts_pattern2.match)(key).with("AND", () => this.and(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("OR", () => this.or(eb, ...enumerate(payload).map((subPayload) => this.buildFilter(eb, model, modelAlias, subPayload)))).with("NOT", () => eb.not(this.buildCompositeFilter(eb, model, modelAlias, "AND", payload))).exhaustive();
617
- }
618
- buildRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
619
- if (!fieldDef.array) {
620
- return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
621
- } else {
622
- return this.buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload);
623
- }
624
- }
625
- buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
626
- if (payload === null) {
627
- const { ownedByModel, keyPairs } = getRelationForeignKeyFieldPairs(this.schema, model, field);
628
- if (ownedByModel && !fieldDef.originModel) {
629
- return this.and(eb, ...keyPairs.map(({ fk }) => eb(import_kysely.sql.ref(`${modelAlias}.${fk}`), "is", null)));
630
- } else {
631
- return this.buildToOneRelationFilter(eb, model, modelAlias, field, fieldDef, {
632
- is: null
633
- });
634
- }
635
- }
636
- const joinAlias = `${modelAlias}$${field}`;
637
- const joinPairs = buildJoinPairs(
638
- this.schema,
639
- model,
640
- // if field is from a base, use the base model to join
641
- fieldDef.originModel ?? modelAlias,
642
- field,
643
- joinAlias
644
- );
645
- const filterResultField = `${field}$filter`;
646
- const joinSelect = eb.selectFrom(`${fieldDef.type} as ${joinAlias}`).where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right))))).select(() => eb.fn.count(eb.lit(1)).as(filterResultField));
647
- const conditions = [];
648
- if ("is" in payload || "isNot" in payload) {
649
- if ("is" in payload) {
650
- if (payload.is === null) {
651
- conditions.push(eb(joinSelect, "=", 0));
652
- } else {
653
- conditions.push(eb(joinSelect.where(() => this.buildFilter(eb, fieldDef.type, joinAlias, payload.is)), ">", 0));
654
- }
655
- }
656
- if ("isNot" in payload) {
657
- if (payload.isNot === null) {
658
- conditions.push(eb(joinSelect, ">", 0));
659
- } else {
660
- conditions.push(this.or(
661
- eb,
662
- // is null
663
- eb(joinSelect, "=", 0),
664
- // found one that matches the filter
665
- eb(joinSelect.where(() => this.buildFilter(eb, fieldDef.type, joinAlias, payload.isNot)), "=", 0)
666
- ));
667
- }
668
- }
669
- } else {
670
- conditions.push(eb(joinSelect.where(() => this.buildFilter(eb, fieldDef.type, joinAlias, payload)), ">", 0));
671
- }
672
- return this.and(eb, ...conditions);
673
- }
674
- buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
675
- if (payload === null) {
676
- return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
677
- }
678
- const relationModel = fieldDef.type;
679
- const relationFilterSelectAlias = `${modelAlias}$${field}$filter`;
680
- const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
681
- const m2m = getManyToManyRelation(this.schema, model, field);
682
- if (m2m) {
683
- const modelIdFields = requireIdFields(this.schema, model);
684
- (0, import_common_helpers3.invariant)(modelIdFields.length === 1, "many-to-many relation must have exactly one id field");
685
- const relationIdFields = requireIdFields(this.schema, relationModel);
686
- (0, import_common_helpers3.invariant)(relationIdFields.length === 1, "many-to-many relation must have exactly one id field");
687
- return eb2(import_kysely.sql.ref(`${relationFilterSelectAlias}.${relationIdFields[0]}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(import_kysely.sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", import_kysely.sql.ref(`${modelAlias}.${modelIdFields[0]}`)));
688
- } else {
689
- const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
690
- let result2 = this.true(eb2);
691
- for (const { fk, pk } of relationKeyPairs.keyPairs) {
692
- if (relationKeyPairs.ownedByModel) {
693
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${fk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${pk}`)));
694
- } else {
695
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${pk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${fk}`)));
696
- }
697
- }
698
- return result2;
699
- }
700
- }, "buildPkFkWhereRefs");
701
- let result = this.true(eb);
702
- for (const [key, subPayload] of Object.entries(payload)) {
703
- if (!subPayload) {
704
- continue;
705
- }
706
- switch (key) {
707
- case "some": {
708
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), ">", 0));
709
- break;
710
- }
711
- case "every": {
712
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => eb1.not(this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload))), "=", 0));
713
- break;
714
- }
715
- case "none": {
716
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), "=", 0));
717
- break;
718
- }
719
- }
720
- }
721
- return result;
722
- }
723
- buildArrayFilter(eb, fieldRef, fieldDef, payload) {
724
- const clauses = [];
725
- const fieldType = fieldDef.type;
726
- for (const [key, _value] of Object.entries(payload)) {
727
- if (_value === void 0) {
728
- continue;
729
- }
730
- const value = this.transformPrimitive(_value, fieldType, !!fieldDef.array);
731
- switch (key) {
732
- case "equals": {
733
- clauses.push(this.buildLiteralFilter(eb, fieldRef, fieldType, eb.val(value)));
734
- break;
735
- }
736
- case "has": {
737
- clauses.push(eb(fieldRef, "@>", eb.val([
738
- value
739
- ])));
740
- break;
741
- }
742
- case "hasEvery": {
743
- clauses.push(eb(fieldRef, "@>", eb.val(value)));
744
- break;
745
- }
746
- case "hasSome": {
747
- clauses.push(eb(fieldRef, "&&", eb.val(value)));
748
- break;
749
- }
750
- case "isEmpty": {
751
- clauses.push(eb(fieldRef, value === true ? "=" : "!=", eb.val([])));
752
- break;
753
- }
754
- default: {
755
- throw new InternalError(`Invalid array filter key: ${key}`);
756
- }
757
- }
758
- }
759
- return this.and(eb, ...clauses);
760
- }
761
- buildPrimitiveFilter(eb, fieldRef, fieldDef, payload) {
762
- if (payload === null) {
763
- return eb(fieldRef, "is", null);
764
- }
765
- if (isEnum(this.schema, fieldDef.type)) {
766
- return this.buildEnumFilter(eb, fieldRef, fieldDef, payload);
767
- }
768
- return (0, import_ts_pattern2.match)(fieldDef.type).with("String", () => this.buildStringFilter(eb, fieldRef, payload)).with(import_ts_pattern2.P.union("Int", "Float", "Decimal", "BigInt"), (type) => this.buildNumberFilter(eb, fieldRef, type, payload)).with("Boolean", () => this.buildBooleanFilter(eb, fieldRef, payload)).with("DateTime", () => this.buildDateTimeFilter(eb, fieldRef, payload)).with("Bytes", () => this.buildBytesFilter(eb, fieldRef, payload)).with("Json", () => {
769
- throw new InternalError("JSON filters are not supported yet");
770
- }).with("Unsupported", () => {
771
- throw new QueryError(`Unsupported field cannot be used in filters`);
772
- }).exhaustive();
773
- }
774
- buildLiteralFilter(eb, lhs, type, rhs) {
775
- return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
776
- }
777
- buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
778
- if (payload === null || !(0, import_common_helpers3.isPlainObject)(payload)) {
779
- return {
780
- conditions: [
781
- this.buildLiteralFilter(eb, lhs, type, payload)
782
- ],
783
- consumedKeys: []
784
- };
785
- }
786
- const conditions = [];
787
- const consumedKeys = [];
788
- for (const [op, value] of Object.entries(payload)) {
789
- if (onlyForKeys && !onlyForKeys.includes(op)) {
790
- continue;
791
- }
792
- if (excludeKeys.includes(op)) {
793
- continue;
794
- }
795
- const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
796
- const condition = (0, import_ts_pattern2.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
797
- (0, import_common_helpers3.invariant)(Array.isArray(rhs), "right hand side must be an array");
798
- if (rhs.length === 0) {
799
- return this.false(eb);
800
- } else {
801
- return eb(lhs, "in", rhs);
802
- }
803
- }).with("notIn", () => {
804
- (0, import_common_helpers3.invariant)(Array.isArray(rhs), "right hand side must be an array");
805
- if (rhs.length === 0) {
806
- return this.true(eb);
807
- } else {
808
- return eb.not(eb(lhs, "in", rhs));
809
- }
810
- }).with("lt", () => eb(lhs, "<", rhs)).with("lte", () => eb(lhs, "<=", rhs)).with("gt", () => eb(lhs, ">", rhs)).with("gte", () => eb(lhs, ">=", rhs)).with("not", () => eb.not(recurse(value))).with(import_ts_pattern2.P.union(...AGGREGATE_OPERATORS), (op2) => {
811
- const innerResult = this.buildStandardFilter(eb, type, value, aggregate(eb, lhs, op2), getRhs, recurse, throwIfInvalid);
812
- consumedKeys.push(...innerResult.consumedKeys);
813
- return this.and(eb, ...innerResult.conditions);
814
- }).otherwise(() => {
815
- if (throwIfInvalid) {
816
- throw new QueryError(`Invalid filter key: ${op}`);
817
- } else {
818
- return void 0;
819
- }
820
- });
821
- if (condition) {
822
- conditions.push(condition);
823
- consumedKeys.push(op);
824
- }
825
- }
826
- return {
827
- conditions,
828
- consumedKeys
829
- };
830
- }
831
- buildStringFilter(eb, fieldRef, payload) {
832
- let mode;
833
- if (payload && typeof payload === "object" && "mode" in payload) {
834
- mode = payload.mode;
835
- }
836
- const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
837
- fieldRef
838
- ]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
839
- if (payload && typeof payload === "object") {
840
- for (const [key, value] of Object.entries(payload)) {
841
- if (key === "mode" || consumedKeys.includes(key)) {
842
- continue;
843
- }
844
- const condition = (0, import_ts_pattern2.match)(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}`))).otherwise(() => {
845
- throw new QueryError(`Invalid string filter key: ${key}`);
846
- });
847
- if (condition) {
848
- conditions.push(condition);
849
- }
850
- }
851
- }
852
- return this.and(eb, ...conditions);
853
- }
854
- prepStringCasing(eb, value, mode) {
855
- if (!mode || mode === "default") {
856
- return value === null ? value : import_kysely.sql.val(value);
857
- }
858
- if (typeof value === "string") {
859
- return eb.fn("lower", [
860
- import_kysely.sql.val(value)
861
- ]);
862
- } else if (Array.isArray(value)) {
863
- return value.map((v) => this.prepStringCasing(eb, v, mode));
864
- } else {
865
- return value === null ? null : import_kysely.sql.val(value);
866
- }
867
- }
868
- buildNumberFilter(eb, fieldRef, type, payload) {
869
- const { conditions } = this.buildStandardFilter(eb, type, payload, fieldRef, (value) => this.transformPrimitive(value, type, false), (value) => this.buildNumberFilter(eb, fieldRef, type, value));
870
- return this.and(eb, ...conditions);
871
- }
872
- buildBooleanFilter(eb, fieldRef, payload) {
873
- const { conditions } = this.buildStandardFilter(eb, "Boolean", payload, fieldRef, (value) => this.transformPrimitive(value, "Boolean", false), (value) => this.buildBooleanFilter(eb, fieldRef, value), true, [
874
- "equals",
875
- "not"
876
- ]);
877
- return this.and(eb, ...conditions);
878
- }
879
- buildDateTimeFilter(eb, fieldRef, payload) {
880
- const { conditions } = this.buildStandardFilter(eb, "DateTime", payload, fieldRef, (value) => this.transformPrimitive(value, "DateTime", false), (value) => this.buildDateTimeFilter(eb, fieldRef, value), true);
881
- return this.and(eb, ...conditions);
882
- }
883
- buildBytesFilter(eb, fieldRef, payload) {
884
- const conditions = this.buildStandardFilter(eb, "Bytes", payload, fieldRef, (value) => this.transformPrimitive(value, "Bytes", false), (value) => this.buildBytesFilter(eb, fieldRef, value), true, [
885
- "equals",
886
- "in",
887
- "notIn",
888
- "not"
889
- ]);
890
- return this.and(eb, ...conditions.conditions);
891
- }
892
- buildEnumFilter(eb, fieldRef, fieldDef, payload) {
893
- const conditions = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => value, (value) => this.buildEnumFilter(eb, fieldRef, fieldDef, value), true, [
894
- "equals",
895
- "in",
896
- "notIn",
897
- "not"
898
- ]);
899
- return this.and(eb, ...conditions.conditions);
900
- }
901
- buildOrderBy(query, model, modelAlias, orderBy, useDefaultIfEmpty, negated) {
902
- if (!orderBy) {
903
- if (useDefaultIfEmpty) {
904
- orderBy = makeDefaultOrderBy(this.schema, model);
905
- } else {
906
- return query;
907
- }
908
- }
909
- let result = query;
910
- enumerate(orderBy).forEach((orderBy2) => {
911
- for (const [field, value] of Object.entries(orderBy2)) {
912
- if (!value) {
913
- continue;
914
- }
915
- if ([
916
- "_count",
917
- "_avg",
918
- "_sum",
919
- "_min",
920
- "_max"
921
- ].includes(field)) {
922
- (0, import_common_helpers3.invariant)(value && typeof value === "object", `invalid orderBy value for field "${field}"`);
923
- for (const [k, v] of Object.entries(value)) {
924
- (0, import_common_helpers3.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
925
- result = result.orderBy((eb) => aggregate(eb, this.fieldRef(model, k, eb, modelAlias), field), import_kysely.sql.raw(this.negateSort(v, negated)));
926
- }
927
- continue;
928
- }
929
- switch (field) {
930
- case "_count": {
931
- (0, import_common_helpers3.invariant)(value && typeof value === "object", 'invalid orderBy value for field "_count"');
932
- for (const [k, v] of Object.entries(value)) {
933
- (0, import_common_helpers3.invariant)(v === "asc" || v === "desc", `invalid orderBy value for field "${field}"`);
934
- result = result.orderBy((eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)), import_kysely.sql.raw(this.negateSort(v, negated)));
935
- }
936
- continue;
937
- }
938
- default:
939
- break;
940
- }
941
- const fieldDef = requireField(this.schema, model, field);
942
- if (!fieldDef.relation) {
943
- const fieldRef = this.fieldRef(model, field, (0, import_kysely.expressionBuilder)(), modelAlias);
944
- if (value === "asc" || value === "desc") {
945
- result = result.orderBy(fieldRef, this.negateSort(value, negated));
946
- } else if (value && typeof value === "object" && "nulls" in value && "sort" in value && (value.sort === "asc" || value.sort === "desc") && (value.nulls === "first" || value.nulls === "last")) {
947
- result = result.orderBy(fieldRef, import_kysely.sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`));
948
- }
949
- } else {
950
- const relationModel = fieldDef.type;
951
- if (fieldDef.array) {
952
- if (typeof value !== "object") {
953
- throw new QueryError(`invalid orderBy value for field "${field}"`);
954
- }
955
- if ("_count" in value) {
956
- (0, import_common_helpers3.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
957
- const sort = this.negateSort(value._count, negated);
958
- result = result.orderBy((eb) => {
959
- const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
960
- let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
961
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
962
- subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
963
- subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
964
- return subQuery;
965
- }, sort);
966
- }
967
- } else {
968
- result = result.leftJoin(relationModel, (join) => {
969
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
970
- return join.on((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
971
- });
972
- result = this.buildOrderBy(result, fieldDef.type, relationModel, value, false, negated);
973
- }
974
- }
975
- }
976
- });
977
- return result;
978
- }
979
- buildSelectAllFields(model, query, omit, modelAlias) {
980
- const modelDef = requireModel(this.schema, model);
981
- let result = query;
982
- for (const field of Object.keys(modelDef.fields)) {
983
- if (isRelationField(this.schema, model, field)) {
984
- continue;
985
- }
986
- if (omit?.[field] === true) {
987
- continue;
988
- }
989
- result = this.buildSelectField(result, model, modelAlias, field);
990
- }
991
- const descendants = getDelegateDescendantModels(this.schema, model);
992
- for (const subModel of descendants) {
993
- result = this.buildDelegateJoin(model, modelAlias, subModel.name, result);
994
- result = result.select((eb) => {
995
- const jsonObject = {};
996
- for (const field of Object.keys(subModel.fields)) {
997
- if (isRelationField(this.schema, subModel.name, field) || isInheritedField(this.schema, subModel.name, field)) {
998
- continue;
999
- }
1000
- jsonObject[field] = eb.ref(`${subModel.name}.${field}`);
1001
- }
1002
- return this.buildJsonObject(eb, jsonObject).as(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`);
1003
- });
1004
- }
1005
- return result;
1006
- }
1007
- buildModelSelect(eb, model, subQueryAlias, payload, selectAllFields) {
1008
- let subQuery = this.buildSelectModel(eb, model, subQueryAlias);
1009
- if (selectAllFields) {
1010
- subQuery = this.buildSelectAllFields(model, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1011
- }
1012
- if (payload && typeof payload === "object") {
1013
- subQuery = this.buildFilterSortTake(model, payload, subQuery, subQueryAlias);
1014
- }
1015
- return subQuery;
1016
- }
1017
- buildSelectField(query, model, modelAlias, field) {
1018
- const fieldDef = requireField(this.schema, model, field);
1019
- if (fieldDef.computed) {
1020
- return query.select((eb) => this.fieldRef(model, field, eb, modelAlias).as(field));
1021
- } else if (!fieldDef.originModel) {
1022
- return query.select(import_kysely.sql.ref(`${modelAlias}.${field}`).as(field));
1023
- } else {
1024
- return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
1025
- }
1026
- }
1027
- buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
1028
- const idFields = requireIdFields(this.schema, thisModel);
1029
- query = query.leftJoin(otherModelAlias, (qb) => {
1030
- for (const idField of idFields) {
1031
- qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
1032
- }
1033
- return qb;
1034
- });
1035
- return query;
1036
- }
1037
- buildCountJson(model, eb, parentAlias, payload) {
1038
- const modelDef = requireModel(this.schema, model);
1039
- const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
1040
- const selections = payload === true ? {
1041
- select: toManyRelations.reduce((acc, [field]) => {
1042
- acc[field] = true;
1043
- return acc;
1044
- }, {})
1045
- } : payload;
1046
- const jsonObject = {};
1047
- for (const [field, value] of Object.entries(selections.select)) {
1048
- const fieldDef = requireField(this.schema, model, field);
1049
- const fieldModel = fieldDef.type;
1050
- let fieldCountQuery;
1051
- const m2m = getManyToManyRelation(this.schema, model, field);
1052
- if (m2m) {
1053
- fieldCountQuery = eb.selectFrom(fieldModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.joinTable}.${m2m.otherFkName}`, "=", `${fieldModel}.${m2m.otherPKName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${parentAlias}.${m2m.parentPKName}`)).select(eb.fn.countAll().as(`_count$${field}`));
1054
- } else {
1055
- fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
1056
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
1057
- for (const [left, right] of joinPairs) {
1058
- fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
1059
- }
1060
- }
1061
- if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
1062
- const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
1063
- fieldCountQuery = fieldCountQuery.where(filter);
1064
- }
1065
- jsonObject[field] = fieldCountQuery;
1066
- }
1067
- return this.buildJsonObject(eb, jsonObject);
1068
- }
1069
- // #endregion
1070
- // #region utils
1071
- negateSort(sort, negated) {
1072
- return negated ? sort === "asc" ? "desc" : "asc" : sort;
1073
- }
1074
- true(eb) {
1075
- return eb.lit(this.transformPrimitive(true, "Boolean", false));
1076
- }
1077
- false(eb) {
1078
- return eb.lit(this.transformPrimitive(false, "Boolean", false));
1079
- }
1080
- isTrue(expression) {
1081
- const node = expression.toOperationNode();
1082
- if (node.kind !== "ValueNode") {
1083
- return false;
1084
- }
1085
- return node.value === true || node.value === 1;
1086
- }
1087
- isFalse(expression) {
1088
- const node = expression.toOperationNode();
1089
- if (node.kind !== "ValueNode") {
1090
- return false;
1091
- }
1092
- return node.value === false || node.value === 0;
1093
- }
1094
- and(eb, ...args) {
1095
- const nonTrueArgs = args.filter((arg) => !this.isTrue(arg));
1096
- if (nonTrueArgs.length === 0) {
1097
- return this.true(eb);
1098
- } else if (nonTrueArgs.length === 1) {
1099
- return nonTrueArgs[0];
1100
- } else {
1101
- return eb.and(nonTrueArgs);
1102
- }
1103
- }
1104
- or(eb, ...args) {
1105
- const nonFalseArgs = args.filter((arg) => !this.isFalse(arg));
1106
- if (nonFalseArgs.length === 0) {
1107
- return this.false(eb);
1108
- } else if (nonFalseArgs.length === 1) {
1109
- return nonFalseArgs[0];
1110
- } else {
1111
- return eb.or(nonFalseArgs);
1112
- }
1113
- }
1114
- not(eb, ...args) {
1115
- return eb.not(this.and(eb, ...args));
1116
- }
1117
- fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1118
- return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1119
- }
1120
- canJoinWithoutNestedSelect(modelDef, payload) {
1121
- if (modelDef.computedFields) {
1122
- return false;
1123
- }
1124
- if (modelDef.baseModel || modelDef.isDelegate) {
1125
- return false;
1126
- }
1127
- if (typeof payload === "object" && (payload.orderBy || payload.skip !== void 0 || payload.take !== void 0 || payload.cursor || payload.distinct)) {
1128
- return false;
1129
- }
1130
- return true;
1131
- }
1132
- };
1133
-
1134
- // src/client/crud/dialects/postgresql.ts
1135
- var PostgresCrudDialect = class extends BaseCrudDialect {
1136
- static {
1137
- __name(this, "PostgresCrudDialect");
1138
- }
1139
- constructor(schema, options) {
1140
- super(schema, options);
1141
- }
1142
- get provider() {
1143
- return "postgresql";
1144
- }
1145
- transformPrimitive(value, type, forArrayField) {
1146
- if (value === void 0) {
1147
- return value;
1148
- }
1149
- if (Array.isArray(value)) {
1150
- if (type === "Json" && !forArrayField) {
1151
- return JSON.stringify(value);
1152
- } else {
1153
- return value.map((v) => this.transformPrimitive(v, type, false));
1154
- }
1155
- } else {
1156
- return (0, import_ts_pattern3.match)(type).with("DateTime", () => value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value).with("Decimal", () => value !== null ? value.toString() : value).otherwise(() => value);
1157
- }
1158
- }
1159
- transformOutput(value, type) {
1160
- if (value === null || value === void 0) {
1161
- return value;
1162
- }
1163
- return (0, import_ts_pattern3.match)(type).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Decimal", () => this.transformDecimal(value)).otherwise(() => super.transformOutput(value, type));
1164
- }
1165
- transformOutputBigInt(value) {
1166
- if (typeof value === "bigint") {
1167
- return value;
1168
- }
1169
- (0, import_common_helpers4.invariant)(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
1170
- return BigInt(value);
1171
- }
1172
- transformDecimal(value) {
1173
- if (value instanceof import_decimal.default) {
1174
- return value;
1175
- }
1176
- (0, import_common_helpers4.invariant)(typeof value === "string" || typeof value === "number" || value instanceof import_decimal.default, `Expected string, number or Decimal, got ${typeof value}`);
1177
- return new import_decimal.default(value);
1178
- }
1179
- transformOutputDate(value) {
1180
- if (typeof value === "string") {
1181
- return new Date(value);
1182
- } else if (value instanceof Date && this.options.fixPostgresTimezone !== false) {
1183
- return new Date(value.getTime() - value.getTimezoneOffset() * 60 * 1e3);
1184
- } else {
1185
- return value;
1186
- }
1187
- }
1188
- transformOutputBytes(value) {
1189
- return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
1190
- }
1191
- buildRelationSelection(query, model, relationField, parentAlias, payload) {
1192
- const relationResultName = `${parentAlias}$${relationField}`;
1193
- const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
1194
- return joinedQuery.select(`${relationResultName}.$data as ${relationField}`);
1195
- }
1196
- buildRelationJSON(model, qb, relationField, parentAlias, payload, resultName) {
1197
- const relationFieldDef = requireField(this.schema, model, relationField);
1198
- const relationModel = relationFieldDef.type;
1199
- return qb.leftJoinLateral((eb) => {
1200
- const relationSelectName = `${resultName}$sub`;
1201
- const relationModelDef = requireModel(this.schema, relationModel);
1202
- let tbl;
1203
- if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1204
- tbl = this.buildModelSelect(eb, relationModel, relationSelectName, payload, false);
1205
- tbl = this.buildRelationJoinFilter(tbl, model, relationField, relationModel, relationSelectName, parentAlias);
1206
- } else {
1207
- tbl = eb.selectFrom(() => {
1208
- let subQuery = this.buildModelSelect(eb, relationModel, `${relationSelectName}$t`, payload, true);
1209
- subQuery = this.buildRelationJoinFilter(subQuery, model, relationField, relationModel, `${relationSelectName}$t`, parentAlias);
1210
- return subQuery.as(relationSelectName);
1211
- });
1212
- }
1213
- tbl = this.buildRelationObjectSelect(relationModel, relationSelectName, relationFieldDef, tbl, payload, resultName);
1214
- tbl = this.buildRelationJoins(tbl, relationModel, relationSelectName, payload, resultName);
1215
- return tbl.as(resultName);
1216
- }, (join) => join.onTrue());
1217
- }
1218
- buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1219
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1220
- if (m2m) {
1221
- const parentIds = requireIdFields(this.schema, model);
1222
- const relationIds = requireIdFields(this.schema, relationModel);
1223
- (0, import_common_helpers4.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1224
- (0, import_common_helpers4.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1225
- query = query.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1226
- } else {
1227
- const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
1228
- query = query.where((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely2.sql.ref(left), "=", import_kysely2.sql.ref(right)))));
1229
- }
1230
- return query;
1231
- }
1232
- buildRelationObjectSelect(relationModel, relationModelAlias, relationFieldDef, qb, payload, parentResultName) {
1233
- qb = qb.select((eb) => {
1234
- const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
1235
- if (relationFieldDef.array) {
1236
- return eb.fn.coalesce(import_kysely2.sql`jsonb_agg(jsonb_build_object(${import_kysely2.sql.join(objArgs)}))`, import_kysely2.sql`'[]'::jsonb`).as("$data");
1237
- } else {
1238
- return import_kysely2.sql`jsonb_build_object(${import_kysely2.sql.join(objArgs)})`.as("$data");
1239
- }
1240
- });
1241
- return qb;
1242
- }
1243
- buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
1244
- const relationModelDef = requireModel(this.schema, relationModel);
1245
- const objArgs = [];
1246
- const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1247
- if (descendantModels.length > 0) {
1248
- objArgs.push(...descendantModels.map((subModel) => [
1249
- import_kysely2.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1250
- eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1251
- ]).flatMap((v) => v));
1252
- }
1253
- if (payload === true || !payload.select) {
1254
- objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
1255
- import_kysely2.sql.lit(field),
1256
- this.fieldRef(relationModel, field, eb, relationModelAlias, false)
1257
- ]).flatMap((v) => v));
1258
- } else if (payload.select) {
1259
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1260
- if (field === "_count") {
1261
- const subJson = this.buildCountJson(relationModel, eb, relationModelAlias, value);
1262
- return [
1263
- import_kysely2.sql.lit(field),
1264
- subJson
1265
- ];
1266
- } else {
1267
- const fieldDef = requireField(this.schema, relationModel, field);
1268
- const fieldValue = fieldDef.relation ? eb.ref(`${parentResultName}$${field}.$data`) : this.fieldRef(relationModel, field, eb, relationModelAlias, false);
1269
- return [
1270
- import_kysely2.sql.lit(field),
1271
- fieldValue
1272
- ];
1273
- }
1274
- }).flatMap((v) => v));
1275
- }
1276
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
1277
- objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
1278
- import_kysely2.sql.lit(field),
1279
- // reference the synthesized JSON field
1280
- eb.ref(`${parentResultName}$${field}.$data`)
1281
- ]).flatMap((v) => v));
1282
- }
1283
- return objArgs;
1284
- }
1285
- buildRelationJoins(query, relationModel, relationModelAlias, payload, parentResultName) {
1286
- let result = query;
1287
- if (typeof payload === "object") {
1288
- const selectInclude = payload.include ?? payload.select;
1289
- if (selectInclude && typeof selectInclude === "object") {
1290
- Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1291
- result = this.buildRelationJSON(relationModel, result, field, relationModelAlias, value, `${parentResultName}$${field}`);
1292
- });
1293
- }
1294
- }
1295
- return result;
1296
- }
1297
- buildSkipTake(query, skip, take) {
1298
- if (take !== void 0) {
1299
- query = query.limit(take);
1300
- }
1301
- if (skip !== void 0) {
1302
- query = query.offset(skip);
1303
- }
1304
- return query;
1305
- }
1306
- buildJsonObject(eb, value) {
1307
- return eb.fn("jsonb_build_object", Object.entries(value).flatMap(([key, value2]) => [
1308
- import_kysely2.sql.lit(key),
1309
- value2
1310
- ]));
1311
- }
1312
- get supportsUpdateWithLimit() {
1313
- return false;
1314
- }
1315
- get supportsDeleteWithLimit() {
1316
- return false;
1317
- }
1318
- get supportsDistinctOn() {
1319
- return true;
1320
- }
1321
- buildArrayLength(eb, array) {
1322
- return eb.fn("array_length", [
1323
- array
1324
- ]);
1325
- }
1326
- buildArrayLiteralSQL(values) {
1327
- if (values.length === 0) {
1328
- return "{}";
1329
- } else {
1330
- return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
1331
- }
1332
- }
1333
- get supportInsertWithDefault() {
1334
- return true;
1335
- }
1336
- getFieldSqlType(fieldDef) {
1337
- if (fieldDef.relation) {
1338
- throw new QueryError("Cannot get SQL type of a relation field");
1339
- }
1340
- let result;
1341
- if (this.schema.enums?.[fieldDef.type]) {
1342
- result = "text";
1343
- } else {
1344
- result = (0, import_ts_pattern3.match)(fieldDef.type).with("String", () => "text").with("Boolean", () => "boolean").with("Int", () => "integer").with("BigInt", () => "bigint").with("Float", () => "double precision").with("Decimal", () => "decimal").with("DateTime", () => "timestamp").with("Bytes", () => "bytea").with("Json", () => "jsonb").otherwise(() => "text");
1345
- }
1346
- if (fieldDef.array) {
1347
- result += "[]";
1348
- }
1349
- return result;
1350
- }
1351
- getStringCasingBehavior() {
1352
- return {
1353
- supportsILike: true,
1354
- likeCaseSensitive: true
1355
- };
1356
- }
1357
- };
1358
-
1359
- // src/client/crud/dialects/sqlite.ts
1360
- var import_common_helpers5 = require("@zenstackhq/common-helpers");
1361
- var import_decimal2 = __toESM(require("decimal.js"), 1);
1362
- var import_kysely3 = require("kysely");
1363
- var import_ts_pattern4 = require("ts-pattern");
1364
- var SqliteCrudDialect = class extends BaseCrudDialect {
1365
- static {
1366
- __name(this, "SqliteCrudDialect");
1367
- }
1368
- get provider() {
1369
- return "sqlite";
1370
- }
1371
- transformPrimitive(value, type, _forArrayField) {
1372
- if (value === void 0) {
1373
- return value;
1374
- }
1375
- if (Array.isArray(value)) {
1376
- return value.map((v) => this.transformPrimitive(v, type, false));
1377
- } else {
1378
- if (this.schema.typeDefs && type in this.schema.typeDefs) {
1379
- return JSON.stringify(value);
1380
- } else {
1381
- return (0, import_ts_pattern4.match)(type).with("Boolean", () => value ? 1 : 0).with("DateTime", () => value instanceof Date ? value.toISOString() : typeof value === "string" ? new Date(value).toISOString() : value).with("Decimal", () => value.toString()).with("Bytes", () => Buffer.from(value)).with("Json", () => JSON.stringify(value)).otherwise(() => value);
1382
- }
1383
- }
1384
- }
1385
- transformOutput(value, type) {
1386
- if (value === null || value === void 0) {
1387
- return value;
1388
- } else if (this.schema.typeDefs && type in this.schema.typeDefs) {
1389
- return this.transformOutputJson(value);
1390
- } else {
1391
- return (0, import_ts_pattern4.match)(type).with("Boolean", () => this.transformOutputBoolean(value)).with("DateTime", () => this.transformOutputDate(value)).with("Bytes", () => this.transformOutputBytes(value)).with("Decimal", () => this.transformOutputDecimal(value)).with("BigInt", () => this.transformOutputBigInt(value)).with("Json", () => this.transformOutputJson(value)).otherwise(() => super.transformOutput(value, type));
1392
- }
1393
- }
1394
- transformOutputDecimal(value) {
1395
- if (value instanceof import_decimal2.default) {
1396
- return value;
1397
- }
1398
- (0, import_common_helpers5.invariant)(typeof value === "string" || typeof value === "number" || value instanceof import_decimal2.default, `Expected string, number or Decimal, got ${typeof value}`);
1399
- return new import_decimal2.default(value);
1400
- }
1401
- transformOutputBigInt(value) {
1402
- if (typeof value === "bigint") {
1403
- return value;
1404
- }
1405
- (0, import_common_helpers5.invariant)(typeof value === "string" || typeof value === "number", `Expected string or number, got ${typeof value}`);
1406
- return BigInt(value);
1407
- }
1408
- transformOutputBoolean(value) {
1409
- return !!value;
1410
- }
1411
- transformOutputDate(value) {
1412
- if (typeof value === "number") {
1413
- return new Date(value);
1414
- } else if (typeof value === "string") {
1415
- return new Date(value);
1416
- } else {
1417
- return value;
1418
- }
1419
- }
1420
- transformOutputBytes(value) {
1421
- return Buffer.isBuffer(value) ? Uint8Array.from(value) : value;
1422
- }
1423
- transformOutputJson(value) {
1424
- if (typeof value === "string") {
1425
- try {
1426
- return JSON.parse(value);
1427
- } catch (e) {
1428
- throw new QueryError("Invalid JSON returned", e);
1429
- }
1430
- }
1431
- return value;
1432
- }
1433
- buildRelationSelection(query, model, relationField, parentAlias, payload) {
1434
- return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
1435
- }
1436
- buildRelationJSON(model, eb, relationField, parentAlias, payload) {
1437
- const relationFieldDef = requireField(this.schema, model, relationField);
1438
- const relationModel = relationFieldDef.type;
1439
- const relationModelDef = requireModel(this.schema, relationModel);
1440
- const subQueryName = `${parentAlias}$${relationField}`;
1441
- let tbl;
1442
- if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1443
- tbl = this.buildModelSelect(eb, relationModel, subQueryName, payload, false);
1444
- tbl = this.buildRelationJoinFilter(tbl, model, relationField, subQueryName, parentAlias);
1445
- } else {
1446
- tbl = eb.selectFrom(() => {
1447
- const selectModelAlias = `${parentAlias}$${relationField}$sub`;
1448
- let selectModelQuery = this.buildModelSelect(eb, relationModel, selectModelAlias, payload, true);
1449
- selectModelQuery = this.buildRelationJoinFilter(selectModelQuery, model, relationField, selectModelAlias, parentAlias);
1450
- return selectModelQuery.as(subQueryName);
1451
- });
1452
- }
1453
- tbl = tbl.select(() => {
1454
- const objArgs = [];
1455
- const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
1456
- if (descendantModels.length > 0) {
1457
- objArgs.push(...descendantModels.map((subModel) => [
1458
- import_kysely3.sql.lit(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`),
1459
- eb.ref(`${DELEGATE_JOINED_FIELD_PREFIX}${subModel.name}`)
1460
- ]).flatMap((v) => v));
1461
- }
1462
- if (payload === true || !payload.select) {
1463
- objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
1464
- import_kysely3.sql.lit(field),
1465
- this.fieldRef(relationModel, field, eb, subQueryName, false)
1466
- ]).flatMap((v) => v));
1467
- } else if (payload.select) {
1468
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1469
- if (field === "_count") {
1470
- const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1471
- return [
1472
- import_kysely3.sql.lit(field),
1473
- subJson
1474
- ];
1475
- } else {
1476
- const fieldDef = requireField(this.schema, relationModel, field);
1477
- if (fieldDef.relation) {
1478
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1479
- return [
1480
- import_kysely3.sql.lit(field),
1481
- subJson
1482
- ];
1483
- } else {
1484
- return [
1485
- import_kysely3.sql.lit(field),
1486
- this.fieldRef(relationModel, field, eb, subQueryName, false)
1487
- ];
1488
- }
1489
- }
1490
- }).flatMap((v) => v));
1491
- }
1492
- if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
1493
- objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
1494
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1495
- return [
1496
- import_kysely3.sql.lit(field),
1497
- subJson
1498
- ];
1499
- }).flatMap((v) => v));
1500
- }
1501
- if (relationFieldDef.array) {
1502
- return eb.fn.coalesce(import_kysely3.sql`json_group_array(json_object(${import_kysely3.sql.join(objArgs)}))`, import_kysely3.sql`json_array()`).as("$data");
1503
- } else {
1504
- return import_kysely3.sql`json_object(${import_kysely3.sql.join(objArgs)})`.as("$data");
1505
- }
1506
- });
1507
- return tbl;
1508
- }
1509
- buildRelationJoinFilter(selectModelQuery, model, relationField, relationModelAlias, parentAlias) {
1510
- const fieldDef = requireField(this.schema, model, relationField);
1511
- const relationModel = fieldDef.type;
1512
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1513
- if (m2m) {
1514
- const parentIds = requireIdFields(this.schema, model);
1515
- const relationIds = requireIdFields(this.schema, relationModel);
1516
- (0, import_common_helpers5.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1517
- (0, import_common_helpers5.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1518
- selectModelQuery = selectModelQuery.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1519
- } else {
1520
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1521
- keyPairs.forEach(({ fk, pk }) => {
1522
- if (ownedByModel) {
1523
- selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1524
- } else {
1525
- selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1526
- }
1527
- });
1528
- }
1529
- return selectModelQuery;
1530
- }
1531
- buildSkipTake(query, skip, take) {
1532
- if (take !== void 0) {
1533
- query = query.limit(take);
1534
- }
1535
- if (skip !== void 0) {
1536
- query = query.offset(skip);
1537
- if (take === void 0) {
1538
- query = query.limit(-1);
1539
- }
1540
- }
1541
- return query;
1542
- }
1543
- buildJsonObject(eb, value) {
1544
- return eb.fn("json_object", Object.entries(value).flatMap(([key, value2]) => [
1545
- import_kysely3.sql.lit(key),
1546
- value2
1547
- ]));
1548
- }
1549
- get supportsUpdateWithLimit() {
1550
- return false;
1551
- }
1552
- get supportsDeleteWithLimit() {
1553
- return false;
1554
- }
1555
- get supportsDistinctOn() {
1556
- return false;
1557
- }
1558
- buildArrayLength(eb, array) {
1559
- return eb.fn("json_array_length", [
1560
- array
1561
- ]);
1562
- }
1563
- buildArrayLiteralSQL(_values) {
1564
- throw new Error("SQLite does not support array literals");
1565
- }
1566
- get supportInsertWithDefault() {
1567
- return false;
1568
- }
1569
- getFieldSqlType(fieldDef) {
1570
- if (fieldDef.relation) {
1571
- throw new QueryError("Cannot get SQL type of a relation field");
1572
- }
1573
- if (fieldDef.array) {
1574
- throw new QueryError("SQLite does not support scalar list type");
1575
- }
1576
- if (this.schema.enums?.[fieldDef.type]) {
1577
- return "text";
1578
- }
1579
- return (0, import_ts_pattern4.match)(fieldDef.type).with("String", () => "text").with("Boolean", () => "integer").with("Int", () => "integer").with("BigInt", () => "integer").with("Float", () => "real").with("Decimal", () => "decimal").with("DateTime", () => "numeric").with("Bytes", () => "blob").with("Json", () => "jsonb").otherwise(() => "text");
1580
- }
1581
- getStringCasingBehavior() {
1582
- return {
1583
- supportsILike: false,
1584
- likeCaseSensitive: false
1585
- };
1586
- }
1587
- };
1588
-
1589
- // src/client/crud/dialects/index.ts
1590
- function getCrudDialect(schema, options) {
1591
- return (0, import_ts_pattern5.match)(schema.provider.type).with("sqlite", () => new SqliteCrudDialect(schema, options)).with("postgresql", () => new PostgresCrudDialect(schema, options)).exhaustive();
1592
- }
1593
- __name(getCrudDialect, "getCrudDialect");
1594
-
1595
- // src/client/crud/operations/count.ts
1596
- var import_kysely6 = require("kysely");
1597
-
1598
- // src/client/crud/operations/create.ts
1599
- var import_ts_pattern8 = require("ts-pattern");
1600
-
1601
- // src/client/crud/operations/delete.ts
1602
- var import_ts_pattern9 = require("ts-pattern");
1603
-
1604
- // src/client/crud/operations/group-by.ts
1605
- var import_kysely7 = require("kysely");
1606
- var import_ts_pattern10 = require("ts-pattern");
1607
-
1608
- // src/client/crud/operations/update.ts
1609
- var import_ts_pattern11 = require("ts-pattern");
1610
-
1611
- // src/client/crud/validator.ts
1612
- var import_common_helpers7 = require("@zenstackhq/common-helpers");
1613
- var import_decimal3 = __toESM(require("decimal.js"), 1);
1614
- var import_json_stable_stringify = __toESM(require("json-stable-stringify"), 1);
1615
- var import_ts_pattern12 = require("ts-pattern");
1616
- var import_zod = require("zod");
1617
-
1618
- // src/utils/zod-utils.ts
1619
- var import_v3 = require("zod-validation-error/v3");
1620
- var import_v4 = require("zod-validation-error/v4");
1621
-
1622
- // src/client/executor/zenstack-query-executor.ts
1623
- var import_common_helpers9 = require("@zenstackhq/common-helpers");
1624
- var import_kysely10 = require("kysely");
1625
- var import_ts_pattern13 = require("ts-pattern");
1626
-
1627
- // src/client/kysely-utils.ts
1628
- var import_kysely8 = require("kysely");
1629
- function extractFieldName(node) {
1630
- if (import_kysely8.ReferenceNode.is(node) && import_kysely8.ColumnNode.is(node.column)) {
1631
- return node.column.column.name;
1632
- } else if (import_kysely8.ColumnNode.is(node)) {
1633
- return node.column.name;
1634
- } else {
1635
- return void 0;
1636
- }
1637
- }
1638
- __name(extractFieldName, "extractFieldName");
1639
-
1640
- // src/client/executor/name-mapper.ts
1641
- var import_common_helpers8 = require("@zenstackhq/common-helpers");
1642
- var import_kysely9 = require("kysely");
1643
-
1644
- // src/client/functions.ts
1645
- var import_common_helpers10 = require("@zenstackhq/common-helpers");
1646
- var import_kysely11 = require("kysely");
1647
- var import_ts_pattern14 = require("ts-pattern");
1648
-
1649
- // src/client/helpers/schema-db-pusher.ts
1650
- var import_common_helpers11 = require("@zenstackhq/common-helpers");
1651
- var import_kysely12 = require("kysely");
1652
- var import_toposort = __toESM(require("toposort"), 1);
1653
- var import_ts_pattern15 = require("ts-pattern");
1654
-
1655
- // src/client/index.ts
1656
- var import_kysely14 = require("kysely");
1657
-
1658
- // src/plugins/policy/errors.ts
1659
- var RejectedByPolicyReason = /* @__PURE__ */ function(RejectedByPolicyReason2) {
1660
- RejectedByPolicyReason2["NO_ACCESS"] = "no-access";
1661
- RejectedByPolicyReason2["CANNOT_READ_BACK"] = "cannot-read-back";
1662
- RejectedByPolicyReason2["OTHER"] = "other";
1663
- return RejectedByPolicyReason2;
1664
- }({});
1665
- var RejectedByPolicyError = class extends ZenStackError {
1666
- static {
1667
- __name(this, "RejectedByPolicyError");
1668
- }
1669
- model;
1670
- reason;
1671
- constructor(model, reason = "no-access", message) {
1672
- super(message ?? `Operation rejected by policy${model ? ": " + model : ""}`), this.model = model, this.reason = reason;
1673
- }
1674
- };
1675
-
1676
- // src/plugins/policy/functions.ts
1677
- var import_common_helpers16 = require("@zenstackhq/common-helpers");
1678
- var import_kysely19 = require("kysely");
1679
-
1680
- // src/plugins/policy/policy-handler.ts
1681
- var import_common_helpers15 = require("@zenstackhq/common-helpers");
1682
- var import_kysely18 = require("kysely");
1683
- var import_ts_pattern19 = require("ts-pattern");
1684
-
1685
- // src/utils/expression-utils.ts
1686
- var import_ts_pattern16 = require("ts-pattern");
1687
- var ExpressionVisitor = class {
1688
- static {
1689
- __name(this, "ExpressionVisitor");
1690
- }
1691
- visit(expr2) {
1692
- (0, import_ts_pattern16.match)(expr2).with({
1693
- kind: "literal"
1694
- }, (e) => this.visitLiteral(e)).with({
1695
- kind: "array"
1696
- }, (e) => this.visitArray(e)).with({
1697
- kind: "field"
1698
- }, (e) => this.visitField(e)).with({
1699
- kind: "member"
1700
- }, (e) => this.visitMember(e)).with({
1701
- kind: "binary"
1702
- }, (e) => this.visitBinary(e)).with({
1703
- kind: "unary"
1704
- }, (e) => this.visitUnary(e)).with({
1705
- kind: "call"
1706
- }, (e) => this.visitCall(e)).with({
1707
- kind: "this"
1708
- }, (e) => this.visitThis(e)).with({
1709
- kind: "null"
1710
- }, (e) => this.visitNull(e)).exhaustive();
1711
- }
1712
- visitLiteral(_e) {
1713
- }
1714
- visitArray(e) {
1715
- e.items.forEach((item) => this.visit(item));
1716
- }
1717
- visitField(_e) {
1718
- }
1719
- visitMember(e) {
1720
- this.visit(e.receiver);
1721
- }
1722
- visitBinary(e) {
1723
- this.visit(e.left);
1724
- this.visit(e.right);
1725
- }
1726
- visitUnary(e) {
1727
- this.visit(e.operand);
1728
- }
1729
- visitCall(e) {
1730
- e.args?.forEach((arg) => this.visit(arg));
1731
- }
1732
- visitThis(_e) {
1733
- }
1734
- visitNull(_e) {
1735
- }
1736
- };
1737
-
1738
- // src/utils/default-operation-node-visitor.ts
1739
- var import_kysely15 = require("kysely");
1740
- var DefaultOperationNodeVisitor = class extends import_kysely15.OperationNodeVisitor {
1741
- static {
1742
- __name(this, "DefaultOperationNodeVisitor");
1743
- }
1744
- defaultVisit(node) {
1745
- Object.values(node).forEach((value) => {
1746
- if (!value) {
1747
- return;
1748
- }
1749
- if (Array.isArray(value)) {
1750
- value.forEach((el) => this.defaultVisit(el));
1751
- }
1752
- if (typeof value === "object" && "kind" in value && typeof value.kind === "string") {
1753
- this.visitNode(value);
1754
- }
1755
- });
1756
- }
1757
- visitSelectQuery(node) {
1758
- this.defaultVisit(node);
1759
- }
1760
- visitSelection(node) {
1761
- this.defaultVisit(node);
1762
- }
1763
- visitColumn(node) {
1764
- this.defaultVisit(node);
1765
- }
1766
- visitAlias(node) {
1767
- this.defaultVisit(node);
1768
- }
1769
- visitTable(node) {
1770
- this.defaultVisit(node);
1771
- }
1772
- visitFrom(node) {
1773
- this.defaultVisit(node);
1774
- }
1775
- visitReference(node) {
1776
- this.defaultVisit(node);
1777
- }
1778
- visitAnd(node) {
1779
- this.defaultVisit(node);
1780
- }
1781
- visitOr(node) {
1782
- this.defaultVisit(node);
1783
- }
1784
- visitValueList(node) {
1785
- this.defaultVisit(node);
1786
- }
1787
- visitParens(node) {
1788
- this.defaultVisit(node);
1789
- }
1790
- visitJoin(node) {
1791
- this.defaultVisit(node);
1792
- }
1793
- visitRaw(node) {
1794
- this.defaultVisit(node);
1795
- }
1796
- visitWhere(node) {
1797
- this.defaultVisit(node);
1798
- }
1799
- visitInsertQuery(node) {
1800
- this.defaultVisit(node);
1801
- }
1802
- visitDeleteQuery(node) {
1803
- this.defaultVisit(node);
1804
- }
1805
- visitReturning(node) {
1806
- this.defaultVisit(node);
1807
- }
1808
- visitCreateTable(node) {
1809
- this.defaultVisit(node);
1810
- }
1811
- visitAddColumn(node) {
1812
- this.defaultVisit(node);
1813
- }
1814
- visitColumnDefinition(node) {
1815
- this.defaultVisit(node);
1816
- }
1817
- visitDropTable(node) {
1818
- this.defaultVisit(node);
1819
- }
1820
- visitOrderBy(node) {
1821
- this.defaultVisit(node);
1822
- }
1823
- visitOrderByItem(node) {
1824
- this.defaultVisit(node);
1825
- }
1826
- visitGroupBy(node) {
1827
- this.defaultVisit(node);
1828
- }
1829
- visitGroupByItem(node) {
1830
- this.defaultVisit(node);
1831
- }
1832
- visitUpdateQuery(node) {
1833
- this.defaultVisit(node);
1834
- }
1835
- visitColumnUpdate(node) {
1836
- this.defaultVisit(node);
1837
- }
1838
- visitLimit(node) {
1839
- this.defaultVisit(node);
1840
- }
1841
- visitOffset(node) {
1842
- this.defaultVisit(node);
1843
- }
1844
- visitOnConflict(node) {
1845
- this.defaultVisit(node);
1846
- }
1847
- visitOnDuplicateKey(node) {
1848
- this.defaultVisit(node);
1849
- }
1850
- visitCheckConstraint(node) {
1851
- this.defaultVisit(node);
1852
- }
1853
- visitDataType(node) {
1854
- this.defaultVisit(node);
1855
- }
1856
- visitSelectAll(node) {
1857
- this.defaultVisit(node);
1858
- }
1859
- visitIdentifier(node) {
1860
- this.defaultVisit(node);
1861
- }
1862
- visitSchemableIdentifier(node) {
1863
- this.defaultVisit(node);
1864
- }
1865
- visitValue(node) {
1866
- this.defaultVisit(node);
1867
- }
1868
- visitPrimitiveValueList(node) {
1869
- this.defaultVisit(node);
1870
- }
1871
- visitOperator(node) {
1872
- this.defaultVisit(node);
1873
- }
1874
- visitCreateIndex(node) {
1875
- this.defaultVisit(node);
1876
- }
1877
- visitDropIndex(node) {
1878
- this.defaultVisit(node);
1879
- }
1880
- visitList(node) {
1881
- this.defaultVisit(node);
1882
- }
1883
- visitPrimaryKeyConstraint(node) {
1884
- this.defaultVisit(node);
1885
- }
1886
- visitUniqueConstraint(node) {
1887
- this.defaultVisit(node);
1888
- }
1889
- visitReferences(node) {
1890
- this.defaultVisit(node);
1891
- }
1892
- visitWith(node) {
1893
- this.defaultVisit(node);
1894
- }
1895
- visitCommonTableExpression(node) {
1896
- this.defaultVisit(node);
1897
- }
1898
- visitCommonTableExpressionName(node) {
1899
- this.defaultVisit(node);
1900
- }
1901
- visitHaving(node) {
1902
- this.defaultVisit(node);
1903
- }
1904
- visitCreateSchema(node) {
1905
- this.defaultVisit(node);
1906
- }
1907
- visitDropSchema(node) {
1908
- this.defaultVisit(node);
1909
- }
1910
- visitAlterTable(node) {
1911
- this.defaultVisit(node);
1912
- }
1913
- visitDropColumn(node) {
1914
- this.defaultVisit(node);
1915
- }
1916
- visitRenameColumn(node) {
1917
- this.defaultVisit(node);
1918
- }
1919
- visitAlterColumn(node) {
1920
- this.defaultVisit(node);
1921
- }
1922
- visitModifyColumn(node) {
1923
- this.defaultVisit(node);
1924
- }
1925
- visitAddConstraint(node) {
1926
- this.defaultVisit(node);
1927
- }
1928
- visitDropConstraint(node) {
1929
- this.defaultVisit(node);
1930
- }
1931
- visitForeignKeyConstraint(node) {
1932
- this.defaultVisit(node);
1933
- }
1934
- visitCreateView(node) {
1935
- this.defaultVisit(node);
1936
- }
1937
- visitDropView(node) {
1938
- this.defaultVisit(node);
1939
- }
1940
- visitGenerated(node) {
1941
- this.defaultVisit(node);
1942
- }
1943
- visitDefaultValue(node) {
1944
- this.defaultVisit(node);
1945
- }
1946
- visitOn(node) {
1947
- this.defaultVisit(node);
1948
- }
1949
- visitValues(node) {
1950
- this.defaultVisit(node);
1951
- }
1952
- visitSelectModifier(node) {
1953
- this.defaultVisit(node);
1954
- }
1955
- visitCreateType(node) {
1956
- this.defaultVisit(node);
1957
- }
1958
- visitDropType(node) {
1959
- this.defaultVisit(node);
1960
- }
1961
- visitExplain(node) {
1962
- this.defaultVisit(node);
1963
- }
1964
- visitDefaultInsertValue(node) {
1965
- this.defaultVisit(node);
1966
- }
1967
- visitAggregateFunction(node) {
1968
- this.defaultVisit(node);
1969
- }
1970
- visitOver(node) {
1971
- this.defaultVisit(node);
1972
- }
1973
- visitPartitionBy(node) {
1974
- this.defaultVisit(node);
1975
- }
1976
- visitPartitionByItem(node) {
1977
- this.defaultVisit(node);
1978
- }
1979
- visitSetOperation(node) {
1980
- this.defaultVisit(node);
1981
- }
1982
- visitBinaryOperation(node) {
1983
- this.defaultVisit(node);
1984
- }
1985
- visitUnaryOperation(node) {
1986
- this.defaultVisit(node);
1987
- }
1988
- visitUsing(node) {
1989
- this.defaultVisit(node);
1990
- }
1991
- visitFunction(node) {
1992
- this.defaultVisit(node);
1993
- }
1994
- visitCase(node) {
1995
- this.defaultVisit(node);
1996
- }
1997
- visitWhen(node) {
1998
- this.defaultVisit(node);
1999
- }
2000
- visitJSONReference(node) {
2001
- this.defaultVisit(node);
2002
- }
2003
- visitJSONPath(node) {
2004
- this.defaultVisit(node);
2005
- }
2006
- visitJSONPathLeg(node) {
2007
- this.defaultVisit(node);
2008
- }
2009
- visitJSONOperatorChain(node) {
2010
- this.defaultVisit(node);
2011
- }
2012
- visitTuple(node) {
2013
- this.defaultVisit(node);
2014
- }
2015
- visitMergeQuery(node) {
2016
- this.defaultVisit(node);
2017
- }
2018
- visitMatched(node) {
2019
- this.defaultVisit(node);
2020
- }
2021
- visitAddIndex(node) {
2022
- this.defaultVisit(node);
2023
- }
2024
- visitCast(node) {
2025
- this.defaultVisit(node);
2026
- }
2027
- visitFetch(node) {
2028
- this.defaultVisit(node);
2029
- }
2030
- visitTop(node) {
2031
- this.defaultVisit(node);
2032
- }
2033
- visitOutput(node) {
2034
- this.defaultVisit(node);
2035
- }
2036
- };
2037
-
2038
- // src/plugins/policy/column-collector.ts
2039
- var ColumnCollector = class extends DefaultOperationNodeVisitor {
2040
- static {
2041
- __name(this, "ColumnCollector");
2042
- }
2043
- columns = [];
2044
- collect(node) {
2045
- this.columns = [];
2046
- this.visitNode(node);
2047
- return this.columns;
2048
- }
2049
- visitColumn(node) {
2050
- if (!this.columns.includes(node.column.name)) {
2051
- this.columns.push(node.column.name);
2052
- }
2053
- }
2054
- };
2055
-
2056
- // src/plugins/policy/expression-transformer.ts
2057
- var import_common_helpers14 = require("@zenstackhq/common-helpers");
2058
- var import_kysely17 = require("kysely");
2059
- var import_ts_pattern18 = require("ts-pattern");
2060
-
2061
- // src/plugins/policy/expression-evaluator.ts
2062
- var import_common_helpers13 = require("@zenstackhq/common-helpers");
2063
- var import_ts_pattern17 = require("ts-pattern");
2064
- var ExpressionEvaluator = class {
2065
- static {
2066
- __name(this, "ExpressionEvaluator");
2067
- }
2068
- evaluate(expression, context) {
2069
- const result = (0, import_ts_pattern17.match)(expression).when(ExpressionUtils.isArray, (expr2) => this.evaluateArray(expr2, context)).when(ExpressionUtils.isBinary, (expr2) => this.evaluateBinary(expr2, context)).when(ExpressionUtils.isField, (expr2) => this.evaluateField(expr2, context)).when(ExpressionUtils.isLiteral, (expr2) => this.evaluateLiteral(expr2)).when(ExpressionUtils.isMember, (expr2) => this.evaluateMember(expr2, context)).when(ExpressionUtils.isUnary, (expr2) => this.evaluateUnary(expr2, context)).when(ExpressionUtils.isCall, (expr2) => this.evaluateCall(expr2, context)).when(ExpressionUtils.isThis, () => context.thisValue).when(ExpressionUtils.isNull, () => null).exhaustive();
2070
- return result ?? null;
2071
- }
2072
- evaluateCall(expr2, context) {
2073
- if (expr2.function === "auth") {
2074
- return context.auth;
2075
- } else {
2076
- throw new Error(`Unsupported call expression function: ${expr2.function}`);
2077
- }
2078
- }
2079
- evaluateUnary(expr2, context) {
2080
- return (0, import_ts_pattern17.match)(expr2.op).with("!", () => !this.evaluate(expr2.operand, context)).exhaustive();
2081
- }
2082
- evaluateMember(expr2, context) {
2083
- let val = this.evaluate(expr2.receiver, context);
2084
- for (const member of expr2.members) {
2085
- val = val?.[member];
2086
- }
2087
- return val;
2088
- }
2089
- evaluateLiteral(expr2) {
2090
- return expr2.value;
2091
- }
2092
- evaluateField(expr2, context) {
2093
- return context.thisValue?.[expr2.field];
2094
- }
2095
- evaluateArray(expr2, context) {
2096
- return expr2.items.map((item) => this.evaluate(item, context));
2097
- }
2098
- evaluateBinary(expr2, context) {
2099
- if (expr2.op === "?" || expr2.op === "!" || expr2.op === "^") {
2100
- return this.evaluateCollectionPredicate(expr2, context);
2101
- }
2102
- const left = this.evaluate(expr2.left, context);
2103
- const right = this.evaluate(expr2.right, context);
2104
- return (0, import_ts_pattern17.match)(expr2.op).with("==", () => left === right).with("!=", () => left !== right).with(">", () => left > right).with(">=", () => left >= right).with("<", () => left < right).with("<=", () => left <= right).with("&&", () => left && right).with("||", () => left || right).with("in", () => {
2105
- const _right = right ?? [];
2106
- (0, import_common_helpers13.invariant)(Array.isArray(_right), 'expected array for "in" operator');
2107
- return _right.includes(left);
2108
- }).exhaustive();
2109
- }
2110
- evaluateCollectionPredicate(expr2, context) {
2111
- const op = expr2.op;
2112
- (0, import_common_helpers13.invariant)(op === "?" || op === "!" || op === "^", 'expected "?" or "!" or "^" operator');
2113
- const left = this.evaluate(expr2.left, context);
2114
- if (!left) {
2115
- return false;
2116
- }
2117
- (0, import_common_helpers13.invariant)(Array.isArray(left), "expected array");
2118
- return (0, import_ts_pattern17.match)(op).with("?", () => left.some((item) => this.evaluate(expr2.right, {
2119
- ...context,
2120
- thisValue: item
2121
- }))).with("!", () => left.every((item) => this.evaluate(expr2.right, {
2122
- ...context,
2123
- thisValue: item
2124
- }))).with("^", () => !left.some((item) => this.evaluate(expr2.right, {
2125
- ...context,
2126
- thisValue: item
2127
- }))).exhaustive();
2128
- }
2129
- };
2130
-
2131
- // src/plugins/policy/utils.ts
2132
- var import_kysely16 = require("kysely");
2133
- function trueNode(dialect) {
2134
- return import_kysely16.ValueNode.createImmediate(dialect.transformPrimitive(true, "Boolean", false));
2135
- }
2136
- __name(trueNode, "trueNode");
2137
- function falseNode(dialect) {
2138
- return import_kysely16.ValueNode.createImmediate(dialect.transformPrimitive(false, "Boolean", false));
2139
- }
2140
- __name(falseNode, "falseNode");
2141
- function isTrueNode(node) {
2142
- return import_kysely16.ValueNode.is(node) && (node.value === true || node.value === 1);
2143
- }
2144
- __name(isTrueNode, "isTrueNode");
2145
- function isFalseNode(node) {
2146
- return import_kysely16.ValueNode.is(node) && (node.value === false || node.value === 0);
2147
- }
2148
- __name(isFalseNode, "isFalseNode");
2149
- function conjunction(dialect, nodes) {
2150
- if (nodes.length === 0) {
2151
- return trueNode(dialect);
2152
- }
2153
- if (nodes.length === 1) {
2154
- return nodes[0];
2155
- }
2156
- if (nodes.some(isFalseNode)) {
2157
- return falseNode(dialect);
2158
- }
2159
- const items = nodes.filter((n) => !isTrueNode(n));
2160
- if (items.length === 0) {
2161
- return trueNode(dialect);
2162
- }
2163
- return items.reduce((acc, node) => import_kysely16.AndNode.create(wrapParensIf(acc, import_kysely16.OrNode.is), wrapParensIf(node, import_kysely16.OrNode.is)));
2164
- }
2165
- __name(conjunction, "conjunction");
2166
- function disjunction(dialect, nodes) {
2167
- if (nodes.length === 0) {
2168
- return falseNode(dialect);
2169
- }
2170
- if (nodes.length === 1) {
2171
- return nodes[0];
2172
- }
2173
- if (nodes.some(isTrueNode)) {
2174
- return trueNode(dialect);
2175
- }
2176
- const items = nodes.filter((n) => !isFalseNode(n));
2177
- if (items.length === 0) {
2178
- return falseNode(dialect);
2179
- }
2180
- return items.reduce((acc, node) => import_kysely16.OrNode.create(wrapParensIf(acc, import_kysely16.AndNode.is), wrapParensIf(node, import_kysely16.AndNode.is)));
2181
- }
2182
- __name(disjunction, "disjunction");
2183
- function logicalNot(dialect, node) {
2184
- if (isTrueNode(node)) {
2185
- return falseNode(dialect);
2186
- }
2187
- if (isFalseNode(node)) {
2188
- return trueNode(dialect);
2189
- }
2190
- return import_kysely16.UnaryOperationNode.create(import_kysely16.OperatorNode.create("not"), wrapParensIf(node, (n) => import_kysely16.AndNode.is(n) || import_kysely16.OrNode.is(n)));
2191
- }
2192
- __name(logicalNot, "logicalNot");
2193
- function wrapParensIf(node, predicate) {
2194
- return predicate(node) ? import_kysely16.ParensNode.create(node) : node;
2195
- }
2196
- __name(wrapParensIf, "wrapParensIf");
2197
- function buildIsFalse(node, dialect) {
2198
- if (isFalseNode(node)) {
2199
- return trueNode(dialect);
2200
- } else if (isTrueNode(node)) {
2201
- return falseNode(dialect);
2202
- }
2203
- return import_kysely16.BinaryOperationNode.create(
2204
- // coalesce so null is treated as false
2205
- import_kysely16.FunctionNode.create("coalesce", [
2206
- node,
2207
- falseNode(dialect)
2208
- ]),
2209
- import_kysely16.OperatorNode.create("="),
2210
- falseNode(dialect)
2211
- );
2212
- }
2213
- __name(buildIsFalse, "buildIsFalse");
2214
- function getTableName(node) {
2215
- if (!node) {
2216
- return node;
2217
- }
2218
- if (import_kysely16.TableNode.is(node)) {
2219
- return node.table.identifier.name;
2220
- } else if (import_kysely16.AliasNode.is(node)) {
2221
- return getTableName(node.node);
2222
- } else if (import_kysely16.ReferenceNode.is(node) && node.table) {
2223
- return getTableName(node.table);
2224
- }
2225
- return void 0;
2226
- }
2227
- __name(getTableName, "getTableName");
2228
- function isBeforeInvocation(expr2) {
2229
- return ExpressionUtils.isCall(expr2) && expr2.function === "before";
2230
- }
2231
- __name(isBeforeInvocation, "isBeforeInvocation");
2232
-
2233
- // src/plugins/policy/expression-transformer.ts
2234
- function _ts_decorate(decorators, target, key, desc) {
2235
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2236
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2237
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2238
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2239
- }
2240
- __name(_ts_decorate, "_ts_decorate");
2241
- function _ts_metadata(k, v) {
2242
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2243
- }
2244
- __name(_ts_metadata, "_ts_metadata");
2245
- var expressionHandlers = /* @__PURE__ */ new Map();
2246
- function expr(kind) {
2247
- return function(_target, _propertyKey, descriptor) {
2248
- if (!expressionHandlers.get(kind)) {
2249
- expressionHandlers.set(kind, descriptor);
2250
- }
2251
- return descriptor;
2252
- };
2253
- }
2254
- __name(expr, "expr");
2255
- var ExpressionTransformer = class {
2256
- static {
2257
- __name(this, "ExpressionTransformer");
2258
- }
2259
- client;
2260
- dialect;
2261
- constructor(client) {
2262
- this.client = client;
2263
- this.dialect = getCrudDialect(this.schema, this.clientOptions);
2264
- }
2265
- get schema() {
2266
- return this.client.$schema;
2267
- }
2268
- get clientOptions() {
2269
- return this.client.$options;
2270
- }
2271
- get auth() {
2272
- return this.client.$auth;
2273
- }
2274
- get authType() {
2275
- if (!this.schema.authType) {
2276
- throw new InternalError('Schema does not have an "authType" specified');
2277
- }
2278
- return this.schema.authType;
2279
- }
2280
- transform(expression, context) {
2281
- const handler = expressionHandlers.get(expression.kind);
2282
- if (!handler) {
2283
- throw new Error(`Unsupported expression kind: ${expression.kind}`);
2284
- }
2285
- return handler.value.call(this, expression, context);
2286
- }
2287
- _literal(expr2) {
2288
- return this.transformValue(expr2.value, typeof expr2.value === "string" ? "String" : typeof expr2.value === "boolean" ? "Boolean" : "Int");
2289
- }
2290
- _array(expr2, context) {
2291
- return import_kysely17.ValueListNode.create(expr2.items.map((item) => this.transform(item, context)));
2292
- }
2293
- _field(expr2, context) {
2294
- const fieldDef = requireField(this.schema, context.model, expr2.field);
2295
- if (!fieldDef.relation) {
2296
- return this.createColumnRef(expr2.field, context);
2297
- } else {
2298
- const { memberFilter, memberSelect, ...restContext } = context;
2299
- const relation = this.transformRelationAccess(expr2.field, fieldDef.type, restContext);
2300
- return {
2301
- ...relation,
2302
- where: this.mergeWhere(relation.where, memberFilter),
2303
- selections: memberSelect ? [
2304
- memberSelect
2305
- ] : relation.selections
2306
- };
2307
- }
2308
- }
2309
- mergeWhere(where, memberFilter) {
2310
- if (!where) {
2311
- return import_kysely17.WhereNode.create(memberFilter ?? trueNode(this.dialect));
2312
- }
2313
- if (!memberFilter) {
2314
- return where;
2315
- }
2316
- return import_kysely17.WhereNode.create(conjunction(this.dialect, [
2317
- where.where,
2318
- memberFilter
2319
- ]));
2320
- }
2321
- _null() {
2322
- return import_kysely17.ValueNode.createImmediate(null);
2323
- }
2324
- _binary(expr2, context) {
2325
- if (expr2.op === "&&") {
2326
- return conjunction(this.dialect, [
2327
- this.transform(expr2.left, context),
2328
- this.transform(expr2.right, context)
2329
- ]);
2330
- } else if (expr2.op === "||") {
2331
- return disjunction(this.dialect, [
2332
- this.transform(expr2.left, context),
2333
- this.transform(expr2.right, context)
2334
- ]);
2335
- }
2336
- if (this.isAuthCall(expr2.left) || this.isAuthCall(expr2.right)) {
2337
- return this.transformAuthBinary(expr2, context);
2338
- }
2339
- const op = expr2.op;
2340
- if (op === "?" || op === "!" || op === "^") {
2341
- return this.transformCollectionPredicate(expr2, context);
2342
- }
2343
- const { normalizedLeft, normalizedRight } = this.normalizeBinaryOperationOperands(expr2, context);
2344
- const left = this.transform(normalizedLeft, context);
2345
- const right = this.transform(normalizedRight, context);
2346
- if (op === "in") {
2347
- if (this.isNullNode(left)) {
2348
- return this.transformValue(false, "Boolean");
2349
- } else {
2350
- if (import_kysely17.ValueListNode.is(right)) {
2351
- return import_kysely17.BinaryOperationNode.create(left, import_kysely17.OperatorNode.create("in"), right);
2352
- } else {
2353
- return import_kysely17.BinaryOperationNode.create(left, import_kysely17.OperatorNode.create("="), import_kysely17.FunctionNode.create("any", [
2354
- right
2355
- ]));
2356
- }
2357
- }
2358
- }
2359
- if (this.isNullNode(right)) {
2360
- return this.transformNullCheck(left, expr2.op);
2361
- } else if (this.isNullNode(left)) {
2362
- return this.transformNullCheck(right, expr2.op);
2363
- } else {
2364
- return import_kysely17.BinaryOperationNode.create(left, this.transformOperator(op), right);
2365
- }
2366
- }
2367
- transformNullCheck(expr2, operator) {
2368
- (0, import_common_helpers14.invariant)(operator === "==" || operator === "!=", 'operator must be "==" or "!=" for null comparison');
2369
- if (import_kysely17.ValueNode.is(expr2)) {
2370
- if (expr2.value === null) {
2371
- return operator === "==" ? trueNode(this.dialect) : falseNode(this.dialect);
2372
- } else {
2373
- return operator === "==" ? falseNode(this.dialect) : trueNode(this.dialect);
2374
- }
2375
- } else {
2376
- return operator === "==" ? import_kysely17.BinaryOperationNode.create(expr2, import_kysely17.OperatorNode.create("is"), import_kysely17.ValueNode.createImmediate(null)) : import_kysely17.BinaryOperationNode.create(expr2, import_kysely17.OperatorNode.create("is not"), import_kysely17.ValueNode.createImmediate(null));
2377
- }
2378
- }
2379
- normalizeBinaryOperationOperands(expr2, context) {
2380
- let normalizedLeft = expr2.left;
2381
- if (this.isRelationField(expr2.left, context.model)) {
2382
- (0, import_common_helpers14.invariant)(ExpressionUtils.isNull(expr2.right), "only null comparison is supported for relation field");
2383
- const leftRelDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
2384
- (0, import_common_helpers14.invariant)(leftRelDef, "failed to get relation field definition");
2385
- const idFields = requireIdFields(this.schema, leftRelDef.type);
2386
- normalizedLeft = this.makeOrAppendMember(normalizedLeft, idFields[0]);
2387
- }
2388
- let normalizedRight = expr2.right;
2389
- if (this.isRelationField(expr2.right, context.model)) {
2390
- (0, import_common_helpers14.invariant)(ExpressionUtils.isNull(expr2.left), "only null comparison is supported for relation field");
2391
- const rightRelDef = this.getFieldDefFromFieldRef(expr2.right, context.model);
2392
- (0, import_common_helpers14.invariant)(rightRelDef, "failed to get relation field definition");
2393
- const idFields = requireIdFields(this.schema, rightRelDef.type);
2394
- normalizedRight = this.makeOrAppendMember(normalizedRight, idFields[0]);
2395
- }
2396
- return {
2397
- normalizedLeft,
2398
- normalizedRight
2399
- };
2400
- }
2401
- transformCollectionPredicate(expr2, context) {
2402
- (0, import_common_helpers14.invariant)(expr2.op === "?" || expr2.op === "!" || expr2.op === "^", 'expected "?" or "!" or "^" operator');
2403
- if (this.isAuthCall(expr2.left) || this.isAuthMember(expr2.left)) {
2404
- const value = new ExpressionEvaluator().evaluate(expr2, {
2405
- auth: this.auth
2406
- });
2407
- return this.transformValue(value, "Boolean");
2408
- }
2409
- (0, import_common_helpers14.invariant)(ExpressionUtils.isField(expr2.left) || ExpressionUtils.isMember(expr2.left), "left operand must be field or member access");
2410
- let newContextModel;
2411
- const fieldDef = this.getFieldDefFromFieldRef(expr2.left, context.model);
2412
- if (fieldDef) {
2413
- (0, import_common_helpers14.invariant)(fieldDef.relation, `field is not a relation: ${JSON.stringify(expr2.left)}`);
2414
- newContextModel = fieldDef.type;
2415
- } else {
2416
- (0, import_common_helpers14.invariant)(ExpressionUtils.isMember(expr2.left) && ExpressionUtils.isField(expr2.left.receiver), "left operand must be member access with field receiver");
2417
- const fieldDef2 = requireField(this.schema, context.model, expr2.left.receiver.field);
2418
- newContextModel = fieldDef2.type;
2419
- for (const member of expr2.left.members) {
2420
- const memberDef = requireField(this.schema, newContextModel, member);
2421
- newContextModel = memberDef.type;
2422
- }
2423
- }
2424
- let predicateFilter = this.transform(expr2.right, {
2425
- ...context,
2426
- model: newContextModel,
2427
- alias: void 0
2428
- });
2429
- if (expr2.op === "!") {
2430
- predicateFilter = logicalNot(this.dialect, predicateFilter);
2431
- }
2432
- const count = import_kysely17.FunctionNode.create("count", [
2433
- import_kysely17.ValueNode.createImmediate(1)
2434
- ]);
2435
- const predicateResult = (0, import_ts_pattern18.match)(expr2.op).with("?", () => import_kysely17.BinaryOperationNode.create(count, import_kysely17.OperatorNode.create(">"), import_kysely17.ValueNode.createImmediate(0))).with("!", () => import_kysely17.BinaryOperationNode.create(count, import_kysely17.OperatorNode.create("="), import_kysely17.ValueNode.createImmediate(0))).with("^", () => import_kysely17.BinaryOperationNode.create(count, import_kysely17.OperatorNode.create("="), import_kysely17.ValueNode.createImmediate(0))).exhaustive();
2436
- return this.transform(expr2.left, {
2437
- ...context,
2438
- memberSelect: import_kysely17.SelectionNode.create(import_kysely17.AliasNode.create(predicateResult, import_kysely17.IdentifierNode.create("$t"))),
2439
- memberFilter: predicateFilter
2440
- });
2441
- }
2442
- transformAuthBinary(expr2, context) {
2443
- if (expr2.op !== "==" && expr2.op !== "!=") {
2444
- throw new QueryError(`Unsupported operator for \`auth()\` in policy of model "${context.model}": ${expr2.op}`);
2445
- }
2446
- let authExpr;
2447
- let other;
2448
- if (this.isAuthCall(expr2.left)) {
2449
- authExpr = expr2.left;
2450
- other = expr2.right;
2451
- } else {
2452
- authExpr = expr2.right;
2453
- other = expr2.left;
2454
- }
2455
- if (ExpressionUtils.isNull(other)) {
2456
- return this.transformValue(expr2.op === "==" ? !this.auth : !!this.auth, "Boolean");
2457
- } else {
2458
- const authModel = getModel(this.schema, this.authType);
2459
- if (!authModel) {
2460
- throw new QueryError(`Unsupported use of \`auth()\` in policy of model "${context.model}", comparing with \`auth()\` is only possible when auth type is a model`);
2461
- }
2462
- const idFields = Object.values(authModel.fields).filter((f) => f.id).map((f) => f.name);
2463
- (0, import_common_helpers14.invariant)(idFields.length > 0, "auth type model must have at least one id field");
2464
- const conditions = idFields.map((fieldName) => ExpressionUtils.binary(ExpressionUtils.member(authExpr, [
2465
- fieldName
2466
- ]), "==", this.makeOrAppendMember(other, fieldName)));
2467
- let result = this.buildAnd(conditions);
2468
- if (expr2.op === "!=") {
2469
- result = this.buildLogicalNot(result);
2470
- }
2471
- return this.transform(result, context);
2472
- }
2473
- }
2474
- makeOrAppendMember(other, fieldName) {
2475
- if (ExpressionUtils.isMember(other)) {
2476
- return ExpressionUtils.member(other.receiver, [
2477
- ...other.members,
2478
- fieldName
2479
- ]);
2480
- } else {
2481
- return ExpressionUtils.member(other, [
2482
- fieldName
2483
- ]);
2484
- }
2485
- }
2486
- transformValue(value, type) {
2487
- if (value === true) {
2488
- return trueNode(this.dialect);
2489
- } else if (value === false) {
2490
- return falseNode(this.dialect);
2491
- } else {
2492
- return import_kysely17.ValueNode.create(this.dialect.transformPrimitive(value, type, false) ?? null);
2493
- }
2494
- }
2495
- _unary(expr2, context) {
2496
- (0, import_common_helpers14.invariant)(expr2.op === "!", 'only "!" operator is supported');
2497
- return logicalNot(this.dialect, this.transform(expr2.operand, context));
2498
- }
2499
- transformOperator(op) {
2500
- const mappedOp = (0, import_ts_pattern18.match)(op).with("==", () => "=").otherwise(() => op);
2501
- return import_kysely17.OperatorNode.create(mappedOp);
2502
- }
2503
- _call(expr2, context) {
2504
- const result = this.transformCall(expr2, context);
2505
- return result.toOperationNode();
2506
- }
2507
- transformCall(expr2, context) {
2508
- const func = this.getFunctionImpl(expr2.function);
2509
- if (!func) {
2510
- throw new QueryError(`Function not implemented: ${expr2.function}`);
2511
- }
2512
- const eb = (0, import_kysely17.expressionBuilder)();
2513
- return func(eb, (expr2.args ?? []).map((arg) => this.transformCallArg(eb, arg, context)), {
2514
- client: this.client,
2515
- dialect: this.dialect,
2516
- model: context.model,
2517
- modelAlias: context.alias ?? context.model,
2518
- operation: context.operation
2519
- });
2520
- }
2521
- getFunctionImpl(functionName) {
2522
- let func = this.clientOptions.functions?.[functionName];
2523
- if (!func) {
2524
- for (const plugin of this.clientOptions.plugins ?? []) {
2525
- if (plugin.functions?.[functionName]) {
2526
- func = plugin.functions[functionName];
2527
- break;
2528
- }
2529
- }
2530
- }
2531
- return func;
2532
- }
2533
- transformCallArg(eb, arg, context) {
2534
- if (ExpressionUtils.isLiteral(arg)) {
2535
- return eb.val(arg.value);
2536
- }
2537
- if (ExpressionUtils.isField(arg)) {
2538
- return eb.ref(arg.field);
2539
- }
2540
- if (ExpressionUtils.isCall(arg)) {
2541
- return this.transformCall(arg, context);
2542
- }
2543
- if (this.isAuthMember(arg)) {
2544
- const valNode = this.valueMemberAccess(this.auth, arg, this.authType);
2545
- return valNode ? eb.val(valNode.value) : eb.val(null);
2546
- }
2547
- throw new InternalError(`Unsupported argument expression: ${arg.kind}`);
2548
- }
2549
- _member(expr2, context) {
2550
- if (this.isAuthCall(expr2.receiver)) {
2551
- return this.valueMemberAccess(this.auth, expr2, this.authType);
2552
- }
2553
- if (isBeforeInvocation(expr2.receiver)) {
2554
- (0, import_common_helpers14.invariant)(context.operation === "post-update", "before() can only be used in post-update policy");
2555
- (0, import_common_helpers14.invariant)(expr2.members.length === 1, "before() can only be followed by a scalar field access");
2556
- return import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(expr2.members[0]), import_kysely17.TableNode.create("$before"));
2557
- }
2558
- (0, import_common_helpers14.invariant)(ExpressionUtils.isField(expr2.receiver) || ExpressionUtils.isThis(expr2.receiver), 'expect receiver to be field expression or "this"');
2559
- let members = expr2.members;
2560
- let receiver;
2561
- const { memberFilter, memberSelect, ...restContext } = context;
2562
- if (ExpressionUtils.isThis(expr2.receiver)) {
2563
- if (expr2.members.length === 1) {
2564
- return this._field(ExpressionUtils.field(expr2.members[0]), context);
2565
- } else {
2566
- const firstMemberFieldDef = requireField(this.schema, context.model, expr2.members[0]);
2567
- receiver = this.transformRelationAccess(expr2.members[0], firstMemberFieldDef.type, restContext);
2568
- members = expr2.members.slice(1);
2569
- }
2570
- } else {
2571
- receiver = this.transform(expr2.receiver, restContext);
2572
- }
2573
- (0, import_common_helpers14.invariant)(import_kysely17.SelectQueryNode.is(receiver), "expected receiver to be select query");
2574
- let startType;
2575
- if (ExpressionUtils.isField(expr2.receiver)) {
2576
- const receiverField = requireField(this.schema, context.model, expr2.receiver.field);
2577
- startType = receiverField.type;
2578
- } else {
2579
- startType = context.model;
2580
- }
2581
- const memberFields = [];
2582
- let currType = startType;
2583
- for (const member of members) {
2584
- const fieldDef = requireField(this.schema, currType, member);
2585
- memberFields.push({
2586
- fieldDef,
2587
- fromModel: currType
2588
- });
2589
- currType = fieldDef.type;
2590
- }
2591
- let currNode = void 0;
2592
- for (let i = members.length - 1; i >= 0; i--) {
2593
- const member = members[i];
2594
- const { fieldDef, fromModel } = memberFields[i];
2595
- if (fieldDef.relation) {
2596
- const relation = this.transformRelationAccess(member, fieldDef.type, {
2597
- ...restContext,
2598
- model: fromModel,
2599
- alias: void 0
2600
- });
2601
- if (currNode) {
2602
- currNode = {
2603
- ...relation,
2604
- selections: [
2605
- import_kysely17.SelectionNode.create(import_kysely17.AliasNode.create(currNode, import_kysely17.IdentifierNode.create(members[i + 1])))
2606
- ]
2607
- };
2608
- } else {
2609
- currNode = {
2610
- ...relation,
2611
- where: this.mergeWhere(relation.where, memberFilter),
2612
- selections: memberSelect ? [
2613
- memberSelect
2614
- ] : relation.selections
2615
- };
2616
- }
2617
- } else {
2618
- (0, import_common_helpers14.invariant)(i === members.length - 1, "plain field access must be the last segment");
2619
- (0, import_common_helpers14.invariant)(!currNode, "plain field access must be the last segment");
2620
- currNode = import_kysely17.ColumnNode.create(member);
2621
- }
2622
- }
2623
- return {
2624
- ...receiver,
2625
- selections: [
2626
- import_kysely17.SelectionNode.create(import_kysely17.AliasNode.create(currNode, import_kysely17.IdentifierNode.create("$t")))
2627
- ]
2628
- };
2629
- }
2630
- valueMemberAccess(receiver, expr2, receiverType) {
2631
- if (!receiver) {
2632
- return import_kysely17.ValueNode.createImmediate(null);
2633
- }
2634
- if (expr2.members.length !== 1) {
2635
- throw new Error(`Only single member access is supported`);
2636
- }
2637
- const field = expr2.members[0];
2638
- const fieldDef = requireField(this.schema, receiverType, field);
2639
- const fieldValue = receiver[field] ?? null;
2640
- return this.transformValue(fieldValue, fieldDef.type);
2641
- }
2642
- transformRelationAccess(field, relationModel, context) {
2643
- const m2m = getManyToManyRelation(this.schema, context.model, field);
2644
- if (m2m) {
2645
- return this.transformManyToManyRelationAccess(m2m, context);
2646
- }
2647
- const fromModel = context.model;
2648
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, fromModel, field);
2649
- let condition;
2650
- if (ownedByModel) {
2651
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => import_kysely17.BinaryOperationNode.create(import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(fk), import_kysely17.TableNode.create(context.alias ?? fromModel)), import_kysely17.OperatorNode.create("="), import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(pk), import_kysely17.TableNode.create(relationModel)))));
2652
- } else {
2653
- condition = conjunction(this.dialect, keyPairs.map(({ fk, pk }) => import_kysely17.BinaryOperationNode.create(import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(pk), import_kysely17.TableNode.create(context.alias ?? fromModel)), import_kysely17.OperatorNode.create("="), import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(fk), import_kysely17.TableNode.create(relationModel)))));
2654
- }
2655
- return {
2656
- kind: "SelectQueryNode",
2657
- from: import_kysely17.FromNode.create([
2658
- import_kysely17.TableNode.create(relationModel)
2659
- ]),
2660
- where: import_kysely17.WhereNode.create(condition)
2661
- };
2662
- }
2663
- transformManyToManyRelationAccess(m2m, context) {
2664
- const eb = (0, import_kysely17.expressionBuilder)();
2665
- const relationQuery = eb.selectFrom(m2m.otherModel).innerJoin(m2m.joinTable, (join) => join.onRef(`${m2m.otherModel}.${m2m.otherPKName}`, "=", `${m2m.joinTable}.${m2m.otherFkName}`).onRef(`${m2m.joinTable}.${m2m.parentFkName}`, "=", `${context.alias ?? context.model}.${m2m.parentPKName}`));
2666
- return relationQuery.toOperationNode();
2667
- }
2668
- createColumnRef(column, context) {
2669
- return import_kysely17.ReferenceNode.create(import_kysely17.ColumnNode.create(column), import_kysely17.TableNode.create(context.alias ?? context.model));
2670
- }
2671
- isAuthCall(value) {
2672
- return ExpressionUtils.isCall(value) && value.function === "auth";
2673
- }
2674
- isAuthMember(expr2) {
2675
- return ExpressionUtils.isMember(expr2) && this.isAuthCall(expr2.receiver);
2676
- }
2677
- isNullNode(node) {
2678
- return import_kysely17.ValueNode.is(node) && node.value === null;
2679
- }
2680
- buildLogicalNot(result) {
2681
- return ExpressionUtils.unary("!", result);
2682
- }
2683
- buildAnd(conditions) {
2684
- if (conditions.length === 0) {
2685
- return ExpressionUtils.literal(true);
2686
- } else if (conditions.length === 1) {
2687
- return conditions[0];
2688
- } else {
2689
- return conditions.reduce((acc, condition) => ExpressionUtils.binary(acc, "&&", condition));
2690
- }
2691
- }
2692
- isRelationField(expr2, model) {
2693
- const fieldDef = this.getFieldDefFromFieldRef(expr2, model);
2694
- return !!fieldDef?.relation;
2695
- }
2696
- getFieldDefFromFieldRef(expr2, model) {
2697
- if (ExpressionUtils.isField(expr2)) {
2698
- return requireField(this.schema, model, expr2.field);
2699
- } else if (ExpressionUtils.isMember(expr2) && expr2.members.length === 1 && ExpressionUtils.isThis(expr2.receiver)) {
2700
- return requireField(this.schema, model, expr2.members[0]);
2701
- } else {
2702
- return void 0;
2703
- }
2704
- }
2705
- };
2706
- _ts_decorate([
2707
- expr("literal"),
2708
- _ts_metadata("design:type", Function),
2709
- _ts_metadata("design:paramtypes", [
2710
- typeof LiteralExpression === "undefined" ? Object : LiteralExpression
2711
- ]),
2712
- _ts_metadata("design:returntype", void 0)
2713
- ], ExpressionTransformer.prototype, "_literal", null);
2714
- _ts_decorate([
2715
- expr("array"),
2716
- _ts_metadata("design:type", Function),
2717
- _ts_metadata("design:paramtypes", [
2718
- typeof ArrayExpression === "undefined" ? Object : ArrayExpression,
2719
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2720
- ]),
2721
- _ts_metadata("design:returntype", void 0)
2722
- ], ExpressionTransformer.prototype, "_array", null);
2723
- _ts_decorate([
2724
- expr("field"),
2725
- _ts_metadata("design:type", Function),
2726
- _ts_metadata("design:paramtypes", [
2727
- typeof FieldExpression === "undefined" ? Object : FieldExpression,
2728
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2729
- ]),
2730
- _ts_metadata("design:returntype", void 0)
2731
- ], ExpressionTransformer.prototype, "_field", null);
2732
- _ts_decorate([
2733
- expr("null"),
2734
- _ts_metadata("design:type", Function),
2735
- _ts_metadata("design:paramtypes", []),
2736
- _ts_metadata("design:returntype", void 0)
2737
- ], ExpressionTransformer.prototype, "_null", null);
2738
- _ts_decorate([
2739
- expr("binary"),
2740
- _ts_metadata("design:type", Function),
2741
- _ts_metadata("design:paramtypes", [
2742
- typeof BinaryExpression === "undefined" ? Object : BinaryExpression,
2743
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2744
- ]),
2745
- _ts_metadata("design:returntype", void 0)
2746
- ], ExpressionTransformer.prototype, "_binary", null);
2747
- _ts_decorate([
2748
- expr("unary"),
2749
- _ts_metadata("design:type", Function),
2750
- _ts_metadata("design:paramtypes", [
2751
- typeof UnaryExpression === "undefined" ? Object : UnaryExpression,
2752
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2753
- ]),
2754
- _ts_metadata("design:returntype", void 0)
2755
- ], ExpressionTransformer.prototype, "_unary", null);
2756
- _ts_decorate([
2757
- expr("call"),
2758
- _ts_metadata("design:type", Function),
2759
- _ts_metadata("design:paramtypes", [
2760
- typeof CallExpression === "undefined" ? Object : CallExpression,
2761
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2762
- ]),
2763
- _ts_metadata("design:returntype", void 0)
2764
- ], ExpressionTransformer.prototype, "_call", null);
2765
- _ts_decorate([
2766
- expr("member"),
2767
- _ts_metadata("design:type", Function),
2768
- _ts_metadata("design:paramtypes", [
2769
- typeof MemberExpression === "undefined" ? Object : MemberExpression,
2770
- typeof ExpressionTransformerContext === "undefined" ? Object : ExpressionTransformerContext
2771
- ]),
2772
- _ts_metadata("design:returntype", void 0)
2773
- ], ExpressionTransformer.prototype, "_member", null);
2774
-
2775
- // src/plugins/policy/policy-handler.ts
2776
- var PolicyHandler = class extends import_kysely18.OperationNodeTransformer {
2777
- static {
2778
- __name(this, "PolicyHandler");
2779
- }
2780
- client;
2781
- dialect;
2782
- constructor(client) {
2783
- super(), this.client = client;
2784
- this.dialect = getCrudDialect(this.client.$schema, this.client.$options);
2785
- }
2786
- get kysely() {
2787
- return this.client.$qb;
2788
- }
2789
- async handle(node, proceed) {
2790
- if (!this.isCrudQueryNode(node)) {
2791
- throw new RejectedByPolicyError(void 0, RejectedByPolicyReason.OTHER, "non-CRUD queries are not allowed");
2792
- }
2793
- if (!this.isMutationQueryNode(node)) {
2794
- return proceed(this.transformNode(node));
2795
- }
2796
- const { mutationModel } = this.getMutationModel(node);
2797
- if (import_kysely18.InsertQueryNode.is(node)) {
2798
- const isManyToManyJoinTable = this.isManyToManyJoinTable(mutationModel);
2799
- let needCheckPreCreate = true;
2800
- if (!isManyToManyJoinTable) {
2801
- const constCondition = this.tryGetConstantPolicy(mutationModel, "create");
2802
- if (constCondition === true) {
2803
- needCheckPreCreate = false;
2804
- } else if (constCondition === false) {
2805
- throw new RejectedByPolicyError(mutationModel);
2806
- }
2807
- }
2808
- if (needCheckPreCreate) {
2809
- await this.enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed);
2810
- }
2811
- }
2812
- const hasPostUpdatePolicies = import_kysely18.UpdateQueryNode.is(node) && this.hasPostUpdatePolicies(mutationModel);
2813
- let beforeUpdateInfo;
2814
- if (hasPostUpdatePolicies) {
2815
- beforeUpdateInfo = await this.loadBeforeUpdateEntities(mutationModel, node.where, proceed);
2816
- }
2817
- const result = await proceed(this.transformNode(node));
2818
- if (hasPostUpdatePolicies && result.rows.length > 0) {
2819
- const idConditions = this.buildIdConditions(mutationModel, result.rows);
2820
- const postUpdateFilter = this.buildPolicyFilter(mutationModel, void 0, "post-update");
2821
- const eb = (0, import_kysely18.expressionBuilder)();
2822
- const beforeUpdateTable = beforeUpdateInfo ? {
2823
- kind: "SelectQueryNode",
2824
- from: import_kysely18.FromNode.create([
2825
- import_kysely18.ParensNode.create(import_kysely18.ValuesNode.create(beforeUpdateInfo.rows.map((r) => import_kysely18.PrimitiveValueListNode.create(beforeUpdateInfo.fields.map((f) => r[f])))))
2826
- ]),
2827
- selections: beforeUpdateInfo.fields.map((name, index) => {
2828
- const def = requireField(this.client.$schema, mutationModel, name);
2829
- const castedColumnRef = import_kysely18.sql`CAST(${eb.ref(`column${index + 1}`)} as ${import_kysely18.sql.raw(this.dialect.getFieldSqlType(def))})`.as(name);
2830
- return import_kysely18.SelectionNode.create(castedColumnRef.toOperationNode());
2831
- })
2832
- } : void 0;
2833
- const postUpdateQuery = eb.selectFrom(mutationModel).select(() => [
2834
- eb(eb.fn("COUNT", [
2835
- eb.lit(1)
2836
- ]), "=", result.rows.length).as("$condition")
2837
- ]).where(() => new import_kysely18.ExpressionWrapper(conjunction(this.dialect, [
2838
- idConditions,
2839
- postUpdateFilter
2840
- ]))).$if(!!beforeUpdateInfo, (qb) => qb.leftJoin(() => new import_kysely18.ExpressionWrapper(beforeUpdateTable).as("$before"), (join) => {
2841
- const idFields = requireIdFields(this.client.$schema, mutationModel);
2842
- return idFields.reduce((acc, f) => acc.onRef(`${mutationModel}.${f}`, "=", `$before.${f}`), join);
2843
- }));
2844
- const postUpdateResult = await proceed(postUpdateQuery.toOperationNode());
2845
- if (!postUpdateResult.rows[0]?.$condition) {
2846
- throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.NO_ACCESS, "some or all updated rows failed to pass post-update policy check");
2847
- }
2848
- }
2849
- if (!node.returning || this.onlyReturningId(node)) {
2850
- return this.postProcessMutationResult(result, node);
2851
- } else {
2852
- const readBackResult = await this.processReadBack(node, result, proceed);
2853
- if (readBackResult.rows.length !== result.rows.length) {
2854
- throw new RejectedByPolicyError(mutationModel, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
2855
- }
2856
- return readBackResult;
2857
- }
2858
- }
2859
- // correction to kysely mutation result may be needed because we might have added
2860
- // returning clause to the query and caused changes to the result shape
2861
- postProcessMutationResult(result, node) {
2862
- if (node.returning) {
2863
- return result;
2864
- } else {
2865
- return {
2866
- ...result,
2867
- rows: [],
2868
- numAffectedRows: result.numAffectedRows ?? BigInt(result.rows.length)
2869
- };
2870
- }
2871
- }
2872
- hasPostUpdatePolicies(model) {
2873
- const policies = this.getModelPolicies(model, "post-update");
2874
- return policies.length > 0;
2875
- }
2876
- async loadBeforeUpdateEntities(model, where, proceed) {
2877
- const beforeUpdateAccessFields = this.getFieldsAccessForBeforeUpdatePolicies(model);
2878
- if (!beforeUpdateAccessFields || beforeUpdateAccessFields.length === 0) {
2879
- return void 0;
2880
- }
2881
- const query = {
2882
- kind: "SelectQueryNode",
2883
- from: import_kysely18.FromNode.create([
2884
- import_kysely18.TableNode.create(model)
2885
- ]),
2886
- where,
2887
- selections: [
2888
- ...beforeUpdateAccessFields.map((f) => import_kysely18.SelectionNode.create(import_kysely18.ColumnNode.create(f)))
2889
- ]
2890
- };
2891
- const result = await proceed(query);
2892
- return {
2893
- fields: beforeUpdateAccessFields,
2894
- rows: result.rows
2895
- };
2896
- }
2897
- getFieldsAccessForBeforeUpdatePolicies(model) {
2898
- const policies = this.getModelPolicies(model, "post-update");
2899
- if (policies.length === 0) {
2900
- return void 0;
2901
- }
2902
- const fields = /* @__PURE__ */ new Set();
2903
- const fieldCollector = new class extends ExpressionVisitor {
2904
- visitMember(e) {
2905
- if (isBeforeInvocation(e.receiver)) {
2906
- (0, import_common_helpers15.invariant)(e.members.length === 1, "before() can only be followed by a scalar field access");
2907
- fields.add(e.members[0]);
2908
- }
2909
- super.visitMember(e);
2910
- }
2911
- }();
2912
- for (const policy of policies) {
2913
- fieldCollector.visit(policy.condition);
2914
- }
2915
- if (fields.size === 0) {
2916
- return void 0;
2917
- }
2918
- requireIdFields(this.client.$schema, model).forEach((f) => fields.add(f));
2919
- return Array.from(fields).sort();
2920
- }
2921
- // #region overrides
2922
- transformSelectQuery(node) {
2923
- let whereNode = this.transformNode(node.where);
2924
- const policyFilter = this.createPolicyFilterForFrom(node.from);
2925
- if (policyFilter) {
2926
- whereNode = import_kysely18.WhereNode.create(whereNode?.where ? conjunction(this.dialect, [
2927
- whereNode.where,
2928
- policyFilter
2929
- ]) : policyFilter);
2930
- }
2931
- const baseResult = super.transformSelectQuery({
2932
- ...node,
2933
- where: void 0
2934
- });
2935
- return {
2936
- ...baseResult,
2937
- where: whereNode
2938
- };
2939
- }
2940
- transformJoin(node) {
2941
- const table = this.extractTableName(node.table);
2942
- if (!table) {
2943
- return super.transformJoin(node);
2944
- }
2945
- const filter = this.buildPolicyFilter(table.model, table.alias, "read");
2946
- const nestedSelect = {
2947
- kind: "SelectQueryNode",
2948
- from: import_kysely18.FromNode.create([
2949
- node.table
2950
- ]),
2951
- selections: [
2952
- import_kysely18.SelectionNode.createSelectAll()
2953
- ],
2954
- where: import_kysely18.WhereNode.create(filter)
2955
- };
2956
- return {
2957
- ...node,
2958
- table: import_kysely18.AliasNode.create(import_kysely18.ParensNode.create(nestedSelect), import_kysely18.IdentifierNode.create(table.alias ?? table.model))
2959
- };
2960
- }
2961
- transformInsertQuery(node) {
2962
- let onConflict = node.onConflict;
2963
- if (onConflict?.updates) {
2964
- const { mutationModel, alias } = this.getMutationModel(node);
2965
- const filter = this.buildPolicyFilter(mutationModel, alias, "update");
2966
- if (onConflict.updateWhere) {
2967
- onConflict = {
2968
- ...onConflict,
2969
- updateWhere: import_kysely18.WhereNode.create(conjunction(this.dialect, [
2970
- onConflict.updateWhere.where,
2971
- filter
2972
- ]))
2973
- };
2974
- } else {
2975
- onConflict = {
2976
- ...onConflict,
2977
- updateWhere: import_kysely18.WhereNode.create(filter)
2978
- };
2979
- }
2980
- }
2981
- const processedNode = onConflict ? {
2982
- ...node,
2983
- onConflict
2984
- } : node;
2985
- const result = super.transformInsertQuery(processedNode);
2986
- let returning = result.returning;
2987
- if (returning) {
2988
- const { mutationModel } = this.getMutationModel(node);
2989
- const idFields = requireIdFields(this.client.$schema, mutationModel);
2990
- returning = import_kysely18.ReturningNode.create(idFields.map((f) => import_kysely18.SelectionNode.create(import_kysely18.ColumnNode.create(f))));
2991
- }
2992
- return {
2993
- ...result,
2994
- returning
2995
- };
2996
- }
2997
- transformUpdateQuery(node) {
2998
- const result = super.transformUpdateQuery(node);
2999
- const { mutationModel, alias } = this.getMutationModel(node);
3000
- let filter = this.buildPolicyFilter(mutationModel, alias, "update");
3001
- if (node.from) {
3002
- const joinFilter = this.createPolicyFilterForFrom(node.from);
3003
- if (joinFilter) {
3004
- filter = conjunction(this.dialect, [
3005
- filter,
3006
- joinFilter
3007
- ]);
3008
- }
3009
- }
3010
- let returning = result.returning;
3011
- if (returning || this.hasPostUpdatePolicies(mutationModel)) {
3012
- const idFields = requireIdFields(this.client.$schema, mutationModel);
3013
- returning = import_kysely18.ReturningNode.create(idFields.map((f) => import_kysely18.SelectionNode.create(import_kysely18.ColumnNode.create(f))));
3014
- }
3015
- return {
3016
- ...result,
3017
- where: import_kysely18.WhereNode.create(result.where ? conjunction(this.dialect, [
3018
- result.where.where,
3019
- filter
3020
- ]) : filter),
3021
- returning
3022
- };
3023
- }
3024
- transformDeleteQuery(node) {
3025
- const result = super.transformDeleteQuery(node);
3026
- const { mutationModel, alias } = this.getMutationModel(node);
3027
- let filter = this.buildPolicyFilter(mutationModel, alias, "delete");
3028
- if (node.using) {
3029
- const joinFilter = this.createPolicyFilterForTables(node.using.tables);
3030
- if (joinFilter) {
3031
- filter = conjunction(this.dialect, [
3032
- filter,
3033
- joinFilter
3034
- ]);
3035
- }
3036
- }
3037
- return {
3038
- ...result,
3039
- where: import_kysely18.WhereNode.create(result.where ? conjunction(this.dialect, [
3040
- result.where.where,
3041
- filter
3042
- ]) : filter)
3043
- };
3044
- }
3045
- // #endregion
3046
- // #region helpers
3047
- onlyReturningId(node) {
3048
- if (!node.returning) {
3049
- return true;
3050
- }
3051
- const { mutationModel } = this.getMutationModel(node);
3052
- const idFields = requireIdFields(this.client.$schema, mutationModel);
3053
- if (node.returning.selections.some((s) => import_kysely18.SelectAllNode.is(s.selection))) {
3054
- const modelDef = requireModel(this.client.$schema, mutationModel);
3055
- if (Object.keys(modelDef.fields).some((f) => !idFields.includes(f))) {
3056
- return false;
3057
- } else {
3058
- return true;
3059
- }
3060
- }
3061
- const collector = new ColumnCollector();
3062
- const selectedColumns = collector.collect(node.returning);
3063
- return selectedColumns.every((c) => idFields.includes(c));
3064
- }
3065
- async enforcePreCreatePolicy(node, mutationModel, isManyToManyJoinTable, proceed) {
3066
- const fields = node.columns?.map((c) => c.column.name) ?? [];
3067
- const valueRows = node.values ? this.unwrapCreateValueRows(node.values, mutationModel, fields, isManyToManyJoinTable) : [
3068
- []
3069
- ];
3070
- for (const values of valueRows) {
3071
- if (isManyToManyJoinTable) {
3072
- await this.enforcePreCreatePolicyForManyToManyJoinTable(mutationModel, fields, values.map((v) => v.node), proceed);
3073
- } else {
3074
- await this.enforcePreCreatePolicyForOne(mutationModel, fields, values.map((v) => v.node), proceed);
3075
- }
3076
- }
3077
- }
3078
- async enforcePreCreatePolicyForManyToManyJoinTable(tableName, fields, values, proceed) {
3079
- const m2m = this.resolveManyToManyJoinTable(tableName);
3080
- (0, import_common_helpers15.invariant)(m2m);
3081
- (0, import_common_helpers15.invariant)(fields.includes("A") && fields.includes("B"), "many-to-many join table must have A and B fk fields");
3082
- const aIndex = fields.indexOf("A");
3083
- const aNode = values[aIndex];
3084
- const bIndex = fields.indexOf("B");
3085
- const bNode = values[bIndex];
3086
- (0, import_common_helpers15.invariant)(import_kysely18.ValueNode.is(aNode) && import_kysely18.ValueNode.is(bNode), "A and B values must be ValueNode");
3087
- const aValue = aNode.value;
3088
- const bValue = bNode.value;
3089
- (0, import_common_helpers15.invariant)(aValue !== null && aValue !== void 0, "A value cannot be null or undefined");
3090
- (0, import_common_helpers15.invariant)(bValue !== null && bValue !== void 0, "B value cannot be null or undefined");
3091
- const eb = (0, import_kysely18.expressionBuilder)();
3092
- const filterA = this.buildPolicyFilter(m2m.firstModel, void 0, "update");
3093
- const queryA = eb.selectFrom(m2m.firstModel).where(eb(eb.ref(`${m2m.firstModel}.${m2m.firstIdField}`), "=", aValue)).select(() => new import_kysely18.ExpressionWrapper(filterA).as("$t"));
3094
- const filterB = this.buildPolicyFilter(m2m.secondModel, void 0, "update");
3095
- const queryB = eb.selectFrom(m2m.secondModel).where(eb(eb.ref(`${m2m.secondModel}.${m2m.secondIdField}`), "=", bValue)).select(() => new import_kysely18.ExpressionWrapper(filterB).as("$t"));
3096
- const queryNode = {
3097
- kind: "SelectQueryNode",
3098
- selections: [
3099
- import_kysely18.SelectionNode.create(import_kysely18.AliasNode.create(queryA.toOperationNode(), import_kysely18.IdentifierNode.create("$conditionA"))),
3100
- import_kysely18.SelectionNode.create(import_kysely18.AliasNode.create(queryB.toOperationNode(), import_kysely18.IdentifierNode.create("$conditionB")))
3101
- ]
3102
- };
3103
- const result = await proceed(queryNode);
3104
- if (!result.rows[0]?.$conditionA) {
3105
- throw new RejectedByPolicyError(m2m.firstModel, RejectedByPolicyReason.CANNOT_READ_BACK, `many-to-many relation participant model "${m2m.firstModel}" not updatable`);
3106
- }
3107
- if (!result.rows[0]?.$conditionB) {
3108
- throw new RejectedByPolicyError(m2m.secondModel, RejectedByPolicyReason.NO_ACCESS, `many-to-many relation participant model "${m2m.secondModel}" not updatable`);
3109
- }
3110
- }
3111
- async enforcePreCreatePolicyForOne(model, fields, values, proceed) {
3112
- const allFields = Object.entries(requireModel(this.client.$schema, model).fields).filter(([, def]) => !def.relation);
3113
- const allValues = [];
3114
- for (const [name, _def] of allFields) {
3115
- const index = fields.indexOf(name);
3116
- if (index >= 0) {
3117
- allValues.push(values[index]);
3118
- } else {
3119
- allValues.push(import_kysely18.ValueNode.createImmediate(null));
3120
- }
3121
- }
3122
- const eb = (0, import_kysely18.expressionBuilder)();
3123
- const constTable = {
3124
- kind: "SelectQueryNode",
3125
- from: import_kysely18.FromNode.create([
3126
- import_kysely18.AliasNode.create(import_kysely18.ParensNode.create(import_kysely18.ValuesNode.create([
3127
- import_kysely18.ValueListNode.create(allValues)
3128
- ])), import_kysely18.IdentifierNode.create("$t"))
3129
- ]),
3130
- selections: allFields.map(([name, def], index) => {
3131
- const castedColumnRef = import_kysely18.sql`CAST(${eb.ref(`column${index + 1}`)} as ${import_kysely18.sql.raw(this.dialect.getFieldSqlType(def))})`.as(name);
3132
- return import_kysely18.SelectionNode.create(castedColumnRef.toOperationNode());
3133
- })
3134
- };
3135
- const filter = this.buildPolicyFilter(model, void 0, "create");
3136
- const preCreateCheck = {
3137
- kind: "SelectQueryNode",
3138
- from: import_kysely18.FromNode.create([
3139
- import_kysely18.AliasNode.create(constTable, import_kysely18.IdentifierNode.create(model))
3140
- ]),
3141
- selections: [
3142
- import_kysely18.SelectionNode.create(import_kysely18.AliasNode.create(import_kysely18.BinaryOperationNode.create(import_kysely18.FunctionNode.create("COUNT", [
3143
- import_kysely18.ValueNode.createImmediate(1)
3144
- ]), import_kysely18.OperatorNode.create(">"), import_kysely18.ValueNode.createImmediate(0)), import_kysely18.IdentifierNode.create("$condition")))
3145
- ],
3146
- where: import_kysely18.WhereNode.create(filter)
3147
- };
3148
- const result = await proceed(preCreateCheck);
3149
- if (!result.rows[0]?.$condition) {
3150
- throw new RejectedByPolicyError(model);
3151
- }
3152
- }
3153
- unwrapCreateValueRows(node, model, fields, isManyToManyJoinTable) {
3154
- if (import_kysely18.ValuesNode.is(node)) {
3155
- return node.values.map((v) => this.unwrapCreateValueRow(v.values, model, fields, isManyToManyJoinTable));
3156
- } else if (import_kysely18.PrimitiveValueListNode.is(node)) {
3157
- return [
3158
- this.unwrapCreateValueRow(node.values, model, fields, isManyToManyJoinTable)
3159
- ];
3160
- } else {
3161
- throw new InternalError(`Unexpected node kind: ${node.kind} for unwrapping create values`);
3162
- }
3163
- }
3164
- unwrapCreateValueRow(data, model, fields, isImplicitManyToManyJoinTable) {
3165
- (0, import_common_helpers15.invariant)(data.length === fields.length, "data length must match fields length");
3166
- const result = [];
3167
- for (let i = 0; i < data.length; i++) {
3168
- const item = data[i];
3169
- if (typeof item === "object" && item && "kind" in item) {
3170
- const fieldDef = requireField(this.client.$schema, model, fields[i]);
3171
- (0, import_common_helpers15.invariant)(item.kind === "ValueNode", "expecting a ValueNode");
3172
- result.push({
3173
- node: import_kysely18.ValueNode.create(this.dialect.transformPrimitive(item.value, fieldDef.type, !!fieldDef.array)),
3174
- raw: item.value
3175
- });
3176
- } else {
3177
- let value = item;
3178
- if (!isImplicitManyToManyJoinTable) {
3179
- const fieldDef = requireField(this.client.$schema, model, fields[i]);
3180
- value = this.dialect.transformPrimitive(item, fieldDef.type, !!fieldDef.array);
3181
- }
3182
- if (Array.isArray(value)) {
3183
- result.push({
3184
- node: import_kysely18.RawNode.createWithSql(this.dialect.buildArrayLiteralSQL(value)),
3185
- raw: value
3186
- });
3187
- } else {
3188
- result.push({
3189
- node: import_kysely18.ValueNode.create(value),
3190
- raw: value
3191
- });
3192
- }
3193
- }
3194
- }
3195
- return result;
3196
- }
3197
- tryGetConstantPolicy(model, operation) {
3198
- const policies = this.getModelPolicies(model, operation);
3199
- if (!policies.some((p) => p.kind === "allow")) {
3200
- return false;
3201
- } else if (
3202
- // unconditional deny
3203
- policies.some((p) => p.kind === "deny" && this.isTrueExpr(p.condition))
3204
- ) {
3205
- return false;
3206
- } else if (
3207
- // unconditional allow
3208
- !policies.some((p) => p.kind === "deny") && policies.some((p) => p.kind === "allow" && this.isTrueExpr(p.condition))
3209
- ) {
3210
- return true;
3211
- } else {
3212
- return void 0;
3213
- }
3214
- }
3215
- isTrueExpr(expr2) {
3216
- return ExpressionUtils.isLiteral(expr2) && expr2.value === true;
3217
- }
3218
- async processReadBack(node, result, proceed) {
3219
- if (result.rows.length === 0) {
3220
- return result;
3221
- }
3222
- if (!this.isMutationQueryNode(node) || !node.returning) {
3223
- return result;
3224
- }
3225
- const { mutationModel } = this.getMutationModel(node);
3226
- const idConditions = this.buildIdConditions(mutationModel, result.rows);
3227
- const policyFilter = this.buildPolicyFilter(mutationModel, void 0, "read");
3228
- const select = {
3229
- kind: "SelectQueryNode",
3230
- from: import_kysely18.FromNode.create([
3231
- import_kysely18.TableNode.create(mutationModel)
3232
- ]),
3233
- where: import_kysely18.WhereNode.create(conjunction(this.dialect, [
3234
- idConditions,
3235
- policyFilter
3236
- ])),
3237
- selections: node.returning.selections
3238
- };
3239
- const selectResult = await proceed(select);
3240
- return selectResult;
3241
- }
3242
- buildIdConditions(table, rows) {
3243
- const idFields = requireIdFields(this.client.$schema, table);
3244
- return disjunction(this.dialect, rows.map((row) => conjunction(this.dialect, idFields.map((field) => import_kysely18.BinaryOperationNode.create(import_kysely18.ReferenceNode.create(import_kysely18.ColumnNode.create(field), import_kysely18.TableNode.create(table)), import_kysely18.OperatorNode.create("="), import_kysely18.ValueNode.create(row[field]))))));
3245
- }
3246
- getMutationModel(node) {
3247
- const r = (0, import_ts_pattern19.match)(node).when(import_kysely18.InsertQueryNode.is, (node2) => ({
3248
- mutationModel: getTableName(node2.into),
3249
- alias: void 0
3250
- })).when(import_kysely18.UpdateQueryNode.is, (node2) => {
3251
- if (!node2.table) {
3252
- throw new QueryError("Update query must have a table");
3253
- }
3254
- const r2 = this.extractTableName(node2.table);
3255
- return r2 ? {
3256
- mutationModel: r2.model,
3257
- alias: r2.alias
3258
- } : void 0;
3259
- }).when(import_kysely18.DeleteQueryNode.is, (node2) => {
3260
- if (node2.from.froms.length !== 1) {
3261
- throw new QueryError("Only one from table is supported for delete");
3262
- }
3263
- const r2 = this.extractTableName(node2.from.froms[0]);
3264
- return r2 ? {
3265
- mutationModel: r2.model,
3266
- alias: r2.alias
3267
- } : void 0;
3268
- }).exhaustive();
3269
- if (!r) {
3270
- throw new InternalError(`Unable to get table name for query node: ${node}`);
3271
- }
3272
- return r;
3273
- }
3274
- isCrudQueryNode(node) {
3275
- return import_kysely18.SelectQueryNode.is(node) || import_kysely18.InsertQueryNode.is(node) || import_kysely18.UpdateQueryNode.is(node) || import_kysely18.DeleteQueryNode.is(node);
3276
- }
3277
- isMutationQueryNode(node) {
3278
- return import_kysely18.InsertQueryNode.is(node) || import_kysely18.UpdateQueryNode.is(node) || import_kysely18.DeleteQueryNode.is(node);
3279
- }
3280
- buildPolicyFilter(model, alias, operation) {
3281
- const m2mFilter = this.getModelPolicyFilterForManyToManyJoinTable(model, alias, operation);
3282
- if (m2mFilter) {
3283
- return m2mFilter;
3284
- }
3285
- const policies = this.getModelPolicies(model, operation);
3286
- const allows = policies.filter((policy) => policy.kind === "allow").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
3287
- const denies = policies.filter((policy) => policy.kind === "deny").map((policy) => this.compilePolicyCondition(model, alias, operation, policy));
3288
- let combinedPolicy;
3289
- if (allows.length === 0) {
3290
- if (operation === "post-update") {
3291
- combinedPolicy = trueNode(this.dialect);
3292
- } else {
3293
- combinedPolicy = falseNode(this.dialect);
3294
- }
3295
- } else {
3296
- combinedPolicy = disjunction(this.dialect, allows);
3297
- }
3298
- if (denies.length !== 0) {
3299
- const combinedDenies = conjunction(this.dialect, denies.map((d) => buildIsFalse(d, this.dialect)));
3300
- combinedPolicy = conjunction(this.dialect, [
3301
- combinedPolicy,
3302
- combinedDenies
3303
- ]);
3304
- }
3305
- return combinedPolicy;
3306
- }
3307
- extractTableName(node) {
3308
- if (import_kysely18.TableNode.is(node)) {
3309
- return {
3310
- model: node.table.identifier.name
3311
- };
3312
- }
3313
- if (import_kysely18.AliasNode.is(node)) {
3314
- const inner = this.extractTableName(node.node);
3315
- if (!inner) {
3316
- return void 0;
3317
- }
3318
- return {
3319
- model: inner.model,
3320
- alias: import_kysely18.IdentifierNode.is(node.alias) ? node.alias.name : void 0
3321
- };
3322
- } else {
3323
- return void 0;
3324
- }
3325
- }
3326
- createPolicyFilterForFrom(node) {
3327
- if (!node) {
3328
- return void 0;
3329
- }
3330
- return this.createPolicyFilterForTables(node.froms);
3331
- }
3332
- createPolicyFilterForTables(tables) {
3333
- return tables.reduce((acc, table) => {
3334
- const extractResult = this.extractTableName(table);
3335
- if (extractResult) {
3336
- const { model, alias } = extractResult;
3337
- const filter = this.buildPolicyFilter(model, alias, "read");
3338
- return acc ? conjunction(this.dialect, [
3339
- acc,
3340
- filter
3341
- ]) : filter;
3342
- }
3343
- return acc;
3344
- }, void 0);
3345
- }
3346
- compilePolicyCondition(model, alias, operation, policy) {
3347
- return new ExpressionTransformer(this.client).transform(policy.condition, {
3348
- model,
3349
- alias,
3350
- operation
3351
- });
3352
- }
3353
- getModelPolicies(model, operation) {
3354
- const modelDef = requireModel(this.client.$schema, model);
3355
- const result = [];
3356
- const extractOperations = /* @__PURE__ */ __name((expr2) => {
3357
- (0, import_common_helpers15.invariant)(ExpressionUtils.isLiteral(expr2), "expecting a literal");
3358
- (0, import_common_helpers15.invariant)(typeof expr2.value === "string", "expecting a string literal");
3359
- return expr2.value.split(",").filter((v) => !!v).map((v) => v.trim());
3360
- }, "extractOperations");
3361
- if (modelDef.attributes) {
3362
- result.push(...modelDef.attributes.filter((attr) => attr.name === "@@allow" || attr.name === "@@deny").map((attr) => ({
3363
- kind: attr.name === "@@allow" ? "allow" : "deny",
3364
- operations: extractOperations(attr.args[0].value),
3365
- condition: attr.args[1].value
3366
- })).filter((policy) => operation !== "post-update" && policy.operations.includes("all") || policy.operations.includes(operation)));
3367
- }
3368
- return result;
3369
- }
3370
- resolveManyToManyJoinTable(tableName) {
3371
- for (const model of Object.values(this.client.$schema.models)) {
3372
- for (const field of Object.values(model.fields)) {
3373
- const m2m = getManyToManyRelation(this.client.$schema, model.name, field.name);
3374
- if (m2m?.joinTable === tableName) {
3375
- const sortedRecord = [
3376
- {
3377
- model: model.name,
3378
- field: field.name
3379
- },
3380
- {
3381
- model: m2m.otherModel,
3382
- field: m2m.otherField
3383
- }
3384
- ].sort(this.manyToManySorter);
3385
- const firstIdFields = requireIdFields(this.client.$schema, sortedRecord[0].model);
3386
- const secondIdFields = requireIdFields(this.client.$schema, sortedRecord[1].model);
3387
- (0, import_common_helpers15.invariant)(firstIdFields.length === 1 && secondIdFields.length === 1, "only single-field id is supported for implicit many-to-many join table");
3388
- return {
3389
- firstModel: sortedRecord[0].model,
3390
- firstField: sortedRecord[0].field,
3391
- firstIdField: firstIdFields[0],
3392
- secondModel: sortedRecord[1].model,
3393
- secondField: sortedRecord[1].field,
3394
- secondIdField: secondIdFields[0]
3395
- };
3396
- }
3397
- }
3398
- }
3399
- return void 0;
3400
- }
3401
- manyToManySorter(a, b) {
3402
- return a.model !== b.model ? a.model.localeCompare(b.model) : a.field.localeCompare(b.field);
3403
- }
3404
- isManyToManyJoinTable(tableName) {
3405
- return !!this.resolveManyToManyJoinTable(tableName);
3406
- }
3407
- getModelPolicyFilterForManyToManyJoinTable(tableName, alias, operation) {
3408
- const m2m = this.resolveManyToManyJoinTable(tableName);
3409
- if (!m2m) {
3410
- return void 0;
3411
- }
3412
- const checkForOperation = operation === "read" ? "read" : "update";
3413
- const eb = (0, import_kysely18.expressionBuilder)();
3414
- const joinTable = alias ?? tableName;
3415
- const aQuery = eb.selectFrom(m2m.firstModel).whereRef(`${m2m.firstModel}.${m2m.firstIdField}`, "=", `${joinTable}.A`).select(() => new import_kysely18.ExpressionWrapper(this.buildPolicyFilter(m2m.firstModel, void 0, checkForOperation)).as("$conditionA"));
3416
- const bQuery = eb.selectFrom(m2m.secondModel).whereRef(`${m2m.secondModel}.${m2m.secondIdField}`, "=", `${joinTable}.B`).select(() => new import_kysely18.ExpressionWrapper(this.buildPolicyFilter(m2m.secondModel, void 0, checkForOperation)).as("$conditionB"));
3417
- return eb.and([
3418
- aQuery,
3419
- bQuery
3420
- ]).toOperationNode();
3421
- }
3422
- };
3423
-
3424
- // src/plugins/policy/functions.ts
3425
- var check = /* @__PURE__ */ __name((eb, args, { client, model, modelAlias, operation }) => {
3426
- (0, import_common_helpers16.invariant)(args.length === 1 || args.length === 2, '"check" function requires 1 or 2 arguments');
3427
- const arg1Node = args[0].toOperationNode();
3428
- const arg2Node = args.length === 2 ? args[1].toOperationNode() : void 0;
3429
- if (arg2Node) {
3430
- (0, import_common_helpers16.invariant)(import_kysely19.ValueNode.is(arg2Node) && typeof arg2Node.value === "string", '"operation" parameter must be a string literal when provided');
3431
- (0, import_common_helpers16.invariant)(CRUD.includes(arg2Node.value), '"operation" parameter must be one of "create", "read", "update", "delete"');
3432
- }
3433
- const fieldName = extractFieldName(arg1Node);
3434
- (0, import_common_helpers16.invariant)(fieldName, 'Failed to extract field name from the first argument of "check" function');
3435
- const fieldDef = requireField(client.$schema, model, fieldName);
3436
- (0, import_common_helpers16.invariant)(fieldDef.relation, `Field "${fieldName}" is not a relation field in model "${model}"`);
3437
- (0, import_common_helpers16.invariant)(!fieldDef.array, `Field "${fieldName}" is a to-many relation, which is not supported by "check"`);
3438
- const relationModel = fieldDef.type;
3439
- const op = arg2Node ? arg2Node.value : operation;
3440
- const policyHandler = new PolicyHandler(client);
3441
- const joinPairs = buildJoinPairs(client.$schema, model, modelAlias, fieldName, relationModel);
3442
- const joinCondition = joinPairs.length === 1 ? eb(eb.ref(joinPairs[0][0]), "=", eb.ref(joinPairs[0][1])) : eb.and(joinPairs.map(([left, right]) => eb(eb.ref(left), "=", eb.ref(right))));
3443
- const policyCondition = policyHandler.buildPolicyFilter(relationModel, void 0, op);
3444
- const result = eb.selectFrom(relationModel).where(joinCondition).select(new import_kysely19.ExpressionWrapper(policyCondition).as("$condition"));
3445
- return result;
3446
- }, "check");
3447
-
3448
- // src/plugins/policy/plugin.ts
3449
- var PolicyPlugin = class {
3450
- static {
3451
- __name(this, "PolicyPlugin");
3452
- }
3453
- get id() {
3454
- return "policy";
3455
- }
3456
- get name() {
3457
- return "Access Policy";
3458
- }
3459
- get description() {
3460
- return "Enforces access policies defined in the schema.";
3461
- }
3462
- get functions() {
3463
- return {
3464
- check
3465
- };
3466
- }
3467
- onKyselyQuery({ query, client, proceed }) {
3468
- const handler = new PolicyHandler(client);
3469
- return handler.handle(query, proceed);
3470
- }
3471
- };
3472
- // Annotate the CommonJS export names for ESM import in node:
3473
- 0 && (module.exports = {
3474
- PolicyPlugin,
3475
- RejectedByPolicyError,
3476
- RejectedByPolicyReason
3477
- });
3478
- //# sourceMappingURL=index.cjs.map