remult 0.27.20 → 0.27.21-next.6
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/remult-mongo.js +3 -1
- package/esm/server/remult-api-server.js +1 -1
- package/esm/src/column.js +3 -4
- package/esm/src/data-api.js +110 -57
- package/esm/src/data-providers/rest-data-provider.js +30 -9
- package/esm/src/remult-proxy.js +6 -2
- package/esm/src/remult3/QueryResultImpl.js +147 -0
- package/esm/src/remult3/RepositoryImplementation.js +111 -134
- package/esm/src/remult3/relationInfoMember.js +2 -0
- package/esm/src/remult3/remult3.js +14 -22
- package/graphql.js +2 -2
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/remult-mongo.js +5 -2
- package/server/remult-api-server.js +6 -3
- package/src/column.js +3 -4
- package/src/data-api.d.ts +9 -4
- package/src/data-api.js +217 -99
- package/src/data-interfaces.d.ts +8 -0
- package/src/data-providers/rest-data-provider.d.ts +9 -0
- package/src/data-providers/rest-data-provider.js +44 -13
- package/src/remult-proxy.js +10 -9
- package/src/remult3/QueryResultImpl.d.ts +16 -0
- package/src/remult3/QueryResultImpl.js +268 -0
- package/src/remult3/RepositoryImplementation.d.ts +13 -6
- package/src/remult3/RepositoryImplementation.js +354 -416
- package/src/remult3/relationInfoMember.js +2 -0
- package/src/remult3/remult3.d.ts +92 -23
- package/src/remult3/remult3.js +14 -22
package/esm/graphql.js
CHANGED
|
@@ -315,7 +315,7 @@ export function remultGraphql(options) {
|
|
|
315
315
|
value: getMetaType(meta),
|
|
316
316
|
}, argErrorDetail, argClientMutationId);
|
|
317
317
|
root[createResolverKey] = handleMutationWithErrors(async (dApi, response, setResult, arg1, req) => {
|
|
318
|
-
await dApi.
|
|
318
|
+
await dApi.httpPost({
|
|
319
319
|
...response,
|
|
320
320
|
created: (y) => {
|
|
321
321
|
const orig = { ...y };
|
|
@@ -324,7 +324,7 @@ export function remultGraphql(options) {
|
|
|
324
324
|
[toCamelCase(getMetaType(meta))]: y,
|
|
325
325
|
});
|
|
326
326
|
},
|
|
327
|
-
}, arg1.input);
|
|
327
|
+
}, { get: () => undefined }, arg1.input, undefined);
|
|
328
328
|
});
|
|
329
329
|
resolversMutation[createResolverKey] = (origItem, args, req, gqlInfo) => root[createResolverKey](args, req, gqlInfo);
|
|
330
330
|
}
|
package/esm/remult-mongo.js
CHANGED
|
@@ -266,7 +266,9 @@ class MongoEntityDataProvider {
|
|
|
266
266
|
const { e, collection } = await this.collection();
|
|
267
267
|
let f = new FilterConsumerBridgeToMongo(e);
|
|
268
268
|
Filter.fromEntityFilter(this.entity, this.entity.idMetadata.getIdFilter(id)).__applyToConsumer(f);
|
|
269
|
-
collection.deleteOne(await f.resolveWhere(), {
|
|
269
|
+
await collection.deleteOne(await f.resolveWhere(), {
|
|
270
|
+
session: this.session,
|
|
271
|
+
});
|
|
270
272
|
}
|
|
271
273
|
async insert(data) {
|
|
272
274
|
let { collection, e } = await this.collection();
|
|
@@ -258,7 +258,7 @@ export class RemultServerImplementation {
|
|
|
258
258
|
if (this.options.logApiEndPoints)
|
|
259
259
|
console.info('[remult] ' + myRoute);
|
|
260
260
|
r.route(myRoute)
|
|
261
|
-
.get(this.process((c, req, res, orig) => dataApiFactory(c).httpGet(res, req, () => this.serializeContext(c))))
|
|
261
|
+
.get(this.process(async (c, req, res, orig) => dataApiFactory(c).httpGet(res, req, () => this.serializeContext(c))))
|
|
262
262
|
.put(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).updateManyThroughPutRequest(res, req, await this.coreOptions.getRequestBody(orig))))
|
|
263
263
|
.delete(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).deleteMany(res, req, undefined)))
|
|
264
264
|
.post(this.process(async (c, req, res, _, __, orig) => dataApiFactory(c).httpPost(res, req, await this.coreOptions.getRequestBody(orig), () => this.serializeContext(c))));
|
package/esm/src/column.js
CHANGED
|
@@ -3,11 +3,10 @@ import { getRepositoryInternals } from './remult3/repository-internals.js';
|
|
|
3
3
|
export function makeTitle(name) {
|
|
4
4
|
// insert a space before all caps
|
|
5
5
|
return (name
|
|
6
|
-
.replace(/([A-Z])/g, ' $
|
|
7
|
-
//
|
|
6
|
+
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
7
|
+
// Uppercase the first character
|
|
8
8
|
.replace(/^./, (str) => str.toUpperCase())
|
|
9
|
-
.replace('Email', 'eMail')
|
|
10
|
-
.replace(' I D', ' ID'));
|
|
9
|
+
.replace('Email', 'eMail'));
|
|
11
10
|
}
|
|
12
11
|
export class LookupColumn {
|
|
13
12
|
repository;
|
package/esm/src/data-api.js
CHANGED
|
@@ -20,7 +20,7 @@ export class DataApi {
|
|
|
20
20
|
case 'count':
|
|
21
21
|
return this.count(res, req, undefined);
|
|
22
22
|
case 'groupBy':
|
|
23
|
-
return this.groupBy(
|
|
23
|
+
return res.success(this.groupBy(req, undefined));
|
|
24
24
|
}
|
|
25
25
|
return this.getArray(res, req, undefined);
|
|
26
26
|
}
|
|
@@ -34,31 +34,90 @@ export class DataApi {
|
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return this.liveQuery(res, req, body, serializeContext, action.substring(liveQueryAction.length));
|
|
40
|
-
}
|
|
41
|
-
switch (action) {
|
|
42
|
-
case 'get':
|
|
43
|
-
validateWhereInBody();
|
|
44
|
-
return this.getArray(res, req, body);
|
|
45
|
-
case 'count':
|
|
46
|
-
validateWhereInBody();
|
|
47
|
-
return this.count(res, req, body);
|
|
48
|
-
case 'groupBy':
|
|
49
|
-
return this.groupBy(res, req, body);
|
|
50
|
-
case 'deleteMany':
|
|
51
|
-
validateWhereInBody();
|
|
52
|
-
return this.deleteMany(res, req, body);
|
|
53
|
-
case 'updateMany':
|
|
37
|
+
try {
|
|
38
|
+
if (action?.startsWith(liveQueryAction)) {
|
|
54
39
|
validateWhereInBody();
|
|
55
|
-
return this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
return this.liveQuery(res, req, body, serializeContext, action.substring(liveQueryAction.length));
|
|
41
|
+
}
|
|
42
|
+
switch (action) {
|
|
43
|
+
case 'get':
|
|
44
|
+
validateWhereInBody();
|
|
45
|
+
return this.getArray(res, req, body);
|
|
46
|
+
case 'count':
|
|
47
|
+
validateWhereInBody();
|
|
48
|
+
return this.count(res, req, body);
|
|
49
|
+
case 'groupBy':
|
|
50
|
+
return res.success(await this.groupBy(req, body));
|
|
51
|
+
case 'deleteMany':
|
|
52
|
+
validateWhereInBody();
|
|
53
|
+
return this.deleteMany(res, req, body);
|
|
54
|
+
case 'updateMany':
|
|
55
|
+
validateWhereInBody();
|
|
56
|
+
return this.updateManyImplementation(res, req, body);
|
|
57
|
+
case 'upsertMany':
|
|
58
|
+
return this.upsertMany(res, req, body);
|
|
59
|
+
case 'endLiveQuery':
|
|
60
|
+
await this.remult.liveQueryStorage.remove(body.id);
|
|
61
|
+
res.success('ok');
|
|
62
|
+
return;
|
|
63
|
+
case 'query':
|
|
64
|
+
return res.success(await this.query(res, req, body));
|
|
65
|
+
default:
|
|
66
|
+
return res.created(await this.post(body));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (err.isForbiddenError)
|
|
71
|
+
res.forbidden(err.message);
|
|
72
|
+
else
|
|
73
|
+
res.error(err, this.repository.metadata);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async upsertMany(response, request, body) {
|
|
77
|
+
return await doTransaction(this.remult, async () => {
|
|
78
|
+
let result = [];
|
|
79
|
+
for (const item of body) {
|
|
80
|
+
let where = await this.buildWhere(request, { where: item.where });
|
|
81
|
+
Filter.throwErrorIfFilterIsEmpty(where, 'upsert');
|
|
82
|
+
let r = await this.repository.find({
|
|
83
|
+
where,
|
|
84
|
+
include: this.includeNone(),
|
|
85
|
+
});
|
|
86
|
+
if (r.length == 0) {
|
|
87
|
+
result.push(await this.post({ ...item.where, ...item.set }));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (item.set !== undefined) {
|
|
91
|
+
result.push((await this.actualUpdate(r[0], item.set)).toApiJson());
|
|
92
|
+
}
|
|
93
|
+
else
|
|
94
|
+
result.push(this.repository.getEntityRef(r[0]).toApiJson());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
response.success(result);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async query(response, request, body) {
|
|
101
|
+
if (!this.repository.metadata.apiReadAllowed) {
|
|
102
|
+
response.forbidden();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
let { aggregate, ...rest } = body;
|
|
107
|
+
let [{ r }, [aggregates]] = await Promise.all([
|
|
108
|
+
this.getArrayImpl(request, rest),
|
|
109
|
+
this.groupBy(request, aggregate),
|
|
110
|
+
]);
|
|
111
|
+
return {
|
|
112
|
+
items: r,
|
|
113
|
+
aggregates,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
if (err.isForbiddenError)
|
|
118
|
+
response.forbidden();
|
|
119
|
+
else
|
|
120
|
+
response.error(err, this.repository.metadata);
|
|
62
121
|
}
|
|
63
122
|
}
|
|
64
123
|
static defaultGetLimit = 0;
|
|
@@ -92,6 +151,7 @@ export class DataApi {
|
|
|
92
151
|
for await (const x of this.repository.query({
|
|
93
152
|
where,
|
|
94
153
|
include: this.includeNone(),
|
|
154
|
+
aggregate: undefined,
|
|
95
155
|
})) {
|
|
96
156
|
await this.actualDelete(x);
|
|
97
157
|
deleted++;
|
|
@@ -103,7 +163,7 @@ export class DataApi {
|
|
|
103
163
|
response.error(err, this.repository.metadata);
|
|
104
164
|
}
|
|
105
165
|
}
|
|
106
|
-
async groupBy(
|
|
166
|
+
async groupBy(request, body) {
|
|
107
167
|
let findOptions = await this.findOptionsFromRequest(request, body);
|
|
108
168
|
let orderBy = {};
|
|
109
169
|
if (body?.orderBy) {
|
|
@@ -146,9 +206,9 @@ export class DataApi {
|
|
|
146
206
|
x[f] = this.repository.fields.find(f).valueConverter.toJson(x[f]);
|
|
147
207
|
}
|
|
148
208
|
});
|
|
149
|
-
|
|
209
|
+
return result;
|
|
150
210
|
}
|
|
151
|
-
async getArrayImpl(
|
|
211
|
+
async getArrayImpl(request, body) {
|
|
152
212
|
let findOptions = await this.findOptionsFromRequest(request, body);
|
|
153
213
|
const r = await this.repository.find(findOptions).then(async (r) => {
|
|
154
214
|
return await Promise.all(r.map(async (y) => this.repository.getEntityRef(y).toApiJson()));
|
|
@@ -224,7 +284,7 @@ export class DataApi {
|
|
|
224
284
|
return;
|
|
225
285
|
}
|
|
226
286
|
try {
|
|
227
|
-
const { r } = await this.getArrayImpl(
|
|
287
|
+
const { r } = await this.getArrayImpl(request, body);
|
|
228
288
|
response.success(r);
|
|
229
289
|
}
|
|
230
290
|
catch (err) {
|
|
@@ -240,7 +300,7 @@ export class DataApi {
|
|
|
240
300
|
return;
|
|
241
301
|
}
|
|
242
302
|
try {
|
|
243
|
-
const r = await this.getArrayImpl(
|
|
303
|
+
const r = await this.getArrayImpl(request, body);
|
|
244
304
|
const data = {
|
|
245
305
|
requestJson: await serializeContext(),
|
|
246
306
|
findOptionsJson: findOptionsToJson(r.findOptions, this.repository.metadata),
|
|
@@ -345,6 +405,7 @@ export class DataApi {
|
|
|
345
405
|
for await (const x of this.repository.query({
|
|
346
406
|
where,
|
|
347
407
|
include: this.includeNone(),
|
|
408
|
+
aggregate: undefined,
|
|
348
409
|
})) {
|
|
349
410
|
await this.actualUpdate(x, body.set);
|
|
350
411
|
updated++;
|
|
@@ -383,35 +444,27 @@ export class DataApi {
|
|
|
383
444
|
response.deleted();
|
|
384
445
|
});
|
|
385
446
|
}
|
|
386
|
-
async post(
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
throw new ForbiddenError();
|
|
393
|
-
}
|
|
394
|
-
await this.repository.getEntityRef(newr).save();
|
|
395
|
-
return this.repository.getEntityRef(newr).toApiJson();
|
|
396
|
-
};
|
|
397
|
-
if (Array.isArray(body)) {
|
|
398
|
-
const result = [];
|
|
399
|
-
await doTransaction(this.remult, async () => {
|
|
400
|
-
for (const item of body) {
|
|
401
|
-
result.push(await insert(item));
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
response.created(result);
|
|
447
|
+
async post(body) {
|
|
448
|
+
const insert = async (what) => {
|
|
449
|
+
let newr = this.repository.create();
|
|
450
|
+
await this.repository.getEntityRef(newr)._updateEntityBasedOnApi(what);
|
|
451
|
+
if (!this.repository.getEntityRef(newr).apiInsertAllowed) {
|
|
452
|
+
throw new ForbiddenError();
|
|
405
453
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
454
|
+
await this.repository.getEntityRef(newr).save();
|
|
455
|
+
return this.repository.getEntityRef(newr).toApiJson();
|
|
456
|
+
};
|
|
457
|
+
if (Array.isArray(body)) {
|
|
458
|
+
const result = [];
|
|
459
|
+
await doTransaction(this.remult, async () => {
|
|
460
|
+
for (const item of body) {
|
|
461
|
+
result.push(await insert(item));
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
return result;
|
|
414
465
|
}
|
|
466
|
+
else
|
|
467
|
+
return await insert(body);
|
|
415
468
|
}
|
|
416
469
|
}
|
|
417
470
|
export function determineSort(sortUrlParm, dirUrlParam) {
|
|
@@ -103,21 +103,24 @@ export class RestEntityDataProvider {
|
|
|
103
103
|
this.http = http;
|
|
104
104
|
this.entity = entity;
|
|
105
105
|
}
|
|
106
|
+
query(options, aggregateOptions) {
|
|
107
|
+
const r = this.buildFindRequest(options);
|
|
108
|
+
return r
|
|
109
|
+
.run('query', {
|
|
110
|
+
aggregate: this.buildAggregateOptions(aggregateOptions),
|
|
111
|
+
})
|
|
112
|
+
.then(({ items, aggregates }) => ({
|
|
113
|
+
items: items.map((x) => this.translateFromJson(x)),
|
|
114
|
+
aggregates,
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
106
117
|
async groupBy(options) {
|
|
107
118
|
const { run } = this.buildFindRequest({
|
|
108
119
|
where: options?.where,
|
|
109
120
|
limit: options?.limit,
|
|
110
121
|
page: options?.page,
|
|
111
122
|
});
|
|
112
|
-
const body =
|
|
113
|
-
groupBy: options?.group?.map((x) => x.key),
|
|
114
|
-
sum: options?.sum?.map((x) => x.key),
|
|
115
|
-
avg: options?.avg?.map((x) => x.key),
|
|
116
|
-
min: options?.min?.map((x) => x.key),
|
|
117
|
-
max: options?.max?.map((x) => x.key),
|
|
118
|
-
distinctCount: options?.distinctCount?.map((x) => x.key),
|
|
119
|
-
orderBy: options?.orderBy?.map((x) => ({ ...x, field: x.field?.key })),
|
|
120
|
-
};
|
|
123
|
+
const body = this.buildAggregateOptions(options);
|
|
121
124
|
const result = await run('groupBy', Object.keys(body).length > 0 ? body : undefined);
|
|
122
125
|
if (options?.group)
|
|
123
126
|
result.forEach((row) => {
|
|
@@ -127,6 +130,17 @@ export class RestEntityDataProvider {
|
|
|
127
130
|
});
|
|
128
131
|
return result;
|
|
129
132
|
}
|
|
133
|
+
buildAggregateOptions(options) {
|
|
134
|
+
return {
|
|
135
|
+
groupBy: options?.group?.map((x) => x.key),
|
|
136
|
+
sum: options?.sum?.map((x) => x.key),
|
|
137
|
+
avg: options?.avg?.map((x) => x.key),
|
|
138
|
+
min: options?.min?.map((x) => x.key),
|
|
139
|
+
max: options?.max?.map((x) => x.key),
|
|
140
|
+
distinctCount: options?.distinctCount?.map((x) => x.key),
|
|
141
|
+
orderBy: options?.orderBy?.map((x) => ({ ...x, field: x.field?.key })),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
130
144
|
translateFromJson(row) {
|
|
131
145
|
let result = {};
|
|
132
146
|
for (const col of this.entity.fields) {
|
|
@@ -153,6 +167,13 @@ export class RestEntityDataProvider {
|
|
|
153
167
|
const { run } = this.buildFindRequest({ where }, 'put');
|
|
154
168
|
return run('updateMany', this.toJsonOfIncludedKeys(data)).then((r) => +r.updated);
|
|
155
169
|
}
|
|
170
|
+
async upsertMany(options) {
|
|
171
|
+
const { run } = this.buildFindRequest(undefined);
|
|
172
|
+
return run('upsertMany', options.map((x) => ({
|
|
173
|
+
where: this.toJsonOfIncludedKeys(x.where),
|
|
174
|
+
set: x.set !== undefined ? this.toJsonOfIncludedKeys(x.set) : undefined,
|
|
175
|
+
}))).then((r) => r.map((x) => this.translateFromJson(x)));
|
|
176
|
+
}
|
|
156
177
|
find(options) {
|
|
157
178
|
let { run } = this.buildFindRequest(options);
|
|
158
179
|
return run().then((x) => x.map((y) => this.translateFromJson(y)));
|
package/esm/src/remult-proxy.js
CHANGED
|
@@ -161,14 +161,18 @@ export class RemultProxy {
|
|
|
161
161
|
get metadata() {
|
|
162
162
|
return remultStatic.remultFactory().repo(...args).metadata;
|
|
163
163
|
},
|
|
164
|
-
query: (
|
|
164
|
+
query: (options) => self
|
|
165
165
|
.remultFactory()
|
|
166
166
|
.repo(...args)
|
|
167
|
-
.query(
|
|
167
|
+
.query(options),
|
|
168
168
|
save: (args2) => self
|
|
169
169
|
.remultFactory()
|
|
170
170
|
.repo(...args)
|
|
171
171
|
.save(args2),
|
|
172
|
+
upsert: (args2) => self
|
|
173
|
+
.remultFactory()
|
|
174
|
+
.repo(...args)
|
|
175
|
+
.upsert(args2),
|
|
172
176
|
update: (a, b) => self
|
|
173
177
|
.remultFactory()
|
|
174
178
|
.repo(...args)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { queryConfig } from '../context.js';
|
|
2
|
+
import { isOfType } from '../isOfType.js';
|
|
3
|
+
import { Sort } from '../sort.js';
|
|
4
|
+
import { RelationLoader } from './relation-loader.js';
|
|
5
|
+
export class QueryResultImpl {
|
|
6
|
+
options;
|
|
7
|
+
repo;
|
|
8
|
+
constructor(options, repo) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.repo = repo;
|
|
11
|
+
if (!this.options)
|
|
12
|
+
this.options = {};
|
|
13
|
+
if (!this.options.pageSize) {
|
|
14
|
+
this.options.pageSize = queryConfig.defaultPageSize;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
_count = undefined;
|
|
18
|
+
_aggregates;
|
|
19
|
+
async getPage(page) {
|
|
20
|
+
if ((page ?? 0) < 1)
|
|
21
|
+
page = 1;
|
|
22
|
+
return this.repo.find({
|
|
23
|
+
where: this.options.where,
|
|
24
|
+
orderBy: this.options.orderBy,
|
|
25
|
+
limit: this.options.pageSize,
|
|
26
|
+
page: page,
|
|
27
|
+
load: this.options.load,
|
|
28
|
+
include: this.options.include,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async count() {
|
|
32
|
+
if (this._count === undefined)
|
|
33
|
+
this._count = await this.repo.count(this.options.where);
|
|
34
|
+
return this._count;
|
|
35
|
+
}
|
|
36
|
+
async forEach(what) {
|
|
37
|
+
let i = 0;
|
|
38
|
+
for await (const x of this) {
|
|
39
|
+
await what(x);
|
|
40
|
+
i++;
|
|
41
|
+
}
|
|
42
|
+
return i;
|
|
43
|
+
}
|
|
44
|
+
async paginator(pNextPageFilter) {
|
|
45
|
+
this.options.orderBy = Sort.createUniqueEntityOrderBy(this.repo.metadata, this.options.orderBy);
|
|
46
|
+
let options = {
|
|
47
|
+
where: {
|
|
48
|
+
$and: [this.options.where, pNextPageFilter],
|
|
49
|
+
},
|
|
50
|
+
orderBy: this.options.orderBy,
|
|
51
|
+
limit: this.options.pageSize,
|
|
52
|
+
load: this.options.load,
|
|
53
|
+
include: this.options.include,
|
|
54
|
+
};
|
|
55
|
+
let getItems = () => this.repo.find(options);
|
|
56
|
+
if (this._aggregates === undefined &&
|
|
57
|
+
isOfType(this.options, 'aggregate')) {
|
|
58
|
+
let agg = this.options.aggregate;
|
|
59
|
+
if (!this.repo._dataProvider.isProxy) {
|
|
60
|
+
let itemsPromise = getItems();
|
|
61
|
+
getItems = async () => {
|
|
62
|
+
this._aggregates = await this.repo.aggregate({
|
|
63
|
+
...agg,
|
|
64
|
+
where: this.options.where,
|
|
65
|
+
});
|
|
66
|
+
this._count = this._aggregates.$count;
|
|
67
|
+
return itemsPromise;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const loader = new RelationLoader();
|
|
72
|
+
getItems = () => this.repo
|
|
73
|
+
._rawFind(options, false, loader, async (opt) => {
|
|
74
|
+
const r = await this.repo._edp.query(opt, await this.repo.__buildGroupByOptions(agg));
|
|
75
|
+
this._aggregates = r.aggregates;
|
|
76
|
+
return r.items;
|
|
77
|
+
})
|
|
78
|
+
.then(async (y) => {
|
|
79
|
+
await loader.resolveAll();
|
|
80
|
+
return y;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let items = await getItems();
|
|
85
|
+
let nextPage = () => {
|
|
86
|
+
throw new Error('no more pages');
|
|
87
|
+
};
|
|
88
|
+
let hasNextPage = items.length == this.options.pageSize;
|
|
89
|
+
if (hasNextPage) {
|
|
90
|
+
let nextPageFilter = await this.repo._createAfterFilter(this.options.orderBy, items[items.length - 1]);
|
|
91
|
+
nextPage = () => this.paginator(nextPageFilter);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
count: () => this.count(),
|
|
95
|
+
hasNextPage,
|
|
96
|
+
items,
|
|
97
|
+
nextPage,
|
|
98
|
+
//@ts-ignore
|
|
99
|
+
aggregates: this._aggregates,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
[Symbol.asyncIterator]() {
|
|
103
|
+
if (!this.options.where) {
|
|
104
|
+
this.options.where = {};
|
|
105
|
+
}
|
|
106
|
+
let ob = this.options.orderBy;
|
|
107
|
+
this.options.orderBy = Sort.createUniqueEntityOrderBy(this.repo.metadata, ob);
|
|
108
|
+
let itemIndex = -1;
|
|
109
|
+
let currentPage = undefined;
|
|
110
|
+
let itStrategy;
|
|
111
|
+
let j = 0;
|
|
112
|
+
itStrategy = async () => {
|
|
113
|
+
if (this.options.progress) {
|
|
114
|
+
this.options.progress.progress(j++ / (await this.count()));
|
|
115
|
+
}
|
|
116
|
+
if (currentPage === undefined || itemIndex == currentPage.items.length) {
|
|
117
|
+
if (currentPage && !currentPage.hasNextPage)
|
|
118
|
+
return { value: undefined, done: true };
|
|
119
|
+
let prev = currentPage;
|
|
120
|
+
if (currentPage)
|
|
121
|
+
currentPage = await currentPage.nextPage();
|
|
122
|
+
else
|
|
123
|
+
currentPage = await this.paginator();
|
|
124
|
+
itemIndex = 0;
|
|
125
|
+
if (currentPage.items.length == 0) {
|
|
126
|
+
return { value: undefined, done: true };
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
if (prev?.items.length ?? 0 > 0) {
|
|
130
|
+
if (this.repo.getEntityRef(prev.items[0]).getId() ==
|
|
131
|
+
this.repo.getEntityRef(currentPage.items[0]).getId())
|
|
132
|
+
throw new Error('pagination failure, returned same first row');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (itemIndex < currentPage.items.length)
|
|
137
|
+
return { value: currentPage.items[itemIndex++], done: false };
|
|
138
|
+
return { done: true, value: undefined };
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
next: async () => {
|
|
142
|
+
let r = itStrategy();
|
|
143
|
+
return r;
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|