remult 0.27.19 → 0.27.20-next.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/index.js CHANGED
@@ -11,6 +11,7 @@ export { SqlDatabase } from './src/data-providers/sql-database.js'; //V
11
11
  export { CustomSqlFilterBuilder, dbNamesOf, } from './src/filter/filter-consumer-bridge-to-sql-request.js';
12
12
  export { JsonDataProvider, } from './src/data-providers/json-data-provider.js'; //V
13
13
  export { JsonEntityOpfsStorage } from './src/data-providers/json-entity-opfs-storage.js';
14
+ export { JsonEntityIndexedDbStorage } from './src/data-providers/json-entity-indexed-db-data-provider.js';
14
15
  //export * from './src/data-api'; //reconsider if to make internal
15
16
  export { Controller, BackendMethod, ProgressListener, ForbiddenError, } from './src/server-action.js';
16
17
  export { Allow, Remult, withRemult, isBackend, EventSource, } from './src/context.js';
@@ -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))));
@@ -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(res, req, undefined);
23
+ return res.success(this.groupBy(req, undefined));
24
24
  }
25
25
  return this.getArray(res, req, undefined);
26
26
  }
@@ -46,7 +46,7 @@ export class DataApi {
46
46
  validateWhereInBody();
47
47
  return this.count(res, req, body);
48
48
  case 'groupBy':
49
- return this.groupBy(res, req, body);
49
+ return res.success(this.groupBy(req, body));
50
50
  case 'deleteMany':
51
51
  validateWhereInBody();
52
52
  return this.deleteMany(res, req, body);
@@ -57,10 +57,35 @@ export class DataApi {
57
57
  await this.remult.liveQueryStorage.remove(body.id);
58
58
  res.success('ok');
59
59
  return;
60
+ case 'query':
61
+ return res.success(this.query(res, req, body));
60
62
  default:
61
63
  return this.post(res, body);
62
64
  }
63
65
  }
66
+ async query(response, request, body) {
67
+ if (!this.repository.metadata.apiReadAllowed) {
68
+ response.forbidden();
69
+ return;
70
+ }
71
+ try {
72
+ let { aggregate, ...rest } = body;
73
+ let [{ r }, [aggregates]] = await Promise.all([
74
+ this.getArrayImpl(request, rest),
75
+ this.groupBy(request, aggregate),
76
+ ]);
77
+ return {
78
+ items: r,
79
+ aggregates,
80
+ };
81
+ }
82
+ catch (err) {
83
+ if (err.isForbiddenError)
84
+ response.forbidden();
85
+ else
86
+ response.error(err, this.repository.metadata);
87
+ }
88
+ }
64
89
  static defaultGetLimit = 0;
