remult 0.25.8-exp.2 → 0.25.8-exp.3
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 +2 -2
- package/esm/server/expressBridge.js +80 -13
- package/esm/src/data-api.js +30 -16
- package/esm/src/data-providers/rest-data-provider.js +17 -15
- package/esm/src/filter/filter-interfaces.js +31 -0
- package/esm/src/remult3/RepositoryImplementation.js +2 -0
- package/esm/src/remult3/remult3.js +4 -10
- package/esm/src/valueConverters.js +1 -1
- package/graphql.js +2 -4
- package/package.json +1 -1
- package/server/expressBridge.js +77 -15
- package/src/context.d.ts +2 -0
- package/src/data-api.d.ts +10 -6
- package/src/data-api.js +82 -63
- package/src/data-providers/rest-data-provider.js +26 -15
- package/src/filter/filter-interfaces.js +64 -12
- package/src/remult3/RepositoryImplementation.js +2 -0
- package/src/remult3/remult3.js +4 -10
- package/src/valueConverters.js +1 -1
package/esm/graphql.js
CHANGED
|
@@ -904,7 +904,7 @@ export function translateWhereToRestBody(fields, { where }) {
|
|
|
904
904
|
}
|
|
905
905
|
}
|
|
906
906
|
if (where.OR) {
|
|
907
|
-
result.OR = where.OR.map((where) => translateWhereToRestBody(fields, { where }));
|
|
907
|
+
result.OR = where.OR.map((where) => translateWhereToRestBody(fields, { where }).where);
|
|
908
908
|
}
|
|
909
|
-
return result;
|
|
909
|
+
return { where: result };
|
|
910
910
|
}
|
|
@@ -250,8 +250,8 @@ export class RemultServerImplementation {
|
|
|
250
250
|
console.info('[remult] ' + myRoute);
|
|
251
251
|
r.route(myRoute)
|
|
252
252
|
.get(this.process((c, req, res, orig) => dataApiFactory(c).httpGet(res, req, () => this.serializeContext(c))))
|
|
253
|
-
.put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).
|
|
254
|
-
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).
|
|
253
|
+
.put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).updateMany(res, req, await this.coreOptions.getRequestBody(orig))))
|
|
254
|
+
.delete(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).deleteMany(res, req, undefined)))
|
|
255
255
|
.post(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).httpPost(res, req, await this.coreOptions.getRequestBody(orig), () => this.serializeContext(c))));
|
|
256
256
|
r.route(myRoute + '/:id')
|
|
257
257
|
//@ts-ignore
|
|
@@ -467,6 +467,17 @@ export class RemultServerImplementation {
|
|
|
467
467
|
return secureBase(condition, def, item);
|
|
468
468
|
};
|
|
469
469
|
let apiPath = (spec.paths[this.options.rootPath + '/' + key] = {});
|
|
470
|
+
let itemInBody = {
|
|
471
|
+
requestBody: {
|
|
472
|
+
content: {
|
|
473
|
+
'application/json': {
|
|
474
|
+
schema: {
|
|
475
|
+
$ref: '#/components/schemas/' + mutationKey,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
};
|
|
470
481
|
let apiPathWithId = (spec.paths[this.options.rootPath + '/' + key + '/{id}'] = {});
|
|
471
482
|
//https://github.com/2fd/open-api.d.ts
|
|
472
483
|
apiPath.get = secure(meta.options.allowApiRead, true, {
|
|
@@ -519,6 +530,73 @@ export class RemultServerImplementation {
|
|
|
519
530
|
},
|
|
520
531
|
},
|
|
521
532
|
});
|
|
533
|
+
apiPath.delete = secure(meta.options.allowApiDelete, true, {
|
|
534
|
+
description: 'deletes row of ' +
|
|
535
|
+
key +
|
|
536
|
+
'. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)',
|
|
537
|
+
parameters: [...parameters],
|
|
538
|
+
responses: {
|
|
539
|
+
'400': {
|
|
540
|
+
description: 'Error: Bad Request',
|
|
541
|
+
content: {
|
|
542
|
+
'application/json': {
|
|
543
|
+
schema: {
|
|
544
|
+
$ref: '#/components/schemas/InvalidResponse',
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
'200': {
|
|
550
|
+
description: 'returns the number of deleted rows ' + key,
|
|
551
|
+
content: {
|
|
552
|
+
'application/json': {
|
|
553
|
+
schema: {
|
|
554
|
+
type: 'object',
|
|
555
|
+
properties: {
|
|
556
|
+
deleted: {
|
|
557
|
+
type: 'number',
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
});
|
|
566
|
+
apiPath.put = secure(meta.options.allowApiDelete, true, {
|
|
567
|
+
description: 'updates row of ' +
|
|
568
|
+
key +
|
|
569
|
+
'. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)',
|
|
570
|
+
parameters: [...parameters],
|
|
571
|
+
...itemInBody,
|
|
572
|
+
responses: {
|
|
573
|
+
'400': {
|
|
574
|
+
description: 'Error: Bad Request',
|
|
575
|
+
content: {
|
|
576
|
+
'application/json': {
|
|
577
|
+
schema: {
|
|
578
|
+
$ref: '#/components/schemas/InvalidResponse',
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
'200': {
|
|
584
|
+
description: 'returns the number of updated rows ' + key,
|
|
585
|
+
content: {
|
|
586
|
+
'application/json': {
|
|
587
|
+
schema: {
|
|
588
|
+
type: 'object',
|
|
589
|
+
properties: {
|
|
590
|
+
updated: {
|
|
591
|
+
type: 'number',
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
});
|
|
522
600
|
let idParameter = {
|
|
523
601
|
name: 'id',
|
|
524
602
|
in: 'path',
|
|
@@ -526,17 +604,6 @@ export class RemultServerImplementation {
|
|
|
526
604
|
required: true,
|
|
527
605
|
schema: { type: 'string' },
|
|
528
606
|
};
|
|
529
|
-
let itemInBody = {
|
|
530
|
-
requestBody: {
|
|
531
|
-
content: {
|
|
532
|
-
'application/json': {
|
|
533
|
-
schema: {
|
|
534
|
-
$ref: '#/components/schemas/' + mutationKey,
|
|
535
|
-
},
|
|
536
|
-
},
|
|
537
|
-
},
|
|
538
|
-
},
|
|
539
|
-
};
|
|
540
607
|
apiPath.post = secure(meta.options.allowApiInsert, false, {
|
|
541
608
|
//"summary": "insert a " + key,
|
|
542
609
|
//"description": "insert a " + key,
|
package/esm/src/data-api.js
CHANGED
|
@@ -33,7 +33,7 @@ export class DataApi {
|
|
|
33
33
|
case 'deleteMany':
|
|
34
34
|
return this.deleteMany(res, req, body);
|
|
35
35
|
case 'updateMany':
|
|
36
|
-
return this.
|
|
36
|
+
return this.updateManyImplementation(res, req, body);
|
|
37
37
|
case 'endLiveQuery':
|
|
38
38
|
await this.remult.liveQueryStorage.remove(body.id);
|
|
39
39
|
res.success('ok');
|
|
@@ -50,26 +50,28 @@ export class DataApi {
|
|
|
50
50
|
}
|
|
51
51
|
await this.doOnId(response, id, async (row) => response.success(this.repository.getEntityRef(row).toApiJson()));
|
|
52
52
|
}
|
|
53
|
-
async count(response, request,
|
|
53
|
+
async count(response, request, body) {
|
|
54
54
|
if (!this.repository.metadata.apiReadAllowed) {
|
|
55
55
|
response.forbidden();
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
try {
|
|
59
59
|
response.success({
|
|
60
|
-
count: +(await this.repository.count(await this.buildWhere(request,
|
|
60
|
+
count: +(await this.repository.count(await this.buildWhere(request, body))),
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
catch (err) {
|
|
64
64
|
response.error(err, this.repository.metadata);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
async deleteMany(response, request,
|
|
67
|
+
async deleteMany(response, request, body) {
|
|
68
68
|
try {
|
|
69
|
+
let deleted = 0;
|
|
70
|
+
let where = await this.buildWhere(request, body);
|
|
71
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'deleteMany');
|
|
69
72
|
return await doTransaction(this.remult, async () => {
|
|
70
|
-
let deleted = 0;
|
|
71
73
|
for await (const x of this.repository.query({
|
|
72
|
-
where
|
|
74
|
+
where,
|
|
73
75
|
include: this.includeNone(),
|
|
74
76
|
})) {
|
|
75
77
|
await this.actualDelete(x);
|
|
@@ -82,12 +84,12 @@ export class DataApi {
|
|
|
82
84
|
response.error(err, this.repository.metadata);
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
|
-
async getArrayImpl(response, request,
|
|
87
|
+
async getArrayImpl(response, request, body) {
|
|
86
88
|
let findOptions = {
|
|
87
89
|
load: () => [],
|
|
88
90
|
include: this.includeNone(),
|
|
89
91
|
};
|
|
90
|
-
findOptions.where = await this.buildWhere(request,
|
|
92
|
+
findOptions.where = await this.buildWhere(request, body);
|
|
91
93
|
if (request) {
|
|
92
94
|
let sort = request.get('_sort');
|
|
93
95
|
if (sort != undefined) {
|
|
@@ -146,13 +148,13 @@ export class DataApi {
|
|
|
146
148
|
}
|
|
147
149
|
return include;
|
|
148
150
|
}
|
|
149
|
-
async getArray(response, request,
|
|
151
|
+
async getArray(response, request, body) {
|
|
150
152
|
if (!this.repository.metadata.apiReadAllowed) {
|
|
151
153
|
response.forbidden();
|
|
152
154
|
return;
|
|
153
155
|
}
|
|
154
156
|
try {
|
|
155
|
-
const { r } = await this.getArrayImpl(response, request,
|
|
157
|
+
const { r } = await this.getArrayImpl(response, request, body);
|
|
156
158
|
response.success(r);
|
|
157
159
|
}
|
|
158
160
|
catch (err) {
|
|
@@ -162,13 +164,13 @@ export class DataApi {
|
|
|
162
164
|
response.error(err, this.repository.metadata);
|
|
163
165
|
}
|
|
164
166
|
}
|
|
165
|
-
async liveQuery(response, request,
|
|
167
|
+
async liveQuery(response, request, body, serializeContext, queryChannel) {
|
|
166
168
|
if (!this.repository.metadata.apiReadAllowed) {
|
|
167
169
|
response.forbidden();
|
|
168
170
|
return;
|
|
169
171
|
}
|
|
170
172
|
try {
|
|
171
|
-
const r = await this.getArrayImpl(response, request,
|
|
173
|
+
const r = await this.getArrayImpl(response, request, body);
|
|
172
174
|
const data = {
|
|
173
175
|
requestJson: await serializeContext(),
|
|
174
176
|
findOptionsJson: findOptionsToJson(r.findOptions, this.repository.metadata),
|
|
@@ -188,7 +190,7 @@ export class DataApi {
|
|
|
188
190
|
response.error(err, this.repository.metadata);
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
|
-
async buildWhere(request,
|
|
193
|
+
async buildWhere(request, body) {
|
|
192
194
|
var where = [];
|
|
193
195
|
if (this.repository.metadata.options.apiPrefilter) {
|
|
194
196
|
if (typeof this.repository.metadata.options.apiPrefilter === 'function')
|
|
@@ -208,8 +210,8 @@ export class DataApi {
|
|
|
208
210
|
},
|
|
209
211
|
}));
|
|
210
212
|
}
|
|
211
|
-
if (
|
|
212
|
-
where.push(Filter.entityFilterFromJson(this.repository.metadata,
|
|
213
|
+
if (body?.where)
|
|
214
|
+
where.push(Filter.entityFilterFromJson(this.repository.metadata, body.where));
|
|
213
215
|
return { $and: where };
|
|
214
216
|
}
|
|
215
217
|
async doOnId(response, id, what) {
|
|
@@ -245,11 +247,23 @@ export class DataApi {
|
|
|
245
247
|
}
|
|
246
248
|
}
|
|
247
249
|
async updateMany(response, request, body) {
|
|
250
|
+
const action = request?.get('__action');
|
|
251
|
+
if (action == 'emptyId') {
|
|
252
|
+
return this.put(response, '', body);
|
|
253
|
+
}
|
|
254
|
+
let where = await this.buildWhere(request, body);
|
|
255
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'updateMany');
|
|
256
|
+
return this.updateManyImplementation(response, request, {
|
|
257
|
+
where: undefined,
|
|
258
|
+
set: body,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
async updateManyImplementation(response, request, body) {
|
|
248
262
|
try {
|
|
249
263
|
return await doTransaction(this.remult, async () => {
|
|
250
264
|
let updated = 0;
|
|
251
265
|
for await (const x of this.repository.query({
|
|
252
|
-
where: await this.buildWhere(request, body
|
|
266
|
+
where: await this.buildWhere(request, body),
|
|
253
267
|
include: this.includeNone(),
|
|
254
268
|
})) {
|
|
255
269
|
await this.actualUpdate(x, body.set);
|
|
@@ -120,26 +120,27 @@ export class RestEntityDataProvider {
|
|
|
120
120
|
return run('count').then((r) => +r.count);
|
|
121
121
|
}
|
|
122
122
|
async deleteMany(where) {
|
|
123
|
-
const { run } = this.buildFindRequest({ where },
|
|
123
|
+
const { run } = this.buildFindRequest({ where }, 'delete');
|
|
124
124
|
return run('deleteMany').then((r) => +r.deleted);
|
|
125
125
|
}
|
|
126
126
|
async updateMany(where, data) {
|
|
127
|
-
const { run } = this.buildFindRequest({ where },
|
|
128
|
-
return run('updateMany',
|
|
127
|
+
const { run } = this.buildFindRequest({ where }, 'put');
|
|
128
|
+
return run('updateMany', this.toJsonOfIncludedKeys(data)).then((r) => +r.updated);
|
|
129
129
|
}
|
|
130
130
|
find(options) {
|
|
131
131
|
let { run } = this.buildFindRequest(options);
|
|
132
132
|
return run().then((x) => x.map((y) => this.translateFromJson(y)));
|
|
133
133
|
}
|
|
134
134
|
//@internal
|
|
135
|
-
buildFindRequest(options,
|
|
135
|
+
buildFindRequest(options, method) {
|
|
136
|
+
if (!method)
|
|
137
|
+
method = 'get';
|
|
136
138
|
let url = new UrlBuilder(this.url());
|
|
137
139
|
let filterObject;
|
|
138
140
|
if (options) {
|
|
139
141
|
if (options.where) {
|
|
140
142
|
filterObject = options.where.toJson(); // options.where.__applyToConsumer(new FilterConsumnerBridgeToUrlBuilder(url));
|
|
141
|
-
if (
|
|
142
|
-
addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
143
|
+
if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
143
144
|
filterObject = undefined;
|
|
144
145
|
}
|
|
145
146
|
if (options.orderBy && options.orderBy.Segments) {
|
|
@@ -173,15 +174,12 @@ export class RestEntityDataProvider {
|
|
|
173
174
|
}
|
|
174
175
|
if (action)
|
|
175
176
|
u.add('__action', action);
|
|
176
|
-
if (filterObject
|
|
177
|
-
|
|
178
|
-
body = filterObject;
|
|
179
|
-
else
|
|
180
|
-
body = { ...body, where: filterObject };
|
|
177
|
+
if (filterObject) {
|
|
178
|
+
body = { set: body, where: filterObject };
|
|
181
179
|
return this.http().post(u.url, body);
|
|
182
180
|
}
|
|
183
181
|
else
|
|
184
|
-
return this.http()
|
|
182
|
+
return this.http()[method](u.url, body);
|
|
185
183
|
};
|
|
186
184
|
return {
|
|
187
185
|
createKey: () => JSON.stringify({ url, filterObject }),
|
|
@@ -201,7 +199,8 @@ export class RestEntityDataProvider {
|
|
|
201
199
|
}
|
|
202
200
|
update(id, data) {
|
|
203
201
|
return this.http()
|
|
204
|
-
.put(this.url() +
|
|
202
|
+
.put(this.url() +
|
|
203
|
+
(id != '' ? '/' + encodeURIComponent(id) : '?__action=emptyId'), this.toJsonOfIncludedKeys(data))
|
|
205
204
|
.then((y) => this.translateFromJson(y));
|
|
206
205
|
}
|
|
207
206
|
toJsonOfIncludedKeys(data) {
|
|
@@ -213,8 +212,11 @@ export class RestEntityDataProvider {
|
|
|
213
212
|
}
|
|
214
213
|
return result;
|
|
215
214
|
}
|
|
216
|
-
delete(id) {
|
|
217
|
-
|
|
215
|
+
async delete(id) {
|
|
216
|
+
if (id == '')
|
|
217
|
+
await this.deleteMany(Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)));
|
|
218
|
+
else
|
|
219
|
+
return this.http().delete(this.url() + '/' + encodeURIComponent(id));
|
|
218
220
|
}
|
|
219
221
|
insert(data) {
|
|
220
222
|
return this.http()
|
|
@@ -6,6 +6,37 @@ import { getRelationFieldInfo } from '../remult3/relationInfoMember.js';
|
|
|
6
6
|
*/
|
|
7
7
|
export class Filter {
|
|
8
8
|
apply;
|
|
9
|
+
//@internal
|
|
10
|
+
static throwErrorIfFilterIsEmpty(where, methodName) {
|
|
11
|
+
if (Filter.isFilterEmpty(where)) {
|
|
12
|
+
throw {
|
|
13
|
+
message: `${methodName}: requires a filter to protect against accidental delete/update of all rows`,
|
|
14
|
+
httpStatusCode: 400,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//@internal
|
|
19
|
+
static isFilterEmpty(where) {
|
|
20
|
+
if (where.$and) {
|
|
21
|
+
for (const a of where.$and) {
|
|
22
|
+
if (!Filter.isFilterEmpty(a)) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (where.$or) {
|
|
28
|
+
for (const a of where.$or) {
|
|
29
|
+
if (Filter.isFilterEmpty(a)) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (Object.keys(where).filter((x) => !['$or', '$and'].includes(x)).length == 0) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
9
40
|
static createCustom(rawFilterTranslator, key = '') {
|
|
10
41
|
let rawFilterInfo = { key: key, rawFilterTranslator };
|
|
11
42
|
return Object.assign((x) => {
|
|
@@ -270,6 +270,7 @@ export class RepositoryImplementation {
|
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
async updateMany(where, set) {
|
|
273
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'updateMany');
|
|
273
274
|
if (this._dataProvider.isProxy) {
|
|
274
275
|
return this._edp.updateMany(await this._translateWhereToFilter(where), set);
|
|
275
276
|
}
|
|
@@ -636,6 +637,7 @@ export class RepositoryImplementation {
|
|
|
636
637
|
return this._edp.count(await this._translateWhereToFilter(where));
|
|
637
638
|
}
|
|
638
639
|
async deleteMany(where) {
|
|
640
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'deleteMany');
|
|
639
641
|
if (this._dataProvider.isProxy) {
|
|
640
642
|
return this._edp.deleteMany(await this._translateWhereToFilter(where));
|
|
641
643
|
}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
export {};
|
|
2
|
+
//y1 - reconsider adding where to all in case of post - it is a breaking change and no longer required
|
|
3
|
+
//y1 - review that with deleteMany, and updateMany I've taken a similar approach to get, that when the filter is complex, we go to post - one reason is that delete doesn't accept a body.
|
|
4
|
+
//y1 - should the remult api be deleteMany({id:[1,2]}) or deleteMany({where:{id:[1,2]}})
|
|
2
5
|
//p1 - in this video I'll use remult to turn a frontend app to a fullstack app
|
|
3
|
-
/*p1 - discuss using delete & put - with url query language for deleteMany and updateMany -
|
|
4
|
-
- put & delete, similar to get
|
|
5
|
-
- add where to count, deleteMany,updateMany,
|
|
6
|
-
- prevent delete all and update all - must have meaningful where.
|
|
7
|
-
- try forcing this also in typescript
|
|
8
|
-
|
|
9
|
-
- protect against deleting of all rows by mistake
|
|
10
|
-
- https://github.com/remult/remult/issues/221#issuecomment-2016519746
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
6
|
//y1 - getFields didn't work for kobi in the home component
|
|
7
|
+
//y1 - consider replacing all errors with error classes that extend the base Error class
|
|
14
8
|
//p1 - document offline support
|
|
15
9
|
//p1 - add section to Fields doc, explaining field type in db
|
|
16
10
|
//p1 - add section about union type
|
package/graphql.js
CHANGED
|
@@ -1081,10 +1081,8 @@ function translateWhereToRestBody(fields, _a) {
|
|
|
1081
1081
|
finally { if (e_7) throw e_7.error; }
|
|
1082
1082
|
}
|
|
1083
1083
|
if (where.OR) {
|
|
1084
|
-
result.OR = where.OR.map(function (where) {
|
|
1085
|
-
return translateWhereToRestBody(fields, { where: where });
|
|
1086
|
-
});
|
|
1084
|
+
result.OR = where.OR.map(function (where) { return translateWhereToRestBody(fields, { where: where }).where; });
|
|
1087
1085
|
}
|
|
1088
|
-
return result;
|
|
1086
|
+
return { where: result };
|
|
1089
1087
|
}
|
|
1090
1088
|
exports.translateWhereToRestBody = translateWhereToRestBody;
|
package/package.json
CHANGED
package/server/expressBridge.js
CHANGED
|
@@ -444,16 +444,16 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
444
444
|
return tslib_1.__generator(this, function (_d) {
|
|
445
445
|
switch (_d.label) {
|
|
446
446
|
case 0:
|
|
447
|
-
_b = (_a = dataApiFactory(c)).
|
|
447
|
+
_b = (_a = dataApiFactory(c)).updateMany;
|
|
448
448
|
_c = [res,
|
|
449
|
-
|
|
449
|
+
req];
|
|
450
450
|
return [4 /*yield*/, this.coreOptions.getRequestBody(orig)];
|
|
451
451
|
case 1: return [2 /*return*/, _b.apply(_a, _c.concat([_d.sent()]))];
|
|
452
452
|
}
|
|
453
453
|
});
|
|
454
454
|
}); }))
|
|
455
|
-
.delete(this.process(function (c, req, res, orig) { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
|
|
456
|
-
return [2 /*return*/, dataApiFactory(c).
|
|
455
|
+
.delete(this.process(function (c, req, res, _, __, orig) { return tslib_1.__awaiter(_this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) {
|
|
456
|
+
return [2 /*return*/, dataApiFactory(c).deleteMany(res, req, undefined)];
|
|
457
457
|
}); }); }))
|
|
458
458
|
.post(this.process(function (c, req, res, _, __, orig) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
459
459
|
var _a, _b, _c;
|
|
@@ -792,6 +792,17 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
792
792
|
return secureBase(condition, def, item);
|
|
793
793
|
};
|
|
794
794
|
var apiPath = (spec.paths[this_2.options.rootPath + '/' + key] = {});
|
|
795
|
+
var itemInBody = {
|
|
796
|
+
requestBody: {
|
|
797
|
+
content: {
|
|
798
|
+
'application/json': {
|
|
799
|
+
schema: {
|
|
800
|
+
$ref: '#/components/schemas/' + mutationKey,
|
|
801
|
+
},
|
|
802
|
+
},
|
|
803
|
+
},
|
|
804
|
+
},
|
|
805
|
+
};
|
|
795
806
|
var apiPathWithId = (spec.paths[this_2.options.rootPath + '/' + key + '/{id}'] = {});
|
|
796
807
|
//https://github.com/2fd/open-api.d.ts
|
|
797
808
|
apiPath.get = secure(meta.options.allowApiRead, true, {
|
|
@@ -843,6 +854,68 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
843
854
|
},
|
|
844
855
|
},
|
|
845
856
|
});
|
|
857
|
+
apiPath.delete = secure(meta.options.allowApiDelete, true, {
|
|
858
|
+
description: 'deletes row of ' +
|
|
859
|
+
key +
|
|
860
|
+
'. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)',
|
|
861
|
+
parameters: tslib_1.__spreadArray([], tslib_1.__read(parameters), false),
|
|
862
|
+
responses: {
|
|
863
|
+
'400': {
|
|
864
|
+
description: 'Error: Bad Request',
|
|
865
|
+
content: {
|
|
866
|
+
'application/json': {
|
|
867
|
+
schema: {
|
|
868
|
+
$ref: '#/components/schemas/InvalidResponse',
|
|
869
|
+
},
|
|
870
|
+
},
|
|
871
|
+
},
|
|
872
|
+
},
|
|
873
|
+
'200': {
|
|
874
|
+
description: 'returns the number of deleted rows ' + key,
|
|
875
|
+
content: {
|
|
876
|
+
'application/json': {
|
|
877
|
+
schema: {
|
|
878
|
+
type: 'object',
|
|
879
|
+
properties: {
|
|
880
|
+
deleted: {
|
|
881
|
+
type: 'number',
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
},
|
|
885
|
+
},
|
|
886
|
+
},
|
|
887
|
+
},
|
|
888
|
+
},
|
|
889
|
+
});
|
|
890
|
+
apiPath.put = secure(meta.options.allowApiDelete, true, tslib_1.__assign(tslib_1.__assign({ description: 'updates row of ' +
|
|
891
|
+
key +
|
|
892
|
+
'. supports filter operators. For more info on filtering [see this article](https://remult.dev/docs/rest-api.html#filter)', parameters: tslib_1.__spreadArray([], tslib_1.__read(parameters), false) }, itemInBody), { responses: {
|
|
893
|
+
'400': {
|
|
894
|
+
description: 'Error: Bad Request',
|
|
895
|
+
content: {
|
|
896
|
+
'application/json': {
|
|
897
|
+
schema: {
|
|
898
|
+
$ref: '#/components/schemas/InvalidResponse',
|
|
899
|
+
},
|
|
900
|
+
},
|
|
901
|
+
},
|
|
902
|
+
},
|
|
903
|
+
'200': {
|
|
904
|
+
description: 'returns the number of updated rows ' + key,
|
|
905
|
+
content: {
|
|
906
|
+
'application/json': {
|
|
907
|
+
schema: {
|
|
908
|
+
type: 'object',
|
|
909
|
+
properties: {
|
|
910
|
+
updated: {
|
|
911
|
+
type: 'number',
|
|
912
|
+
},
|
|
913
|
+
},
|
|
914
|
+
},
|
|
915
|
+
},
|
|
916
|
+
},
|
|
917
|
+
},
|
|
918
|
+
} }));
|
|
846
919
|
var idParameter = {
|
|
847
920
|
name: 'id',
|
|
848
921
|
in: 'path',
|
|
@@ -850,17 +923,6 @@ var RemultServerImplementation = /** @class */ (function () {
|
|
|
850
923
|
required: true,
|
|
851
924
|
schema: { type: 'string' },
|
|
852
925
|
};
|
|
853
|
-
var itemInBody = {
|
|
854
|
-
requestBody: {
|
|
855
|
-
content: {
|
|
856
|
-
'application/json': {
|
|
857
|
-
schema: {
|
|
858
|
-
$ref: '#/components/schemas/' + mutationKey,
|
|
859
|
-
},
|
|
860
|
-
},
|
|
861
|
-
},
|
|
862
|
-
},
|
|
863
|
-
};
|
|
864
926
|
apiPath.post = secure(meta.options.allowApiInsert, false, tslib_1.__assign(tslib_1.__assign({
|
|
865
927
|
//"summary": "insert a " + key,
|
|
866
928
|
//"description": "insert a " + key,
|
package/src/context.d.ts
CHANGED
|
@@ -92,6 +92,8 @@ export interface ApiClient {
|
|
|
92
92
|
* @example
|
|
93
93
|
* // Using Angular HttpClient
|
|
94
94
|
* remult.apiClient.httpClient = httpClient;
|
|
95
|
+
* @see
|
|
96
|
+
* If you want to add headers using angular httpClient, see: https://medium.com/angular-shots/shot-3-how-to-add-http-headers-to-every-request-in-angular-fab3d10edc26
|
|
95
97
|
*
|
|
96
98
|
* @example
|
|
97
99
|
* // Using fetch (default)
|
package/src/data-api.d.ts
CHANGED
|
@@ -10,18 +10,22 @@ export declare class DataApi<T = any> {
|
|
|
10
10
|
httpPost(res: DataApiResponse, req: DataApiRequest, body: any, serializeContext: () => Promise<any>): Promise<void>;
|
|
11
11
|
static defaultGetLimit: number;
|
|
12
12
|
get(response: DataApiResponse, id: any): Promise<void>;
|
|
13
|
-
count(response: DataApiResponse, request: DataApiRequest,
|
|
14
|
-
deleteMany(response: DataApiResponse, request: DataApiRequest,
|
|
15
|
-
getArrayImpl(response: DataApiResponse, request: DataApiRequest,
|
|
13
|
+
count(response: DataApiResponse, request: DataApiRequest, body?: any): Promise<void>;
|
|
14
|
+
deleteMany(response: DataApiResponse, request: DataApiRequest, body?: any): Promise<void>;
|
|
15
|
+
getArrayImpl(response: DataApiResponse, request: DataApiRequest, body: any): Promise<{
|
|
16
16
|
r: any[];
|
|
17
17
|
findOptions: FindOptions<T>;
|
|
18
18
|
}>;
|
|
19
19
|
private includeNone;
|
|
20
|
-
getArray(response: DataApiResponse, request: DataApiRequest,
|
|
21
|
-
liveQuery(response: DataApiResponse, request: DataApiRequest,
|
|
20
|
+
getArray(response: DataApiResponse, request: DataApiRequest, body?: any): Promise<void>;
|
|
21
|
+
liveQuery(response: DataApiResponse, request: DataApiRequest, body: any, serializeContext: () => Promise<any>, queryChannel: string): Promise<void>;
|
|
22
22
|
private buildWhere;
|
|
23
23
|
private doOnId;
|
|
24
|
-
updateMany(response: DataApiResponse, request: DataApiRequest, body
|
|
24
|
+
updateMany(response: DataApiResponse, request: DataApiRequest, body: any): Promise<void>;
|
|
25
|
+
updateManyImplementation(response: DataApiResponse, request: DataApiRequest, body: {
|
|
26
|
+
where: any;
|
|
27
|
+
set: any;
|
|
28
|
+
}): Promise<void>;
|
|
25
29
|
actualUpdate(row: any, body: any): Promise<rowHelperImplementation<T>>;
|
|
26
30
|
put(response: DataApiResponse, id: any, body: any): Promise<void>;
|
|
27
31
|
actualDelete(row: any): Promise<void>;
|
package/src/data-api.js
CHANGED
|
@@ -44,7 +44,7 @@ var DataApi = /** @class */ (function () {
|
|
|
44
44
|
case 1: return [2 /*return*/, this.getArray(res, req, body)];
|
|
45
45
|
case 2: return [2 /*return*/, this.count(res, req, body)];
|
|
46
46
|
case 3: return [2 /*return*/, this.deleteMany(res, req, body)];
|
|
47
|
-
case 4: return [2 /*return*/, this.
|
|
47
|
+
case 4: return [2 /*return*/, this.updateManyImplementation(res, req, body)];
|
|
48
48
|
case 5: return [4 /*yield*/, this.remult.liveQueryStorage.remove(body.id)];
|
|
49
49
|
case 6:
|
|
50
50
|
_b.sent();
|
|
@@ -75,7 +75,7 @@ var DataApi = /** @class */ (function () {
|
|
|
75
75
|
});
|
|
76
76
|
});
|
|
77
77
|
};
|
|
78
|
-
DataApi.prototype.count = function (response, request,
|
|
78
|
+
DataApi.prototype.count = function (response, request, body) {
|
|
79
79
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
80
80
|
var _a, _b, _c, _d, err_1;
|
|
81
81
|
var _e;
|
|
@@ -92,7 +92,7 @@ var DataApi = /** @class */ (function () {
|
|
|
92
92
|
_b = (_a = response).success;
|
|
93
93
|
_e = {};
|
|
94
94
|
_d = (_c = this.repository).count;
|
|
95
|
-
return [4 /*yield*/, this.buildWhere(request,
|
|
95
|
+
return [4 /*yield*/, this.buildWhere(request, body)];
|
|
96
96
|
case 2: return [4 /*yield*/, _d.apply(_c, [_f.sent()])];
|
|
97
97
|
case 3:
|
|
98
98
|
_b.apply(_a, [(_e.count = +(_f.sent()),
|
|
@@ -107,82 +107,79 @@ var DataApi = /** @class */ (function () {
|
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
109
|
};
|
|
110
|
-
DataApi.prototype.deleteMany = function (response, request,
|
|
110
|
+
DataApi.prototype.deleteMany = function (response, request, body) {
|
|
111
111
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
112
|
-
var err_2;
|
|
112
|
+
var deleted_1, where_1, err_2;
|
|
113
113
|
var _this = this;
|
|
114
114
|
return tslib_1.__generator(this, function (_a) {
|
|
115
115
|
switch (_a.label) {
|
|
116
116
|
case 0:
|
|
117
|
-
_a.trys.push([0,
|
|
117
|
+
_a.trys.push([0, 3, , 4]);
|
|
118
|
+
deleted_1 = 0;
|
|
119
|
+
return [4 /*yield*/, this.buildWhere(request, body)];
|
|
120
|
+
case 1:
|
|
121
|
+
where_1 = _a.sent();
|
|
122
|
+
filter_interfaces_js_1.Filter.throwErrorIfFilterIsEmpty(where_1, 'deleteMany');
|
|
118
123
|
return [4 /*yield*/, (0, context_js_1.doTransaction)(this.remult, function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
119
|
-
var
|
|
120
|
-
var _f;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
switch (_k.label) {
|
|
124
|
+
var _a, _b, _c, x, e_1_1;
|
|
125
|
+
var _d, e_1, _e, _f;
|
|
126
|
+
return tslib_1.__generator(this, function (_g) {
|
|
127
|
+
switch (_g.label) {
|
|
124
128
|
case 0:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return [4 /*yield*/, this.buildWhere(request, filterBody)];
|
|
129
|
+
_g.trys.push([0, 6, 7, 12]);
|
|
130
|
+
_a = true, _b = tslib_1.__asyncValues(this.repository.query({
|
|
131
|
+
where: where_1,
|
|
132
|
+
include: this.includeNone(),
|
|
133
|
+
}));
|
|
134
|
+
_g.label = 1;
|
|
135
|
+
case 1: return [4 /*yield*/, _b.next()];
|
|
133
136
|
case 2:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
_f)])]);
|
|
137
|
-
_k.label = 3;
|
|
138
|
-
case 3: return [4 /*yield*/, _b.next()];
|
|
139
|
-
case 4:
|
|
140
|
-
if (!(_c = _k.sent(), _g = _c.done, !_g)) return [3 /*break*/, 7];
|
|
141
|
-
_j = _c.value;
|
|
137
|
+
if (!(_c = _g.sent(), _d = _c.done, !_d)) return [3 /*break*/, 5];
|
|
138
|
+
_f = _c.value;
|
|
142
139
|
_a = false;
|
|
143
|
-
x =
|
|
140
|
+
x = _f;
|
|
144
141
|
return [4 /*yield*/, this.actualDelete(x)];
|
|
145
|
-
case
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
case
|
|
142
|
+
case 3:
|
|
143
|
+
_g.sent();
|
|
144
|
+
deleted_1++;
|
|
145
|
+
_g.label = 4;
|
|
146
|
+
case 4:
|
|
150
147
|
_a = true;
|
|
151
|
-
return [3 /*break*/,
|
|
152
|
-
case
|
|
153
|
-
case
|
|
154
|
-
e_1_1 =
|
|
148
|
+
return [3 /*break*/, 1];
|
|
149
|
+
case 5: return [3 /*break*/, 12];
|
|
150
|
+
case 6:
|
|
151
|
+
e_1_1 = _g.sent();
|
|
155
152
|
e_1 = { error: e_1_1 };
|
|
156
|
-
return [3 /*break*/,
|
|
157
|
-
case
|
|
158
|
-
|
|
159
|
-
if (!(!_a && !
|
|
160
|
-
return [4 /*yield*/,
|
|
153
|
+
return [3 /*break*/, 12];
|
|
154
|
+
case 7:
|
|
155
|
+
_g.trys.push([7, , 10, 11]);
|
|
156
|
+
if (!(!_a && !_d && (_e = _b.return))) return [3 /*break*/, 9];
|
|
157
|
+
return [4 /*yield*/, _e.call(_b)];
|
|
158
|
+
case 8:
|
|
159
|
+
_g.sent();
|
|
160
|
+
_g.label = 9;
|
|
161
|
+
case 9: return [3 /*break*/, 11];
|
|
161
162
|
case 10:
|
|
162
|
-
_k.sent();
|
|
163
|
-
_k.label = 11;
|
|
164
|
-
case 11: return [3 /*break*/, 13];
|
|
165
|
-
case 12:
|
|
166
163
|
if (e_1) throw e_1.error;
|
|
167
164
|
return [7 /*endfinally*/];
|
|
168
|
-
case
|
|
169
|
-
case
|
|
170
|
-
response.success({ deleted:
|
|
165
|
+
case 11: return [7 /*endfinally*/];
|
|
166
|
+
case 12:
|
|
167
|
+
response.success({ deleted: deleted_1 });
|
|
171
168
|
return [2 /*return*/];
|
|
172
169
|
}
|
|
173
170
|
});
|
|
174
171
|
}); })];
|
|
175
|
-
case
|
|
176
|
-
case
|
|
172
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
173
|
+
case 3:
|
|
177
174
|
err_2 = _a.sent();
|
|
178
175
|
response.error(err_2, this.repository.metadata);
|
|
179
|
-
return [3 /*break*/,
|
|
180
|
-
case
|
|
176
|
+
return [3 /*break*/, 4];
|
|
177
|
+
case 4: return [2 /*return*/];
|
|
181
178
|
}
|
|
182
179
|
});
|
|
183
180
|
});
|
|
184
181
|
};
|
|
185
|
-
DataApi.prototype.getArrayImpl = function (response, request,
|
|
182
|
+
DataApi.prototype.getArrayImpl = function (response, request, body) {
|
|
186
183
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
187
184
|
var findOptions, _a, sort, dir, limit, hasId_1, w, r;
|
|
188
185
|
var _this = this;
|
|
@@ -194,7 +191,7 @@ var DataApi = /** @class */ (function () {
|
|
|
194
191
|
include: this.includeNone(),
|
|
195
192
|
};
|
|
196
193
|
_a = findOptions;
|
|
197
|
-
return [4 /*yield*/, this.buildWhere(request,
|
|
194
|
+
return [4 /*yield*/, this.buildWhere(request, body)];
|
|
198
195
|
case 1:
|
|
199
196
|
_a.where = _b.sent();
|
|
200
197
|
if (request) {
|
|
@@ -281,7 +278,7 @@ var DataApi = /** @class */ (function () {
|
|
|
281
278
|
}
|
|
282
279
|
return include;
|
|
283
280
|
};
|
|
284
|
-
DataApi.prototype.getArray = function (response, request,
|
|
281
|
+
DataApi.prototype.getArray = function (response, request, body) {
|
|
285
282
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
286
283
|
var r, err_3;
|
|
287
284
|
return tslib_1.__generator(this, function (_a) {
|
|
@@ -294,7 +291,7 @@ var DataApi = /** @class */ (function () {
|
|
|
294
291
|
_a.label = 1;
|
|
295
292
|
case 1:
|
|
296
293
|
_a.trys.push([1, 3, , 4]);
|
|
297
|
-
return [4 /*yield*/, this.getArrayImpl(response, request,
|
|
294
|
+
return [4 /*yield*/, this.getArrayImpl(response, request, body)];
|
|
298
295
|
case 2:
|
|
299
296
|
r = (_a.sent()).r;
|
|
300
297
|
response.success(r);
|
|
@@ -311,7 +308,7 @@ var DataApi = /** @class */ (function () {
|
|
|
311
308
|
});
|
|
312
309
|
});
|
|
313
310
|
};
|
|
314
|
-
DataApi.prototype.liveQuery = function (response, request,
|
|
311
|
+
DataApi.prototype.liveQuery = function (response, request, body, serializeContext, queryChannel) {
|
|
315
312
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
316
313
|
var r, data, err_4;
|
|
317
314
|
var _a;
|
|
@@ -326,7 +323,7 @@ var DataApi = /** @class */ (function () {
|
|
|
326
323
|
_b.label = 1;
|
|
327
324
|
case 1:
|
|
328
325
|
_b.trys.push([1, 5, , 6]);
|
|
329
|
-
return [4 /*yield*/, this.getArrayImpl(response, request,
|
|
326
|
+
return [4 /*yield*/, this.getArrayImpl(response, request, body)];
|
|
330
327
|
case 2:
|
|
331
328
|
r = _b.sent();
|
|
332
329
|
_a = {};
|
|
@@ -357,7 +354,7 @@ var DataApi = /** @class */ (function () {
|
|
|
357
354
|
});
|
|
358
355
|
});
|
|
359
356
|
};
|
|
360
|
-
DataApi.prototype.buildWhere = function (request,
|
|
357
|
+
DataApi.prototype.buildWhere = function (request, body) {
|
|
361
358
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
362
359
|
var where, _a, _b;
|
|
363
360
|
return tslib_1.__generator(this, function (_c) {
|
|
@@ -387,8 +384,8 @@ var DataApi = /** @class */ (function () {
|
|
|
387
384
|
},
|
|
388
385
|
}));
|
|
389
386
|
}
|
|
390
|
-
if (
|
|
391
|
-
where.push(filter_interfaces_js_1.Filter.entityFilterFromJson(this.repository.metadata,
|
|
387
|
+
if (body === null || body === void 0 ? void 0 : body.where)
|
|
388
|
+
where.push(filter_interfaces_js_1.Filter.entityFilterFromJson(this.repository.metadata, body.where));
|
|
392
389
|
return [2 /*return*/, { $and: where }];
|
|
393
390
|
}
|
|
394
391
|
});
|
|
@@ -455,6 +452,28 @@ var DataApi = /** @class */ (function () {
|
|
|
455
452
|
});
|
|
456
453
|
};
|
|
457
454
|
DataApi.prototype.updateMany = function (response, request, body) {
|
|
455
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
456
|
+
var action, where;
|
|
457
|
+
return tslib_1.__generator(this, function (_a) {
|
|
458
|
+
switch (_a.label) {
|
|
459
|
+
case 0:
|
|
460
|
+
action = request === null || request === void 0 ? void 0 : request.get('__action');
|
|
461
|
+
if (action == 'emptyId') {
|
|
462
|
+
return [2 /*return*/, this.put(response, '', body)];
|
|
463
|
+
}
|
|
464
|
+
return [4 /*yield*/, this.buildWhere(request, body)];
|
|
465
|
+
case 1:
|
|
466
|
+
where = _a.sent();
|
|
467
|
+
filter_interfaces_js_1.Filter.throwErrorIfFilterIsEmpty(where, 'updateMany');
|
|
468
|
+
return [2 /*return*/, this.updateManyImplementation(response, request, {
|
|
469
|
+
where: undefined,
|
|
470
|
+
set: body,
|
|
471
|
+
})];
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
};
|
|
476
|
+
DataApi.prototype.updateManyImplementation = function (response, request, body) {
|
|
458
477
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
459
478
|
var err_6;
|
|
460
479
|
var _this = this;
|
|
@@ -476,7 +495,7 @@ var DataApi = /** @class */ (function () {
|
|
|
476
495
|
_a = true;
|
|
477
496
|
_e = (_d = this.repository).query;
|
|
478
497
|
_f = {};
|
|
479
|
-
return [4 /*yield*/, this.buildWhere(request, body
|
|
498
|
+
return [4 /*yield*/, this.buildWhere(request, body)];
|
|
480
499
|
case 2:
|
|
481
500
|
_b = tslib_1.__asyncValues.apply(void 0, [_e.apply(_d, [(_f.where = _k.sent(),
|
|
482
501
|
_f.include = this.includeNone(),
|
|
@@ -165,7 +165,7 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
165
165
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
166
166
|
var run;
|
|
167
167
|
return tslib_1.__generator(this, function (_a) {
|
|
168
|
-
run = this.buildFindRequest({ where: where },
|
|
168
|
+
run = this.buildFindRequest({ where: where }, 'delete').run;
|
|
169
169
|
return [2 /*return*/, run('deleteMany').then(function (r) { return +r.deleted; })];
|
|
170
170
|
});
|
|
171
171
|
});
|
|
@@ -174,8 +174,8 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
174
174
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
175
175
|
var run;
|
|
176
176
|
return tslib_1.__generator(this, function (_a) {
|
|
177
|
-
run = this.buildFindRequest({ where: where },
|
|
178
|
-
return [2 /*return*/, run('updateMany',
|
|
177
|
+
run = this.buildFindRequest({ where: where }, 'put').run;
|
|
178
|
+
return [2 /*return*/, run('updateMany', this.toJsonOfIncludedKeys(data)).then(function (r) { return +r.updated; })];
|
|
179
179
|
});
|
|
180
180
|
});
|
|
181
181
|
};
|
|
@@ -185,16 +185,16 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
185
185
|
return run().then(function (x) { return x.map(function (y) { return _this.translateFromJson(y); }); });
|
|
186
186
|
};
|
|
187
187
|
//@internal
|
|
188
|
-
RestEntityDataProvider.prototype.buildFindRequest = function (options,
|
|
188
|
+
RestEntityDataProvider.prototype.buildFindRequest = function (options, method) {
|
|
189
189
|
var _this = this;
|
|
190
|
-
if (
|
|
190
|
+
if (!method)
|
|
191
|
+
method = 'get';
|
|
191
192
|
var url = new urlBuilder_js_1.UrlBuilder(this.url());
|
|
192
193
|
var filterObject;
|
|
193
194
|
if (options) {
|
|
194
195
|
if (options.where) {
|
|
195
196
|
filterObject = options.where.toJson(); // options.where.__applyToConsumer(new FilterConsumnerBridgeToUrlBuilder(url));
|
|
196
|
-
if (
|
|
197
|
-
addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
197
|
+
if (addFilterToUrlAndReturnTrueIfSuccessful(filterObject, url))
|
|
198
198
|
filterObject = undefined;
|
|
199
199
|
}
|
|
200
200
|
if (options.orderBy && options.orderBy.Segments) {
|
|
@@ -228,15 +228,12 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
228
228
|
}
|
|
229
229
|
if (action)
|
|
230
230
|
u.add('__action', action);
|
|
231
|
-
if (filterObject
|
|
232
|
-
|
|
233
|
-
body = filterObject;
|
|
234
|
-
else
|
|
235
|
-
body = tslib_1.__assign(tslib_1.__assign({}, body), { where: filterObject });
|
|
231
|
+
if (filterObject) {
|
|
232
|
+
body = { set: body, where: filterObject };
|
|
236
233
|
return _this.http().post(u.url, body);
|
|
237
234
|
}
|
|
238
235
|
else
|
|
239
|
-
return _this.http()
|
|
236
|
+
return _this.http()[method](u.url, body);
|
|
240
237
|
};
|
|
241
238
|
return {
|
|
242
239
|
createKey: function () { return JSON.stringify({ url: url, filterObject: filterObject }); },
|
|
@@ -270,7 +267,8 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
270
267
|
RestEntityDataProvider.prototype.update = function (id, data) {
|
|
271
268
|
var _this = this;
|
|
272
269
|
return this.http()
|
|
273
|
-
.put(this.url() +
|
|
270
|
+
.put(this.url() +
|
|
271
|
+
(id != '' ? '/' + encodeURIComponent(id) : '?__action=emptyId'), this.toJsonOfIncludedKeys(data))
|
|
274
272
|
.then(function (y) { return _this.translateFromJson(y); });
|
|
275
273
|
};
|
|
276
274
|
RestEntityDataProvider.prototype.toJsonOfIncludedKeys = function (data) {
|
|
@@ -294,7 +292,20 @@ var RestEntityDataProvider = /** @class */ (function () {
|
|
|
294
292
|
return result;
|
|
295
293
|
};
|
|
296
294
|
RestEntityDataProvider.prototype.delete = function (id) {
|
|
297
|
-
return
|
|
295
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
296
|
+
return tslib_1.__generator(this, function (_a) {
|
|
297
|
+
switch (_a.label) {
|
|
298
|
+
case 0:
|
|
299
|
+
if (!(id == '')) return [3 /*break*/, 2];
|
|
300
|
+
return [4 /*yield*/, this.deleteMany(filter_interfaces_js_1.Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)))];
|
|
301
|
+
case 1:
|
|
302
|
+
_a.sent();
|
|
303
|
+
return [3 /*break*/, 3];
|
|
304
|
+
case 2: return [2 /*return*/, this.http().delete(this.url() + '/' + encodeURIComponent(id))];
|
|
305
|
+
case 3: return [2 /*return*/];
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
});
|
|
298
309
|
};
|
|
299
310
|
RestEntityDataProvider.prototype.insert = function (data) {
|
|
300
311
|
var _this = this;
|
|
@@ -12,6 +12,58 @@ var Filter = /** @class */ (function () {
|
|
|
12
12
|
function Filter(apply) {
|
|
13
13
|
this.apply = apply;
|
|
14
14
|
}
|
|
15
|
+
//@internal
|
|
16
|
+
Filter.throwErrorIfFilterIsEmpty = function (where, methodName) {
|
|
17
|
+
if (Filter.isFilterEmpty(where)) {
|
|
18
|
+
throw {
|
|
19
|
+
message: "".concat(methodName, ": requires a filter to protect against accidental delete/update of all rows"),
|
|
20
|
+
httpStatusCode: 400,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
//@internal
|
|
25
|
+
Filter.isFilterEmpty = function (where) {
|
|
26
|
+
var e_1, _a, e_2, _b;
|
|
27
|
+
if (where.$and) {
|
|
28
|
+
try {
|
|
29
|
+
for (var _c = tslib_1.__values(where.$and), _d = _c.next(); !_d.done; _d = _c.next()) {
|
|
30
|
+
var a = _d.value;
|
|
31
|
+
if (!Filter.isFilterEmpty(a)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
37
|
+
finally {
|
|
38
|
+
try {
|
|
39
|
+
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
|
40
|
+
}
|
|
41
|
+
finally { if (e_1) throw e_1.error; }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (where.$or) {
|
|
45
|
+
try {
|
|
46
|
+
for (var _e = tslib_1.__values(where.$or), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
47
|
+
var a = _f.value;
|
|
48
|
+
if (Filter.isFilterEmpty(a)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
54
|
+
finally {
|
|
55
|
+
try {
|
|
56
|
+
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
|
|
57
|
+
}
|
|
58
|
+
finally { if (e_2) throw e_2.error; }
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (Object.keys(where).filter(function (x) { return !['$or', '$and'].includes(x); }).length == 0) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
};
|
|
15
67
|
Filter.createCustom = function (rawFilterTranslator, key) {
|
|
16
68
|
if (key === void 0) { key = ''; }
|
|
17
69
|
var rawFilterInfo = { key: key, rawFilterTranslator: rawFilterTranslator };
|
|
@@ -317,19 +369,19 @@ var filterHelper = /** @class */ (function () {
|
|
|
317
369
|
filterHelper.prototype.isNotIn = function (values) {
|
|
318
370
|
var _this = this;
|
|
319
371
|
return new Filter(function (add) {
|
|
320
|
-
var
|
|
372
|
+
var e_3, _a;
|
|
321
373
|
try {
|
|
322
374
|
for (var values_1 = tslib_1.__values(values), values_1_1 = values_1.next(); !values_1_1.done; values_1_1 = values_1.next()) {
|
|
323
375
|
var v = values_1_1.value;
|
|
324
376
|
add.isDifferentFrom(_this.metadata, _this.processVal(v));
|
|
325
377
|
}
|
|
326
378
|
}
|
|
327
|
-
catch (
|
|
379
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
328
380
|
finally {
|
|
329
381
|
try {
|
|
330
382
|
if (values_1_1 && !values_1_1.done && (_a = values_1.return)) _a.call(values_1);
|
|
331
383
|
}
|
|
332
|
-
finally { if (
|
|
384
|
+
finally { if (e_3) throw e_3.error; }
|
|
333
385
|
}
|
|
334
386
|
});
|
|
335
387
|
};
|
|
@@ -462,7 +514,7 @@ var AndFilter = /** @class */ (function (_super) {
|
|
|
462
514
|
filters[_i] = arguments[_i];
|
|
463
515
|
}
|
|
464
516
|
var _this = _super.call(this, function (add) {
|
|
465
|
-
var
|
|
517
|
+
var e_4, _a;
|
|
466
518
|
try {
|
|
467
519
|
for (var _b = tslib_1.__values(_this.filters), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
468
520
|
var iterator = _c.value;
|
|
@@ -470,12 +522,12 @@ var AndFilter = /** @class */ (function (_super) {
|
|
|
470
522
|
iterator.__applyToConsumer(add);
|
|
471
523
|
}
|
|
472
524
|
}
|
|
473
|
-
catch (
|
|
525
|
+
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
|
474
526
|
finally {
|
|
475
527
|
try {
|
|
476
528
|
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
477
529
|
}
|
|
478
|
-
finally { if (
|
|
530
|
+
finally { if (e_4) throw e_4.error; }
|
|
479
531
|
}
|
|
480
532
|
}) || this;
|
|
481
533
|
_this.filters = filters;
|
|
@@ -595,7 +647,7 @@ function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
595
647
|
tslib_1.__spreadArray([], tslib_1.__read(entity.fields), false).forEach(function (col) {
|
|
596
648
|
var _a, _b;
|
|
597
649
|
function addFilter(operation, theFilter, jsonArray, asString) {
|
|
598
|
-
var
|
|
650
|
+
var e_5, _a;
|
|
599
651
|
if (jsonArray === void 0) { jsonArray = false; }
|
|
600
652
|
if (asString === void 0) { asString = false; }
|
|
601
653
|
var val = filterInfo.get(col.key + operation);
|
|
@@ -638,12 +690,12 @@ function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
638
690
|
addFilter_1(x);
|
|
639
691
|
}
|
|
640
692
|
}
|
|
641
|
-
catch (
|
|
693
|
+
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
|
642
694
|
finally {
|
|
643
695
|
try {
|
|
644
696
|
if (array_1_1 && !array_1_1.done && (_a = array_1.return)) _a.call(array_1);
|
|
645
697
|
}
|
|
646
|
-
finally { if (
|
|
698
|
+
finally { if (e_5) throw e_5.error; }
|
|
647
699
|
}
|
|
648
700
|
}
|
|
649
701
|
}
|
|
@@ -717,7 +769,7 @@ function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
717
769
|
return where[0];
|
|
718
770
|
return { $and: where };
|
|
719
771
|
function separateArrayFromInnerArray(val) {
|
|
720
|
-
var
|
|
772
|
+
var e_6, _a;
|
|
721
773
|
if (!Array.isArray(val))
|
|
722
774
|
return [val];
|
|
723
775
|
var nonArray = [], array = [];
|
|
@@ -731,12 +783,12 @@ function buildFilterFromRequestParameters(entity, filterInfo) {
|
|
|
731
783
|
nonArray.push(v);
|
|
732
784
|
}
|
|
733
785
|
}
|
|
734
|
-
catch (
|
|
786
|
+
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
|
735
787
|
finally {
|
|
736
788
|
try {
|
|
737
789
|
if (val_1_1 && !val_1_1.done && (_a = val_1.return)) _a.call(val_1);
|
|
738
790
|
}
|
|
739
|
-
finally { if (
|
|
791
|
+
finally { if (e_6) throw e_6.error; }
|
|
740
792
|
}
|
|
741
793
|
array.push(nonArray);
|
|
742
794
|
return array;
|
|
@@ -442,6 +442,7 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
442
442
|
return tslib_1.__generator(this, function (_j) {
|
|
443
443
|
switch (_j.label) {
|
|
444
444
|
case 0:
|
|
445
|
+
filter_interfaces_js_1.Filter.throwErrorIfFilterIsEmpty(where, 'updateMany');
|
|
445
446
|
if (!this._dataProvider.isProxy) return [3 /*break*/, 2];
|
|
446
447
|
_e = (_d = this._edp).updateMany;
|
|
447
448
|
return [4 /*yield*/, this._translateWhereToFilter(where)];
|
|
@@ -1093,6 +1094,7 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
1093
1094
|
return tslib_1.__generator(this, function (_j) {
|
|
1094
1095
|
switch (_j.label) {
|
|
1095
1096
|
case 0:
|
|
1097
|
+
filter_interfaces_js_1.Filter.throwErrorIfFilterIsEmpty(where, 'deleteMany');
|
|
1096
1098
|
if (!this._dataProvider.isProxy) return [3 /*break*/, 2];
|
|
1097
1099
|
_e = (_d = this._edp).deleteMany;
|
|
1098
1100
|
return [4 /*yield*/, this._translateWhereToFilter(where)];
|
package/src/remult3/remult3.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//y1 - reconsider adding where to all in case of post - it is a breaking change and no longer required
|
|
4
|
+
//y1 - review that with deleteMany, and updateMany I've taken a similar approach to get, that when the filter is complex, we go to post - one reason is that delete doesn't accept a body.
|
|
5
|
+
//y1 - should the remult api be deleteMany({id:[1,2]}) or deleteMany({where:{id:[1,2]}})
|
|
3
6
|
//p1 - in this video I'll use remult to turn a frontend app to a fullstack app
|
|
4
|
-
/*p1 - discuss using delete & put - with url query language for deleteMany and updateMany -
|
|
5
|
-
- put & delete, similar to get
|
|
6
|
-
- add where to count, deleteMany,updateMany,
|
|
7
|
-
- prevent delete all and update all - must have meaningful where.
|
|
8
|
-
- try forcing this also in typescript
|
|
9
|
-
|
|
10
|
-
- protect against deleting of all rows by mistake
|
|
11
|
-
- https://github.com/remult/remult/issues/221#issuecomment-2016519746
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
7
|
//y1 - getFields didn't work for kobi in the home component
|
|
8
|
+
//y1 - consider replacing all errors with error classes that extend the base Error class
|
|
15
9
|
//p1 - document offline support
|
|
16
10
|
//p1 - add section to Fields doc, explaining field type in db
|
|
17
11
|
//p1 - add section about union type
|
package/src/valueConverters.js
CHANGED
|
@@ -138,7 +138,7 @@ var ValueConverters = /** @class */ (function () {
|
|
|
138
138
|
toJson: function (value) { return ValueConverters.Number.toDb(value); },
|
|
139
139
|
fromInput: function (x, type) {
|
|
140
140
|
var r = +x;
|
|
141
|
-
if (
|
|
141
|
+
if (x === null || x === undefined)
|
|
142
142
|
return undefined;
|
|
143
143
|
return r;
|
|
144
144
|
},
|