@nhtio/lucid-resourceful 0.1.0-master-1570171e → 0.1.0-master-3ec631a4

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.
Files changed (47) hide show
  1. package/{definitions-DgI468dW.cjs → data_type_schemas-BqeljaQB.cjs} +21 -177
  2. package/data_type_schemas-BqeljaQB.cjs.map +1 -0
  3. package/data_type_schemas-Cpco9Zba.js +225 -0
  4. package/data_type_schemas-Cpco9Zba.js.map +1 -0
  5. package/{decorator_utils-U_rZo8tv.cjs → decorator_utils-DSvYjLYD.cjs} +204 -60
  6. package/decorator_utils-DSvYjLYD.cjs.map +1 -0
  7. package/{decorator_utils-YSb1EGJ6.js → decorator_utils-gyymixlk.js} +207 -65
  8. package/decorator_utils-gyymixlk.js.map +1 -0
  9. package/definitions-DcB6B_4d.js +174 -0
  10. package/definitions-DcB6B_4d.js.map +1 -0
  11. package/definitions-DjQRkCeH.cjs +173 -0
  12. package/definitions-DjQRkCeH.cjs.map +1 -0
  13. package/definitions.cjs +1 -1
  14. package/definitions.mjs +11 -11
  15. package/{errors-B1rr67uM.js → errors-C-x5_jRE.js} +162 -27
  16. package/errors-C-x5_jRE.js.map +1 -0
  17. package/{errors-D8jb9VxY.cjs → errors-CNwuNhBV.cjs} +138 -5
  18. package/errors-CNwuNhBV.cjs.map +1 -0
  19. package/errors.cjs +5 -1
  20. package/errors.cjs.map +1 -1
  21. package/errors.d.ts +24 -2
  22. package/errors.mjs +19 -15
  23. package/index.cjs +1471 -771
  24. package/index.cjs.map +1 -1
  25. package/index.mjs +1716 -1016
  26. package/index.mjs.map +1 -1
  27. package/joi.cjs +1854 -3368
  28. package/joi.cjs.map +1 -1
  29. package/joi.mjs +1857 -3371
  30. package/joi.mjs.map +1 -1
  31. package/package.json +1 -1
  32. package/private/decorators.d.ts +8 -8
  33. package/private/lucene_to_lucid_translator.d.ts +21 -175
  34. package/private/mixin.d.ts +68 -5
  35. package/private/services/open_api_schema_service.d.ts +111 -0
  36. package/private/type_guards.d.ts +62 -0
  37. package/private/types.d.ts +1 -1
  38. package/private/utils.d.ts +24 -0
  39. package/utils.cjs +1 -1
  40. package/utils.mjs +2 -2
  41. package/decorator_utils-U_rZo8tv.cjs.map +0 -1
  42. package/decorator_utils-YSb1EGJ6.js.map +0 -1
  43. package/definitions-B88XBTUF.js +0 -381
  44. package/definitions-B88XBTUF.js.map +0 -1
  45. package/definitions-DgI468dW.cjs.map +0 -1
  46. package/errors-B1rr67uM.js.map +0 -1
  47. package/errors-D8jb9VxY.cjs.map +0 -1
package/index.cjs CHANGED
@@ -10,19 +10,16 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
10
10
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
11
11
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
12
12
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
13
- var _a, _hookHandlers, _cleanupHandlers, _state, _handlersToIgnore, _skipAllHooks, _Runner_instances, filter_fn, exec_fn, _b, _hooks, _c, _d;
13
+ var _attributesToColumns, _allowedColumns, _connection, _dialect, _primaryKey, _tableName, _model, _LuceneLucidQueryBuilder_instances, getSearchableColumns_fn, _OpenApiSchemaService_instances, getFieldKey_fn, extractDataTypeInfo_fn, _a, _hookHandlers, _cleanupHandlers, _state, _handlersToIgnore, _skipAllHooks, _Runner_instances, filter_fn, exec_fn, _b, _hooks, _c, _d;
14
14
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
15
- const decorator_utils = require("./decorator_utils-U_rZo8tv.cjs");
15
+ const decorator_utils = require("./decorator_utils-DSvYjLYD.cjs");
16
16
  const joi = require("./joi.cjs");
17
17
  const liqe = require("liqe");
18
- const errors = require("./errors-D8jb9VxY.cjs");
19
- const definitions = require("./definitions-DgI468dW.cjs");
18
+ const errors = require("./errors-CNwuNhBV.cjs");
20
19
  const require$$0 = require("util");
21
20
  require("node:path");
22
21
  require("node:url");