65
90
  async get(response, id) {
66
91
  if (!this.repository.metadata.apiReadAllowed) {
@@ -92,6 +117,7 @@ export class DataApi {
92
117
  for await (const x of this.repository.query({
93
118
  where,
94
119
  include: this.includeNone(),
120
+ aggregate: undefined,
95
121
  })) {
96
122
  await this.actualDelete(x);
97
123
  deleted++;
@@ -103,7 +129,7 @@ export class DataApi {
103
129
  response.error(err, this.repository.metadata);
104
130
  }
105
131
  }
106
- async groupBy(response, request, body) {
132
+ async groupBy(request, body) {
107
133
  let findOptions = await this.findOptionsFromRequest(request, body);
108
134
  let orderBy = {};
109
135
  if (body?.orderBy) {
@@ -146,9 +172,9 @@ export class DataApi {
146
172
  x[f] = this.repository.fields.find(f).valueConverter.toJson(x[f]);
147
173
  }
148
174
  });
149
- response.success(result);
175
+ return result;
150
176
  }
151
- async getArrayImpl(response, request, body) {
177
+ async getArrayImpl(request, body) {
152
178
  let findOptions = await this.findOptionsFromRequest(request, body);
153
179
  const r = await this.repository.find(findOptions).then(async (r) => {
154
180
  return await Promise.all(r.map(async (y) => this.repository.getEntityRef(y).toApiJson()));
@@ -224,7 +250,7 @@ export class DataApi {
224
250
  return;
225
251
  }
226
252
  try {
227
- const { r } = await this.getArrayImpl(response, request, body);
253
+ const { r } = await this.getArrayImpl(request, body);
228
254
  response.success(r);
229
255
  }
230
256
  catch (err) {
@@ -240,7 +266,7 @@ export class DataApi {
240
266
  return;
241
267
  }
242
268
  try {
243
- const r = await this.getArrayImpl(response, request, body);
269
+ const r = await this.getArrayImpl(request, body);
244
270
  const data = {
245
271
  requestJson: await serializeContext(),
246
272
  findOptionsJson: findOptionsToJson(r.findOptions, this.repository.metadata),
@@ -345,6 +371,7 @@ export class DataApi {
345
371
  for await (const x of this.repository.query({
346
372
  where,
347
373
  include: this.includeNone(),
374
+ aggregate: undefined,
348
375
  })) {
349
376
  await this.actualUpdate(x, body.set);
350
377
  updated++;
@@ -30,9 +30,11 @@ class JsonEntityDataProvider {
30
30
  let dbName = await this.entity.dbName;
31
31
  let s = await this.helper.getItem(dbName);
32
32
  if (s)
33
- data = JSON.parse(s);
33
+ data = this.helper.supportsRawJson ? s : JSON.parse(s);
34
34
  let dp = new ArrayEntityDataProvider(this.entity, () => data);
35
- return what(dp, async () => await this.helper.setItem(dbName, JSON.stringify(data, undefined, this.formatted ? 2 : undefined)));
35
+ return what(dp, async () => await this.helper.setItem(dbName, this.helper.supportsRawJson
36
+ ? data
37
+ : JSON.stringify(data, undefined, this.formatted ? 2 : undefined)));
36
38
  }
37
39
  p = Promise.resolve();
38
40
  find(options) {
@@ -0,0 +1,55 @@
1
+ export class JsonEntityIndexedDbStorage {
2
+ dbName;
3
+ storeName;
4
+ constructor(dbName = 'db', storeName = 'jsonStore') {
5
+ this.dbName = dbName;
6
+ this.storeName = storeName;
7
+ }
8
+ supportsRawJson = true;
9
+ //@internal
10
+ db;
11
+ async getItem(entityDbName) {
12
+ return new Promise(async (resolve, reject) => {
13
+ const transaction = (await this.init()).transaction([this.storeName], 'readonly');
14
+ const store = transaction.objectStore(this.storeName);
15
+ const request = store.get(entityDbName);
16
+ request.onerror = (event) => reject(request.error);
17
+ request.onsuccess = (event) => {
18
+ if (request.result) {
19
+ resolve(request.result);
20
+ }
21
+ else {
22
+ resolve(null);
23
+ }
24
+ };
25
+ });
26
+ }
27
+ //@internal
28
+ async init() {
29
+ if (!this.db) {
30
+ this.db = await new Promise((resolve, reject) => {
31
+ let db;
32
+ const request = indexedDB.open(this.dbName, 1);
33
+ request.onerror = (event) => reject(request.error);
34
+ request.onsuccess = (event) => {
35
+ db = request.result;
36
+ resolve(db);
37
+ };
38
+ request.onupgradeneeded = (event) => {
39
+ db = request.result;
40
+ db.createObjectStore(this.storeName);
41
+ };
42
+ });
43
+ }
44
+ return this.db;
45
+ }
46
+ async setItem(entityDbName, json) {
47
+ return new Promise(async (resolve, reject) => {
48
+ const transaction = (await this.init()).transaction([this.storeName], 'readwrite');
49
+ const store = transaction.objectStore(this.storeName);
50
+ const request = store.put(json, entityDbName);
51
+ request.onerror = (event) => reject(request.error);
52
+ request.onsuccess = (event) => resolve();
53
+ });
54
+ }
55
+ }
@@ -103,21 +103,19 @@ 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.run('query', {
109
+ aggregate: this.buildAggregateOptions(aggregateOptions),
110
+ });
111
+ }
106
112
  async groupBy(options) {
107
113
  const { run } = this.buildFindRequest({
108
114
  where: options?.where,
109
115
  limit: options?.limit,
110
116
  page: options?.page,
111
117
  });
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
- };
118
+ const body = this.buildAggregateOptions(options);
121
119
  const result = await run('groupBy', Object.keys(body).length > 0 ? body : undefined);
122
120
  if (options?.group)
123
121
  result.forEach((row) => {
@@ -127,6 +125,17 @@ export class RestEntityDataProvider {
127
125
  });
128
126
  return result;
129
127
  }
128
+ buildAggregateOptions(options) {
129
+ return {
130
+ groupBy: options?.group?.map((x) => x.key),
131
+ sum: options?.sum?.map((x) => x.key),
132
+ avg: options?.avg?.map((x) => x.key),
133
+ min: options?.min?.map((x) => x.key),
134
+ max: options?.max?.map((x) => x.key),
135
+ distinctCount: options?.distinctCount?.map((x) => x.key),
136
+ orderBy: options?.orderBy?.map((x) => ({ ...x, field: x.field?.key })),
137
+ };
138
+ }
130
139
  translateFromJson(row) {
131
140
  let result = {};
132
141
  for (const col of this.entity.fields) {
@@ -161,10 +161,10 @@ export class RemultProxy {
161
161
  get metadata() {
162
162
  return remultStatic.remultFactory().repo(...args).metadata;
163
163
  },
164
- query: (...args2) => self
164
+ query: (options) => self
165
165
  .remultFactory()
166
166
  .repo(...args)
167
- .query(...args2),
167
+ .query(options),
168
168
  save: (args2) => self
169
169
  .remultFactory()
170
170
  .repo(...args)
@@ -0,0 +1,146 @@
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
+ return itemsPromise;
67
+ };
68
+ }
69
+ else {
70
+ const loader = new RelationLoader();
71
+ getItems = () => this.repo
72
+ ._rawFind(options, false, loader, async (opt) => {
73
+ const r = await this.repo._edp.query(opt, await this.repo.__buildGroupByOptions(agg));
74
+ this._aggregates = r.aggregates;
75
+ return r.items;
76
+ })
77
+ .then(async (y) => {
78
+ await loader.resolveAll();
79
+ return y;
80
+ });
81
+ }
82
+ }
83
+ let items = await getItems();
84
+ let nextPage = () => {
85
+ throw new Error('no more pages');
86
+ };
87
+ let hasNextPage = items.length == this.options.pageSize;
88
+ if (hasNextPage) {
89
+ let nextPageFilter = await this.repo._createAfterFilter(this.options.orderBy, items[items.length - 1]);
90
+ nextPage = () => this.paginator(nextPageFilter);
91
+ }
92
+ return {
93
+ count: () => this.count(),
94
+ hasNextPage,
95
+ items,
96
+ nextPage,
97
+ //@ts-ignore
98
+ aggregates: this._aggregates,
99
+ };
100
+ }
101
+ [Symbol.asyncIterator]() {
102
+ if (!this.options.where) {
103
+ this.options.where = {};
104
+ }
105
+ let ob = this.options.orderBy;
106
+ this.options.orderBy = Sort.createUniqueEntityOrderBy(this.repo.metadata, ob);
107
+ let itemIndex = -1;
108
+ let currentPage = undefined;
109
+ let itStrategy;
110
+ let j = 0;
111
+ itStrategy = async () => {
112
+ if (this.options.progress) {
113
+ this.options.progress.progress(j++ / (await this.count()));
114
+ }
115
+ if (currentPage === undefined || itemIndex == currentPage.items.length) {
116
+ if (currentPage && !currentPage.hasNextPage)
117
+ return { value: undefined, done: true };
118
+ let prev = currentPage;
119
+ if (currentPage)
120
+ currentPage = await currentPage.nextPage();
121
+ else
122
+ currentPage = await this.paginator();
123
+ itemIndex = 0;
124
+ if (currentPage.items.length == 0) {
125
+ return { value: undefined, done: true };
126
+ }
127
+ else {
128
+ if (prev?.items.length ?? 0 > 0) {
129
+ if (this.repo.getEntityRef(prev.items[0]).getId() ==
130
+ this.repo.getEntityRef(currentPage.items[0]).getId())
131
+ throw new Error('pagination failure, returned same first row');
132
+ }
133
+ }
134
+ }
135
+ if (itemIndex < currentPage.items.length)
136
+ return { value: currentPage.items[itemIndex++], done: false };
137
+ return { done: true, value: undefined };
138
+ };
139
+ return {
140
+ next: async () => {
141
+ let r = itStrategy();
142
+ return r;
143
+ },
144
+ };
145
+ }
146
+ }
@@ -1,6 +1,6 @@
1
1
  import { LookupColumn, makeTitle } from '../column.js';
2
2
  import { CompoundIdField } from '../CompoundIdField.js';
3
- import { Remult, isBackend, queryConfig } from '../context.js';
3
+ import { Remult, isBackend } from '../context.js';
4
4
  import { Filter } from '../filter/filter-interfaces.js';
5
5
  import { Sort } from '../sort.js';
6
6
  import { GroupByForApiKey, } from './remult3.js';
@@ -18,6 +18,7 @@ import { remultStatic } from '../remult-static.js';
18
18
  import { Validators } from '../validators.js';
19
19
  import { addValidator } from './addValidator.js';
20
20
  import { isOfType } from '../isOfType.js';
21
+ import { QueryResultImpl } from './QueryResultImpl.js';
21
22
  //import { remult } from "../remult-proxy";
22
23
  let classValidatorValidate = undefined;
23
24
  // import ("class-validator".toString())
@@ -132,6 +133,23 @@ export class RepositoryImplementation {
132
133
  return (await this.groupBy(options))[0];
133
134
  }
134
135
  async groupBy(options) {
136
+ var dpOptions = await this.__buildGroupByOptions(options);
137
+ const result = await this._edp.groupBy(dpOptions);
138
+ //@ts-ignore
139
+ if (!options?.[GroupByForApiKey] && options.group) {
140
+ const loaderOptions = {
141
+ include: {},
142
+ };
143
+ for (const key of options.group) {
144
+ loaderOptions.include[key] = true;
145
+ }
146
+ const loader = new RelationLoader();
147
+ await this._populateRelationsForFields(dpOptions.group, loaderOptions, result, loader);
148
+ await loader.resolveAll();
149
+ }
150
+ return result;
151
+ }
152
+ async __buildGroupByOptions(options) {
135
153
  let findOptions = await this._buildEntityDataProviderFindOptions({
136
154
  ...options,
137
155
  });
@@ -185,20 +203,7 @@ export class RepositoryImplementation {
185
203
  }
186
204
  }
187
205
  }
188
- const result = await this._edp.groupBy(dpOptions);
189
- //@ts-ignore
190
- if (!options?.[GroupByForApiKey] && options.group) {
191
- const loaderOptions = {
192
- include: {},
193
- };
194
- for (const key of options.group) {
195
- loaderOptions.include[key] = true;
196
- }
197
- const loader = new RelationLoader();
198
- await this._populateRelationsForFields(dpOptions.group, loaderOptions, result, loader);
199
- await loader.resolveAll();
200
- }
201
- return result;
206
+ return dpOptions;
202
207
  }
203
208
  _idCache = new Map();
204
209
  _getCachedById(id, doNotLoadIfNotFound) {
@@ -352,7 +357,7 @@ export class RepositoryImplementation {
352
357
  }
353
358
  else {
354
359
  let updated = 0;
355
- for await (const item of this.query({ where })) {
360
+ for await (const item of this.query({ where, aggregate: undefined })) {
356
361
  assign(item, set);
357
362
  await getEntityRef(item).save();
358
363
  updated++;
@@ -465,7 +470,7 @@ export class RepositoryImplementation {
465
470
  },
466
471
  };
467
472
  }
468
- async _rawFind(options, skipOrderByAndLimit = false, loader) {
473
+ async _rawFind(options, skipOrderByAndLimit = false, loader, actualFind) {
469
474
  if (!options)
470
475
  options = {};
471
476
  if (this._defaultFindOptions) {
@@ -477,13 +482,13 @@ export class RepositoryImplementation {
477
482
  delete opt.limit;
478
483
  }
479
484
  Remult.onFind(this._info, options);
480
- const rawRows = await this._edp.find(opt);
485
+ const rawRows = await actualFind(opt);
481
486
  let result = await this._loadManyToOneForManyRows(rawRows, options, loader);
482
487
  return result;
483
488
  }
484
489
  async find(options, skipOrderByAndLimit = false) {
485
490
  const loader = new RelationLoader();
486
- const result = await this._rawFind(options, skipOrderByAndLimit, loader);
491
+ const result = await this._rawFind(options, skipOrderByAndLimit, loader, (x) => this._edp.find(x));
487
492
  await loader.resolveAll();
488
493
  return result;
489
494
  }
@@ -578,7 +583,7 @@ export class RepositoryImplementation {
578
583
  loader
579
584
  .load({
580
585
  entityType,
581
- find: (options) => toRepo._rawFind(options, false, loader),
586
+ find: (options) => toRepo._rawFind(options, false, loader, (o) => toRepo._edp.find(o)),
582
587
  metadata: toRepo.metadata,
583
588
  }, findOptions)
584
589
  .then((result) => {
@@ -729,7 +734,7 @@ export class RepositoryImplementation {
729
734
  }
730
735
  else {
731
736
  let deleted = 0;
732
- for await (const item of this.query({ where })) {
737
+ for await (const item of this.query({ where, aggregate: undefined })) {
733
738
  await getEntityRef(item).delete();
734
739
  deleted++;
735
740
  }
@@ -2380,116 +2385,6 @@ export class ControllerBase {
2380
2385
  return getControllerRef(this, this.remult);
2381
2386
  }
2382
2387
  }
2383
- class QueryResultImpl {
2384
- options;
2385
- repo;
2386
- constructor(options, repo) {
2387
- this.options = options;
2388
- this.repo = repo;
2389
- if (!this.options)
2390
- this.options = {};
2391
- if (!this.options.pageSize) {
2392
- this.options.pageSize = queryConfig.defaultPageSize;
2393
- }
2394
- }
2395
- _count = undefined;
2396
- async getPage(page) {
2397
- if ((page ?? 0) < 1)
2398
- page = 1;
2399
- return this.repo.find({
2400
- where: this.options.where,
2401
- orderBy: this.options.orderBy,
2402
- limit: this.options.pageSize,
2403
- page: page,
2404
- load: this.options.load,
2405
- include: this.options.include,
2406
- });
2407
- }
2408
- async count() {
2409
- if (this._count === undefined)
2410
- this._count = await this.repo.count(this.options.where);
2411
- return this._count;
2412
- }
2413
- async forEach(what) {
2414
- let i = 0;
2415
- for await (const x of this) {
2416
- await what(x);
2417
- i++;
2418
- }
2419
- return i;
2420
- }
2421
- async paginator(pNextPageFilter) {
2422
- this.options.orderBy = Sort.createUniqueEntityOrderBy(this.repo.metadata, this.options.orderBy);
2423
- let items = await this.repo.find({
2424
- where: {
2425
- $and: [this.options.where, pNextPageFilter],
2426
- },
2427
- orderBy: this.options.orderBy,
2428
- limit: this.options.pageSize,
2429
- load: this.options.load,
2430
- include: this.options.include,
2431
- });
2432
- let nextPage = () => {
2433
- throw new Error('no more pages');
2434
- };
2435
- let hasNextPage = items.length == this.options.pageSize;
2436
- if (hasNextPage) {
2437
- let nextPageFilter = await this.repo._createAfterFilter(this.options.orderBy, items[items.length - 1]);
2438
- nextPage = () => this.paginator(nextPageFilter);
2439
- }
2440
- return {
2441
- count: () => this.count(),
2442
- hasNextPage,
2443
- items,
2444
- nextPage,
2445
- };
2446
- }
2447
- [Symbol.asyncIterator]() {
2448
- if (!this.options.where) {
2449
- this.options.where = {};
2450
- }
2451
- let ob = this.options.orderBy;
2452
- this.options.orderBy = Sort.createUniqueEntityOrderBy(this.repo.metadata, ob);
2453
- let itemIndex = -1;
2454
- let currentPage = undefined;
2455
- let itStrategy;
2456
- let j = 0;
2457
- itStrategy = async () => {
2458
- if (this.options.progress) {
2459
- this.options.progress.progress(j++ / (await this.count()));
2460
- }
2461
- if (currentPage === undefined || itemIndex == currentPage.items.length) {
2462
- if (currentPage && !currentPage.hasNextPage)
2463
- return { value: undefined, done: true };
2464
- let prev = currentPage;
2465
- if (currentPage)
2466
- currentPage = await currentPage.nextPage();
2467
- else
2468
- currentPage = await this.paginator();
2469
- itemIndex = 0;
2470
- if (currentPage.items.length == 0) {
2471
- return { value: undefined, done: true };
2472
- }
2473
- else {
2474
- if (prev?.items.length ?? 0 > 0) {
2475
- if (this.repo.getEntityRef(prev.items[0]).getId() ==
2476
- this.repo.getEntityRef(currentPage.items[0]).getId())
2477
- throw new Error('pagination failure, returned same first row');
2478
- }
2479
- }
2480
- }
2481
- if (itemIndex < currentPage.items.length)
2482
- return { value: currentPage.items[itemIndex++], done: false };
2483
- return { done: true, value: undefined };
2484
- };
2485
- return {
2486
- next: async () => {
2487
- let r = itStrategy();
2488
- return r;
2489
- },
2490
- };
2491
- }
2492
- }
2493
2388
  class cacheEntityInfo {
2494
2389
  value = {};
2495
2390
  promise;