remult 3.2.3 → 3.3.0
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/graphql.js +1 -1
- package/esm/remult-knex/index.js +8 -2
- package/esm/remult-mongo.js +7 -3
- package/esm/server/remult-api-server.js +1 -1
- package/esm/src/data-api.js +30 -19
- package/esm/src/data-providers/rest-data-provider.js +50 -35
- package/esm/src/data-providers/sql-database.js +35 -13
- package/esm/src/filter/fieldDbName.js +4 -1
- package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +5 -2
- package/esm/src/remult-proxy.js +4 -4
- package/esm/src/remult3/RepositoryImplementation.js +34 -17
- package/esm/src/remult3/remult3.js +8 -0
- package/esm/src/valueConverters.js +10 -5
- package/graphql.js +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/remult-knex/index.js +16 -8
- package/remult-mongo.js +6 -2
- package/server/remult-api-server.js +1 -0
- package/src/column-interfaces.d.ts +3 -1
- package/src/data-api.d.ts +4 -4
- package/src/data-api.js +50 -30
- package/src/data-interfaces.d.ts +7 -6
- package/src/data-providers/rest-data-provider.d.ts +4 -4
- package/src/data-providers/rest-data-provider.js +50 -35
- package/src/data-providers/sql-database.js +158 -90
- 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/remult-proxy.js +4 -4
- package/src/remult3/RepositoryImplementation.d.ts +6 -6
- package/src/remult3/RepositoryImplementation.js +209 -169
- package/src/remult3/remult3.d.ts +11 -7
- package/src/remult3/remult3.js +8 -0
- package/src/valueConverters.d.ts +3 -1
- package/src/valueConverters.js +10 -6
package/esm/graphql.js
CHANGED
package/esm/remult-knex/index.js
CHANGED
|
@@ -208,7 +208,7 @@ class KnexEntityDataProvider {
|
|
|
208
208
|
wrapIdentifier: r.wrapIdentifier,
|
|
209
209
|
};
|
|
210
210
|
}
|
|
211
|
-
async update(id, data) {
|
|
211
|
+
async update(id, data, options) {
|
|
212
212
|
const e = await this.init();
|
|
213
213
|
let f = new FilterConsumerBridgeToKnexRequest(e, this.rawSqlWrapIdentifier);
|
|
214
214
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
@@ -228,6 +228,8 @@ class KnexEntityDataProvider {
|
|
|
228
228
|
await this.getEntityFrom(e)
|
|
229
229
|
.update(updateObject)
|
|
230
230
|
.where((b) => where.forEach((w) => w(b)));
|
|
231
|
+
if (options?.select === 'none')
|
|
232
|
+
return undefined;
|
|
231
233
|
return getRowAfterUpdate(this.entity, this, data, id, 'update');
|
|
232
234
|
}
|
|
233
235
|
async delete(id) {
|
|
@@ -239,7 +241,7 @@ class KnexEntityDataProvider {
|
|
|
239
241
|
.delete()
|
|
240
242
|
.where((b) => where.forEach((w) => w(b)));
|
|
241
243
|
}
|
|
242
|
-
async insert(data) {
|
|
244
|
+
async insert(data, options) {
|
|
243
245
|
const e = await this.init();
|
|
244
246
|
let insertObject = {};
|
|
245
247
|
for (const x of this.entity.fields) {
|
|
@@ -265,12 +267,16 @@ class KnexEntityDataProvider {
|
|
|
265
267
|
let result = await insert.returning(this.entity.idMetadata.field.dbName);
|
|
266
268
|
newId = result[0][this.entity.idMetadata.field.dbName];
|
|
267
269
|
}
|
|
270
|
+
if (options?.select === 'none')
|
|
271
|
+
return undefined;
|
|
268
272
|
return this.find({
|
|
269
273
|
where: new Filter((x) => x.isEqualTo(this.entity.idMetadata.field, newId)),
|
|
270
274
|
}).then((y) => y[0]);
|
|
271
275
|
}
|
|
272
276
|
else
|
|
273
277
|
await insert;
|
|
278
|
+
if (options?.select === 'none')
|
|
279
|
+
return undefined;
|
|
274
280
|
return getRowAfterUpdate(this.entity, this, data, undefined, 'insert');
|
|
275
281
|
}
|
|
276
282
|
}
|
package/esm/remult-mongo.js
CHANGED
|
@@ -5,7 +5,7 @@ import { remult as remultContext } from './src/remult-proxy.js';
|
|
|
5
5
|
import { getRepository } from './src/remult3/RepositoryImplementation.js';
|
|
6
6
|
import { getRepositoryInternals } from './src/remult3/repository-internals.js';
|
|
7
7
|
import { getRowAfterUpdate } from './src/data-providers/sql-database.js';
|
|
8
|
-
import { GroupByCountMember, GroupByOperators } from './src/remult3/remult3.js';
|
|
8
|
+
import { GroupByCountMember, GroupByOperators, } from './src/remult3/remult3.js';
|
|
9
9
|
export class MongoDataProvider {
|
|
10
10
|
db;
|
|
11
11
|
client;
|
|
@@ -246,7 +246,7 @@ class MongoEntityDataProvider {
|
|
|
246
246
|
.map((x) => this.translateFromDb(x, e, options.select))
|
|
247
247
|
.toArray());
|
|
248
248
|
}
|
|
249
|
-
async update(id, data) {
|
|
249
|
+
async update(id, data, options) {
|
|
250
250
|
let { collection, e } = await this.collection();
|
|
251
251
|
let f = new FilterConsumerBridgeToMongo(e);
|
|
252
252
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
@@ -262,6 +262,8 @@ class MongoEntityDataProvider {
|
|
|
262
262
|
let r = await collection.updateOne(await f.resolveWhere(), {
|
|
263
263
|
$set: newR,
|
|
264
264
|
}, { session: this.session });
|
|
265
|
+
if (options?.select === 'none')
|
|
266
|
+
return undefined;
|
|
265
267
|
return getRowAfterUpdate(this.entity, this, data, id, 'update');
|
|
266
268
|
}
|
|
267
269
|
async delete(id) {
|
|
@@ -272,11 +274,13 @@ class MongoEntityDataProvider {
|
|
|
272
274
|
session: this.session,
|
|
273
275
|
});
|
|
274
276
|
}
|
|
275
|
-
async insert(data) {
|
|
277
|
+
async insert(data, options) {
|
|
276
278
|
let { collection, e } = await this.collection();
|
|
277
279
|
let r = await collection.insertOne(await this.translateToDb(data, e), {
|
|
278
280
|
session: this.session,
|
|
279
281
|
});
|
|
282
|
+
if (options?.select === 'none')
|
|
283
|
+
return undefined;
|
|
280
284
|
return await this.translateFromDb(await collection.findOne({ _id: r.insertedId }, { session: this.session }), e);
|
|
281
285
|
}
|
|
282
286
|
async collection() {
|
|
@@ -316,7 +316,7 @@ export class RemultServerImplementation {
|
|
|
316
316
|
//@ts-ignore
|
|
317
317
|
.get(this.process(async (c, req, res, orig) => dataApiFactory(c).get(res, orig.params.id)))
|
|
318
318
|
//@ts-ignore
|
|
319
|
-
.put(this.process(async (c, req, res, reqInfo, _, orig) => dataApiFactory(c).put(res, reqInfo.params.id, await this.coreOptions.getRequestBody(orig))))
|
|
319
|
+
.put(this.process(async (c, req, res, reqInfo, _, orig) => dataApiFactory(c).put(res, req, reqInfo.params.id, await this.coreOptions.getRequestBody(orig))))
|
|
320
320
|
//@ts-ignore
|
|
321
321
|
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, orig.params.id)));
|
|
322
322
|
}
|
package/esm/src/data-api.js
CHANGED
|
@@ -72,7 +72,7 @@ export class DataApi {
|
|
|
72
72
|
case 'query':
|
|
73
73
|
return res.success(await this.query(res, req, body));
|
|
74
74
|
default:
|
|
75
|
-
return res.created(await this.post(body));
|
|
75
|
+
return res.created(await this.post(body, req));
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
catch (err) {
|
|
@@ -93,11 +93,11 @@ export class DataApi {
|
|
|
93
93
|
include: this.includeNone(),
|
|
94
94
|
});
|
|
95
95
|
if (r.length == 0) {
|
|
96
|
-
result.push(await this.post({ ...item.where, ...item.set }));
|
|
96
|
+
result.push(await this.post({ ...item.where, ...item.set }, request));
|
|
97
97
|
}
|
|
98
98
|
else {
|
|
99
99
|
if (item.set !== undefined) {
|
|
100
|
-
result.push(
|
|
100
|
+
result.push(await this.actualUpdate(r[0], item.set, request));
|
|
101
101
|
}
|
|
102
102
|
else
|
|
103
103
|
result.push(this.repository.getEntityRef(r[0]).toApiJson());
|
|
@@ -154,8 +154,7 @@ export class DataApi {
|
|
|
154
154
|
async deleteMany(response, request, body) {
|
|
155
155
|
try {
|
|
156
156
|
let deleted = 0;
|
|
157
|
-
let where = await this.
|
|
158
|
-
Filter.throwErrorIfFilterIsEmpty(where, 'deleteMany');
|
|
157
|
+
let where = await this.prepareWhereForManyOperation(body, request);
|
|
159
158
|
return await doTransaction(this.remult, async () => {
|
|
160
159
|
for await (const x of this.repository.query({
|
|
161
160
|
where,
|
|
@@ -172,6 +171,14 @@ export class DataApi {
|
|
|
172
171
|
response.error(err, this.repository.metadata);
|
|
173
172
|
}
|
|
174
173
|
}
|
|
174
|
+
async prepareWhereForManyOperation(body, request) {
|
|
175
|
+
let where = undefined;
|
|
176
|
+
if (body?.where !== 'all') {
|
|
177
|
+
where = await this.buildWhere(request, body);
|
|
178
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'deleteMany');
|
|
179
|
+
}
|
|
180
|
+
return where;
|
|
181
|
+
}
|
|
175
182
|
async groupBy(request, body) {
|
|
176
183
|
if (!this.repository.metadata.apiReadAllowed) {
|
|
177
184
|
throw new ForbiddenError();
|
|
@@ -233,6 +240,8 @@ export class DataApi {
|
|
|
233
240
|
include: this.includeNone(),
|
|
234
241
|
};
|
|
235
242
|
findOptions.where = await this.buildWhere(request, body);
|
|
243
|
+
if (body?.args)
|
|
244
|
+
findOptions.args = body.args;
|
|
236
245
|
if (request) {
|
|
237
246
|
let sort = request.get('_sort');
|
|
238
247
|
if (sort != undefined) {
|
|
@@ -410,7 +419,7 @@ export class DataApi {
|
|
|
410
419
|
async updateManyThroughPutRequest(response, request, body) {
|
|
411
420
|
const action = request?.get('__action');
|
|
412
421
|
if (action == 'emptyId') {
|
|
413
|
-
return this.put(response, '', body);
|
|
422
|
+
return this.put(response, request, '', body);
|
|
414
423
|
}
|
|
415
424
|
return this.updateManyImplementation(response, request, {
|
|
416
425
|
where: undefined,
|
|
@@ -419,8 +428,7 @@ export class DataApi {
|
|
|
419
428
|
}
|
|
420
429
|
async updateManyImplementation(response, request, body) {
|
|
421
430
|
try {
|
|
422
|
-
let where = await this.
|
|
423
|
-
Filter.throwErrorIfFilterIsEmpty(where, 'updateMany');
|
|
431
|
+
let where = await this.prepareWhereForManyOperation(body, request);
|
|
424
432
|
return await doTransaction(this.remult, async () => {
|
|
425
433
|
let updated = 0;
|
|
426
434
|
for await (const x of this.repository.query({
|
|
@@ -428,7 +436,7 @@ export class DataApi {
|
|
|
428
436
|
include: this.includeNone(),
|
|
429
437
|
aggregate: undefined,
|
|
430
438
|
})) {
|
|
431
|
-
await this.actualUpdate(x, body.set);
|
|
439
|
+
await this.actualUpdate(x, body.set, request);
|
|
432
440
|
updated++;
|
|
433
441
|
}
|
|
434
442
|
response.success({ updated });
|
|
@@ -438,20 +446,20 @@ export class DataApi {
|
|
|
438
446
|
response.error(err, this.repository.metadata);
|
|
439
447
|
}
|
|
440
448
|
}
|
|
441
|
-
async actualUpdate(row, body) {
|
|
449
|
+
async actualUpdate(row, body, req) {
|
|
442
450
|
let ref = this.repository.getEntityRef(row);
|
|
443
451
|
await ref._updateEntityBasedOnApi(body);
|
|
444
452
|
if (!ref.apiUpdateAllowed) {
|
|
445
453
|
throw new ForbiddenError();
|
|
446
454
|
}
|
|
447
|
-
|
|
448
|
-
|
|
455
|
+
let options = req.get('_select') === 'none' ? { select: 'none' } : undefined;
|
|
456
|
+
await ref.save(options);
|
|
457
|
+
if (options?.select === 'none')
|
|
458
|
+
return undefined;
|
|
459
|
+
return ref.toApiJson();
|
|
449
460
|
}
|
|
450
|
-
async put(response, id, body) {
|
|
451
|
-
await this.doOnId(response, id, async (row) =>
|
|
452
|
-
const ref = await this.actualUpdate(row, body);
|
|
453
|
-
response.success(ref.toApiJson());
|
|
454
|
-
});
|
|
461
|
+
async put(response, req, id, body) {
|
|
462
|
+
await this.doOnId(response, id, async (row) => response.success(await this.actualUpdate(row, body, req)));
|
|
455
463
|
}
|
|
456
464
|
async actualDelete(row) {
|
|
457
465
|
if (!this.repository.getEntityRef(row).apiDeleteAllowed) {
|
|
@@ -465,14 +473,17 @@ export class DataApi {
|
|
|
465
473
|
response.deleted();
|
|
466
474
|
});
|
|
467
475
|
}
|
|
468
|
-
async post(body) {
|
|
476
|
+
async post(body, req) {
|
|
477
|
+
let options = req.get('_select') === 'none' ? { select: 'none' } : undefined;
|
|
469
478
|
const insert = async (what) => {
|
|
470
479
|
let newr = this.repository.create();
|
|
471
480
|
await this.repository.getEntityRef(newr)._updateEntityBasedOnApi(what);
|
|
472
481
|
if (!this.repository.getEntityRef(newr).apiInsertAllowed) {
|
|
473
482
|
throw new ForbiddenError();
|
|
474
483
|
}
|
|
475
|
-
await this.repository.getEntityRef(newr).save();
|
|
484
|
+
await this.repository.getEntityRef(newr).save(options);
|
|
485
|
+
if (options?.select === 'none')
|
|
486
|
+
return undefined;
|
|
476
487
|
return this.repository.getEntityRef(newr).toApiJson();
|
|
477
488
|
};
|
|
478
489
|
if (Array.isArray(body)) {
|
|
@@ -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') {
|
|
@@ -198,36 +199,42 @@ export class RestEntityDataProvider {
|
|
|
198
199
|
let url = new UrlBuilder(this.url());
|
|
199
200
|
let filterObject;
|
|
200
201
|
if (options) {
|
|
201
|
-
if (options.where) {
|
|
202
|
-
filterObject =
|
|
203
|
-
if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
204
|
-
filterObject = undefined;
|
|
202
|
+
if (options.where === 'all') {
|
|
203
|
+
filterObject = 'all';
|
|
205
204
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
205
|
+
else {
|
|
206
|
+
if (options.where) {
|
|
207
|
+
filterObject = options.where.toJson();
|
|
208
|
+
if (options.args === undefined)
|
|
209
|
+
if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
210
|
+
filterObject = undefined;
|
|
211
|
+
}
|
|
212
|
+
if (options.orderBy && options.orderBy.Segments) {
|
|
213
|
+
let sort = '';
|
|
214
|
+
let order = '';
|
|
215
|
+
let hasDescending = false;
|
|
216
|
+
options.orderBy.Segments.forEach((c) => {
|
|
217
|
+
if (sort.length > 0) {
|
|
218
|
+
sort += ',';
|
|
219
|
+
order += ',';
|
|
220
|
+
}
|
|
221
|
+
sort += c.field.key;
|
|
222
|
+
order += c.isDescending ? 'desc' : 'asc';
|
|
223
|
+
if (c.isDescending)
|
|
224
|
+
hasDescending = true;
|
|
225
|
+
});
|
|
226
|
+
if (sort)
|
|
227
|
+
url.add('_sort', sort);
|
|
228
|
+
if (hasDescending)
|
|
229
|
+
url.add('_order', order);
|
|
230
|
+
}
|
|
231
|
+
if (options.limit)
|
|
232
|
+
url.add('_limit', options.limit);
|
|
233
|
+
if (options.page)
|
|
234
|
+
url.add('_page', options.page);
|
|
235
|
+
if (options.select) {
|
|
236
|
+
url.add('_select', options.select.join(','));
|
|
237
|
+
}
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
const run = (action, body) => {
|
|
@@ -244,6 +251,8 @@ export class RestEntityDataProvider {
|
|
|
244
251
|
else
|
|
245
252
|
body = { ...body, where: filterObject };
|
|
246
253
|
}
|
|
254
|
+
if (options && 'args' in options)
|
|
255
|
+
body.args = options.args;
|
|
247
256
|
if (body && method != 'put')
|
|
248
257
|
return this.http().post(u.url, body);
|
|
249
258
|
else
|
|
@@ -265,10 +274,16 @@ export class RestEntityDataProvider {
|
|
|
265
274
|
},
|
|
266
275
|
};
|
|
267
276
|
}
|
|
268
|
-
update(id, data) {
|
|
277
|
+
update(id, data, options) {
|
|
278
|
+
const urlArgs = [];
|
|
279
|
+
if (id == '')
|
|
280
|
+
urlArgs.push('__action=emptyId');
|
|
281
|
+
if (options?.select === 'none')
|
|
282
|
+
urlArgs.push('_select=$none');
|
|
269
283
|
return this.http()
|
|
270
284
|
.put(this.url() +
|
|
271
|
-
(id != '' ? '/' + encodeURIComponent(id) : '
|
|
285
|
+
(id != '' ? '/' + encodeURIComponent(id) : '') +
|
|
286
|
+
(urlArgs.length > 0 ? '?' + urlArgs.join('&') : ''), this.toJsonOfIncludedKeys(data))
|
|
272
287
|
.then((y) => this.translateFromJson(y));
|
|
273
288
|
}
|
|
274
289
|
toJsonOfIncludedKeys(data) {
|
|
@@ -286,14 +301,14 @@ export class RestEntityDataProvider {
|
|
|
286
301
|
else
|
|
287
302
|
return this.http().delete(this.url() + '/' + encodeURIComponent(id));
|
|
288
303
|
}
|
|
289
|
-
insert(data) {
|
|
304
|
+
insert(data, options) {
|
|
290
305
|
return this.http()
|
|
291
|
-
.post(this.url(), this.translateToJson(data))
|
|
306
|
+
.post(this.url() + (options?.select === 'none' ? '?_select=$none' : ''), this.translateToJson(data))
|
|
292
307
|
.then((y) => this.translateFromJson(y));
|
|
293
308
|
}
|
|
294
|
-
insertMany(data) {
|
|
309
|
+
insertMany(data, options) {
|
|
295
310
|
return this.http()
|
|
296
|
-
.post(this.url(), data.map((data) => this.translateToJson(data)))
|
|
311
|
+
.post(this.url() + (options?.select === 'none' ? '?_select=$none' : ''), data.map((data) => this.translateToJson(data)))
|
|
297
312
|
.then((y) => y.map((y) => this.translateFromJson(y)));
|
|
298
313
|
}
|
|
299
314
|
}
|
|
@@ -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);
|
|
@@ -381,7 +392,7 @@ class ActualSQLEntityDataProvider {
|
|
|
381
392
|
}
|
|
382
393
|
return { colKeys, select };
|
|
383
394
|
}
|
|
384
|
-
async update(id, data) {
|
|
395
|
+
async update(id, data, options) {
|
|
385
396
|
let e = await this.init();
|
|
386
397
|
let r = this.sql.createCommand();
|
|
387
398
|
let statement = 'update ' + e.$entityName + ' set ';
|
|
@@ -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,10 +415,12 @@ 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;
|
|
422
|
+
if (options?.select === 'none')
|
|
423
|
+
returning = false;
|
|
411
424
|
if (returning &&
|
|
412
425
|
this.sql._getSourceSql().doesNotSupportReturningSyntaxOnlyForUpdate)
|
|
413
426
|
returning = false;
|
|
@@ -416,6 +429,8 @@ class ActualSQLEntityDataProvider {
|
|
|
416
429
|
return r.execute(statement).then((sqlResult) => {
|
|
417
430
|
this.sql._getSourceSql().afterMutation?.();
|
|
418
431
|
if (!returning) {
|
|
432
|
+
if (options?.select === 'none')
|
|
433
|
+
return undefined;
|
|
419
434
|
return getRowAfterUpdate(this.entity, this, data, id, 'update');
|
|
420
435
|
}
|
|
421
436
|
if (sqlResult.rows.length != 1)
|
|
@@ -437,7 +452,7 @@ class ActualSQLEntityDataProvider {
|
|
|
437
452
|
this.sql._getSourceSql().afterMutation?.();
|
|
438
453
|
});
|
|
439
454
|
}
|
|
440
|
-
async insert(data) {
|
|
455
|
+
async insert(data, options) {
|
|
441
456
|
let e = await this.init();
|
|
442
457
|
let r = this.sql.createCommand();
|
|
443
458
|
let cols = '';
|
|
@@ -456,13 +471,14 @@ class ActualSQLEntityDataProvider {
|
|
|
456
471
|
vals += ', ';
|
|
457
472
|
}
|
|
458
473
|
cols += e.$dbNameOf(x);
|
|
459
|
-
vals += r
|
|
474
|
+
vals += toDbSql(r, x, v);
|
|
460
475
|
}
|
|
461
476
|
}
|
|
462
477
|
}
|
|
463
478
|
let statement = `insert into ${e.$entityName} (${cols}) values (${vals})`;
|
|
464
|
-
let { colKeys, select } = this.buildSelect(e);
|
|
465
|
-
if (!this.sql._getSourceSql().doesNotSupportReturningSyntax
|
|
479
|
+
let { colKeys, select } = await this.buildSelect(e, r, undefined, undefined);
|
|
480
|
+
if (!this.sql._getSourceSql().doesNotSupportReturningSyntax &&
|
|
481
|
+
!(options?.select === 'none'))
|
|
466
482
|
statement += ' returning ' + select;
|
|
467
483
|
return await r.execute(statement).then((sql) => {
|
|
468
484
|
this.sql._getSourceSql().afterMutation?.();
|
|
@@ -472,14 +488,20 @@ class ActualSQLEntityDataProvider {
|
|
|
472
488
|
if (typeof id !== 'number')
|
|
473
489
|
throw new Error('Auto increment, for a database that is does not support returning syntax, should return an array with the single last added id. Instead it returned: ' +
|
|
474
490
|
JSON.stringify(id));
|
|
491
|
+
if (options?.select === 'none')
|
|
492
|
+
return undefined;
|
|
475
493
|
return this.find({
|
|
476
494
|
where: new Filter((x) => x.isEqualTo(this.entity.idMetadata.field, id)),
|
|
477
495
|
}).then((r) => r[0]);
|
|
478
496
|
}
|
|
479
497
|
else {
|
|
498
|
+
if (options?.select === 'none')
|
|
499
|
+
return undefined;
|
|
480
500
|
return getRowAfterUpdate(this.entity, this, data, undefined, 'insert');
|
|
481
501
|
}
|
|
482
502
|
}
|
|
503
|
+
if (options?.select === 'none')
|
|
504
|
+
return undefined;
|
|
483
505
|
return this.buildResultRow(colKeys, sql.rows[0], sql);
|
|
484
506
|
});
|
|
485
507
|
}
|
|
@@ -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
|
+
}
|
package/esm/src/remult-proxy.js
CHANGED
|
@@ -156,10 +156,10 @@ export class RemultProxy {
|
|
|
156
156
|
.remultFactory()
|
|
157
157
|
.repo(...args)
|
|
158
158
|
.getEntityRef(...args2),
|
|
159
|
-
insert: (args2) => self
|
|
159
|
+
insert: (args2, args3) => self
|
|
160
160
|
.remultFactory()
|
|
161
161
|
.repo(...args)
|
|
162
|
-
.insert(args2),
|
|
162
|
+
.insert(args2, args3),
|
|
163
163
|
liveQuery: (...args2) => self
|
|
164
164
|
.remultFactory()
|
|
165
165
|
.repo(...args)
|
|
@@ -179,10 +179,10 @@ export class RemultProxy {
|
|
|
179
179
|
.remultFactory()
|
|
180
180
|
.repo(...args)
|
|
181
181
|
.upsert(args2),
|
|
182
|
-
update: (a, b) => self
|
|
182
|
+
update: (a, b, c) => self
|
|
183
183
|
.remultFactory()
|
|
184
184
|
.repo(...args)
|
|
185
|
-
.update(a, b),
|
|
185
|
+
.update(a, b, c),
|
|
186
186
|
};
|
|
187
187
|
entityCache.set(args[1], result);
|
|
188
188
|
return result;
|