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.
- package/esm/remult-solid-start.js +5 -2
- package/esm/src/data-api.js +2 -0
- package/esm/src/data-providers/rest-data-provider.js +6 -2
- package/esm/src/data-providers/sql-database.js +21 -10
- package/esm/src/filter/fieldDbName.js +4 -1
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +5 -2
- package/esm/src/remult3/RepositoryImplementation.js +2 -0
- package/esm/src/remult3/remult3.js +8 -0
- package/esm/src/valueConverters.js +1 -0
- package/package.json +1 -1
- package/remult-solid-start.js +12 -9
- package/src/column-interfaces.d.ts +3 -1
- package/src/data-api.js +2 -0
- package/src/data-interfaces.d.ts +1 -0
- package/src/data-providers/rest-data-provider.js +6 -2
- package/src/data-providers/sql-database.js +144 -87
- package/src/filter/fieldDbName.d.ts +2 -1
- package/src/filter/fieldDbName.js +5 -1
- package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +1 -0
- package/src/filter/filter-consumer-bridge-to-sql-request.js +7 -2
- package/src/remult3/RepositoryImplementation.js +2 -0
- package/src/remult3/remult3.d.ts +1 -0
- package/src/remult3/remult3.js +8 -0
- package/src/valueConverters.js +1 -0
|
@@ -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 =
|
|
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: () => { },
|
package/esm/src/data-api.js
CHANGED
|
@@ -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 (
|
|
204
|
-
filterObject
|
|
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
|
|
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 +=
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
package/remult-solid-start.js
CHANGED
|
@@ -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 (
|
|
29
|
-
switch (
|
|
30
|
-
case 0:
|
|
31
|
-
|
|
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
|
|
83
|
-
responseFromRemultHandler =
|
|
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
|
|
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) {
|
package/src/data-interfaces.d.ts
CHANGED
|
@@ -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 (
|
|
292
|
-
filterObject
|
|
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,
|
|
417
|
-
var
|
|
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 (
|
|
420
|
-
switch (
|
|
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 =
|
|
424
|
-
|
|
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
|
-
|
|
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
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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
|
-
|
|
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
|
-
|
|
499
|
-
case
|
|
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
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
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) + ' = ' +
|
|
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
|
-
|
|
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 +=
|
|
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
|
-
|
|
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
|
|
769
|
+
case 3: return [2 /*return*/, _e.sent()];
|
|
713
770
|
}
|
|
714
771
|
});
|
|
715
772
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type { EntityMetadata } from
|
|
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
|
-
|
|
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
|
|
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
|
|
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]; })
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -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
|
}
|
package/src/remult3/remult3.js
CHANGED
|
@@ -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...)
|
package/src/valueConverters.js
CHANGED
|
@@ -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',
|