23
- const stripUndefinedValuesFromObject = (obj) => {
24
- return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value !== void 0));
25
- };
22
+ const definitions = require("./definitions-DjQRkCeH.cjs");
26
23
  async function pMap(iterable, mapper, {
27
24
  concurrency = Number.POSITIVE_INFINITY,
28
25
  stopOnError = true,
@@ -144,384 +141,426 @@ async function pMap(iterable, mapper, {
144
141
  });
145
142
  }
146
143
  const pMapSkip = Symbol("skip");
147
- const applyLuceneLogicalExpressionAst = (ast, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
148
- const operatorType = ast.operator.operator;
149
- query.where((subQuery) => {
150
- if (operatorType === "AND") {
151
- applyLuceneAst(ast.left, subQuery, attributesToColumns, primaryKey, tableName, allowedColumns);
152
- applyLuceneAst(
153
- ast.right,
154
- subQuery,
155
- attributesToColumns,
156
- primaryKey,
157
- tableName,
158
- allowedColumns
159
- );
160
- } else {
161
- subQuery.orWhere((orSubQuery) => {
162
- applyLuceneAst(
163
- ast.left,
164
- orSubQuery,
165
- attributesToColumns,
166
- primaryKey,
167
- tableName,
168
- allowedColumns
169
- );
144
+ const _LuceneLucidQueryBuilder = class _LuceneLucidQueryBuilder {
145
+ constructor(connection, query, attributesToColumns, primaryKey, tableName, allowedColumns, model) {
146
+ __privateAdd(this, _LuceneLucidQueryBuilder_instances);
147
+ __privateAdd(this, _attributesToColumns);
148
+ __privateAdd(this, _allowedColumns);
149
+ __privateAdd(this, _connection);
150
+ __privateAdd(this, _dialect);
151
+ // @ts-ignore - not used yet
152
+ __privateAdd(this, _primaryKey);
153
+ // @ts-ignore - not used yet
154
+ __privateAdd(this, _tableName);
155
+ // @ts-ignore - not used yet
156
+ __privateAdd(this, _model);
157
+ __privateSet(this, _attributesToColumns, attributesToColumns);
158
+ __privateSet(this, _primaryKey, primaryKey);
159
+ __privateSet(this, _tableName, tableName);
160
+ __privateSet(this, _allowedColumns, allowedColumns);
161
+ __privateSet(this, _model, model);
162
+ __privateSet(this, _connection, connection);
163
+ __privateSet(this, _dialect, query.client.dialect.name);
164
+ }
165
+ applyLuceneAst(ast, query, throwOnInvalidType = false) {
166
+ switch (ast.type) {
167
+ case "EmptyExpression":
168
+ this.applyLuceneEmptyExpressionAst(ast, query);
169
+ break;
170
+ case "LogicalExpression":
171
+ this.applyLuceneLogicalExpressionAst(ast, query);
172
+ break;
173
+ case "ParenthesizedExpression":
174
+ this.applyLuceneParenthesizedExpressionAst(ast, query);
175
+ break;
176
+ case "UnaryOperator":
177
+ this.applyLuceneUnaryOperatorAst(ast, query);
178
+ break;
179
+ case "Tag":
180
+ this.applyLuceneTagAst(ast, query);
181
+ break;
182
+ default:
183
+ if (throwOnInvalidType) {
184
+ throw new errors.E_LUCENE_INVALID_TYPE(ast.type);
185
+ }
186
+ break;
187
+ }
188
+ }
189
+ applyLuceneEmptyExpressionAst(_ast, _query) {
190
+ }
191
+ applyLuceneLogicalExpressionAst(ast, query) {
192
+ const operatorType = ast.operator.operator;
193
+ query.where((subQuery) => {
194
+ if (operatorType === "AND") {
195
+ this.applyLuceneAst(ast.left, subQuery);
196
+ this.applyLuceneAst(ast.right, subQuery);
197
+ } else {
198
+ subQuery.orWhere((orSubQuery) => {
199
+ this.applyLuceneAst(ast.left, orSubQuery);
200
+ });
201
+ subQuery.orWhere((orSubQuery) => {
202
+ this.applyLuceneAst(ast.right, orSubQuery);
203
+ });
204
+ }
205
+ });
206
+ }
207
+ applyLuceneParenthesizedExpressionAst(ast, query) {
208
+ query.where((subQuery) => {
209
+ this.applyLuceneAst(ast.expression, subQuery);
210
+ });
211
+ }
212
+ applyLuceneUnaryOperatorAst(ast, query) {
213
+ const operator = ast.operator;
214
+ if (operator === "NOT" || operator === "-") {
215
+ query.whereNot((subQuery) => {
216
+ this.applyLuceneAst(ast.operand, subQuery);
170
217
  });
171
- subQuery.orWhere((orSubQuery) => {
172
- applyLuceneAst(
173
- ast.right,
174
- orSubQuery,
175
- attributesToColumns,
176
- primaryKey,
177
- tableName,
178
- allowedColumns
179
- );
218
+ } else {
219
+ query.where((subQuery) => {
220
+ this.applyLuceneAst(ast.operand, subQuery);
180
221
  });
181
222
  }
182
- });
183
- };
184
- const applyLuceneParenthesizedExpressionAst = (ast, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
185
- query.where((subQuery) => {
186
- applyLuceneAst(
187
- ast.expression,
188
- subQuery,
189
- attributesToColumns,
190
- primaryKey,
191
- tableName,
192
- allowedColumns
193
- );
194
- });
195
- };
196
- const applyLuceneEmptyExpression = (column2, _expression, operator, query, _attributesToColumns, _primaryKey, _tableName, _allowedColumns) => {
197
- switch (operator.operator) {
198
- case ":":
199
- case ":=":
200
- case ":<=":
201
- case ":>=":
202
- query.where((sub) => {
203
- sub.whereNull(column2);
204
- sub.orWhere(column2, "=", "");
223
+ }
224
+ applyLuceneTagAst(ast, query) {
225
+ const { expression, field, operator } = ast;
226
+ switch (field.type) {
227
+ case "ImplicitField":
228
+ this.applyLuceneImplicitFieldAst(field, expression, operator, query);
229
+ break;
230
+ case "Field":
231
+ this.applyLuceneFieldAst(field, expression, operator, query);
232
+ break;
233
+ }
234
+ }
235
+ applyLuceneImplicitFieldAst(_field, expression, operator, query) {
236
+ const searchableColumns = __privateMethod(this, _LuceneLucidQueryBuilder_instances, getSearchableColumns_fn).call(this);
237
+ const defaultOperator = operator || {
238
+ operator: ":",
239
+ type: "ComparisonOperator",
240
+ location: { start: 0, end: 0 }
241
+ };
242
+ searchableColumns.forEach((columnName) => {
243
+ const fakeField = {
244
+ name: columnName,
245
+ type: "Field",
246
+ location: { start: 0, end: 0 },
247
+ quoted: false
248
+ };
249
+ query.orWhere((s) => {
250
+ this.applyLuceneFieldAst(fakeField, expression, defaultOperator, s);
205
251
  });
206
- break;
252
+ });
207
253
  }
208
- };
209
- const applyLuceneLiteralExpression = (column2, expression, operator, query, _attributesToColumns, _primaryKey, _tableName, _allowedColumns) => {
210
- let value = expression.value;
211
- if (value === null) {
254
+ applyLuceneFieldAst(field, expression, operator, query, forModel) {
255
+ const columnName = !forModel ? __privateGet(this, _attributesToColumns).get(field.name) : forModel.$keys.attributesToColumns.get(field.name);
256
+ if (!columnName || !forModel && __privateGet(this, _allowedColumns) && !__privateGet(this, _allowedColumns).includes(field.name)) {
257
+ if (field.name.includes(".")) {
258
+ const parts = field.name.split(".").filter((p) => "string" === typeof p && p.trim().length > 0).map((p) => p.trim());
259
+ const relationship = parts.shift();
260
+ if (!relationship || parts.length === 0) return;
261
+ this.applyLuceneRelatedFieldAst(
262
+ relationship,
263
+ parts.join("."),
264
+ expression,
265
+ operator,
266
+ query,
267
+ forModel
268
+ );
269
+ }
270
+ return;
271
+ }
272
+ switch (expression.type) {
273
+ case "EmptyExpression":
274
+ this.applyLuceneEmptyExpression(columnName, expression, operator, query);
275
+ break;
276
+ case "LiteralExpression":
277
+ this.applyLuceneLiteralExpression(columnName, expression, operator, query);
278
+ break;
279
+ case "RangeExpression":
280
+ this.applyLuceneRangeExpression(columnName, expression, operator, query);
281
+ break;
282
+ case "RegexExpression":
283
+ this.applyLuceneRegexExpression(columnName, expression, operator, query);
284
+ break;
285
+ }
286
+ }
287
+ applyLuceneRelatedFieldAst(relationship, relatedProperty, expression, operator, query, forModel) {
288
+ if (!forModel && !__privateGet(this, _model)) return;
289
+ const targetModel = forModel || __privateGet(this, _model);
290
+ const lucidRelationshipDefinition = targetModel.$relationsDefinitions.get(relationship);
291
+ if (!lucidRelationshipDefinition) return;
292
+ const sub = lucidRelationshipDefinition.subQuery(__privateGet(this, _connection));
293
+ const relatedField = {
294
+ name: relatedProperty,
295
+ type: "Field",
296
+ location: { start: 0, end: 0 },
297
+ quoted: false
298
+ };
299
+ const relatedModel = lucidRelationshipDefinition.relatedModel();
300
+ this.applyLuceneFieldAst(relatedField, expression, operator, sub, relatedModel);
301
+ query.whereExists(sub.prepare());
302
+ }
303
+ applyLuceneEmptyExpression(column2, _expression, operator, query) {
212
304
  switch (operator.operator) {
213
305
  case ":":
214
306
  case ":=":
307
+ case ":<=":
308
+ case ":>=":
215
309
  query.where((sub) => {
216
310
  sub.whereNull(column2);
217
311
  sub.orWhere(column2, "=", "");
218
- sub.orWhere(column2, "=", 0);
219
312
  });
220
313
  break;
221
- case ":<":
222
- query.where(column2, "<", 0);
223
- break;
224
- case ":<=":
225
- query.where(column2, "<=", 0);
226
- break;
227
- case ":>":
228
- query.where(column2, ">", 0);
229
- break;
230
- case ":>=":
231
- query.where(column2, ">=", 0);
232
- break;
233
314
  }
234
- return;
235
315
  }
236
- if ("string" === typeof value && expression.quoted) {
237
- if (expression.quotes === "double") {
238
- value = value.replace(/^"/g, "").replace(/"$/g, "");
239
- } else if (expression.quotes === "single") {
240
- value = value.replace(/^'/g, "").replace(/'$/g, "");
241
- }
242
- }
243
- switch (typeof value) {
244
- case "string":
316
+ applyLuceneLiteralExpression(column2, expression, operator, query) {
317
+ let value = expression.value;
318
+ let isCaseSensitive = false;
319
+ if (value === null) {
245
320
  switch (operator.operator) {
246
321
  case ":":
247
322
  case ":=":
248
323
  query.where((sub) => {
249
- sub.where(column2, "=", value);
250
- sub.orWhere(column2, "like", value);
324
+ sub.whereNull(column2);
325
+ sub.orWhere(column2, "=", "");
326
+ sub.orWhere(column2, "=", 0);
251
327
  });
252
328
  break;
253
329
  case ":<":
254
- query.where(column2, "<", value);
330
+ query.where(column2, "<", 0);
255
331
  break;
256
332
  case ":<=":
257
- query.where(column2, "<=", value);
333
+ query.where(column2, "<=", 0);
258
334
  break;
259
335
  case ":>":
260
- query.where(column2, ">", value);
336
+ query.where(column2, ">", 0);
261
337
  break;
262
338
  case ":>=":
263
- query.where(column2, ">=", value);
339
+ query.where(column2, ">=", 0);
264
340
  break;
265
341
  }
266
- break;
267
- case "number":
268
- switch (operator.operator) {
269
- case ":":
270
- case ":=":
271
- query.where(column2, "=", value);
272
- break;
273
- case ":<":
274
- query.where(column2, "<", value);
275
- break;
276
- case ":<=":
277
- query.where(column2, "<=", value);
278
- break;
279
- case ":>":
280
- query.where(column2, ">", value);
281
- break;
282
- case ":>=":
283
- query.where(column2, ">=", value);
284
- break;
285
- }
286
- break;
287
- case "boolean":
288
- switch (operator.operator) {
289
- case ":":
290
- case ":=":
291
- query.where(column2, "=", value);
292
- break;
293
- case ":<":
294
- query.where(column2, "<", value);
295
- break;
296
- case ":<=":
297
- query.where(column2, "<=", value);
298
- break;
299
- case ":>":
300
- query.where(column2, ">", value);
301
- break;
302
- case ":>=":
303
- query.where(column2, ">=", value);
304
- break;
342
+ return;
343
+ }
344
+ if ("string" === typeof value && expression.quoted) {
345
+ isCaseSensitive = true;
346
+ if (expression.quotes === "double") {
347
+ value = value.replace(/^"/g, "").replace(/"$/g, "");
348
+ } else if (expression.quotes === "single") {
349
+ value = value.replace(/^'/g, "").replace(/'$/g, "");
305
350
  }
306
- break;
307
- }
308
- };
309
- const applyLuceneRangeExpression = (column2, expression, operator, query, _attributesToColumns, _primaryKey, _tableName, _allowedColumns) => {
310
- const comparableMin = expression.range.minInclusive ? expression.range.min : expression.range.min + 1;
311
- const comparableMax = expression.range.maxInclusive ? expression.range.max : expression.range.max - 1;
312
- switch (operator.operator) {
313
- case ":":
314
- case ":=":
315
- query.whereBetween(column2, [comparableMin, comparableMax]);
316
- break;
317
- }
318
- };
319
- const applyLuceneRegexExpression = (column2, expression, operator, query, _attributesToColumns, _primaryKey, _tableName, _allowedColumns) => {
320
- let value = expression.value;
321
- value = value.replace(/%/g, "\\%").replace(/_/g, "\\_");
322
- value = value.replace(/\*/g, "%").replace(/\?/g, "_");
323
- switch (operator.operator) {
324
- case ":":
325
- case ":=":
326
- query.whereLike(column2, value);
327
- break;
328
- }
329
- };
330
- const applyLuceneImplicitFieldAst = (_field, expression, operator, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
331
- const columnName = primaryKey;
332
- if (allowedColumns && !allowedColumns.includes(columnName)) {
333
- return;
334
- }
335
- const defaultOperator = operator || {
336
- operator: ":"
337
- };
338
- switch (expression.type) {
339
- case "EmptyExpression":
340
- applyLuceneEmptyExpression(
341
- columnName,
342
- expression,
343
- defaultOperator,
344
- query
345
- );
346
- break;
347
- case "LiteralExpression":
348
- applyLuceneLiteralExpression(
349
- columnName,
350
- expression,
351
- defaultOperator,
352
- query
353
- );
354
- break;
355
- case "RangeExpression":
356
- applyLuceneRangeExpression(
357
- columnName,
358
- expression,
359
- defaultOperator,
360
- query
361
- );
362
- break;
363
- case "RegexExpression":
364
- applyLuceneRegexExpression(
365
- columnName,
366
- expression,
367
- defaultOperator,
368
- query
369
- );
370
- break;
371
- }
372
- };
373
- const applyLuceneFieldAst = (field, expression, operator, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
374
- const columnName = attributesToColumns.get(field.name);
375
- if (!columnName || allowedColumns && !allowedColumns.includes(field.name)) {
376
- return;
377
- }
378
- switch (expression.type) {
379
- case "EmptyExpression":
380
- applyLuceneEmptyExpression(
381
- columnName,
382
- expression,
383
- operator,
384
- query
385
- );
386
- break;
387
- case "LiteralExpression":
388
- applyLuceneLiteralExpression(
389
- columnName,
390
- expression,
391
- operator,
392
- query
393
- );
394
- break;
395
- case "RangeExpression":
396
- applyLuceneRangeExpression(
397
- columnName,
398
- expression,
399
- operator,
400
- query
401
- );
402
- break;
403
- case "RegexExpression":
404
- applyLuceneRegexExpression(
405
- columnName,
406
- expression,
407
- operator,
408
- query
409
- );
410
- break;
351
+ }
352
+ switch (typeof value) {
353
+ case "string":
354
+ switch (operator.operator) {
355
+ case ":":
356
+ case ":=":
357
+ if (value.includes("*") || value.includes("?")) {
358
+ let likeValue = value.replace(/%/g, "\\%").replace(/_/g, "\\_");
359
+ likeValue = likeValue.replace(/\*/g, "%").replace(/\?/g, "_");
360
+ if (isCaseSensitive) {
361
+ query.whereLike(column2, likeValue);
362
+ } else {
363
+ query.if(
364
+ ["postgres", "pg"].includes(__privateGet(this, _dialect)),
365
+ (q) => {
366
+ q.whereILike(column2, likeValue);
367
+ },
368
+ (q) => {
369
+ q.whereLike(column2, likeValue);
370
+ }
371
+ );
372
+ }
373
+ } else {
374
+ query.where((sub) => {
375
+ if (isCaseSensitive) {
376
+ sub.where(column2, "=", value);
377
+ } else {
378
+ query.if(
379
+ ["postgres", "pg"].includes(__privateGet(this, _dialect)),
380
+ () => {
381
+ sub.orWhereILike(column2, value);
382
+ },
383
+ () => {
384
+ sub.whereLike(column2, value);
385
+ }
386
+ );
387
+ }
388
+ });
389
+ }
390
+ break;
391
+ case ":<":
392
+ query.where(column2, "<", value);
393
+ break;
394
+ case ":<=":
395
+ query.where(column2, "<=", value);
396
+ break;
397
+ case ":>":
398
+ query.where(column2, ">", value);
399
+ break;
400
+ case ":>=":
401
+ query.where(column2, ">=", value);
402
+ break;
403
+ }
404
+ break;
405
+ case "number":
406
+ switch (operator.operator) {
407
+ case ":":
408
+ case ":=":
409
+ query.where(column2, "=", value);
410
+ break;
411
+ case ":<":
412
+ query.where(column2, "<", value);
413
+ break;
414
+ case ":<=":
415
+ query.where(column2, "<=", value);
416
+ break;
417
+ case ":>":
418
+ query.where(column2, ">", value);
419
+ break;
420
+ case ":>=":
421
+ query.where(column2, ">=", value);
422
+ break;
423
+ }
424
+ break;
425
+ case "boolean":
426
+ switch (operator.operator) {
427
+ case ":":
428
+ case ":=":
429
+ query.where(column2, "=", value);
430
+ break;
431
+ case ":<":
432
+ query.where(column2, "<", value);
433
+ break;
434
+ case ":<=":
435
+ query.where(column2, "<=", value);
436
+ break;
437
+ case ":>":
438
+ query.where(column2, ">", value);
439
+ break;
440
+ case ":>=":
441
+ query.where(column2, ">=", value);
442
+ break;
443
+ }
444
+ break;
445
+ }
411
446
  }
412
- };
413
- const applyLuceneTagAst = (ast, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
414
- const { expression, field, operator } = ast;
415
- switch (field.type) {
416
- case "ImplicitField":
417
- applyLuceneImplicitFieldAst(
418
- field,
419
- expression,
420
- operator,
421
- query,
422
- attributesToColumns,
423
- primaryKey,
424
- tableName,
425
- allowedColumns
426
- );
427
- break;
428
- case "Field":
429
- applyLuceneFieldAst(
430
- field,
431
- expression,
432
- operator,
433
- query,
434
- attributesToColumns,
435
- primaryKey,
436
- tableName,
437
- allowedColumns
438
- );
439
- break;
447
+ applyLuceneRangeExpression(column2, expression, operator, query) {
448
+ const comparableMin = expression.range.minInclusive ? expression.range.min : expression.range.min + 1;
449
+ const comparableMax = expression.range.maxInclusive ? expression.range.max : expression.range.max - 1;
450
+ switch (operator.operator) {
451
+ case ":":
452
+ case ":=":
453
+ query.whereBetween(column2, [comparableMin, comparableMax]);
454
+ break;
455
+ }
440
456
  }
441
- };
442
- const applyLuceneUnaryOperatorAst = (ast, query, attributesToColumns, primaryKey, tableName, allowedColumns) => {
443
- const operator = ast.operator;
444
- if (operator === "NOT" || operator === "-") {
445
- query.whereNot((subQuery) => {
446
- applyLuceneAst(
447
- ast.operand,
448
- subQuery,
449
- attributesToColumns,
450
- primaryKey,
451
- tableName,
452
- allowedColumns
453
- );
454
- });
455
- } else {
456
- query.where((subQuery) => {
457
- applyLuceneAst(
458
- ast.operand,
459
- subQuery,
460
- attributesToColumns,
461
- primaryKey,
462
- tableName,
463
- allowedColumns
464
- );
465
- });
457
+ applyLuceneRegexExpression(column2, expression, operator, query) {
458
+ let value = expression.value;
459
+ switch (__privateGet(this, _dialect)) {
460
+ case "mysql":
461
+ case "mariadb":
462
+ switch (operator.operator) {
463
+ case ":":
464
+ case ":=":
465
+ query.whereRaw(`?? REGEXP ?`, [column2, value]);
466
+ break;
467
+ }
468
+ break;
469
+ case "pg":
470
+ case "postgres":
471
+ switch (operator.operator) {
472
+ case ":":
473
+ case ":=":
474
+ query.whereRaw(`?? ~ ?`, [column2, value]);
475
+ break;
476
+ }
477
+ break;
478
+ case "oracle":
479
+ case "oracledb":
480
+ case "tedious":
481
+ case "mssql":
482
+ switch (operator.operator) {
483
+ case ":":
484
+ case ":=":
485
+ query.whereRaw(`REGEXP_LIKE(??, ?)`, [column2, value]);
486
+ break;
487
+ }
488
+ break;
489
+ case "sqlite3":
490
+ case "better-sqlite3":
491
+ throw new errors.E_LUCENE_REGEX_NOT_SUPPORTED();
492
+ default:
493
+ value = value.replace(/%/g, "\\%").replace(/_/g, "\\_");
494
+ value = value.replace(/\*/g, "%").replace(/\?/g, "_");
495
+ switch (operator.operator) {
496
+ case ":":
497
+ case ":=":
498
+ query.whereLike(column2, value);
499
+ break;
500
+ }
501
+ break;
502
+ }
466
503
  }
467
- };
468
- const applyLuceneAst = (ast, query, attributesToColumns, primaryKey, tableName, allowedColumns, throwOnInvalidType = false) => {
469
- switch (ast.type) {
470
- case "EmptyExpression":
471
- break;
472
- case "LogicalExpression":
473
- applyLuceneLogicalExpressionAst(
474
- ast,
475
- query,
476
- attributesToColumns,
477
- primaryKey,
478
- tableName,
479
- allowedColumns
480
- );
481
- break;
482
- case "ParenthesizedExpression":
483
- applyLuceneParenthesizedExpressionAst(
484
- ast,
485
- query,
486
- attributesToColumns,
487
- primaryKey,
488
- tableName,
489
- allowedColumns
490
- );
491
- break;
492
- case "Tag":
493
- applyLuceneTagAst(ast, query, attributesToColumns, primaryKey, tableName, allowedColumns);
494
- break;
495
- case "UnaryOperator":
496
- applyLuceneUnaryOperatorAst(
497
- ast,
498
- query,
499
- attributesToColumns,
500
- primaryKey,
501
- tableName,
502
- allowedColumns
503
- );
504
- break;
505
- default:
506
- if (throwOnInvalidType) {
507
- throw new errors.E_LUCENE_INVALID_TYPE(ast.type);
504
+ static get(luceneQuery, connection, attributesToColumns, primaryKey, tableName, allowedColumns, model) {
505
+ let parsed;
506
+ try {
507
+ parsed = liqe.parse(luceneQuery);
508
+ } catch (error) {
509
+ if (error instanceof liqe.SyntaxError) {
510
+ throw new errors.E_LUCENE_SYNTAX_EXCEPTION(luceneQuery, error);
508
511
  }
509
- break;
512
+ throw new errors.E_LUCENE_UNEXPECTED_EXCEPTION(error);
513
+ }
514
+ const query = connection.query().from(tableName);
515
+ const builder = new _LuceneLucidQueryBuilder(
516
+ connection,
517
+ query,
518
+ attributesToColumns,
519
+ primaryKey,
520
+ tableName,
521
+ allowedColumns,
522
+ model
523
+ );
524
+ builder.applyLuceneAst(parsed, query, true);
525
+ return query;
510
526
  }
511
527
  };
512
- const luceneToLucid = (luceneQuery, connection, attributesToColumns, primaryKey, tableName, allowedColumns) => {
513
- let parsed;
514
- try {
515
- parsed = liqe.parse(luceneQuery);
516
- } catch (error) {
517
- if (error instanceof liqe.SyntaxError) {
518
- throw new errors.E_LUCENE_SYNTAX_EXCEPTION(error);
528
+ _attributesToColumns = new WeakMap();
529
+ _allowedColumns = new WeakMap();
530
+ _connection = new WeakMap();
531
+ _dialect = new WeakMap();
532
+ _primaryKey = new WeakMap();
533
+ _tableName = new WeakMap();
534
+ _model = new WeakMap();
535
+ _LuceneLucidQueryBuilder_instances = new WeakSet();
536
+ getSearchableColumns_fn = function() {
537
+ if (__privateGet(this, _model) && "$resourcefulColumns" in __privateGet(this, _model) && __privateGet(this, _model).$resourcefulColumns instanceof Map) {
538
+ const modelFields = [];
539
+ __privateGet(this, _model).$resourcefulColumns.forEach((_c2, k) => {
540
+ modelFields.push(k);
541
+ });
542
+ if ("$resourcefulRelationships" in __privateGet(this, _model) && __privateGet(this, _model).$resourcefulRelationships instanceof Map) {
543
+ __privateGet(this, _model).$resourcefulRelationships.forEach((_r, k) => {
544
+ modelFields.push(k);
545
+ });
519
546
  }
520
- throw new errors.E_LUCENE_UNEXPECTED_EXCEPTION(error);
547
+ return Array.from(new Set(modelFields)).filter(
548
+ (f) => !__privateGet(this, _allowedColumns) || __privateGet(this, _allowedColumns).includes(f)
549
+ );
521
550
  }
522
- const query = connection.query().from(tableName);
523
- applyLuceneAst(parsed, query, attributesToColumns, primaryKey, tableName, allowedColumns, true);
524
- return query;
551
+ return Object.entries(__privateGet(this, _attributesToColumns).all()).filter(([attr]) => !__privateGet(this, _allowedColumns) || __privateGet(this, _allowedColumns).includes(attr)).map(([, column2]) => column2);
552
+ };
553
+ let LuceneLucidQueryBuilder = _LuceneLucidQueryBuilder;
554
+ const luceneToLucid = (luceneQuery, connection, attributesToColumns, primaryKey, tableName, allowedColumns, model) => {
555
+ return LuceneLucidQueryBuilder.get(
556
+ luceneQuery,
557
+ connection,
558
+ attributesToColumns,
559
+ primaryKey,
560
+ tableName,
561
+ allowedColumns,
562
+ model
563
+ );
525
564
  };
526
565
  var o = Object.defineProperty;
527
566
  var a = (t, s, r) => s in t ? o(t, s, { enumerable: true, configurable: true, writable: true, value: r }) : t[s] = r;
@@ -589,9 +628,388 @@ class l {
589
628
  ) : this.e[s] = []), this;
590
629
  }
591
630
  }
631
+ class OpenApiSchemaService {
632
+ constructor() {
633
+ __privateAdd(this, _OpenApiSchemaService_instances);
634
+ }
635
+ /**
636
+ * Generates a complete OpenAPI schema object for a resourceful model.
637
+ *
638
+ * This method creates a comprehensive OpenAPI v3 schema representation of the model
639
+ * by processing the provided metadata schema. The metadata should already have
640
+ * field-level access control permissions evaluated for the given request context.
641
+ *
642
+ * @param resourcefulModelMetaSchema - The resourceful model metadata with ACL filtering applied
643
+ * @returns Complete OpenAPI schema object
644
+ *
645
+ * @example
646
+ * ```typescript
647
+ * const service = new OpenApiSchemaService()
648
+ * const schema = service.generateModelSchema(metaSchema)
649
+ * // Returns complete OpenAPI schema with accessible fields only
650
+ * ```
651
+ */
652
+ /* istanbul ignore next -- @preserve */
653
+ generateModelSchema(operation = "read", resourcefulModelMetaSchema, model) {
654
+ if (!errors.isObject(resourcefulModelMetaSchema) || !resourcefulModelMetaSchema.name || !decorator_utils.isResourcefulModel(model)) {
655
+ return {
656
+ type: "object",
657
+ properties: {},
658
+ required: []
659
+ };
660
+ }
661
+ const schema = {
662
+ type: "object",
663
+ title: resourcefulModelMetaSchema.name,
664
+ description: resourcefulModelMetaSchema.description,
665
+ externalDocs: resourcefulModelMetaSchema.externalDocs,
666
+ example: resourcefulModelMetaSchema.example,
667
+ properties: {}
668
+ };
669
+ /* istanbul ignore next -- @preserve */
670
+ Object.entries(resourcefulModelMetaSchema.properties).forEach(([propertyKey, propertyMeta]) => {
671
+ const resolvedColumnName = __privateMethod(this, _OpenApiSchemaService_instances, getFieldKey_fn).call(this, propertyKey, propertyMeta.lucidDefinitions);
672
+ if (null === resolvedColumnName) {
673
+ return;
674
+ }
675
+ switch (propertyMeta.kind) {
676
+ case "column": {
677
+ schema.properties[propertyKey] = this.generateColumnSchema(
678
+ propertyKey,
679
+ propertyMeta
680
+ );
681
+ return;
682
+ }
683
+ case "computedAccessor": {
684
+ schema.properties[propertyKey] = this.generateComputedAccessorSchema(
685
+ propertyKey,
686
+ propertyMeta
687
+ );
688
+ return;
689
+ }
690
+ case "relationship": {
691
+ const relatedSchema = this.generateRelationshipSchema(
692
+ propertyKey,
693
+ propertyMeta
694
+ );
695
+ if (relatedSchema) {
696
+ schema.properties[propertyKey] = relatedSchema;
697
+ }
698
+ return;
699
+ }
700
+ }
701
+ });
702
+ const requiredPropSet = /* @__PURE__ */ new Set();
703
+ Object.entries(schema.properties).forEach(([propertyKey, propertySchema]) => {
704
+ if (!errors.isObject(propertySchema) || "$ref" in propertySchema) {
705
+ return;
706
+ }
707
+ const isNullable = propertySchema.nullable === true;
708
+ if (!isNullable && ("read" === operation || !model.$resourcefulComputedAccessors.has(propertyKey) && !model.$resourcefulRelationships.has(propertyKey))) {
709
+ requiredPropSet.add(propertyKey);
710
+ }
711
+ });
712
+ schema.required = Array.from(requiredPropSet);
713
+ return schema;
714
+ }
715
+ /**
716
+ * Generates OpenAPI schema for a column property.
717
+ *
718
+ * This method converts resourceful column metadata into an OpenAPI schema object,
719
+ * properly extracting data type information and preserving all existing schema
720
+ * properties such as validation constraints, nullability, and access modifiers.
721
+ *
722
+ * @param propertyKey - The name of the column property
723
+ * @param propertyMeta - The resourceful metadata for the column
724
+ * @returns OpenAPI schema object for the column
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * const service = new OpenApiSchemaService()
729
+ * const schema = service.generateColumnSchema('name', columnMeta)
730
+ * // Returns: { type: 'string', minLength: 1, maxLength: 100, ... }
731
+ * ```
732
+ */
733
+ generateColumnSchema(propertyKey, propertyMeta) {
734
+ if (!errors.isObject(propertyMeta) || !propertyMeta.definition || !propertyMeta.lucidDefinitions) {
735
+ return {};
736
+ }
737
+ const dataTypeInfo = __privateMethod(this, _OpenApiSchemaService_instances, extractDataTypeInfo_fn).call(this, propertyMeta.definition.type);
738
+ const fieldKey = __privateMethod(this, _OpenApiSchemaService_instances, getFieldKey_fn).call(this, propertyKey, propertyMeta.lucidDefinitions);
739
+ const dataType = propertyMeta.definition.type;
740
+ const definition = propertyMeta.definition;
741
+ /* istanbul ignore next -- @preserve */
742
+ const schemaProperties = errors.stripUndefinedValuesFromObject({
743
+ // Core OpenAPI type information (properly extracted)
744
+ type: dataTypeInfo.type,
745
+ format: dataTypeInfo.format,
746
+ // Schema metadata
747
+ items: definition.items || dataType.items,
748
+ title: fieldKey || propertyKey,
749
+ description: definition.description,
750
+ default: "default" in definition ? definition.default : this.getDefaultValueFromPropertyMeta(propertyMeta),
751
+ // Numeric constraints (from data type or definition)
752
+ multipleOf: definition.multipleOf || dataType.multipleOf,
753
+ maximum: definition.maximum || dataType.maximum,
754
+ exclusiveMaximum: definition.exclusiveMaximum || dataType.exclusiveMaximum,
755
+ minimum: definition.minimum || dataType.minimum,
756
+ exclusiveMinimum: definition.exclusiveMinimum || dataType.exclusiveMinimum,
757
+ // String constraints (from data type or definition)
758
+ maxLength: definition.maxLength || dataType.maxLength,
759
+ minLength: definition.minLength || dataType.minLength,
760
+ pattern: definition.pattern || dataType.pattern,
761
+ // Object constraints (from data type or definition)
762
+ additionalProperties: definition.additionalProperties || dataType.additionalProperties,
763
+ maxProperties: definition.maxProperties || dataType.maxProperties,
764
+ minProperties: definition.minProperties || dataType.minProperties,
765
+ properties: definition.properties || dataType.properties,
766
+ // Array constraints (from data type or definition)
767
+ maxItems: definition.maxItems || dataType.maxItems,
768
+ minItems: definition.minItems || dataType.minItems,
769
+ uniqueItems: definition.uniqueItems || dataType.uniqueItems,
770
+ // Schema composition (from data type or definition)
771
+ allOf: definition.allOf || dataType.allOf,
772
+ oneOf: definition.oneOf || dataType.oneOf,
773
+ anyOf: definition.anyOf || dataType.anyOf,
774
+ not: definition.not || dataType.not,
775
+ // Validation and constraints (from data type or definition)
776
+ required: definition.required || dataType.required,
777
+ enum: definition.enum || dataType.enum,
778
+ nullable: definition.nullable !== void 0 ? definition.nullable : dataType.nullable || false,
779
+ // Access control
780
+ readOnly: propertyMeta.canRead && !propertyMeta.canWrite,
781
+ writeOnly: !propertyMeta.canRead && propertyMeta.canWrite,
782
+ // Documentation
783
+ externalDocs: definition.externalDocs,
784
+ example: definition.example
785
+ });
786
+ return schemaProperties;
787
+ }
788
+ /**
789
+ * Generates OpenAPI schema for a computed accessor property.
790
+ *
791
+ * This method converts resourceful computed accessor metadata into an OpenAPI
792
+ * schema object, applying the same data type extraction improvements as column
793
+ * schema generation while maintaining all existing functionality.
794
+ *
795
+ * @param propertyKey - The name of the computed accessor property
796
+ * @param propertyMeta - The resourceful metadata for the computed accessor
797
+ * @returns OpenAPI schema object for the computed accessor
798
+ *
799
+ * @example
800
+ * ```typescript
801
+ * const service = new OpenApiSchemaService()
802
+ * const schema = service.generateComputedAccessorSchema('fullName', accessorMeta)
803
+ * // Returns: { type: 'string', readOnly: true, ... }
804
+ * ```
805
+ */
806
+ generateComputedAccessorSchema(propertyKey, propertyMeta) {
807
+ if (!errors.isObject(propertyMeta) || !propertyMeta.definition || !propertyMeta.lucidDefinitions) {
808
+ return {};
809
+ }
810
+ const dataTypeInfo = __privateMethod(this, _OpenApiSchemaService_instances, extractDataTypeInfo_fn).call(this, propertyMeta.definition.type);
811
+ const fieldKey = __privateMethod(this, _OpenApiSchemaService_instances, getFieldKey_fn).call(this, propertyKey, propertyMeta.lucidDefinitions);
812
+ const dataType = propertyMeta.definition.type;
813
+ const definition = propertyMeta.definition;
814
+ /* istanbul ignore next -- @preserve */
815
+ const schemaProperties = errors.stripUndefinedValuesFromObject({
816
+ // Core OpenAPI type information (properly extracted)
817
+ type: dataTypeInfo.type,
818
+ format: dataTypeInfo.format,
819
+ // Schema metadata
820
+ items: definition.items || dataType.items,
821
+ title: fieldKey || propertyKey,
822
+ description: definition.description,
823
+ default: "default" in definition ? definition.default : this.getDefaultValueFromPropertyMeta(propertyMeta),
824
+ // Numeric constraints (from data type or definition)
825
+ multipleOf: definition.multipleOf || dataType.multipleOf,
826
+ maximum: definition.maximum || dataType.maximum,
827
+ exclusiveMaximum: definition.exclusiveMaximum || dataType.exclusiveMaximum,
828
+ minimum: definition.minimum || dataType.minimum,
829
+ exclusiveMinimum: definition.exclusiveMinimum || dataType.exclusiveMinimum,
830
+ // String constraints (from data type or definition)
831
+ maxLength: definition.maxLength || dataType.maxLength,
832
+ minLength: definition.minLength || dataType.minLength,
833
+ pattern: definition.pattern || dataType.pattern,
834
+ // Object constraints (from data type or definition)
835
+ additionalProperties: definition.additionalProperties || dataType.additionalProperties,
836
+ maxProperties: definition.maxProperties || dataType.maxProperties,
837
+ minProperties: definition.minProperties || dataType.minProperties,
838
+ properties: definition.properties || dataType.properties,
839
+ // Array constraints (from data type or definition)
840
+ maxItems: definition.maxItems || dataType.maxItems,
841
+ minItems: definition.minItems || dataType.minItems,
842
+ uniqueItems: definition.uniqueItems || dataType.uniqueItems,
843
+ // Schema composition (from data type or definition)
844
+ allOf: definition.allOf || dataType.allOf,
845
+ oneOf: definition.oneOf || dataType.oneOf,
846
+ anyOf: definition.anyOf || dataType.anyOf,
847
+ not: definition.not || dataType.not,
848
+ // Validation and constraints (from data type or definition)
849
+ required: definition.required || dataType.required,
850
+ enum: definition.enum || dataType.enum,
851
+ nullable: definition.nullable !== void 0 ? definition.nullable : dataType.nullable || false,
852
+ // Access control
853
+ readOnly: propertyMeta.canRead && !propertyMeta.canWrite,
854
+ writeOnly: !propertyMeta.canRead && propertyMeta.canWrite,
855
+ // Documentation
856
+ externalDocs: definition.externalDocs,
857
+ example: definition.example
858
+ });
859
+ return schemaProperties;
860
+ }
861
+ /**
862
+ * Generates OpenAPI schema for a relationship property.
863
+ *
864
+ * This method converts resourceful relationship metadata into an OpenAPI
865
+ * reference object, preserving existing relationship reference generation
866
+ * logic and ensuring proper handling of related model references.
867
+ *
868
+ * @param propertyKey - The name of the relationship property
869
+ * @param propertyMeta - The resourceful metadata for the relationship
870
+ * @returns OpenAPI reference object for the relationship, or undefined if not applicable
871
+ *
872
+ * @example
873
+ * ```typescript
874
+ * const service = new OpenApiSchemaService()
875
+ * const schema = service.generateRelationshipSchema('user', relationshipMeta)
876
+ * // Returns: { $ref: '#/components/schemas/User' }
877
+ * ```
878
+ */
879
+ generateRelationshipSchema(_propertyKey, propertyMeta) {
880
+ if (!errors.isObject(propertyMeta) || !propertyMeta.definition || !propertyMeta.lucidDefinitions || !propertyMeta.relatedModel) {
881
+ return void 0;
882
+ }
883
+ const relatedModel = propertyMeta.relatedModel();
884
+ /* istanbul ignore if -- @preserve */
885
+ if (!relatedModel) {
886
+ return void 0;
887
+ }
888
+ /* istanbul ignore if -- @preserve */
889
+ if (!decorator_utils.isResourcefulModel(relatedModel)) {
890
+ return void 0;
891
+ }
892
+ const ref2 = `#/components/schemas/${relatedModel.$resourcefulName}`;
893
+ return {
894
+ $ref: ref2
895
+ };
896
+ }
897
+ /**
898
+ * Extracts default value from property metadata using Joi description.
899
+ *
900
+ * This protected method provides access to the default value extraction logic
901
+ * that was previously part of the mixin. It examines the Joi validator
902
+ * description to find default values specified in the schema.
903
+ *
904
+ * @param propertyMeta - The resourceful metadata containing the validator
905
+ * @returns The default value if found, undefined otherwise
906
+ *
907
+ * @example
908
+ * ```typescript
909
+ * const service = new OpenApiSchemaService()
910
+ * const defaultValue = service.getDefaultValueFromPropertyMeta(propertyMeta)
911
+ * ```
912
+ */
913
+ getDefaultValueFromPropertyMeta(propertyMeta) {
914
+ const joiDescription = propertyMeta.validator.describe();
915
+ /* istanbul ignore if -- @preserve */
916
+ if (errors.isObject(joiDescription) && "flags" in joiDescription && errors.isObject(joiDescription.flags) && "default" in joiDescription.flags) {
917
+ return joiDescription.flags.default;
918
+ }
919
+ /* istanbul ignore next -- @preserve */
920
+ return void 0;
921
+ }
922
+ }
923
+ _OpenApiSchemaService_instances = new WeakSet();
924
+ /**
925
+ * Gets the field key for a property, handling serializeAs transformation.
926
+ *
927
+ * This private method extracts the appropriate field name for a property,
928
+ * taking into account the serializeAs option from Lucid model definitions.
929
+ * Returns null if the field cannot be read (following Lucid's serializeAs behavior).
930
+ *
931
+ * @param key - The original property key
932
+ * @param definition - The Lucid model definition (column, computed, or relation)
933
+ * @returns The field key to use, the original key if no transformation is needed, or null if field cannot be read
934
+ */
935
+ getFieldKey_fn = function(key, definition) {
936
+ if (definition.serializeAs === null) {
937
+ return null;
938
+ }
939
+ /* istanbul ignore if -- @preserve */
940
+ if (errors.isString(definition.serializeAs)) {
941
+ return definition.serializeAs;
942
+ }
943
+ /* istanbul ignore next -- @preserve */
944
+ return key;
945
+ };
946
+ /**
947
+ * Extracts OpenAPI type and format information from resourceful data types.
948
+ *
949
+ * This private method handles the mapping from resourceful data type instances
950
+ * to their corresponding OpenAPI type and format specifications. It properly
951
+ * handles all supported resourceful data types and provides appropriate
952
+ * fallback behavior for unknown types.
953
+ *
954
+ * @param dataType - The resourceful data type instance to extract information from
955
+ * @returns Object containing the OpenAPI type and optional format
956
+ *
957
+ * @example
958
+ * ```typescript
959
+ * const info = this.#extractDataTypeInfo(ResourcefulStringType())
960
+ * // Returns: { type: 'string' }
961
+ *
962
+ * const info = this.#extractDataTypeInfo(ResourcefulDateTimeType())
963
+ * // Returns: { type: 'string', format: 'date-time' }
964
+ * ```
965
+ */
966
+ extractDataTypeInfo_fn = function(dataType) {
967
+ let baseType;
968
+ try {
969
+ baseType = dataType.type;
970
+ } catch (error) {
971
+ /* istanbul ignore next -- @preserve */
972
+ return { type: "string" };
973
+ }
974
+ const format = "format" in dataType && typeof dataType.format === "string" ? dataType.format : void 0;
975
+ /* istanbul ignore next -- @preserve */
976
+ switch (baseType) {
977
+ case "string": {
978
+ if (format) {
979
+ return { type: "string", format };
980
+ }
981
+ return { type: "string" };
982
+ }
983
+ case "number": {
984
+ if (format === "float" || format === "double") {
985
+ return { type: "number", format };
986
+ }
987
+ return { type: "number" };
988
+ }
989
+ case "integer": {
990
+ if (format === "int32" || format === "int64") {
991
+ return { type: "integer", format };
992
+ }
993
+ return { type: "integer" };
994
+ }
995
+ case "boolean": {
996
+ return { type: "boolean" };
997
+ }
998
+ case "object": {
999
+ return { type: "object" };
1000
+ }
1001
+ case "array": {
1002
+ return { type: "array" };
1003
+ }
1004
+ default: {
1005
+ /* istanbul ignore next -- @preserve */
1006
+ return { type: "string" };
1007
+ }
1008
+ }
1009
+ };
592
1010
  const ResourcefulErrorHandlerMethod = ["bubble", "pass", "fail"];
593
1011
  const getFieldKey = (key, definition) => {
594
- if (decorator_utils.isString(definition.serializeAs)) {
1012
+ if (errors.isString(definition.serializeAs)) {
595
1013
  return definition.serializeAs;
596
1014
  }
597
1015
  return key;
@@ -614,6 +1032,10 @@ function withResourceful(options = {}) {
614
1032
  list: joi.joi.array().items(joi.joi.function()).default([]),
615
1033
  access: joi.joi.array().items(joi.joi.function()).default([])
616
1034
  }).default({}),
1035
+ payloadValidationSchemaBuilders: joi.joi.object({
1036
+ create: joi.joi.array().items(joi.joi.function()).default([]),
1037
+ update: joi.joi.array().items(joi.joi.function()).default([])
1038
+ }).default({ create: [], update: [] }),
617
1039
  description: joi.joi.string().optional(),
618
1040
  externalDocs: joi.joi.object({
619
1041
  description: joi.joi.string().optional(),
@@ -672,6 +1094,7 @@ function withResourceful(options = {}) {
672
1094
  Array.from(this.$resourcefulColumns.entries()),
673
1095
  async ([propertyKey, columnDefinition]) => {
674
1096
  const lucidDefinitions = this.$getColumn(propertyKey);
1097
+ /* istanbul ignore if -- @preserve */
675
1098
  if (!lucidDefinitions) return;
676
1099
  const resourcefulModelColumnMetaSchema = {
677
1100
  propertyKey,
@@ -709,6 +1132,7 @@ function withResourceful(options = {}) {
709
1132
  Array.from(this.$resourcefulComputedAccessors.entries()),
710
1133
  async ([propertyKey, computedAccessorDefinition]) => {
711
1134
  const lucidDefinitions = this.$getComputed(propertyKey);
1135
+ /* istanbul ignore if -- @preserve */
712
1136
  if (!lucidDefinitions) return;
713
1137
  const resourcefulModelComputedAccessorMetaSchema = {
714
1138
  propertyKey,
@@ -736,6 +1160,7 @@ function withResourceful(options = {}) {
736
1160
  computedAccessorDefinition.writable
737
1161
  )
738
1162
  };
1163
+ /* istanbul ignore if -- @preserve */
739
1164
  if (!resourcefulModelComputedAccessorMetaSchema.canRead && !resourcefulModelComputedAccessorMetaSchema.canWrite)
740
1165
  return;
741
1166
  resourcefulModelMetaSchema.properties[propertyKey] = resourcefulModelComputedAccessorMetaSchema;
@@ -748,6 +1173,7 @@ function withResourceful(options = {}) {
748
1173
  Array.from(this.$resourcefulRelationships.entries()),
749
1174
  async ([propertyKey, relationshipDefinition]) => {
750
1175
  const lucidDefinitions = this.$getRelation(propertyKey);
1176
+ /* istanbul ignore if -- @preserve */
751
1177
  if (!lucidDefinitions) return;
752
1178
  const resourcefulModelRelationshipMetaSchema = {
753
1179
  propertyKey,
@@ -766,6 +1192,7 @@ function withResourceful(options = {}) {
766
1192
  validator: joi.joi.forbidden(),
767
1193
  relatedModel: relationshipDefinition.relatedModel
768
1194
  };
1195
+ /* istanbul ignore if -- @preserve */
769
1196
  if (!resourcefulModelRelationshipMetaSchema.canRead && !resourcefulModelRelationshipMetaSchema.canWrite)
770
1197
  return;
771
1198
  resourcefulModelMetaSchema.properties[propertyKey] = resourcefulModelRelationshipMetaSchema;
@@ -781,8 +1208,11 @@ function withResourceful(options = {}) {
781
1208
  return joi.joi.any().forbidden();
782
1209
  }
783
1210
  const baseValidator = this.$getPropertyBaseValidator(datatype, nullable, kind, writable);
1211
+ let retValidator = baseValidator;
784
1212
  if (Array.isArray(validationScopes) && validationScopes.length > 0) {
785
1213
  validationScopes.forEach((validationScope) => {
1214
+ /* istanbul ignore if -- @preserve */
1215
+ if (retValidator !== baseValidator) return;
786
1216
  try {
787
1217
  validationScope(baseValidator);
788
1218
  } catch (err) {
@@ -800,12 +1230,13 @@ function withResourceful(options = {}) {
800
1230
  case "pass":
801
1231
  break;
802
1232
  case "fail":
803
- return joi.joi.any().forbidden();
1233
+ retValidator = joi.joi.any().forbidden();
1234
+ break;
804
1235
  }
805
1236
  }
806
1237
  });
807
1238
  }
808
- return baseValidator;
1239
+ return retValidator;
809
1240
  }
810
1241
  static $getPropertyBaseValidator(datatype, nullable, kind, writable = false) {
811
1242
  if ("relationship" === kind || "computedAccessor" === kind && !writable) {
@@ -813,132 +1244,178 @@ function withResourceful(options = {}) {
813
1244
  }
814
1245
  nullable = nullable || "boolean" === typeof datatype.nullable && datatype.nullable;
815
1246
  switch (true) {
816
- case datatype instanceof definitions.ResourcefulStringType: {
817
- const d = datatype;
818
- const r = joi.joi.string().min(d.minLength).max(d.maxLength);
819
- if (d.pattern) {
820
- r.pattern(new RegExp(d.pattern));
821
- }
822
- if (d.enum) {
823
- r.valid(...d.enum);
824
- }
1247
+ case decorator_utils.isResourcefulDateType(datatype): {
1248
+ let r = joi.joi.date().iso();
825
1249
  if (nullable) {
826
- r.allow(null);
1250
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
827
1251
  }
828
1252
  return r;
829
1253
  }
830
- case datatype instanceof definitions.ResourcefulDateType: {
831
- const r = joi.joi.date().iso();
1254
+ case decorator_utils.isResourcefulDateTimeType(datatype): {
1255
+ let r = joi.joi.date().iso();
832
1256
  if (nullable) {
833
- r.allow(null);
1257
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
834
1258
  }
835
1259
  return r;
836
1260
  }
837
- case datatype instanceof definitions.ResourcefulDateTimeType: {
838
- const r = joi.joi.date().iso();
1261
+ case decorator_utils.isResourcefulBinaryType(datatype): {
1262
+ const d = datatype;
1263
+ const min2 = "number" === typeof d.minLength ? Math.abs(d.minLength) : 0;
1264
+ const max2 = "number" === typeof d.maxLength ? Math.abs(d.maxLength) : Number.MAX_SAFE_INTEGER;
1265
+ let r = joi.joi.string().min(min2).max(max2);
839
1266
  if (nullable) {
840
- r.allow(null);
1267
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
841
1268
  }
842
1269
  return r;
843
1270
  }
844
- case datatype instanceof definitions.ResourcefulBinaryType: {
1271
+ case decorator_utils.isResourcefulStringType(datatype): {
845
1272
  const d = datatype;
846
- const r = joi.joi.string();
847
- if (nullable) {
848
- r.allow(null);
1273
+ let r = joi.joi.string().min(d.minLength).max(d.maxLength);
1274
+ if (d.pattern) {
1275
+ r = r.concat(r.pattern(new RegExp(d.pattern)));
849
1276
  }
850
- if (d.minLength !== void 0) {
851
- r.min(d.minLength);
1277
+ if (d.enum) {
1278
+ r = r.concat(joi.joi.string().valid(...d.enum));
852
1279
  }
853
- if (d.maxLength !== void 0) {
854
- r.max(d.maxLength);
1280
+ if (nullable) {
1281
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
855
1282
  }
856
1283
  return r;
857
1284
  }
858
- case datatype instanceof definitions.ResourcefulNumberType: {
1285
+ case decorator_utils.isResourcefulIntegerType(datatype): {
859
1286
  const d = datatype;
860
- const r = joi.joi.number();
861
- if (nullable) {
862
- r.allow(null);
863
- }
864
- r.multiple(d.multipleOf);
1287
+ let r = joi.joi.number();
1288
+ r = r.concat(joi.joi.number().integer().multiple(d.multipleOf));
865
1289
  if (d.exclusiveMaximum) {
866
- r.less(d.maximum);
1290
+ r = r.concat(joi.joi.number().less(d.maximum));
867
1291
  } else {
868
- r.max(d.maximum);
1292
+ r = r.concat(joi.joi.number().max(d.maximum));
869
1293
  }
870
1294
  if (d.exclusiveMinimum) {
871
- r.greater(d.minimum);
1295
+ r = r.concat(joi.joi.number().greater(d.minimum));
872
1296
  } else {
873
- r.min(d.minimum);
1297
+ r = r.concat(joi.joi.number().min(d.minimum));
1298
+ }
1299
+ if (nullable) {
1300
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
874
1301
  }
875
1302
  return r;
876
1303
  }
877
- case datatype instanceof definitions.ResourcefulIntegerType: {
1304
+ case decorator_utils.isResourcefulBigintType(datatype): {
878
1305
  const d = datatype;
879
- const r = joi.joi.number();
880
- if (nullable) {
881
- r.allow(null);
1306
+ if ("undefined" === typeof d.minimum) {
1307
+ d.minimum = 0n;
1308
+ }
1309
+ if ("undefined" === typeof d.maximum) {
1310
+ d.maximum = BigInt(Number.MAX_SAFE_INTEGER);
1311
+ }
1312
+ if ("undefined" === typeof d.multipleOf) {
1313
+ d.multipleOf = 1n;
882
1314
  }
883
- r.integer().multiple(d.multipleOf);
1315
+ let b = joi.joi.bigint();
1316
+ let i = joi.joi.number().integer();
1317
+ b = b.concat(
1318
+ joi.joi.bigint().multiple("number" === typeof d.multipleOf ? BigInt(d.multipleOf) : d.multipleOf)
1319
+ );
1320
+ i = i.concat(
1321
+ joi.joi.number().multiple(
1322
+ "bigint" === typeof d.multipleOf ? Number.parseInt(d.multipleOf.toString()) : d.multipleOf
1323
+ )
1324
+ );
884
1325
  if (d.exclusiveMaximum) {
885
- r.less(d.maximum);
1326
+ if (["number", "bigint"].includes(typeof d.maximum)) {
1327
+ b = b.concat(
1328
+ joi.joi.bigint().less("number" === typeof d.maximum ? BigInt(d.maximum) : d.maximum)
1329
+ );
1330
+ }
1331
+ i = i.concat(
1332
+ joi.joi.number().less(
1333
+ "bigint" === typeof d.maximum ? Number.parseInt(d.maximum.toString()) : d.maximum
1334
+ )
1335
+ );
886
1336
  } else {
887
- r.max(d.maximum);
1337
+ if (["number", "bigint"].includes(typeof d.maximum)) {
1338
+ b = b.concat(
1339
+ joi.joi.bigint().max("number" === typeof d.maximum ? BigInt(d.maximum) : d.maximum)
1340
+ );
1341
+ }
1342
+ i = i.concat(
1343
+ joi.joi.number().max(
1344
+ "bigint" === typeof d.maximum ? Number.parseInt(d.maximum.toString()) : d.maximum
1345
+ )
1346
+ );
888
1347
  }
889
1348
  if (d.exclusiveMinimum) {
890
- r.greater(d.minimum);
1349
+ b = b.concat(
1350
+ joi.joi.bigint().greater("number" === typeof d.minimum ? BigInt(d.minimum) : d.minimum)
1351
+ );
1352
+ i = i.concat(
1353
+ joi.joi.number().greater(
1354
+ "bigint" === typeof d.minimum ? Number.parseInt(d.minimum.toString()) : d.minimum
1355
+ )
1356
+ );
891
1357
  } else {
892
- r.min(d.minimum);
1358
+ b = b.concat(
1359
+ joi.joi.bigint().min("number" === typeof d.minimum ? BigInt(d.minimum) : d.minimum)
1360
+ );
1361
+ i = i.concat(
1362
+ joi.joi.number().min(
1363
+ "bigint" === typeof d.minimum ? Number.parseInt(d.minimum.toString()) : d.minimum
1364
+ )
1365
+ );
1366
+ }
1367
+ let r = joi.joi.alternatives(b, i);
1368
+ if (nullable) {
1369
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
893
1370
  }
894
1371
  return r;
895
1372
  }
896
- case datatype instanceof definitions.ResourcefulBigintType: {
1373
+ case decorator_utils.isResourcefulUnsignedIntegerType(datatype): {
897
1374
  const d = datatype;
898
- const r = joi.joi.bigint();
899
- if (nullable) {
900
- r.allow(null);
901
- }
902
- r.multiple(d.multipleOf);
1375
+ let r = joi.joi.number().unsafe();
1376
+ r = r.concat(joi.joi.number().integer().multiple(d.multipleOf));
903
1377
  if (d.exclusiveMaximum) {
904
- r.less(d.maximum);
1378
+ r = r.concat(joi.joi.number().less(d.maximum));
905
1379
  } else {
906
- r.max(d.maximum);
1380
+ r = r.concat(joi.joi.number().max(d.maximum));
907
1381
  }
908
1382
  if (d.exclusiveMinimum) {
909
- r.greater(d.minimum);
1383
+ r = r.concat(joi.joi.number().greater(d.minimum));
910
1384
  } else {
911
- r.min(d.minimum);
1385
+ r = r.concat(joi.joi.number().min(d.minimum));
1386
+ }
1387
+ if (nullable) {
1388
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
912
1389
  }
913
1390
  return r;
914
1391
  }
915
- case datatype instanceof definitions.ResourcefulUnsignedIntegerType: {
1392
+ case decorator_utils.isResourcefulNumberType(datatype): {
916
1393
  const d = datatype;
917
- const r = joi.joi.number().unsafe();
918
- if (nullable) {
919
- r.allow(null);
920
- }
921
- r.integer().multiple(d.multipleOf);
1394
+ let r = joi.joi.number();
1395
+ r = r.concat(joi.joi.number().multiple(d.multipleOf));
922
1396
  if (d.exclusiveMaximum) {
923
- r.less(d.maximum);
1397
+ r = r.concat(joi.joi.number().less(d.maximum));
924
1398
  } else {
925
- r.max(d.maximum);
1399
+ r = r.concat(joi.joi.number().max(d.maximum));
926
1400
  }
927
1401
  if (d.exclusiveMinimum) {
928
- r.greater(d.minimum);
1402
+ r = r.concat(joi.joi.number().greater(d.minimum));
929
1403
  } else {
930
- r.min(d.minimum);
1404
+ r = r.concat(joi.joi.number().min(d.minimum));
1405
+ }
1406
+ if (nullable) {
1407
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
931
1408
  }
932
1409
  return r;
933
1410
  }
934
- case datatype instanceof definitions.ResourcefulBooleanType: {
935
- const r = joi.joi.boolean();
1411
+ case decorator_utils.isResourcefulBooleanType(datatype): {
1412
+ let r = joi.joi.boolean();
936
1413
  if (nullable) {
937
- r.allow(null);
1414
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
938
1415
  }
939
1416
  return r;
940
1417
  }
941
- case datatype instanceof definitions.ResourcefulObjectType: {
1418
+ case decorator_utils.isResourcefulObjectType(datatype): {
942
1419
  const d = datatype;
943
1420
  const objectSchema = {};
944
1421
  Object.entries(d.properties).forEach(([propKey, propDef]) => {
@@ -952,7 +1429,7 @@ function withResourceful(options = {}) {
952
1429
  !(item.readOnly || false)
953
1430
  )
954
1431
  );
955
- propValidator = joi.joi.alternatives().try(...alternatives);
1432
+ propValidator = joi.joi.alternatives(...alternatives);
956
1433
  } else if ("allOf" in propDef) {
957
1434
  const schemas = propDef.allOf.map(
958
1435
  (item) => this.$getPropertyBaseValidator(
@@ -972,7 +1449,7 @@ function withResourceful(options = {}) {
972
1449
  !(item.readOnly || false)
973
1450
  )
974
1451
  );
975
- propValidator = joi.joi.alternatives().try(...alternatives);
1452
+ propValidator = joi.joi.alternatives(...alternatives);
976
1453
  } else if ("not" in propDef) {
977
1454
  const notSchemas = propDef.not.map(
978
1455
  (item) => this.$getPropertyBaseValidator(
@@ -982,7 +1459,12 @@ function withResourceful(options = {}) {
982
1459
  !(item.readOnly || false)
983
1460
  )
984
1461
  );
985
- propValidator = joi.joi.any().not(...notSchemas);
1462
+ propValidator = joi.joi.any();
1463
+ notSchemas.forEach((notSchema) => {
1464
+ propValidator = propValidator.concat(
1465
+ joi.joi.when(notSchema, { then: joi.joi.forbidden() })
1466
+ );
1467
+ });
986
1468
  } else {
987
1469
  propValidator = this.$getPropertyBaseValidator(
988
1470
  propDef,
@@ -990,44 +1472,46 @@ function withResourceful(options = {}) {
990
1472
  kind,
991
1473
  !(propDef.readOnly || false)
992
1474
  );
1475
+ if (Array.isArray(d.required) && d.required.includes(propKey)) {
1476
+ propValidator = propValidator.concat(joi.joi.any().required());
1477
+ }
993
1478
  }
994
1479
  if (d.required && d.required.includes(propKey)) {
995
1480
  propValidator.required();
996
1481
  }
997
1482
  objectSchema[propKey] = propValidator;
998
1483
  });
999
- const r = joi.joi.object(objectSchema);
1000
- if (nullable) {
1001
- r.allow(null);
1002
- }
1484
+ let r = joi.joi.object(objectSchema);
1003
1485
  if (d.minProperties !== void 0) {
1004
- r.min(d.minProperties);
1486
+ r = r.concat(joi.joi.object().min(d.minProperties));
1005
1487
  }
1006
1488
  if (d.maxProperties !== void 0) {
1007
- r.max(d.maxProperties);
1489
+ r = r.concat(joi.joi.object().max(d.maxProperties));
1008
1490
  }
1009
1491
  if (decorator_utils.isObject(d.additionalProperties)) {
1010
1492
  const additionalPropertiesType = d.additionalProperties;
1011
- r.pattern(
1012
- joi.joi.string(),
1013
- this.$getPropertyBaseValidator(
1014
- additionalPropertiesType,
1015
- additionalPropertiesType.nullable || false,
1016
- kind,
1017
- !(additionalPropertiesType.readOnly || false)
1493
+ r = r.concat(
1494
+ joi.joi.object().pattern(
1495
+ joi.joi.string(),
1496
+ this.$getPropertyBaseValidator(
1497
+ additionalPropertiesType,
1498
+ additionalPropertiesType.nullable || false,
1499
+ kind,
1500
+ !(additionalPropertiesType.readOnly || false)
1501
+ )
1018
1502
  )
1019
1503
  );
1020
1504
  } else {
1021
- r.unknown(true === d.additionalProperties);
1505
+ r = r.concat(joi.joi.object().unknown(true === d.additionalProperties));
1506
+ }
1507
+ if (nullable) {
1508
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
1022
1509
  }
1023
1510
  return r;
1024
1511
  }
1025
- case datatype instanceof definitions.ResourcefulArrayType: {
1512
+ case decorator_utils.isResourcefulArrayType(datatype): {
1026
1513
  const d = datatype;
1027
- const r = joi.joi.array();
1028
- if (nullable) {
1029
- r.allow(null);
1030
- }
1514
+ let r = joi.joi.array();
1031
1515
  let itemValidator;
1032
1516
  if ("oneOf" in d.items) {
1033
1517
  const alternatives = d.items.oneOf.map(
@@ -1038,7 +1522,7 @@ function withResourceful(options = {}) {
1038
1522
  !(item.readOnly || false)
1039
1523
  )
1040
1524
  );
1041
- itemValidator = joi.joi.alternatives().try(...alternatives);
1525
+ itemValidator = joi.joi.alternatives(...alternatives);
1042
1526
  } else if ("allOf" in d.items) {
1043
1527
  const schemas = d.items.allOf.map(
1044
1528
  (item) => this.$getPropertyBaseValidator(
@@ -1058,7 +1542,7 @@ function withResourceful(options = {}) {
1058
1542
  !(item.readOnly || false)
1059
1543
  )
1060
1544
  );
1061
- itemValidator = joi.joi.alternatives().try(...alternatives);
1545
+ itemValidator = joi.joi.alternatives(...alternatives);
1062
1546
  } else if ("not" in d.items) {
1063
1547
  const notSchemas = d.items.not.map(
1064
1548
  (item) => this.$getPropertyBaseValidator(
@@ -1068,7 +1552,10 @@ function withResourceful(options = {}) {
1068
1552
  !(item.readOnly || false)
1069
1553
  )
1070
1554
  );
1071
- itemValidator = joi.joi.any().not(...notSchemas);
1555
+ itemValidator = joi.joi.any();
1556
+ notSchemas.forEach((notSchema) => {
1557
+ itemValidator = itemValidator.concat(joi.joi.when(notSchema, { then: joi.joi.forbidden() }));
1558
+ });
1072
1559
  } else {
1073
1560
  itemValidator = this.$getPropertyBaseValidator(
1074
1561
  d.items,
@@ -1077,15 +1564,18 @@ function withResourceful(options = {}) {
1077
1564
  !(d.items.readOnly || false)
1078
1565
  );
1079
1566
  }
1080
- r.items(itemValidator);
1567
+ r = r.concat(joi.joi.array().items(itemValidator));
1081
1568
  if (d.minItems !== void 0) {
1082
- r.min(d.minItems);
1569
+ r = r.concat(joi.joi.array().min(d.minItems));
1083
1570
  }
1084
1571
  if (d.maxItems !== void 0) {
1085
- r.max(d.maxItems);
1572
+ r = r.concat(joi.joi.array().max(d.maxItems));
1086
1573
  }
1087
1574
  if (d.uniqueItems) {
1088
- r.unique();
1575
+ r = r.concat(joi.joi.array().unique());
1576
+ }
1577
+ if (nullable) {
1578
+ return joi.joi.alternatives(r, joi.joi.any().valid(null));
1089
1579
  }
1090
1580
  return r;
1091
1581
  }
@@ -1135,158 +1625,14 @@ function withResourceful(options = {}) {
1135
1625
  );
1136
1626
  return results.every((result) => result === true);
1137
1627
  }
1138
- static async $asOpenApiSchemaObject(ctx, app) {
1628
+ static async $asOpenApiSchemaObject(ctx, app, operation = "read") {
1139
1629
  const resourcefulModelMetaSchema = await this.$getAsResourcefulForContext(ctx, app);
1140
- const ret = {
1141
- type: "object",
1142
- title: resourcefulModelMetaSchema.name,
1143
- description: resourcefulModelMetaSchema.description,
1144
- externalDocs: resourcefulModelMetaSchema.externalDocs,
1145
- example: resourcefulModelMetaSchema.example,
1146
- properties: {}
1147
- };
1148
- Object.entries(resourcefulModelMetaSchema.properties).forEach(
1149
- ([propertyKey, propertyMeta]) => {
1150
- const resolvedColumnName = getFieldKey(
1151
- propertyKey,
1152
- propertyMeta.lucidDefinitions
1153
- );
1154
- if (null === resolvedColumnName) {
1155
- return;
1156
- }
1157
- switch (propertyMeta.kind) {
1158
- case "column": {
1159
- ret.properties[propertyKey] = this.$resourcefulModelColumnMetaToOpenApiSchema(
1160
- propertyKey,
1161
- propertyMeta
1162
- );
1163
- return;
1164
- }
1165
- case "computedAccessor": {
1166
- ret.properties[propertyKey] = this.$resourcefulModelComputedAccessorMetaToOpenApiSchema(
1167
- propertyKey,
1168
- propertyMeta
1169
- );
1170
- return;
1171
- }
1172
- case "relationship": {
1173
- const relatedSchema = this.$resourcefulModelRelationshipMetaToOpenApiSchema(
1174
- propertyKey,
1175
- propertyMeta
1176
- );
1177
- if (relatedSchema) {
1178
- ret.properties[propertyKey] = relatedSchema;
1179
- }
1180
- return;
1181
- }
1182
- }
1183
- }
1184
- );
1185
- const requiredPropSet = /* @__PURE__ */ new Set();
1186
- Object.entries(ret.properties).forEach(([propertyKey, schema]) => {
1187
- if (!decorator_utils.isObject(schema) || "$ref" in schema || !("nullable" in schema) || schema.nullable)
1188
- return;
1189
- requiredPropSet.add(propertyKey);
1190
- });
1191
- ret.required = Array.from(requiredPropSet);
1192
- return ret;
1193
- }
1194
- static $getDefaultValueFromPropertyMeta(propertyMeta) {
1195
- const joiDescription = propertyMeta.validator.describe();
1196
- if (decorator_utils.isObject(joiDescription) && "flags" in joiDescription && decorator_utils.isObject(joiDescription.flags) && "default" in joiDescription.flags) {
1197
- return joiDescription.flags.default;
1198
- }
1199
- }
1200
- static $resourcefulModelColumnMetaToOpenApiSchema(propertyKey, propertyMeta) {
1201
- const ret = stripUndefinedValuesFromObject({
1202
- items: propertyMeta.definition.items,
1203
- title: getFieldKey(propertyKey, propertyMeta.lucidDefinitions) || propertyKey,
1204
- description: propertyMeta.definition.description,
1205
- format: propertyMeta.definition.format,
1206
- default: this.$getDefaultValueFromPropertyMeta(propertyMeta),
1207
- multipleOf: propertyMeta.definition.multipleOf,
1208
- maximum: propertyMeta.definition.maximum,
1209
- exclusiveMaximum: propertyMeta.definition.exclusiveMaximum,
1210
- minimum: propertyMeta.definition.minimum,
1211
- exclusiveMinimum: propertyMeta.definition.exclusiveMinimum,
1212
- maxLength: propertyMeta.definition.maxLength,
1213
- minLength: propertyMeta.definition.minLength,
1214
- pattern: propertyMeta.definition.pattern,
1215
- additionalProperties: propertyMeta.definition.additionalProperties,
1216
- maxItems: propertyMeta.definition.maxItems,
1217
- minItems: propertyMeta.definition.minItems,
1218
- uniqueItems: propertyMeta.definition.uniqueItems,
1219
- maxProperties: propertyMeta.definition.maxProperties,
1220
- minProperties: propertyMeta.definition.minProperties,
1221
- required: propertyMeta.definition.required,
1222
- enum: propertyMeta.definition.enum,
1223
- properties: propertyMeta.definition.properties,
1224
- allOf: propertyMeta.definition.allOf,
1225
- oneOf: propertyMeta.definition.oneOf,
1226
- anyOf: propertyMeta.definition.anyOf,
1227
- not: propertyMeta.definition.not,
1228
- nullable: propertyMeta.definition.nullable,
1229
- readOnly: propertyMeta.canRead && !propertyMeta.canWrite,
1230
- writeOnly: !propertyMeta.canRead && propertyMeta.canWrite,
1231
- externalDocs: propertyMeta.definition.externalDocs,
1232
- example: propertyMeta.definition.example,
1233
- ...propertyMeta.definition.type
1234
- });
1235
- return ret;
1236
- }
1237
- static $resourcefulModelComputedAccessorMetaToOpenApiSchema(propertyKey, propertyMeta) {
1238
- const ret = stripUndefinedValuesFromObject({
1239
- items: propertyMeta.definition.items,
1240
- title: getFieldKey(propertyKey, propertyMeta.lucidDefinitions) || propertyKey,
1241
- description: propertyMeta.definition.description,
1242
- format: propertyMeta.definition.format,
1243
- default: this.$getDefaultValueFromPropertyMeta(propertyMeta),
1244
- multipleOf: propertyMeta.definition.multipleOf,
1245
- maximum: propertyMeta.definition.maximum,
1246
- exclusiveMaximum: propertyMeta.definition.exclusiveMaximum,
1247
- minimum: propertyMeta.definition.minimum,
1248
- exclusiveMinimum: propertyMeta.definition.exclusiveMinimum,
1249
- maxLength: propertyMeta.definition.maxLength,
1250
- minLength: propertyMeta.definition.minLength,
1251
- pattern: propertyMeta.definition.pattern,
1252
- additionalProperties: propertyMeta.definition.additionalProperties,
1253
- maxItems: propertyMeta.definition.maxItems,
1254
- minItems: propertyMeta.definition.minItems,
1255
- uniqueItems: propertyMeta.definition.uniqueItems,
1256
- maxProperties: propertyMeta.definition.maxProperties,
1257
- minProperties: propertyMeta.definition.minProperties,
1258
- required: propertyMeta.definition.required,
1259
- enum: propertyMeta.definition.enum,
1260
- properties: propertyMeta.definition.properties,
1261
- allOf: propertyMeta.definition.allOf,
1262
- oneOf: propertyMeta.definition.oneOf,
1263
- anyOf: propertyMeta.definition.anyOf,
1264
- not: propertyMeta.definition.not,
1265
- nullable: propertyMeta.definition.nullable,
1266
- readOnly: propertyMeta.canRead && !propertyMeta.canWrite,
1267
- writeOnly: !propertyMeta.canRead && propertyMeta.canWrite,
1268
- externalDocs: propertyMeta.definition.externalDocs,
1269
- example: propertyMeta.definition.example,
1270
- ...propertyMeta.definition.type
1271
- });
1272
- return ret;
1273
- }
1274
- static $resourcefulModelRelationshipMetaToOpenApiSchema(_propertyKey, propertyMeta) {
1275
- const relatedModel = propertyMeta.relatedModel();
1276
- if (!relatedModel) {
1277
- return void 0;
1278
- }
1279
- if (!decorator_utils.isResourcefulModel(relatedModel)) {
1280
- return void 0;
1281
- }
1282
- const ref2 = `#/components/schemas/${relatedModel.$resourcefulName}`;
1283
- return {
1284
- $ref: ref2
1285
- };
1630
+ const service = new OpenApiSchemaService();
1631
+ return service.generateModelSchema(operation, resourcefulModelMetaSchema, this);
1286
1632
  }
1287
1633
  static async $resourcefulCheckAccess(config) {
1288
1634
  const { ctx, app, operation, instance } = config;
1289
- const allowedFieldsMap = /* @__PURE__ */ new Map();
1635
+ const allowedSerializedMap = /* @__PURE__ */ new Map();
1290
1636
  const allowedColumnsMap = /* @__PURE__ */ new Map();
1291
1637
  const mixinAccessControlFilters = validatedOptions.accessControlFilters[operation];
1292
1638
  if (mixinAccessControlFilters) {
@@ -1298,37 +1644,72 @@ function withResourceful(options = {}) {
1298
1644
  return {
1299
1645
  isForbidden: true,
1300
1646
  message: "Access denied by Mixin ACLs.",
1301
- allowedFieldsMap: void 0
1647
+ allowedSerializedMap: void 0
1302
1648
  };
1303
1649
  }
1304
1650
  }
1305
- if (operation === decorator_utils.CRUDOperationsEnum.DELETE) {
1306
- return { isForbidden: false, allowedFieldsMap, allowedColumnsMap };
1651
+ if (operation === errors.CRUDOperationsEnum.DELETE) {
1652
+ return {
1653
+ isForbidden: false,
1654
+ allowedSerializedMap,
1655
+ allowedColumnsMap
1656
+ };
1307
1657
  }
1308
1658
  const columnsOptions = this.$resourcefulColumns.values();
1309
- const aclOperation = decorator_utils.operationCRUDToACL(operation);
1310
- const addColumnOptionToAllowedFieldsMap = (propertyKey) => {
1659
+ const aclOperation = errors.operationCRUDToACL(operation);
1660
+ const addColumnOptionToallowedSerializedMap = (propertyKey) => {
1311
1661
  const serializedName = this.$keys.attributesToSerialized.resolve(propertyKey);
1312
1662
  const columnName = this.$keys.serializedToColumns.resolve(serializedName);
1313
- if (serializedName) {
1314
- allowedFieldsMap.set(propertyKey, true);
1315
- }
1316
- if (columnName) {
1317
- allowedColumnsMap.set(columnName, true);
1663
+ if (aclOperation === errors.ACLOperationsEnum.WRITE && serializedName === null) {
1664
+ if (columnName) {
1665
+ allowedSerializedMap.set(columnName, true);
1666
+ allowedColumnsMap.set(columnName, true);
1667
+ }
1668
+ } else if ("string" === typeof serializedName) {
1669
+ allowedSerializedMap.set(serializedName, true);
1670
+ if (columnName) {
1671
+ allowedColumnsMap.set(columnName, true);
1672
+ }
1318
1673
  }
1319
1674
  };
1320
1675
  for (const columnOptions of columnsOptions) {
1321
- const propertyACLFilters = aclOperation === decorator_utils.ACLOperationsEnum.READ ? columnOptions.readAccessControlFilters : columnOptions.writeAccessControlFilters;
1676
+ const propertyACLFilters = aclOperation === errors.ACLOperationsEnum.READ ? columnOptions.readAccessControlFilters : columnOptions.writeAccessControlFilters;
1322
1677
  if (!propertyACLFilters) {
1323
- addColumnOptionToAllowedFieldsMap(columnOptions.propertyKey);
1678
+ addColumnOptionToallowedSerializedMap(columnOptions.propertyKey);
1324
1679
  continue;
1325
1680
  }
1326
1681
  const isAllowed = await this.$evaluatePropertyAccess(ctx, app, propertyACLFilters);
1327
1682
  if (isAllowed) {
1328
- addColumnOptionToAllowedFieldsMap(columnOptions.propertyKey);
1683
+ addColumnOptionToallowedSerializedMap(columnOptions.propertyKey);
1684
+ }
1685
+ }
1686
+ if (aclOperation === errors.ACLOperationsEnum.READ) {
1687
+ const computedAccessorsOptions = this.$resourcefulComputedAccessors.values();
1688
+ for (const computedAccessorOptions of computedAccessorsOptions) {
1689
+ const propertyACLFilters = computedAccessorOptions.readAccessControlFilters;
1690
+ if (!propertyACLFilters) {
1691
+ allowedSerializedMap.set(computedAccessorOptions.propertyKey, true);
1692
+ continue;
1693
+ }
1694
+ const isAllowed = await this.$evaluatePropertyAccess(ctx, app, propertyACLFilters);
1695
+ if (isAllowed) {
1696
+ allowedSerializedMap.set(computedAccessorOptions.propertyKey, true);
1697
+ }
1698
+ }
1699
+ const relationshipOptions = this.$resourcefulRelationships.values();
1700
+ for (const relationshipOption of relationshipOptions) {
1701
+ const propertyACLFilters = relationshipOption.readAccessControlFilters;
1702
+ if (!propertyACLFilters) {
1703
+ allowedSerializedMap.set(relationshipOption.propertyKey, true);
1704
+ continue;
1705
+ }
1706
+ const isAllowed = await this.$evaluatePropertyAccess(ctx, app, propertyACLFilters);
1707
+ if (isAllowed) {
1708
+ allowedSerializedMap.set(relationshipOption.propertyKey, true);
1709
+ }
1329
1710
  }
1330
1711
  }
1331
- const hasNoAllowedFields = !allowedFieldsMap.size;
1712
+ const hasNoAllowedFields = !allowedSerializedMap.size;
1332
1713
  if (hasNoAllowedFields) {
1333
1714
  return {
1334
1715
  isForbidden: true,
@@ -1337,7 +1718,7 @@ function withResourceful(options = {}) {
1337
1718
  }
1338
1719
  return {
1339
1720
  isForbidden: false,
1340
- allowedFieldsMap,
1721
+ allowedSerializedMap,
1341
1722
  allowedColumnsMap
1342
1723
  };
1343
1724
  }
@@ -1350,6 +1731,40 @@ function withResourceful(options = {}) {
1350
1731
  });
1351
1732
  return ret;
1352
1733
  }
1734
+ static $loadPossibilitiesForResourcefulRecord() {
1735
+ const allRelationships = Array.from(this.$resourcefulRelationships.entries()).filter(([propertyKey]) => {
1736
+ const relation = this.$getRelation(propertyKey);
1737
+ return !relation ? false : true;
1738
+ }).map(([propertyKey]) => propertyKey);
1739
+ const possibleRelationships = Array.from(this.$resourcefulRelationships.entries()).filter(([propertyKey]) => {
1740
+ const relation = this.$getRelation(propertyKey);
1741
+ if (!relation) return false;
1742
+ if (relation.serializeAs === null) return false;
1743
+ return relation.type === "belongsTo" || relation.type === "hasOne";
1744
+ }).map(([propertyKey]) => propertyKey);
1745
+ const possibleColumns = Array.from(this.$resourcefulColumns.entries()).map(([propertyKey]) => propertyKey).filter((propertyKey) => {
1746
+ const lucidColumnOptions = this.$getColumn(propertyKey);
1747
+ if (!lucidColumnOptions) return false;
1748
+ if (lucidColumnOptions.serializeAs === null) return false;
1749
+ return lucidColumnOptions.serializeAs !== null;
1750
+ });
1751
+ const possibleComputed = Array.from(this.$resourcefulComputedAccessors.entries()).map(([propertyKey]) => propertyKey).filter((propertyKey) => {
1752
+ const lucidComputedOptions = this.$getComputed(propertyKey);
1753
+ if (!lucidComputedOptions) return false;
1754
+ if (lucidComputedOptions.serializeAs === null) return false;
1755
+ return lucidComputedOptions.serializeAs !== null;
1756
+ });
1757
+ const possibleFields = Array.from(
1758
+ /* @__PURE__ */ new Set([...possibleColumns, ...possibleComputed, ...possibleRelationships])
1759
+ ).map((prop) => this.$keys.attributesToSerialized.get(prop) || prop).filter((s) => "string" === typeof s);
1760
+ return {
1761
+ allRelationships,
1762
+ possibleRelationships,
1763
+ possibleColumns,
1764
+ possibleComputed,
1765
+ possibleFields
1766
+ };
1767
+ }
1353
1768
  /**
1354
1769
  * Performs paginated listing and searching of model records with comprehensive filtering.
1355
1770
  *
@@ -1409,22 +1824,33 @@ function withResourceful(options = {}) {
1409
1824
  * );
1410
1825
  * ```
1411
1826
  */
1412
- static $formatResourcefulRecord(record) {
1827
+ static $formatResourcefulRecord(record, possibleFields) {
1828
+ if (null === record || void 0 === record) {
1829
+ return record;
1830
+ }
1413
1831
  const result = {};
1414
- for (const [key, value] of Object.entries(record)) {
1415
- const serializable = this.$keys.columnsToSerialized.get(key);
1416
- const attribute = this.$keys.columnsToAttributes.get(key);
1417
- if (!attribute || !serializable) {
1418
- continue;
1419
- }
1420
- const opts = this.$getColumn(attribute);
1421
- if (!opts) {
1422
- continue;
1832
+ const { possibleFields: allPossibleFields } = this.$loadPossibilitiesForResourcefulRecord();
1833
+ possibleFields = possibleFields.filter((field) => allPossibleFields.includes(field));
1834
+ possibleFields.forEach((field) => {
1835
+ const attribute = this.$keys.serializedToAttributes.get(field) || field;
1836
+ if (!attribute) return;
1837
+ const value = record[attribute];
1838
+ if (value !== void 0) {
1839
+ const resourcefulRelationshipOptions = this.$resourcefulRelationships.get(attribute);
1840
+ if (resourcefulRelationshipOptions) {
1841
+ const relatedModel = resourcefulRelationshipOptions.relatedModel();
1842
+ if ("function" === typeof relatedModel.$formatResourcefulRecord && "function" === typeof relatedModel.$loadPossibilitiesForResourcefulRecord) {
1843
+ const { possibleFields: relatedPossibleFields } = relatedModel.$loadPossibilitiesForResourcefulRecord();
1844
+ result[field] = relatedModel.$formatResourcefulRecord(value, relatedPossibleFields);
1845
+ } else if ("function" === typeof value.serialize) {
1846
+ result[field] = value.serialize();
1847
+ }
1848
+ } else {
1849
+ result[field] = value;
1850
+ }
1423
1851
  }
1424
- const preparedValue = decorator_utils.isFunction(opts.consume) ? opts.consume(value, attribute, this) : value;
1425
- result[serializable] = preparedValue;
1426
- }
1427
- return result;
1852
+ });
1853
+ return errors.stripUndefinedValuesFromObject(result);
1428
1854
  }
1429
1855
  static async $validatePayloadWithValidationGetters(ctx, app, payload, validationGetters) {
1430
1856
  const schemas = await Promise.all(validationGetters.map((getter) => getter(ctx, app)));
@@ -1456,19 +1882,22 @@ function withResourceful(options = {}) {
1456
1882
  if (!primaryKey) {
1457
1883
  throw new errors.E_MISSING_PRIMARY_KEY_EXCEPTION(this.$resourcefulName);
1458
1884
  }
1459
- if (!decorator_utils.isString(filter)) {
1885
+ if (!errors.isString(filter)) {
1460
1886
  filter = "";
1461
1887
  }
1462
- fields = decorator_utils.prepareFields(fields, primaryKey);
1463
- const { isForbidden, allowedFieldsMap, message } = await this.$resourcefulCheckAccess({
1888
+ fields = errors.prepareFields(fields, primaryKey);
1889
+ const { isForbidden, allowedSerializedMap, message } = await this.$resourcefulCheckAccess({
1464
1890
  ctx,
1465
1891
  app,
1466
- operation: decorator_utils.CRUDOperationsEnum.LIST
1892
+ operation: errors.CRUDOperationsEnum.LIST
1467
1893
  });
1468
1894
  if (isForbidden) {
1469
1895
  throw new errors.E_FORBIDDEN(message);
1470
1896
  }
1471
- const possibleFields = Array.from(allowedFieldsMap.keys());
1897
+ const { allRelationships, possibleRelationships, possibleColumns, possibleComputed } = this.$loadPossibilitiesForResourcefulRecord();
1898
+ const possibleFields = Array.from(allowedSerializedMap.keys()).filter(
1899
+ (f) => possibleColumns.includes(f) || possibleComputed.includes(f) || !allRelationships.includes(f) || possibleRelationships.includes(f)
1900
+ );
1472
1901
  if (possibleFields.length === 0) {
1473
1902
  throw new errors.E_INVALID_COLUMN_ACCESS("No fields available for access");
1474
1903
  }
@@ -1498,7 +1927,8 @@ function withResourceful(options = {}) {
1498
1927
  this.$keys.serializedToColumns,
1499
1928
  primaryKey,
1500
1929
  this.table,
1501
- possibleFields
1930
+ possibleFields,
1931
+ this
1502
1932
  );
1503
1933
  for (const scopeCallback of [
1504
1934
  ...this.$resourcefulQueryScopeCallbacks.list || [],
@@ -1506,28 +1936,47 @@ function withResourceful(options = {}) {
1506
1936
  ]) {
1507
1937
  await scopeCallback(ctx, app, query);
1508
1938
  }
1509
- const columnsToSelect = validatedMethodOptions.fields.filter((field) => allowedFieldsMap.has(field)).map((field) => this.$keys.serializedToColumns.get(field)).filter((column2) => !!column2);
1510
1939
  const countQuery = query.clone();
1511
1940
  const recordsQuery = query.clone();
1941
+ const privateKeyColumn = this.$keys.attributesToColumns.get(primaryKey);
1512
1942
  countQuery.count("*", "total");
1513
- recordsQuery.select(columnsToSelect).forPage(validatedMethodOptions.page, validatedMethodOptions.perPage);
1943
+ recordsQuery.select(privateKeyColumn).forPage(validatedMethodOptions.page, validatedMethodOptions.perPage);
1514
1944
  if (Array.isArray(sort) && sort.length > 0) {
1515
1945
  sort.forEach(([field, direction]) => {
1516
- if (allowedFieldsMap.has(field)) {
1517
- recordsQuery.orderBy(field, direction);
1946
+ const columnName = this.$keys.serializedToColumns.get(field);
1947
+ if (allowedSerializedMap.has(field) && columnName) {
1948
+ recordsQuery.orderBy(columnName, direction);
1518
1949
  }
1519
1950
  });
1520
1951
  }
1521
1952
  const countQueryQuery = countQuery.toQuery();
1522
1953
  const recordsQueryQuery = recordsQuery.toQuery();
1523
- const [countResults, rawRecords] = await Promise.all([countQuery, recordsQuery]);
1954
+ const [countResults, rawRecordIds] = await Promise.all([countQuery, recordsQuery]);
1524
1955
  const totalRaw = Number((_a2 = countResults == null ? void 0 : countResults[0]) == null ? void 0 : _a2.total);
1956
+ const rawRecordsUnsortedQuery = this.query().whereIn(
1957
+ privateKeyColumn,
1958
+ rawRecordIds.map((r) => r[privateKeyColumn])
1959
+ );
1960
+ const relationsToSelect = validatedMethodOptions.fields.filter(
1961
+ (field) => allowedSerializedMap.has(field) && possibleRelationships.includes(field)
1962
+ );
1963
+ relationsToSelect.forEach((prop) => {
1964
+ rawRecordsUnsortedQuery.preload(prop);
1965
+ });
1966
+ const rawRecordsUnsorted = await rawRecordsUnsortedQuery;
1967
+ const rawRecords = rawRecordsUnsorted.sort((a2, b) => {
1968
+ const aId = a2.$getAttribute(primaryKey);
1969
+ const bId = b.$getAttribute(primaryKey);
1970
+ const rawRecordIdResultsIndexA = rawRecordIds.findIndex((r) => r[primaryKey] === aId);
1971
+ const rawRecordIdResultsIndexB = rawRecordIds.findIndex((r) => r[primaryKey] === bId);
1972
+ return rawRecordIdResultsIndexA - rawRecordIdResultsIndexB;
1973
+ });
1525
1974
  return {
1526
1975
  total: Number.isNaN(totalRaw) ? 0 : totalRaw,
1527
1976
  page: validatedMethodOptions.page,
1528
1977
  perPage: validatedMethodOptions.perPage,
1529
1978
  records: rawRecords.map(
1530
- (record) => this.$formatResourcefulRecord(record)
1979
+ (record) => this.$formatResourcefulRecord(record, possibleFields)
1531
1980
  ),
1532
1981
  countQuery: countQueryQuery,
1533
1982
  recordsQuery: recordsQueryQuery
@@ -1570,27 +2019,211 @@ function withResourceful(options = {}) {
1570
2019
  throw new errors.E_RECORD_NOT_FOUND_EXCEPTION();
1571
2020
  }
1572
2021
  const rid = recordRaw[this.primaryKey];
1573
- const record = await this.query().where(this.primaryKey, rid).first();
2022
+ const recordQuery = this.query().where(this.primaryKey, rid);
2023
+ const { possibleRelationships, possibleFields } = this.$loadPossibilitiesForResourcefulRecord();
2024
+ possibleRelationships.forEach((prop) => {
2025
+ recordQuery.preload(prop);
2026
+ });
2027
+ const record = await recordQuery.first();
1574
2028
  if (!record) {
1575
2029
  throw new errors.E_RECORD_NOT_FOUND_EXCEPTION();
1576
2030
  }
1577
- const { isForbidden, allowedFieldsMap, message } = await this.$resourcefulCheckAccess({
2031
+ const { isForbidden, allowedSerializedMap, message } = await this.$resourcefulCheckAccess({
1578
2032
  ctx,
1579
2033
  app,
1580
2034
  instance: record,
1581
- operation: decorator_utils.CRUDOperationsEnum.READ
2035
+ operation: errors.CRUDOperationsEnum.READ
1582
2036
  });
1583
2037
  if (isForbidden) {
1584
2038
  throw new errors.E_FORBIDDEN(message);
1585
2039
  }
1586
- const recordObject = record.toObject();
1587
- const recordObjectWithAllowedFields = {};
1588
- for (const [key, value] of Object.entries(recordObject)) {
1589
- if (allowedFieldsMap.has(key)) {
1590
- recordObjectWithAllowedFields[key] = value;
2040
+ return this.$formatResourcefulRecord(
2041
+ record,
2042
+ possibleFields.filter((f) => allowedSerializedMap.get(f) === true)
2043
+ );
2044
+ }
2045
+ /**
2046
+ * Loads a specific relationship for a model record with pagination, filtering, and access control.
2047
+ *
2048
+ * This method provides paginated relationship loading by leveraging the related model's
2049
+ * $onResourcefulIndex method with automatically generated relationship constraints.
2050
+ * It supports full filtering, sorting, and pagination capabilities while maintaining
2051
+ * proper access control and scoping.
2052
+ *
2053
+ * The method automatically generates query scope hooks to constrain results to only
2054
+ * records related to the specified parent record, preventing unauthorized data access
2055
+ * and ensuring proper relationship boundaries are maintained.
2056
+ *
2057
+ * @param uid - The unique identifier of the parent record
2058
+ * @param relationshipKey - The name of the relationship property to load
2059
+ * @param filter - Lucene-style query string for filtering related records
2060
+ * @param page - The page number for pagination (must be ≥ 1)
2061
+ * @param perPage - Number of records per page (must be ≥ 1 and ≤ 100)
2062
+ * @param fields - Array of field names to include in the response from the related model
2063
+ * @param sort - Array of sort criteria as [field, direction] tuples
2064
+ * @param ctx - HTTP context containing request information and authentication
2065
+ * @param app - Application service instance for accessing app-level services
2066
+ * @param hooks - Optional array of additional query scope callbacks
2067
+ *
2068
+ * @returns Promise resolving to paginated relationship results with the same structure as $onResourcefulIndex
2069
+ *
2070
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
2071
+ * @throws {E_INVALID_RELATIONSHIP_EXCEPTION} When the specified relationship doesn't exist or isn't resourceful
2072
+ * @throws {E_FORBIDDEN} When access is denied by model-level or field-level ACL filters
2073
+ * @throws {E_INVALID_RESOUREFUL_INDEX_REQUEST_EXCEPTION} When input validation fails
2074
+ *
2075
+ * @example
2076
+ * ```typescript
2077
+ * // Load user's posts with filtering and pagination
2078
+ * const userPosts = await Post.$onResourcefulReadRelationship(
2079
+ * 123, // user ID
2080
+ * 'posts', // relationship name
2081
+ * 'status:published', // filter
2082
+ * 1, // page
2083
+ * 10, // perPage
2084
+ * ['id', 'title'], // fields
2085
+ * [['createdAt', 'desc']], // sort
2086
+ * ctx,
2087
+ * app
2088
+ * );
2089
+ *
2090
+ * // Load user's skills (many-to-many)
2091
+ * const userSkills = await Skill.$onResourcefulReadRelationship(
2092
+ * 123,
2093
+ * 'skills',
2094
+ * null, // no filter
2095
+ * 1,
2096
+ * 50,
2097
+ * null, // all fields
2098
+ * null, // default sort
2099
+ * ctx,
2100
+ * app
2101
+ * );
2102
+ * ```
2103
+ */
2104
+ static async $onResourcefulReadRelationship(uid, relationshipKey, filter, page, perPage, fields, sort, ctx, app, hooks = []) {
2105
+ const primaryKey = this.$getPrivateKeyAttribute();
2106
+ if (!primaryKey) {
2107
+ throw new errors.E_MISSING_PRIMARY_KEY_EXCEPTION(this.$resourcefulName);
2108
+ }
2109
+ const relationshipDefinition = this.$resourcefulRelationships.get(relationshipKey);
2110
+ if (!relationshipDefinition) {
2111
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2112
+ `Relationship '${relationshipKey}' not found on model '${this.$resourcefulName}'`
2113
+ );
2114
+ }
2115
+ const lucidRelationshipDefinition = this.$getRelation(relationshipKey);
2116
+ if (!lucidRelationshipDefinition) {
2117
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2118
+ `Lucid relationship '${relationshipKey}' not found on model '${this.$resourcefulName}'`
2119
+ );
2120
+ }
2121
+ const RelatedModel = relationshipDefinition.relatedModel();
2122
+ if (typeof RelatedModel.$onResourcefulIndex !== "function") {
2123
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2124
+ `Related model for '${relationshipKey}' does not implement resourceful operations`
2125
+ );
2126
+ }
2127
+ const relationshipHook = async (_hookCtx, _hookApp, query) => {
2128
+ const relationshipType = lucidRelationshipDefinition.type;
2129
+ switch (relationshipType) {
2130
+ case "hasMany":
2131
+ {
2132
+ const foreignKey = lucidRelationshipDefinition.foreignKey;
2133
+ if (!foreignKey) {
2134
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2135
+ `HasMany relationship '${relationshipKey}' missing foreignKey`
2136
+ );
2137
+ }
2138
+ const foreignColumn = RelatedModel.$keys.attributesToColumns.get(foreignKey);
2139
+ if (!foreignColumn) {
2140
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2141
+ `Foreign key '${foreignKey}' not found in related model columns`
2142
+ );
2143
+ }
2144
+ query.where(foreignColumn, uid);
2145
+ }
2146
+ break;
2147
+ case "manyToMany":
2148
+ {
2149
+ const pivotTable = lucidRelationshipDefinition.pivotTable;
2150
+ const localKey = lucidRelationshipDefinition.localKey;
2151
+ const relatedKey = lucidRelationshipDefinition.relatedKey;
2152
+ const pivotForeignKey = lucidRelationshipDefinition.pivotForeignKey;
2153
+ const pivotRelatedForeignKey = lucidRelationshipDefinition.pivotRelatedForeignKey;
2154
+ if (!pivotTable || !localKey || !relatedKey || !pivotForeignKey || !pivotRelatedForeignKey) {
2155
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2156
+ `ManyToMany relationship '${relationshipKey}' missing required pivot configuration`
2157
+ );
2158
+ }
2159
+ const relatedColumn = RelatedModel.$keys.attributesToColumns.get(relatedKey);
2160
+ if (!relatedColumn) {
2161
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2162
+ `Related key '${relatedKey}' not found in related model columns`
2163
+ );
2164
+ }
2165
+ query.whereExists((subQuery) => {
2166
+ subQuery.from(pivotTable).select(1).whereColumn(
2167
+ `${pivotTable}.${pivotRelatedForeignKey}`,
2168
+ `${RelatedModel.table}.${relatedColumn}`
2169
+ ).where(`${pivotTable}.${pivotForeignKey}`, uid);
2170
+ });
2171
+ }
2172
+ break;
2173
+ case "hasManyThrough":
2174
+ {
2175
+ const throughModel = lucidRelationshipDefinition.options.throughModel ? lucidRelationshipDefinition.options.throughModel() : void 0;
2176
+ const foreignKey = lucidRelationshipDefinition.options.foreignKey || RelatedModel.primaryKey;
2177
+ const localKey = lucidRelationshipDefinition.options.localKey || this.primaryKey;
2178
+ const throughForeignKey = lucidRelationshipDefinition.options.throughForeignKey;
2179
+ const throughLocalKey = lucidRelationshipDefinition.options.throughLocalKey || (throughModel == null ? void 0 : throughModel.primaryKey);
2180
+ if (!throughModel || !foreignKey || !localKey || !throughForeignKey || !throughLocalKey) {
2181
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2182
+ `HasManyThrough relationship '${relationshipKey}' missing required through configuration`
2183
+ );
2184
+ }
2185
+ const foreignColumn = RelatedModel.$keys.attributesToColumns.get(foreignKey);
2186
+ const localColumn = this.$keys.attributesToColumns.get(localKey);
2187
+ const throughForeignColumn = RelatedModel.$keys.attributesToColumns.get(throughForeignKey);
2188
+ const throughLocalColumn = throughModel.$keys.attributesToColumns.get(throughLocalKey);
2189
+ if (!throughLocalColumn || !throughForeignColumn || !foreignColumn || !localColumn) {
2190
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2191
+ `HasManyThrough relationship '${relationshipKey}' has invalid key mappings`
2192
+ );
2193
+ }
2194
+ query.whereExists((subQuery) => {
2195
+ subQuery.from(throughModel.table).select(1).where(`${throughModel.table}.${throughLocalColumn}`, uid).whereColumn(
2196
+ `${throughModel.table}.${foreignColumn}`,
2197
+ `${RelatedModel.table}.${throughForeignColumn}`
2198
+ ).limit(1);
2199
+ });
2200
+ }
2201
+ break;
2202
+ default:
2203
+ throw new errors.E_INVALID_RELATIONSHIP_EXCEPTION(
2204
+ `Relationship type '${relationshipType}' is not supported for paginated loading`
2205
+ );
2206
+ }
2207
+ };
2208
+ const allHooks = [relationshipHook, ...hooks];
2209
+ try {
2210
+ return RelatedModel.$onResourcefulIndex(
2211
+ filter,
2212
+ page,
2213
+ perPage,
2214
+ fields,
2215
+ sort,
2216
+ ctx,
2217
+ app,
2218
+ allHooks
2219
+ );
2220
+ } catch (err) {
2221
+ if (err instanceof errors.E_INVALID_RESOUREFUL_INDEX_REQUEST_EXCEPTION) {
2222
+ throw new errors.E_INVALID_RESOUREFUL_READ_RELATIONSHIP_REQUEST_EXCEPTION(err);
2223
+ } else {
2224
+ throw err;
1591
2225
  }
1592
2226
  }
1593
- return recordObjectWithAllowedFields;
1594
2227
  }
1595
2228
  /**
1596
2229
  * Creates a new model record with payload validation and access control.
@@ -1631,23 +2264,31 @@ function withResourceful(options = {}) {
1631
2264
  throw new errors.E_FORBIDDEN_PAYLOAD_EXCEPTION(payloadSchemaGettersError);
1632
2265
  }
1633
2266
  }
1634
- const { isForbidden, allowedFieldsMap, message } = await this.$resourcefulCheckAccess({
2267
+ const { isForbidden, allowedSerializedMap, message } = await this.$resourcefulCheckAccess({
1635
2268
  ctx,
1636
2269
  app,
1637
- operation: decorator_utils.CRUDOperationsEnum.CREATE
2270
+ operation: errors.CRUDOperationsEnum.CREATE
1638
2271
  });
1639
2272
  if (isForbidden) {
1640
2273
  throw new errors.E_FORBIDDEN(message);
1641
2274
  }
1642
2275
  const preparedPayload = {};
1643
2276
  for (const [key, value] of Object.entries(payload)) {
1644
- const attribute = this.$keys.serializedToAttributes.get(key);
2277
+ let attribute = this.$keys.serializedToAttributes.get(key);
1645
2278
  const isValueNull = value === null || value === void 0;
1646
2279
  if (!attribute) {
1647
- continue;
2280
+ const columnExists = typeof this.$keys.attributesToColumns.get(key) !== "undefined";
2281
+ if (columnExists) {
2282
+ attribute = key;
2283
+ } else {
2284
+ continue;
2285
+ }
1648
2286
  }
1649
- if (!isValueNull && !allowedFieldsMap.has(attribute)) {
1650
- throw new errors.E_FORBIDDEN(`User does not has write access to field ${attribute}.`);
2287
+ const isAllowedBySerializedName = allowedSerializedMap.has(key);
2288
+ const isAllowedByColumnName = allowedSerializedMap.has(attribute);
2289
+ const isAllowed = isAllowedBySerializedName || isAllowedByColumnName;
2290
+ if (!isValueNull && !isAllowed) {
2291
+ throw new errors.E_FORBIDDEN(`User does not has write access to field ${key}.`);
1651
2292
  }
1652
2293
  preparedPayload[attribute] = value;
1653
2294
  }
@@ -1707,23 +2348,31 @@ function withResourceful(options = {}) {
1707
2348
  if (!record) {
1708
2349
  throw new errors.E_RECORD_NOT_FOUND_EXCEPTION();
1709
2350
  }
1710
- const { isForbidden, allowedFieldsMap, message } = await this.$resourcefulCheckAccess({
2351
+ const { isForbidden, allowedSerializedMap, message } = await this.$resourcefulCheckAccess({
1711
2352
  ctx,
1712
2353
  app,
1713
2354
  instance: record,
1714
- operation: decorator_utils.CRUDOperationsEnum.UPDATE
2355
+ operation: errors.CRUDOperationsEnum.UPDATE
1715
2356
  });
1716
2357
  if (isForbidden) {
1717
2358
  throw new errors.E_FORBIDDEN(message);
1718
2359
  }
1719
2360
  const preparedPayload = {};
1720
- for (const [key, value] of Object.entries(payload)) {
1721
- const attribute = this.$keys.serializedToAttributes.get(key);
2361
+ for (const [serializedKey, value] of Object.entries(payload)) {
2362
+ let attribute = this.$keys.serializedToAttributes.get(serializedKey);
1722
2363
  const isValueNull = value === null || value === void 0;
1723
2364
  if (!attribute) {
1724
- continue;
2365
+ const columnExists = typeof this.$keys.attributesToColumns.get(serializedKey) !== "undefined";
2366
+ if (columnExists) {
2367
+ attribute = serializedKey;
2368
+ } else {
2369
+ continue;
2370
+ }
1725
2371
  }
1726
- if (!isValueNull && !allowedFieldsMap.has(attribute)) {
2372
+ const isAllowedBySerializedName = allowedSerializedMap.has(serializedKey);
2373
+ const isAllowedByColumnName = allowedSerializedMap.has(attribute);
2374
+ const isAllowed = isAllowedBySerializedName || isAllowedByColumnName;
2375
+ if (!isValueNull && !isAllowed) {
1727
2376
  throw new errors.E_FORBIDDEN(`User does not has write access to field ${attribute}.`);
1728
2377
  }
1729
2378
  preparedPayload[attribute] = value;
@@ -1769,18 +2418,88 @@ function withResourceful(options = {}) {
1769
2418
  if (!rawRecord) {
1770
2419
  throw new errors.E_RECORD_NOT_FOUND_EXCEPTION();
1771
2420
  }
1772
- const record = new this().merge(this.$formatResourcefulRecord(rawRecord));
2421
+ const { possibleFields } = this.$loadPossibilitiesForResourcefulRecord();
2422
+ const record = new this().merge(this.$formatResourcefulRecord(rawRecord, possibleFields));
1773
2423
  const { isForbidden, message } = await this.$resourcefulCheckAccess({
1774
2424
  ctx,
1775
2425
  app,
1776
2426
  instance: record,
1777
- operation: decorator_utils.CRUDOperationsEnum.DELETE
2427
+ operation: errors.CRUDOperationsEnum.DELETE
1778
2428
  });
1779
2429
  if (isForbidden) {
1780
2430
  throw new errors.E_FORBIDDEN(message);
1781
2431
  }
1782
2432
  await record.delete();
1783
2433
  }
2434
+ static async $onResourcefulBulkUpdate(filter, payload, ctx, app, hooks = {}) {
2435
+ const primaryKey = this.$getPrivateKeyAttribute();
2436
+ if (!primaryKey) {
2437
+ throw new errors.E_MISSING_PRIMARY_KEY_EXCEPTION(this.$resourcefulName);
2438
+ }
2439
+ const ctor = this;
2440
+ async function* resourcefulIndexIteratorForUpdate(f) {
2441
+ let page = 1;
2442
+ let pages = 0;
2443
+ const pk = ctor.$getPrivateKeyAttribute();
2444
+ if (!pk) return;
2445
+ const whileAbortController = new AbortController();
2446
+ while ((pages === 0 || page <= pages) && whileAbortController.signal.aborted === false) {
2447
+ try {
2448
+ const result = await ctor.$onResourcefulIndex(
2449
+ f,
2450
+ page,
2451
+ 100,
2452
+ [pk],
2453
+ [[pk, "asc"]],
2454
+ ctx,
2455
+ app,
2456
+ hooks.queryScopeCallbacks || []
2457
+ );
2458
+ if (result.total === 0) {
2459
+ whileAbortController.abort();
2460
+ break;
2461
+ }
2462
+ pages = Math.ceil(result.total / result.perPage);
2463
+ page++;
2464
+ yield result.records;
2465
+ } catch (err) {
2466
+ whileAbortController.abort();
2467
+ if (err instanceof Error) {
2468
+ throw err;
2469
+ } else {
2470
+ throw new errors.E_BULK_UPDATE_SEARCH_UNKNOWN_EXCEPTION();
2471
+ }
2472
+ }
2473
+ }
2474
+ }
2475
+ const uids = /* @__PURE__ */ new Set();
2476
+ for await (const records of resourcefulIndexIteratorForUpdate(filter)) {
2477
+ for (const record of records) {
2478
+ const uid = record[primaryKey];
2479
+ if (uid !== void 0 && uid !== null) {
2480
+ uids.add(uid);
2481
+ }
2482
+ }
2483
+ }
2484
+ return await this.$onResourcefulBulkUpdateByUid(Array.from(uids), payload, ctx, app, hooks);
2485
+ }
2486
+ static async $onResourcefulBulkUpdateByUid(uids, payload, ctx, app, hooks, concurrency = 5) {
2487
+ const results = {};
2488
+ /* istanbul ignore next -- @preserve */
2489
+ await pMap(
2490
+ uids,
2491
+ async (uid) => {
2492
+ try {
2493
+ results[uid] = await this.$onResourcefulUpdate(uid, payload, ctx, app, hooks);
2494
+ } catch (err) {
2495
+ const e = err instanceof Error ? err : new Error("Unknown error during update");
2496
+ results[uid] = e;
2497
+ }
2498
+ },
2499
+ { concurrency }
2500
+ );
2501
+ return results;
2502
+ }
1784
2503
  }
1785
2504
  __publicField(ResourcefulModel, "$resourcefulColumns", resourcefulColumns);
1786
2505
  __publicField(ResourcefulModel, "$resourcefulRelationships", resourcefulRelationships);
@@ -2820,7 +3539,7 @@ var objectInspect = function inspect_(obj, options, depth, seen) {
2820
3539
  var ys = arrObjKeys(obj, inspect2);
2821
3540
  var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
2822
3541
  var protoTag = obj instanceof Object ? "" : "null prototype";
2823
- var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? "Object" : "";
3542
+ var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr$1(obj), 8, -1) : protoTag ? "Object" : "";
2824
3543
  var constructorTag = isPlainObject || typeof obj.constructor !== "function" ? "" : obj.constructor.name ? obj.constructor.name + " " : "";
2825
3544
  var tag = constructorTag + (stringTag || protoTag ? "[" + $join.call($concat$1.call([], stringTag || [], protoTag || []), ": ") + "] " : "");
2826
3545
  if (ys.length === 0) {
@@ -2845,25 +3564,25 @@ function canTrustToString(obj) {
2845
3564
  return !toStringTag || !(typeof obj === "object" && (toStringTag in obj || typeof obj[toStringTag] !== "undefined"));
2846
3565
  }
2847
3566
  function isArray$3(obj) {
2848
- return toStr(obj) === "[object Array]" && canTrustToString(obj);
3567
+ return toStr$1(obj) === "[object Array]" && canTrustToString(obj);
2849
3568
  }
2850
3569
  function isDate(obj) {
2851
- return toStr(obj) === "[object Date]" && canTrustToString(obj);
3570
+ return toStr$1(obj) === "[object Date]" && canTrustToString(obj);
2852
3571
  }
2853
3572
  function isRegExp$1(obj) {
2854
- return toStr(obj) === "[object RegExp]" && canTrustToString(obj);
3573
+ return toStr$1(obj) === "[object RegExp]" && canTrustToString(obj);
2855
3574
  }
2856
3575
  function isError(obj) {
2857
- return toStr(obj) === "[object Error]" && canTrustToString(obj);
3576
+ return toStr$1(obj) === "[object Error]" && canTrustToString(obj);
2858
3577
  }
2859
3578
  function isString(obj) {
2860
- return toStr(obj) === "[object String]" && canTrustToString(obj);
3579
+ return toStr$1(obj) === "[object String]" && canTrustToString(obj);
2861
3580
  }
2862
3581
  function isNumber(obj) {
2863
- return toStr(obj) === "[object Number]" && canTrustToString(obj);
3582
+ return toStr$1(obj) === "[object Number]" && canTrustToString(obj);
2864
3583
  }
2865
3584
  function isBoolean(obj) {
2866
- return toStr(obj) === "[object Boolean]" && canTrustToString(obj);
3585
+ return toStr$1(obj) === "[object Boolean]" && canTrustToString(obj);
2867
3586
  }
2868
3587
  function isSymbol(obj) {
2869
3588
  if (hasShammedSymbols) {
@@ -2899,7 +3618,7 @@ var hasOwn$1 = Object.prototype.hasOwnProperty || function(key) {
2899
3618
  function has$3(obj, key) {
2900
3619
  return hasOwn$1.call(obj, key);
2901
3620
  }
2902
- function toStr(obj) {
3621
+ function toStr$1(obj) {
2903
3622
  return objectToString.call(obj);
2904
3623
  }
2905
3624
  function nameOf(f) {
@@ -3208,7 +3927,7 @@ var syntax = SyntaxError;
3208
3927
  var uri = URIError;
3209
3928
  var abs$1 = Math.abs;
3210
3929
  var floor$1 = Math.floor;
3211
- var max$1 = Math.max;
3930
+ var max$2 = Math.max;
3212
3931
  var min$1 = Math.min;
3213
3932
  var pow$1 = Math.pow;
3214
3933
  var round$1 = Math.round;
@@ -3337,99 +4056,78 @@ function requireObject_getPrototypeOf() {
3337
4056
  Object_getPrototypeOf = $Object2.getPrototypeOf || null;
3338
4057
  return Object_getPrototypeOf;
3339
4058
  }
3340
- var implementation;
3341
- var hasRequiredImplementation;
3342
- function requireImplementation() {
3343
- if (hasRequiredImplementation) return implementation;
3344
- hasRequiredImplementation = 1;
3345
- var ERROR_MESSAGE = "Function.prototype.bind called on incompatible ";
3346
- var toStr2 = Object.prototype.toString;
3347
- var max2 = Math.max;
3348
- var funcType = "[object Function]";
3349
- var concatty = function concatty2(a2, b) {
3350
- var arr = [];
3351
- for (var i = 0; i < a2.length; i += 1) {
3352
- arr[i] = a2[i];
3353
- }
3354
- for (var j = 0; j < b.length; j += 1) {
3355
- arr[j + a2.length] = b[j];
3356
- }
3357
- return arr;
3358
- };
3359
- var slicy = function slicy2(arrLike, offset) {
3360
- var arr = [];
3361
- for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) {
3362
- arr[j] = arrLike[i];
3363
- }
3364
- return arr;
3365
- };
3366
- var joiny = function(arr, joiner) {
3367
- var str = "";
3368
- for (var i = 0; i < arr.length; i += 1) {
3369
- str += arr[i];
3370
- if (i + 1 < arr.length) {
3371
- str += joiner;
3372
- }
4059
+ var ERROR_MESSAGE = "Function.prototype.bind called on incompatible ";
4060
+ var toStr = Object.prototype.toString;
4061
+ var max$1 = Math.max;
4062
+ var funcType = "[object Function]";
4063
+ var concatty = function concatty2(a2, b) {
4064
+ var arr = [];
4065
+ for (var i = 0; i < a2.length; i += 1) {
4066
+ arr[i] = a2[i];
4067
+ }
4068
+ for (var j = 0; j < b.length; j += 1) {
4069
+ arr[j + a2.length] = b[j];
4070
+ }
4071
+ return arr;
4072
+ };
4073
+ var slicy = function slicy2(arrLike, offset) {
4074
+ var arr = [];
4075
+ for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) {
4076
+ arr[j] = arrLike[i];
4077
+ }
4078
+ return arr;
4079
+ };
4080
+ var joiny = function(arr, joiner) {
4081
+ var str = "";
4082
+ for (var i = 0; i < arr.length; i += 1) {
4083
+ str += arr[i];
4084
+ if (i + 1 < arr.length) {
4085
+ str += joiner;
3373
4086
  }
3374
- return str;
3375
- };
3376
- implementation = function bind2(that) {
3377
- var target = this;
3378
- if (typeof target !== "function" || toStr2.apply(target) !== funcType) {
3379
- throw new TypeError(ERROR_MESSAGE + target);
3380
- }
3381
- var args = slicy(arguments, 1);
3382
- var bound;
3383
- var binder = function() {
3384
- if (this instanceof bound) {
3385
- var result = target.apply(
3386
- this,
3387
- concatty(args, arguments)
3388
- );
3389
- if (Object(result) === result) {
3390
- return result;
3391
- }
3392
- return this;
3393
- }
3394
- return target.apply(
3395
- that,
4087
+ }
4088
+ return str;
4089
+ };
4090
+ var implementation$1 = function bind(that) {
4091
+ var target = this;
4092
+ if (typeof target !== "function" || toStr.apply(target) !== funcType) {
4093
+ throw new TypeError(ERROR_MESSAGE + target);
4094
+ }
4095
+ var args = slicy(arguments, 1);
4096
+ var bound;
4097
+ var binder = function() {
4098
+ if (this instanceof bound) {
4099
+ var result = target.apply(
4100
+ this,
3396
4101
  concatty(args, arguments)
3397
4102
  );
3398
- };
3399
- var boundLength = max2(0, target.length - args.length);
3400
- var boundArgs = [];
3401
- for (var i = 0; i < boundLength; i++) {
3402
- boundArgs[i] = "$" + i;
3403
- }
3404
- bound = Function("binder", "return function (" + joiny(boundArgs, ",") + "){ return binder.apply(this,arguments); }")(binder);
3405
- if (target.prototype) {
3406
- var Empty = function Empty2() {
3407
- };
3408
- Empty.prototype = target.prototype;
3409
- bound.prototype = new Empty();
3410
- Empty.prototype = null;
4103
+ if (Object(result) === result) {
4104
+ return result;
4105
+ }
4106
+ return this;
3411
4107
  }
3412
- return bound;
4108
+ return target.apply(
4109
+ that,
4110
+ concatty(args, arguments)
4111
+ );
3413
4112
  };
3414
- return implementation;
3415
- }
3416
- var functionBind;
3417
- var hasRequiredFunctionBind;
3418
- function requireFunctionBind() {
3419
- if (hasRequiredFunctionBind) return functionBind;
3420
- hasRequiredFunctionBind = 1;
3421
- var implementation2 = requireImplementation();
3422
- functionBind = Function.prototype.bind || implementation2;
3423
- return functionBind;
3424
- }
3425
- var functionCall;
3426
- var hasRequiredFunctionCall;
3427
- function requireFunctionCall() {
3428
- if (hasRequiredFunctionCall) return functionCall;
3429
- hasRequiredFunctionCall = 1;
3430
- functionCall = Function.prototype.call;
3431
- return functionCall;
3432
- }
4113
+ var boundLength = max$1(0, target.length - args.length);
4114
+ var boundArgs = [];
4115
+ for (var i = 0; i < boundLength; i++) {
4116
+ boundArgs[i] = "$" + i;
4117
+ }
4118
+ bound = Function("binder", "return function (" + joiny(boundArgs, ",") + "){ return binder.apply(this,arguments); }")(binder);
4119
+ if (target.prototype) {
4120
+ var Empty = function Empty2() {
4121
+ };
4122
+ Empty.prototype = target.prototype;
4123
+ bound.prototype = new Empty();
4124
+ Empty.prototype = null;
4125
+ }
4126
+ return bound;
4127
+ };
4128
+ var implementation = implementation$1;
4129
+ var functionBind = Function.prototype.bind || implementation;
4130
+ var functionCall = Function.prototype.call;
3433
4131
  var functionApply;
3434
4132
  var hasRequiredFunctionApply;
3435
4133
  function requireFunctionApply() {
@@ -3439,14 +4137,14 @@ function requireFunctionApply() {
3439
4137
  return functionApply;
3440
4138
  }
3441
4139
  var reflectApply = typeof Reflect !== "undefined" && Reflect && Reflect.apply;
3442
- var bind$2 = requireFunctionBind();
4140
+ var bind$2 = functionBind;
3443
4141
  var $apply$1 = requireFunctionApply();
3444
- var $call$2 = requireFunctionCall();
4142
+ var $call$2 = functionCall;
3445
4143
  var $reflectApply = reflectApply;
3446
4144
  var actualApply = $reflectApply || bind$2.call($call$2, $apply$1);
3447
- var bind$1 = requireFunctionBind();
4145
+ var bind$1 = functionBind;
3448
4146
  var $TypeError$4 = type;
3449
- var $call$1 = requireFunctionCall();
4147
+ var $call$1 = functionCall;
3450
4148
  var $actualApply = actualApply;
3451
4149
  var callBindApplyHelpers = function callBindBasic(args) {
3452
4150
  if (args.length < 1 || typeof args[0] !== "function") {
@@ -3512,8 +4210,8 @@ function requireHasown() {
3512
4210
  hasRequiredHasown = 1;
3513
4211
  var call = Function.prototype.call;
3514
4212
  var $hasOwn = Object.prototype.hasOwnProperty;
3515
- var bind2 = requireFunctionBind();
3516
- hasown = bind2.call(call, $hasOwn);
4213
+ var bind3 = functionBind;
4214
+ hasown = bind3.call(call, $hasOwn);
3517
4215
  return hasown;
3518
4216
  }
3519
4217
  var undefined$1;
@@ -3527,7 +4225,7 @@ var $TypeError$3 = type;
3527
4225
  var $URIError = uri;
3528
4226
  var abs = abs$1;
3529
4227
  var floor = floor$1;
3530
- var max = max$1;
4228
+ var max = max$2;
3531
4229
  var min = min$1;
3532
4230
  var pow = pow$1;
3533
4231
  var round = round$1;
@@ -3561,7 +4259,7 @@ var getProto = requireGetProto();
3561
4259
  var $ObjectGPO = requireObject_getPrototypeOf();
3562
4260
  var $ReflectGPO = requireReflect_getPrototypeOf();
3563
4261
  var $apply = requireFunctionApply();
3564
- var $call = requireFunctionCall();
4262
+ var $call = functionCall;
3565
4263
  var needsEval = {};
3566
4264
  var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined$1 : getProto(Uint8Array);
3567
4265
  var INTRINSICS = {
@@ -3732,13 +4430,13 @@ var LEGACY_ALIASES = {
3732
4430
  "%WeakMapPrototype%": ["WeakMap", "prototype"],
3733
4431
  "%WeakSetPrototype%": ["WeakSet", "prototype"]
3734
4432
  };
3735
- var bind = requireFunctionBind();
4433
+ var bind2 = functionBind;
3736
4434
  var hasOwn = requireHasown();
3737
- var $concat = bind.call($call, Array.prototype.concat);
3738
- var $spliceApply = bind.call($apply, Array.prototype.splice);
3739
- var $replace = bind.call($call, String.prototype.replace);
3740
- var $strSlice = bind.call($call, String.prototype.slice);
3741
- var $exec = bind.call($call, RegExp.prototype.exec);
4435
+ var $concat = bind2.call($call, Array.prototype.concat);
4436
+ var $spliceApply = bind2.call($apply, Array.prototype.splice);
4437
+ var $replace = bind2.call($call, String.prototype.replace);
4438
+ var $strSlice = bind2.call($call, String.prototype.slice);
4439
+ var $exec = bind2.call($call, RegExp.prototype.exec);
3742
4440
  var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g;
3743
4441
  var reEscapeChar = /\\(\\)?/g;
3744
4442
  var stringToPath = function stringToPath2(string) {
@@ -11885,10 +12583,12 @@ const resourcefulColumnOptionsSchema = joi.joi.object({
11885
12583
  type: resourcefulDataTypeSchema.required()
11886
12584
  });
11887
12585
  const dataTypeColumnOptionsSchema = joi.joi.object({
11888
- // Lucid ColumnOptions (partial) - excluding 'prepare' and 'consume'
12586
+ // Lucid ColumnOptions (full) - now including 'prepare' and 'consume'
11889
12587
  columnName: joi.joi.string().optional(),
11890
12588
  serializeAs: joi.joi.alternatives().try(joi.joi.string(), joi.joi.valid(null)).optional(),
11891
12589
  serialize: joi.joi.function().optional(),
12590
+ consume: joi.joi.function().optional(),
12591
+ prepare: joi.joi.function().optional(),
11892
12592
  meta: joi.joi.object().optional(),
11893
12593
  isPrimary: joi.joi.boolean().default(false),
11894
12594
  hasDefaultValue: joi.joi.boolean().default(false),
@@ -12751,7 +13451,7 @@ function resourcefulHasManyThrough(model, options = {}) {
12751
13451
  map.set(propertyKey, opts);
12752
13452
  };
12753
13453
  }
12754
- const version = "0.1.0-master-1570171e";
13454
+ const version = "0.1.0-master-3ec631a4";
12755
13455
  exports.errors = errors.errors;
12756
13456
  exports.definitions = definitions.definitions;
12757
13457
  exports.resourcefulBelongsTo = resourcefulBelongsTo;