remult 3.2.2-next.1 → 3.3.0-next.1

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.
@@ -8,6 +8,7 @@ export function remultApi(options) {
8
8
  method: event.request.method,
9
9
  on: (e, do1) => {
10
10
  if (e === 'close') {
11
+ event.locals ??= {};
11
12
  event.locals['_tempOnClose'] = do1;
12
13
  }
13
14
  },
@@ -17,10 +18,12 @@ export function remultApi(options) {
17
18
  getRequestBody: (event) => event.request.json(),
18
19
  });
19
20
  const serverHandler = async (evt) => {
20
- const event = (await getRequestEvent()) ?? evt;
21
+ const event = getRequestEvent() ?? evt;
21
22
  let sseResponse = undefined;
22
- if (event)
23
+ if (event) {
24
+ event.locals ??= {};
23
25
  event.locals['_tempOnClose'] = () => { };
26
+ }
24
27
  const response = {
25
28
  end: () => { },
26
29
  json: () => { },
@@ -233,6 +233,8 @@ export class DataApi {
233
233
  include: this.includeNone(),
234
234
  };
235
235
  findOptions.where = await this.buildWhere(request, body);
236
+ if (body?.args)
237
+ findOptions.args = body.args;
236
238
  if (request) {
237
239
  let sort = request.get('_sort');
238
240
  if (sort != undefined) {
@@ -71,6 +71,7 @@ export function findOptionsFromJson(json, meta) {
71
71
  'orderBy',
72
72
  'include',
73
73
  'select',
74
+ 'args',
74
75
  ]) {
75
76
  if (json[key] !== undefined) {
76
77
  if (key === 'where') {
@@ -200,8 +201,9 @@ export class RestEntityDataProvider {
200
201
  if (options) {
201
202
  if (options.where) {
202
203
  filterObject = options.where.toJson(); // options.where.__applyToConsumer(new FilterConsumnerBridgeToUrlBuilder(url));
203
- if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
204
- filterObject = undefined;
204
+ if (options.args === undefined)
205
+ if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
206
+ filterObject = undefined;
205
207
  }
206
208
  if (options.orderBy && options.orderBy.Segments) {
207
209
  let sort = '';
@@ -244,6 +246,8 @@ export class RestEntityDataProvider {
244
246
  else
245
247
  body = { ...body, where: filterObject };
246
248
  }
249
+ if (options?.args)
250
+ body.args = options.args;
247
251
  if (body && method != 'put')
248
252
  return this.http().post(u.url, body);
249
253
  else
@@ -1,4 +1,4 @@
1
- import { FilterConsumerBridgeToSqlRequest, dbNamesOfWithForceSqlExpression, isDbReadonly, } from '../filter/filter-consumer-bridge-to-sql-request.js';
1
+ import { FilterConsumerBridgeToSqlRequest, dbNamesOfWithForceSqlExpression, isDbReadonly, toDbSql, } from '../filter/filter-consumer-bridge-to-sql-request.js';
2
2
  import { Filter, customDatabaseFilterToken, } from '../filter/filter-interfaces.js';
3
3
  import { remult as defaultRemult } from '../remult-proxy.js';
4
4
  import { GroupByCountMember, GroupByOperators, } from '../remult3/remult3.js';
@@ -7,6 +7,7 @@ import { Sort } from '../sort.js';
7
7
  import { ValueConverters } from '../valueConverters.js';
8
8
  import { getRepositoryInternals } from '../remult3/repository-internals.js';
9
9
  import { isOfType } from '../isOfType.js';
10
+ import { originalSqlExpressionKey } from '../filter/fieldDbName.js';
10
11
  /**
11
12
  * A DataProvider for Sql Databases
12
13
  * @example
@@ -292,10 +293,10 @@ class ActualSQLEntityDataProvider {
292
293
  }
293
294
  async find(options) {
294
295
  let e = await this.init();
295
- let { colKeys, select } = this.buildSelect(e, options?.select);
296
+ let r = this.sql.createCommand();
297
+ let { colKeys, select } = await this.buildSelect(e, r, options?.select, options?.args);
296
298
  select = 'select ' + select;
297
299
  select += '\n from ' + e.$entityName;
298
- let r = this.sql.createCommand();
299
300
  if (options) {
300
301
  if (options.where) {
301
302
  let where = new FilterConsumerBridgeToSqlRequest(r, e);
@@ -321,7 +322,9 @@ class ActualSQLEntityDataProvider {
321
322
  }
322
323
  else
323
324
  select += ', ';
324
- select += e.$dbNameOf(c.field);
325
+ select += c.field.options.sqlExpression
326
+ ? c.field.options.key
327
+ : await e.$dbNameOf(c.field);
325
328
  if (c.isDescending)
326
329
  select += ' desc';
327
330
  if (this.sql._getSourceSql().orderByNullsFirst) {
@@ -362,7 +365,7 @@ class ActualSQLEntityDataProvider {
362
365
  }
363
366
  return result;
364
367
  }
365
- buildSelect(e, selectedFields) {
368
+ async buildSelect(e, r, selectedFields, args) {
366
369
  let select = '';
367
370
  let colKeys = [];
368
371
  for (const x of this.entity.fields) {
@@ -373,7 +376,15 @@ class ActualSQLEntityDataProvider {
373
376
  else {
374
377
  if (colKeys.length > 0)
375
378
  select += ', ';
376
- select += e.$dbNameOf(x);
379
+ if (typeof x.options.sqlExpression === 'function') {
380
+ let sql = await x[originalSqlExpressionKey](this.entity, args, r);
381
+ if (sql.includes(' '))
382
+ select += '(' + sql + ')';
383
+ else
384
+ select += sql;
385
+ }
386
+ else
387
+ select += e.$dbNameOf(x);
377
388
  if (x.options.sqlExpression)
378
389
  select += ' as ' + x.key;
379
390
  colKeys.push(x);
@@ -396,7 +407,7 @@ class ActualSQLEntityDataProvider {
396
407
  added = true;
397
408
  else
398
409
  statement += ', ';
399
- statement += e.$dbNameOf(x) + ' = ' + r.param(v);
410
+ statement += e.$dbNameOf(x) + ' = ' + toDbSql(r, x, v);
400
411
  }
401
412
  }
402
413
  }
@@ -404,7 +415,7 @@ class ActualSQLEntityDataProvider {
404
415
  let f = new FilterConsumerBridgeToSqlRequest(r, e);
405
416
  Filter.fromEntityFilter(this.entity, idFilter).__applyToConsumer(f);
406
417
  statement += await f.resolveWhere();
407
- let { colKeys, select } = this.buildSelect(e);
418
+ let { colKeys, select } = await this.buildSelect(e, r, undefined, undefined);
408
419
  let returning = true;
409
420
  if (this.sql._getSourceSql().doesNotSupportReturningSyntax)
410
421
  returning = false;
@@ -456,12 +467,12 @@ class ActualSQLEntityDataProvider {
456
467
  vals += ', ';
457
468
  }
458
469
  cols += e.$dbNameOf(x);
459
- vals += r.param(v);
470
+ vals += toDbSql(r, x, v);
460
471
  }
461
472
  }
462
473
  }
463
474
  let statement = `insert into ${e.$entityName} (${cols}) values (${vals})`;
464
- let { colKeys, select } = this.buildSelect(e);
475
+ let { colKeys, select } = await this.buildSelect(e, r, undefined, undefined);
465
476
  if (!this.sql._getSourceSql().doesNotSupportReturningSyntax)
466
477
  statement += ' returning ' + select;
467
478
  return await r.execute(statement).then((sql) => {
@@ -1,5 +1,6 @@
1
1
  import { getRelationFieldInfo } from '../remult3/relationInfoMember.js';
2
2
  const sqlExpressionInProgressKey = Symbol.for(`sqlExpressionInProgressKey`);
3
+ export const originalSqlExpressionKey = Symbol.for(`originalSqlExpressionKey`);
3
4
  export async function fieldDbName(f, meta, wrapIdentifier = (x) => x, forceSqlExpression = false) {
4
5
  try {
5
6
  if (f.options.sqlExpression) {
@@ -11,7 +12,9 @@ export async function fieldDbName(f, meta, wrapIdentifier = (x) => x, forceSqlEx
11
12
  try {
12
13
  ;
13
14
  f[sqlExpressionInProgressKey] = true;
14
- result = await f.options.sqlExpression(meta);
15
+ if (!f[originalSqlExpressionKey])
16
+ f[originalSqlExpressionKey] = f.options.sqlExpression;
17
+ result = await f.options.sqlExpression(meta, undefined, undefined);
15
18
  if (!result.includes('\0'))
16
19
  f.options.sqlExpression = () => result;
17
20
  }
@@ -73,7 +73,7 @@ export class FilterConsumerBridgeToSqlRequest {
73
73
  this.addToWhere(this.nameProvider.$dbNameOf(col) +
74
74
  ' in (' +
75
75
  val
76
- .map((x) => this.r.param(col.valueConverter.toDb(x)))
76
+ .map((x) => toDbSql(this.r, col, col.valueConverter.toDb(x)))
77
77
  .join(',') +
78
78
  ')');
79
79
  else
@@ -140,7 +140,7 @@ export class FilterConsumerBridgeToSqlRequest {
140
140
  ' ' +
141
141
  operator +
142
142
  ' ' +
143
- this.r.param(col.valueConverter.toDb(val));
143
+ toDbSql(this.r, col, col.valueConverter.toDb(val));
144
144
  this.addToWhere(x);
145
145
  })());
146
146
  }
@@ -261,3 +261,6 @@ async function internalDbNamesOf(repo, wrapIdentifierOrOptions, forceSqlExpressi
261
261
  }
262
262
  return result;
263
263
  }
264
+ export function toDbSql(r, field, val) {
265
+ return (field.valueConverter.toDbSql ?? ((x) => x))(r.param(val));
266
+ }
@@ -583,6 +583,8 @@ export class RepositoryImplementation {
583
583
  options = { ...options };
584
584
  let opt = {};
585
585
  opt = {};
586
+ if (options.args)
587
+ opt.args = options.args;
586
588
  if (options.select) {
587
589
  opt.select = Object.keys(options.select)
588
590
  .filter((x) => options.select[x])
@@ -41,6 +41,14 @@ export const flags = {
41
41
 
42
42
  -
43
43
  */
44
+ /*p1 - https://github.com/remult/remult/discussions/438
45
+ - should we use the arg for update and insert? for the returning query?
46
+ - Does dbNamesOf still makes sense? I think that abstraction, regarding sql expression has lost it's merit
47
+ - remember caching of sql expression calculations that took a recursive amount of time for JYC
48
+ - maybe introduce a ready dbNamesOf of argument that will be aware of prefixes
49
+ - I've changed the order by to support order by 1
50
+
51
+ */
44
52
  //p1 - deleteAll({title:undefined}) should throw an error - not return 0 (with direct call to db)
45
53
  //p1 - remult-create, move db question ahead of auth - everyone needs a database, not everyone need auth
46
54
  //p1 - allow experimental route registration on remult server, with at least get route, and support redirect, read header and set header - (and the existing get html etc...)
@@ -175,6 +175,7 @@ export class ValueConverters {
175
175
  toDb: (x) => ValueConverters.JsonString.toDb(x),
176
176
  fromInput: (x) => ValueConverters.Default.fromJson(x),
177
177
  toInput: (x) => ValueConverters.Default.toJson(x),
178
+ toDbSql: (x) => x,
178
179
  displayValue: (x) => x + '',
179
180
  fieldTypeInDb: '',
180
181
  inputType: 'text',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "3.2.2-next.1",
3
+ "version": "3.3.0-next.1",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -13,7 +13,9 @@ function remultApi(options) {
13
13
  url: event.request.url,
14
14
  method: event.request.method,
15
15
  on: function (e, do1) {
16
+ var _a;
16
17
  if (e === 'close') {
18
+ (_a = event.locals) !== null && _a !== void 0 ? _a : (event.locals = {});
17
19
  event.locals['_tempOnClose'] = do1;
18
20
  }
19
21
  },
@@ -24,15 +26,16 @@ function remultApi(options) {
24
26
  });
25
27
  var serverHandler = function (evt) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
26
28
  var event, sseResponse, response, responseFromRemultHandler, res;
27
- var _a;
28
- return tslib_1.__generator(this, function (_b) {
29
- switch (_b.label) {
30
- case 0: return [4 /*yield*/, (0, web_1.getRequestEvent)()];
31
- case 1:
32
- event = (_a = (_b.sent())) !== null && _a !== void 0 ? _a : evt;
29
+ var _a, _b;
30
+ return tslib_1.__generator(this, function (_c) {
31
+ switch (_c.label) {
32
+ case 0:
33
+ event = (_a = (0, web_1.getRequestEvent)()) !== null && _a !== void 0 ? _a : evt;
33
34
  sseResponse = undefined;
34
- if (event)
35
+ if (event) {
36
+ (_b = event.locals) !== null && _b !== void 0 ? _b : (event.locals = {});
35
37
  event.locals['_tempOnClose'] = function () { };
38
+ }
36
39
  response = {
37
40
  end: function () { },
38
41
  json: function () { },
@@ -79,8 +82,8 @@ function remultApi(options) {
79
82
  },
80
83
  };
81
84
  return [4 /*yield*/, result.handle(event, response)];
82
- case 2:
83
- responseFromRemultHandler = _b.sent();
85
+ case 1:
86
+ responseFromRemultHandler = _c.sent();
84
87
  if (sseResponse !== undefined) {
85
88
  return [2 /*return*/, sseResponse];
86
89
  }
@@ -1,6 +1,7 @@
1
1
  import type { ClassType } from '../classType.js';
2
2
  import type { AllowedForInstance } from './context.js';
3
3
  import type { EntityMetadata, FieldRef, LifecycleEvent, ValidateFieldEvent } from './remult3/remult3.js';
4
+ import type { SqlCommandWithParameters } from './sql-command.js';
4
5
  export interface FieldOptions<entityType = unknown, valueType = unknown> {
5
6
  /** A human readable name for the field. Can be used to achieve a consistent caption for a field throughout the app
6
7
  * @example
@@ -103,7 +104,7 @@ export interface FieldOptions<entityType = unknown, valueType = unknown> {
103
104
  * @Fields.string()
104
105
  * title='';
105
106
  */
106
- sqlExpression?: string | ((entity: EntityMetadata<entityType>) => string | Promise<string>);
107
+ sqlExpression?: string | ((entity: EntityMetadata<entityType>, args?: any, command?: SqlCommandWithParameters) => string | Promise<string>);
107
108
  /** For fields that shouldn't be part of an update or insert statement */
108
109
  dbReadOnly?: boolean;
109
110
  /** The value converter to be used when loading and saving this field */
@@ -293,6 +294,7 @@ export interface ValueConverter<valueType> {
293
294
  * toDb: val => val?.toISOString()
294
295
  */
295
296
  toDb?(val: valueType): any;
297
+ toDbSql?(val: string): string;
296
298
  /**
297
299
  * Converts a value of valueType to a string suitable for an HTML input element.
298
300
  *
package/src/data-api.js CHANGED
@@ -482,6 +482,8 @@ var DataApi = /** @class */ (function () {
482
482
  return [4 /*yield*/, this.buildWhere(request, body)];
483
483
  case 1:
484
484
  _a.where = _b.sent();
485
+ if (body === null || body === void 0 ? void 0 : body.args)
486
+ findOptions.args = body.args;
485
487
  if (request) {
486
488
  sort = request.get('_sort');
487
489
  if (sort != undefined) {
@@ -49,6 +49,7 @@ export interface EntityDataProviderFindOptions {
49
49
  select?: string[];
50
50
  where?: Filter;
51
51
  limit?: number;
52
+ args?: any;
52
53
  page?: number;
53
54
  orderBy?: Sort;
54
55
  }
@@ -82,6 +82,7 @@ function findOptionsFromJson(json, meta) {
82
82
  'orderBy',
83
83
  'include',
84
84
  'select',
85
+ 'args',
85
86
  ]), _c = _b.next(); !_c.done; _c = _b.next()) {
86
87
  var key = _c.value;
87
88
  if (json[key] !== undefined) {
@@ -288,8 +289,9 @@ var RestEntityDataProvider = /** @class */ (function () {
288
289
  if (options) {
289
290
  if (options.where) {
290
291
  filterObject = options.where.toJson(); // options.where.__applyToConsumer(new FilterConsumnerBridgeToUrlBuilder(url));
291
- if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
292
- filterObject = undefined;
292
+ if (options.args === undefined)
293
+ if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
294
+ filterObject = undefined;
293
295
  }
294
296
  if (options.orderBy && options.orderBy.Segments) {
295
297
  var sort_1 = '';
@@ -332,6 +334,8 @@ var RestEntityDataProvider = /** @class */ (function () {
332
334
  else
333
335
  body = tslib_1.__assign(tslib_1.__assign({}, body), { where: filterObject });
334
336
  }
337
+ if (options === null || options === void 0 ? void 0 : options.args)
338
+ body.args = options.args;
335
339
  if (body && method != 'put')
336
340
  return _this.http().post(u.url, body);
337
341
  else
@@ -13,6 +13,7 @@ var sort_js_1 = require("../sort.js");
13
13
  var valueConverters_js_1 = require("../valueConverters.js");
14
14
  var repository_internals_js_1 = require("../remult3/repository-internals.js");
15
15
  var isOfType_js_1 = require("../isOfType.js");
16
+ var fieldDbName_js_1 = require("../filter/fieldDbName.js");
16
17
  /**
17
18
  * A DataProvider for Sql Databases
18
19
  * @example
@@ -413,78 +414,100 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
413
414
  };
414
415
  ActualSQLEntityDataProvider.prototype.find = function (options) {
415
416
  return tslib_1.__awaiter(this, void 0, void 0, function () {
416
- var e, _a, colKeys, select, r, where, _b, first, segs, _c, _d, s, segs_1, segs_1_1, c, page;
417
- var e_2, _e, e_3, _f;
417
+ var e, r, _a, colKeys, select, where, _b, first, segs, _c, _d, s, segs_1, segs_1_1, c, _e, _f, e_2_1, page;
418
+ var e_3, _g, e_2, _h;
418
419
  var _this = this;
419
- return tslib_1.__generator(this, function (_g) {
420
- switch (_g.label) {
420
+ return tslib_1.__generator(this, function (_j) {
421
+ switch (_j.label) {
421
422
  case 0: return [4 /*yield*/, this.init()];
422
423
  case 1:
423
- e = _g.sent();
424
- _a = this.buildSelect(e, options === null || options === void 0 ? void 0 : options.select), colKeys = _a.colKeys, select = _a.select;
424
+ e = _j.sent();
425
+ r = this.sql.createCommand();
426
+ return [4 /*yield*/, this.buildSelect(e, r, options === null || options === void 0 ? void 0 : options.select, options === null || options === void 0 ? void 0 : options.args)];
427
+ case 2:
428
+ _a = _j.sent(), colKeys = _a.colKeys, select = _a.select;
425
429
  select = 'select ' + select;
426
430
  select += '\n from ' + e.$entityName;
427
- r = this.sql.createCommand();
428
- if (!options) return [3 /*break*/, 4];
429
- if (!options.where) return [3 /*break*/, 3];
431
+ if (!options) return [3 /*break*/, 15];
432
+ if (!options.where) return [3 /*break*/, 4];
430
433
  where = new filter_consumer_bridge_to_sql_request_js_1.FilterConsumerBridgeToSqlRequest(r, e);
431
434
  options.where.__applyToConsumer(where);
432
435
  _b = select;
433
436
  return [4 /*yield*/, where.resolveWhere()];
434
- case 2:
435
- select = _b + _g.sent();
436
- _g.label = 3;
437
437
  case 3:
438
+ select = _b + _j.sent();
439
+ _j.label = 4;
440
+ case 4:
438
441
  if (options.limit) {
439
442
  options.orderBy = sort_js_1.Sort.createUniqueSort(this.entity, options.orderBy);
440
443
  }
441
444
  if (!options.orderBy) {
442
445
  options.orderBy = sort_js_1.Sort.createUniqueSort(this.entity, new sort_js_1.Sort());
443
446
  }
444
- if (options.orderBy) {
445
- first = true;
446
- segs = [];
447
- try {
448
- for (_c = tslib_1.__values(options.orderBy.Segments), _d = _c.next(); !_d.done; _d = _c.next()) {
449
- s = _d.value;
450
- segs.push(s);
451
- }
452
- }
453
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
454
- finally {
455
- try {
456
- if (_d && !_d.done && (_e = _c.return)) _e.call(_c);
457
- }
458
- finally { if (e_2) throw e_2.error; }
447
+ if (!options.orderBy) return [3 /*break*/, 14];
448
+ first = true;
449
+ segs = [];
450
+ try {
451
+ for (_c = tslib_1.__values(options.orderBy.Segments), _d = _c.next(); !_d.done; _d = _c.next()) {
452
+ s = _d.value;
453
+ segs.push(s);
459
454
  }
455
+ }
456
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
457
+ finally {
460
458
  try {
461
- for (segs_1 = tslib_1.__values(segs), segs_1_1 = segs_1.next(); !segs_1_1.done; segs_1_1 = segs_1.next()) {
462
- c = segs_1_1.value;
463
- if (first) {
464
- select += ' Order By ';
465
- first = false;
466
- }
467
- else
468
- select += ', ';
469
- select += e.$dbNameOf(c.field);
470
- if (c.isDescending)
471
- select += ' desc';
472
- if (this.sql._getSourceSql().orderByNullsFirst) {
473
- if (c.isDescending)
474
- select += ' nulls last';
475
- else
476
- select += ' nulls first';
477
- }
478
- }
479
- }
480
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
481
- finally {
482
- try {
483
- if (segs_1_1 && !segs_1_1.done && (_f = segs_1.return)) _f.call(segs_1);
484
- }
485
- finally { if (e_3) throw e_3.error; }
459
+ if (_d && !_d.done && (_g = _c.return)) _g.call(_c);
486
460
  }
461
+ finally { if (e_3) throw e_3.error; }
487
462
  }
463
+ _j.label = 5;
464
+ case 5:
465
+ _j.trys.push([5, 12, 13, 14]);
466
+ segs_1 = tslib_1.__values(segs), segs_1_1 = segs_1.next();
467
+ _j.label = 6;
468
+ case 6:
469
+ if (!!segs_1_1.done) return [3 /*break*/, 11];
470
+ c = segs_1_1.value;
471
+ if (first) {
472
+ select += ' Order By ';
473
+ first = false;
474
+ }
475
+ else
476
+ select += ', ';
477
+ _e = select;
478
+ if (!c.field.options.sqlExpression) return [3 /*break*/, 7];
479
+ _f = c.field.options.key;
480
+ return [3 /*break*/, 9];
481
+ case 7: return [4 /*yield*/, e.$dbNameOf(c.field)];
482
+ case 8:
483
+ _f = _j.sent();
484
+ _j.label = 9;
485
+ case 9:
486
+ select = _e + _f;
487
+ if (c.isDescending)
488
+ select += ' desc';
489
+ if (this.sql._getSourceSql().orderByNullsFirst) {
490
+ if (c.isDescending)
491
+ select += ' nulls last';
492
+ else
493
+ select += ' nulls first';
494
+ }
495
+ _j.label = 10;
496
+ case 10:
497
+ segs_1_1 = segs_1.next();
498
+ return [3 /*break*/, 6];
499
+ case 11: return [3 /*break*/, 14];
500
+ case 12:
501
+ e_2_1 = _j.sent();
502
+ e_2 = { error: e_2_1 };
503
+ return [3 /*break*/, 14];
504
+ case 13:
505
+ try {
506
+ if (segs_1_1 && !segs_1_1.done && (_h = segs_1.return)) _h.call(segs_1);
507
+ }
508
+ finally { if (e_2) throw e_2.error; }
509
+ return [7 /*endfinally*/];
510
+ case 14:
488
511
  if (options.limit) {
489
512
  page = 1;
490
513
  if (options.page)
@@ -495,8 +518,8 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
495
518
  ' ' +
496
519
  this.strategy.getLimitSqlSyntax(options.limit, (page - 1) * options.limit);
497
520
  }
498
- _g.label = 4;
499
- case 4: return [2 /*return*/, r.execute(select).then(function (r) {
521
+ _j.label = 15;
522
+ case 15: return [2 /*return*/, r.execute(select).then(function (r) {
500
523
  return r.rows.map(function (y) {
501
524
  return _this.buildResultRow(colKeys, y, r);
502
525
  });
@@ -518,35 +541,65 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
518
541
  }
519
542
  return result;
520
543
  };
521
- ActualSQLEntityDataProvider.prototype.buildSelect = function (e, selectedFields) {
522
- var e_4, _a;
523
- var select = '';
524
- var colKeys = [];
525
- try {
526
- for (var _b = tslib_1.__values(this.entity.fields), _c = _b.next(); !_c.done; _c = _b.next()) {
527
- var x = _c.value;
528
- if (selectedFields && !selectedFields.includes(x.key))
529
- continue;
530
- if (x.isServerExpression) {
531
- }
532
- else {
533
- if (colKeys.length > 0)
534
- select += ', ';
535
- select += e.$dbNameOf(x);
536
- if (x.options.sqlExpression)
537
- select += ' as ' + x.key;
538
- colKeys.push(x);
544
+ ActualSQLEntityDataProvider.prototype.buildSelect = function (e, r, selectedFields, args) {
545
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
546
+ var select, colKeys, _a, _b, x, sql, e_4_1;
547
+ var e_4, _c;
548
+ return tslib_1.__generator(this, function (_d) {
549
+ switch (_d.label) {
550
+ case 0:
551
+ select = '';
552
+ colKeys = [];
553
+ _d.label = 1;
554
+ case 1:
555
+ _d.trys.push([1, 9, 10, 11]);
556
+ _a = tslib_1.__values(this.entity.fields), _b = _a.next();
557
+ _d.label = 2;
558
+ case 2:
559
+ if (!!_b.done) return [3 /*break*/, 8];
560
+ x = _b.value;
561
+ if (selectedFields && !selectedFields.includes(x.key))
562
+ return [3 /*break*/, 7];
563
+ if (!x.isServerExpression) return [3 /*break*/, 3];
564
+ return [3 /*break*/, 7];
565
+ case 3:
566
+ if (colKeys.length > 0)
567
+ select += ', ';
568
+ if (!(typeof x.options.sqlExpression === 'function')) return [3 /*break*/, 5];
569
+ return [4 /*yield*/, x[fieldDbName_js_1.originalSqlExpressionKey](this.entity, args, r)];
570
+ case 4:
571
+ sql = _d.sent();
572
+ if (sql.includes(' '))
573
+ select += '(' + sql + ')';
574
+ else
575
+ select += sql;
576
+ return [3 /*break*/, 6];
577
+ case 5:
578
+ select += e.$dbNameOf(x);
579
+ _d.label = 6;
580
+ case 6:
581
+ if (x.options.sqlExpression)
582
+ select += ' as ' + x.key;
583
+ colKeys.push(x);
584
+ _d.label = 7;
585
+ case 7:
586
+ _b = _a.next();
587
+ return [3 /*break*/, 2];
588
+ case 8: return [3 /*break*/, 11];
589
+ case 9:
590
+ e_4_1 = _d.sent();
591
+ e_4 = { error: e_4_1 };
592
+ return [3 /*break*/, 11];
593
+ case 10:
594
+ try {
595
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
596
+ }
597
+ finally { if (e_4) throw e_4.error; }
598
+ return [7 /*endfinally*/];
599
+ case 11: return [2 /*return*/, { colKeys: colKeys, select: select }];
539
600
  }
540
- }
541
- }
542
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
543
- finally {
544
- try {
545
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
546
- }
547
- finally { if (e_4) throw e_4.error; }
548
- }
549
- return { colKeys: colKeys, select: select };
601
+ });
602
+ });
550
603
  };
551
604
  ActualSQLEntityDataProvider.prototype.update = function (id, data) {
552
605
  return tslib_1.__awaiter(this, void 0, void 0, function () {
@@ -573,7 +626,7 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
573
626
  added = true;
574
627
  else
575
628
  statement += ', ';
576
- statement += e.$dbNameOf(x) + ' = ' + r.param(v);
629
+ statement += e.$dbNameOf(x) + ' = ' + (0, filter_consumer_bridge_to_sql_request_js_1.toDbSql)(r, x, v);
577
630
  }
578
631
  }
579
632
  }
@@ -592,7 +645,9 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
592
645
  return [4 /*yield*/, f.resolveWhere()];
593
646
  case 2:
594
647
  statement = _c + _f.sent();
595
- _d = this.buildSelect(e), colKeys = _d.colKeys, select = _d.select;
648
+ return [4 /*yield*/, this.buildSelect(e, r, undefined, undefined)];
649
+ case 3:
650
+ _d = _f.sent(), colKeys = _d.colKeys, select = _d.select;
596
651
  returning = true;
597
652
  if (this.sql._getSourceSql().doesNotSupportReturningSyntax)
598
653
  returning = false;
@@ -672,7 +727,7 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
672
727
  vals += ', ';
673
728
  }
674
729
  cols += e.$dbNameOf(x);
675
- vals += r.param(v);
730
+ vals += (0, filter_consumer_bridge_to_sql_request_js_1.toDbSql)(r, x, v);
676
731
  }
677
732
  }
678
733
  }
@@ -685,7 +740,9 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
685
740
  finally { if (e_6) throw e_6.error; }
686
741
  }
687
742
  statement = "insert into ".concat(e.$entityName, " (").concat(cols, ") values (").concat(vals, ")");
688
- _c = this.buildSelect(e), colKeys = _c.colKeys, select = _c.select;
743
+ return [4 /*yield*/, this.buildSelect(e, r, undefined, undefined)];
744
+ case 2:
745
+ _c = _e.sent(), colKeys = _c.colKeys, select = _c.select;
689
746
  if (!this.sql._getSourceSql().doesNotSupportReturningSyntax)
690
747
  statement += ' returning ' + select;
691
748
  return [4 /*yield*/, r.execute(statement).then(function (sql) {
@@ -709,7 +766,7 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
709
766
  }
710
767
  return _this.buildResultRow(colKeys, sql.rows[0], sql);
711
768
  })];
712
- case 2: return [2 /*return*/, _e.sent()];
769
+ case 3: return [2 /*return*/, _e.sent()];
713
770
  }
714
771
  });
715
772
  });
@@ -1,3 +1,4 @@
1
- import type { EntityMetadata } from "../remult3/remult3.js";
1
+ import type { EntityMetadata } from '../remult3/remult3.js';
2
2
  import type { FieldMetadata } from '../column-interfaces.js';
3
+ export declare const originalSqlExpressionKey: unique symbol;
3
4
  export declare function fieldDbName(f: FieldMetadata, meta: EntityMetadata, wrapIdentifier?: (name: string) => string, forceSqlExpression?: boolean): Promise<string>;
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.originalSqlExpressionKey = void 0;
3
4
  exports.fieldDbName = fieldDbName;
4
5
  var tslib_1 = require("tslib");
5
6
  var relationInfoMember_js_1 = require("../remult3/relationInfoMember.js");
6
7
  var sqlExpressionInProgressKey = Symbol.for("sqlExpressionInProgressKey");
8
+ exports.originalSqlExpressionKey = Symbol.for("originalSqlExpressionKey");
7
9
  function fieldDbName(f_1, meta_1) {
8
10
  return tslib_1.__awaiter(this, arguments, void 0, function (f, meta, wrapIdentifier, forceSqlExpression) {
9
11
  var result_1, rel, field, fInfo;
@@ -23,7 +25,9 @@ function fieldDbName(f_1, meta_1) {
23
25
  _a.trys.push([1, , 3, 4]);
24
26
  ;
25
27
  f[sqlExpressionInProgressKey] = true;
26
- return [4 /*yield*/, f.options.sqlExpression(meta)];
28
+ if (!f[exports.originalSqlExpressionKey])
29
+ f[exports.originalSqlExpressionKey] = f.options.sqlExpression;
30
+ return [4 /*yield*/, f.options.sqlExpression(meta, undefined, undefined)];
27
31
  case 2:
28
32
  result_1 = _a.sent();
29
33
  if (!result_1.includes('\0'))
@@ -84,3 +84,4 @@ export interface dbNamesOfOptions {
84
84
  }
85
85
  export declare function dbNamesOf<entityType>(repo: EntityMetadataOverloads<entityType>, wrapIdentifierOrOptions?: ((name: string) => string) | dbNamesOfOptions): Promise<EntityDbNames<entityType>>;
86
86
  export declare function dbNamesOfWithForceSqlExpression<entityType>(repo: EntityMetadataOverloads<entityType>, wrapIdentifierOrOptions?: ((name: string) => string) | dbNamesOfOptions): Promise<EntityDbNames<entityType>>;
87
+ export declare function toDbSql(r: SqlCommandWithParameters, field: FieldMetadata, val: any): string;
@@ -6,6 +6,7 @@ exports.shouldNotCreateField = shouldNotCreateField;
6
6
  exports.shouldCreateEntity = shouldCreateEntity;
7
7
  exports.dbNamesOf = dbNamesOf;
8
8
  exports.dbNamesOfWithForceSqlExpression = dbNamesOfWithForceSqlExpression;
9
+ exports.toDbSql = toDbSql;
9
10
  var tslib_1 = require("tslib");
10
11
  var sql_database_js_1 = require("../data-providers/sql-database.js");
11
12
  var remult_proxy_js_1 = require("../remult-proxy.js");
@@ -162,7 +163,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
162
163
  this.addToWhere(this.nameProvider.$dbNameOf(col) +
163
164
  ' in (' +
164
165
  val
165
- .map(function (x) { return _this.r.param(col.valueConverter.toDb(x)); })
166
+ .map(function (x) { return toDbSql(_this.r, col, col.valueConverter.toDb(x)); })
166
167
  .join(',') +
167
168
  ')');
168
169
  else
@@ -250,7 +251,7 @@ var FilterConsumerBridgeToSqlRequest = /** @class */ (function () {
250
251
  ' ' +
251
252
  operator +
252
253
  ' ' +
253
- this.r.param(col.valueConverter.toDb(val));
254
+ toDbSql(this.r, col, col.valueConverter.toDb(val));
254
255
  this.addToWhere(x);
255
256
  return [2 /*return*/];
256
257
  });
@@ -431,3 +432,7 @@ function internalDbNamesOf(repo_1, wrapIdentifierOrOptions_1) {
431
432
  });
432
433
  });
433
434
  }
435
+ function toDbSql(r, field, val) {
436
+ var _a;
437
+ return ((_a = field.valueConverter.toDbSql) !== null && _a !== void 0 ? _a : (function (x) { return x; }))(r.param(val));
438
+ }
@@ -952,6 +952,8 @@ var RepositoryImplementation = /** @class */ (function () {
952
952
  options = tslib_1.__assign({}, options);
953
953
  opt = {};
954
954
  opt = {};
955
+ if (options.args)
956
+ opt.args = options.args;
955
957
  if (options.select) {
956
958
  opt.select = Object.keys(options.select)
957
959
  .filter(function (x) { return options.select[x]; })
@@ -1069,6 +1069,7 @@ export interface FindOptionsBase<entityType> extends LoadOptions<entityType> {
1069
1069
  * await repo(Products).find({ orderBy: { price: "desc", name: "asc" }})
1070
1070
  */
1071
1071
  orderBy?: EntityOrderBy<entityType>;
1072
+ args?: any;
1072
1073
  }
1073
1074
  export interface FindFirstOptions<entityType> extends FindOptionsBase<entityType>, FindFirstOptionsBase<entityType> {
1074
1075
  }
@@ -44,6 +44,14 @@ exports.flags = {
44
44
 
45
45
  -
46
46
  */
47
+ /*p1 - https://github.com/remult/remult/discussions/438
48
+ - should we use the arg for update and insert? for the returning query?
49
+ - Does dbNamesOf still makes sense? I think that abstraction, regarding sql expression has lost it's merit
50
+ - remember caching of sql expression calculations that took a recursive amount of time for JYC
51
+ - maybe introduce a ready dbNamesOf of argument that will be aware of prefixes
52
+ - I've changed the order by to support order by 1
53
+
54
+ */
47
55
  //p1 - deleteAll({title:undefined}) should throw an error - not return 0 (with direct call to db)
48
56
  //p1 - remult-create, move db question ahead of auth - everyone needs a database, not everyone need auth
49
57
  //p1 - allow experimental route registration on remult server, with at least get route, and support redirect, read header and set header - (and the existing get html etc...)
@@ -173,6 +173,7 @@ var ValueConverters = /** @class */ (function () {
173
173
  toDb: function (x) { return ValueConverters.JsonString.toDb(x); },
174
174
  fromInput: function (x) { return ValueConverters.Default.fromJson(x); },
175
175
  toInput: function (x) { return ValueConverters.Default.toJson(x); },
176
+ toDbSql: function (x) { return x; },
176
177
  displayValue: function (x) { return x + ''; },
177
178
  fieldTypeInDb: '',
178
179
  inputType: 'text',