@travetto/model-mongo 7.0.0-rc.1 → 7.0.0-rc.2

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/README.md CHANGED
@@ -37,8 +37,8 @@ export class Init {
37
37
  @InjectableFactory({
38
38
  primary: true
39
39
  })
40
- static getModelSource(conf: MongoModelConfig) {
41
- return new MongoModelService(conf);
40
+ static getModelSource(config: MongoModelConfig) {
41
+ return new MongoModelService(config);
42
42
  }
43
43
  }
44
44
  ```
@@ -107,11 +107,11 @@ export class MongoModelConfig {
107
107
  * Load all the ssl certs as needed
108
108
  */
109
109
  async postConstruct(): Promise<void> {
110
- const resolve = (file: string): Promise<string> => RuntimeResources.resolve(file).then(v => v, () => file);
110
+ const resolve = (file: string): Promise<string> => RuntimeResources.resolve(file).catch(() => file);
111
111
 
112
112
  if (this.connectionString) {
113
113
  const details = new URL(this.connectionString);
114
- this.hosts ??= details.hostname.split(',').filter(x => !!x);
114
+ this.hosts ??= details.hostname.split(',').filter(host => !!host);
115
115
  this.srvRecord ??= details.protocol === 'mongodb+srv:';
116
116
  this.namespace ??= details.pathname.replace('/', '');
117
117
  Object.assign(this.options, Object.fromEntries(details.searchParams.entries()));
@@ -131,24 +131,24 @@ export class MongoModelConfig {
131
131
  this.hosts = ['localhost'];
132
132
  }
133
133
 
134
- const opts = this.options;
135
- if (opts.ssl) {
136
- if (opts.cert) {
137
- opts.cert = await Promise.all([opts.cert].flat(2).map(f => Buffer.isBuffer(f) ? f : resolve(f)));
134
+ const options = this.options;
135
+ if (options.ssl) {
136
+ if (options.cert) {
137
+ options.cert = await Promise.all([options.cert].flat(2).map(data => Buffer.isBuffer(data) ? data : resolve(data)));
138
138
  }
139
- if (opts.tlsCertificateKeyFile) {
140
- opts.tlsCertificateKeyFile = await resolve(opts.tlsCertificateKeyFile);
139
+ if (options.tlsCertificateKeyFile) {
140
+ options.tlsCertificateKeyFile = await resolve(options.tlsCertificateKeyFile);
141
141
  }
142
- if (opts.tlsCAFile) {
143
- opts.tlsCAFile = await resolve(opts.tlsCAFile);
142
+ if (options.tlsCAFile) {
143
+ options.tlsCAFile = await resolve(options.tlsCAFile);
144
144
  }
145
- if (opts.tlsCRLFile) {
146
- opts.tlsCRLFile = await resolve(opts.tlsCRLFile);
145
+ if (options.tlsCRLFile) {
146
+ options.tlsCRLFile = await resolve(options.tlsCRLFile);
147
147
  }
148
148
  }
149
149
 
150
150
  if (!Runtime.production) {
151
- opts.waitQueueTimeoutMS ??= TimeUtil.asMillis(1, 'd'); // Wait a day in dev mode
151
+ options.waitQueueTimeoutMS ??= TimeUtil.asMillis(1, 'd'); // Wait a day in dev mode
152
152
  }
153
153
  }
154
154
 
@@ -157,14 +157,14 @@ export class MongoModelConfig {
157
157
  */
158
158
  get url(): string {
159
159
  const hosts = this.hosts!
160
- .map(h => (this.srvRecord || h.includes(':')) ? h : `${h}:${this.port ?? 27017}`)
160
+ .map(host => (this.srvRecord || host.includes(':')) ? host : `${host}:${this.port ?? 27017}`)
161
161
  .join(',');
162
- const opts = Object.entries(this.options).map(([k, v]) => `${k}=${v}`).join('&');
162
+ const optionString = Object.entries(this.options).map(([key, value]) => `${key}=${value}`).join('&');
163
163
  let creds = '';
164
164
  if (this.username) {
165
- creds = `${[this.username, this.password].filter(x => !!x).join(':')}@`;
165
+ creds = `${[this.username, this.password].filter(part => !!part).join(':')}@`;
166
166
  }
167
- const url = `mongodb${this.srvRecord ? '+srv' : ''}://${creds}${hosts}/${this.namespace}?${opts}`;
167
+ const url = `mongodb${this.srvRecord ? '+srv' : ''}://${creds}${hosts}/${this.namespace}?${optionString}`;
168
168
  return url;
169
169
  }
170
170
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mongo",
3
- "version": "7.0.0-rc.1",
3
+ "version": "7.0.0-rc.2",
4
4
  "description": "Mongo backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "mongo",
@@ -25,10 +25,10 @@
25
25
  "directory": "module/model-mongo"
26
26
  },
27
27
  "dependencies": {
28
- "@travetto/cli": "^7.0.0-rc.1",
29
- "@travetto/config": "^7.0.0-rc.1",
30
- "@travetto/model": "^7.0.0-rc.1",
31
- "@travetto/model-query": "^7.0.0-rc.1",
28
+ "@travetto/cli": "^7.0.0-rc.2",
29
+ "@travetto/config": "^7.0.0-rc.2",
30
+ "@travetto/model": "^7.0.0-rc.2",
31
+ "@travetto/model-query": "^7.0.0-rc.2",
32
32
  "mongodb": "^7.0.0"
33
33
  },
34
34
  "travetto": {
package/src/config.ts CHANGED
@@ -66,11 +66,11 @@ export class MongoModelConfig {
66
66
  * Load all the ssl certs as needed
67
67
  */
68
68
  async postConstruct(): Promise<void> {
69
- const resolve = (file: string): Promise<string> => RuntimeResources.resolve(file).then(v => v, () => file);
69
+ const resolve = (file: string): Promise<string> => RuntimeResources.resolve(file).catch(() => file);
70
70
 
71
71
  if (this.connectionString) {
72
72
  const details = new URL(this.connectionString);
73
- this.hosts ??= details.hostname.split(',').filter(x => !!x);
73
+ this.hosts ??= details.hostname.split(',').filter(host => !!host);
74
74
  this.srvRecord ??= details.protocol === 'mongodb+srv:';
75
75
  this.namespace ??= details.pathname.replace('/', '');
76
76
  Object.assign(this.options, Object.fromEntries(details.searchParams.entries()));
@@ -90,24 +90,24 @@ export class MongoModelConfig {
90
90
  this.hosts = ['localhost'];
91
91
  }
92
92
 
93
- const opts = this.options;
94
- if (opts.ssl) {
95
- if (opts.cert) {
96
- opts.cert = await Promise.all([opts.cert].flat(2).map(f => Buffer.isBuffer(f) ? f : resolve(f)));
93
+ const options = this.options;
94
+ if (options.ssl) {
95
+ if (options.cert) {
96
+ options.cert = await Promise.all([options.cert].flat(2).map(data => Buffer.isBuffer(data) ? data : resolve(data)));
97
97
  }
98
- if (opts.tlsCertificateKeyFile) {
99
- opts.tlsCertificateKeyFile = await resolve(opts.tlsCertificateKeyFile);
98
+ if (options.tlsCertificateKeyFile) {
99
+ options.tlsCertificateKeyFile = await resolve(options.tlsCertificateKeyFile);
100
100
  }
101
- if (opts.tlsCAFile) {
102
- opts.tlsCAFile = await resolve(opts.tlsCAFile);
101
+ if (options.tlsCAFile) {
102
+ options.tlsCAFile = await resolve(options.tlsCAFile);
103
103
  }
104
- if (opts.tlsCRLFile) {
105
- opts.tlsCRLFile = await resolve(opts.tlsCRLFile);
104
+ if (options.tlsCRLFile) {
105
+ options.tlsCRLFile = await resolve(options.tlsCRLFile);
106
106
  }
107
107
  }
108
108
 
109
109
  if (!Runtime.production) {
110
- opts.waitQueueTimeoutMS ??= TimeUtil.asMillis(1, 'd'); // Wait a day in dev mode
110
+ options.waitQueueTimeoutMS ??= TimeUtil.asMillis(1, 'd'); // Wait a day in dev mode
111
111
  }
112
112
  }
113
113
 
@@ -116,14 +116,14 @@ export class MongoModelConfig {
116
116
  */
117
117
  get url(): string {
118
118
  const hosts = this.hosts!
119
- .map(h => (this.srvRecord || h.includes(':')) ? h : `${h}:${this.port ?? 27017}`)
119
+ .map(host => (this.srvRecord || host.includes(':')) ? host : `${host}:${this.port ?? 27017}`)
120
120
  .join(',');
121
- const opts = Object.entries(this.options).map(([k, v]) => `${k}=${v}`).join('&');
121
+ const optionString = Object.entries(this.options).map(([key, value]) => `${key}=${value}`).join('&');
122
122
  let creds = '';
123
123
  if (this.username) {
124
- creds = `${[this.username, this.password].filter(x => !!x).join(':')}@`;
124
+ creds = `${[this.username, this.password].filter(part => !!part).join(':')}@`;
125
125
  }
126
- const url = `mongodb${this.srvRecord ? '+srv' : ''}://${creds}${hosts}/${this.namespace}?${opts}`;
126
+ const url = `mongodb${this.srvRecord ? '+srv' : ''}://${creds}${hosts}/${this.namespace}?${optionString}`;
127
127
  return url;
128
128
  }
129
129
  }
@@ -7,9 +7,9 @@ import { type DistanceUnit, type PageableModelQuery, type WhereClause, ModelQuer
7
7
  import type { ModelType, IndexField, IndexConfig } from '@travetto/model';
8
8
  import { DataUtil, SchemaRegistryIndex, type Point } from '@travetto/schema';
9
9
 
10
- const PointImpl = toConcrete<Point>();
10
+ const PointConcrete = toConcrete<Point>();
11
11
 
12
- type IdxCfg = CreateIndexesOptions;
12
+ type IdxConfig = CreateIndexesOptions;
13
13
 
14
14
  /**
15
15
  * Converting units to various radians
@@ -31,21 +31,21 @@ export type PlainIdx = Record<string, -1 | 0 | 1>;
31
31
  */
32
32
  export class MongoUtil {
33
33
 
34
- static toIndex<T extends ModelType>(f: IndexField<T>): PlainIdx {
34
+ static toIndex<T extends ModelType>(field: IndexField<T>): PlainIdx {
35
35
  const keys = [];
36
- while (typeof f !== 'number' && typeof f !== 'boolean' && Object.keys(f)) {
37
- const key = TypedObject.keys(f)[0];
38
- f = castTo(f[key]);
36
+ while (typeof field !== 'number' && typeof field !== 'boolean' && Object.keys(field)) {
37
+ const key = TypedObject.keys(field)[0];
38
+ field = castTo(field[key]);
39
39
  keys.push(key);
40
40
  }
41
- const rf: number | boolean = castTo(f);
41
+ const rf: number | boolean = castTo(field);
42
42
  return {
43
43
  [keys.join('.')]: typeof rf === 'boolean' ? (rf ? 1 : 0) : castTo<-1 | 1 | 0>(rf)
44
44
  };
45
45
  }
46
46
 
47
- static uuid(val: string): Binary {
48
- return new Binary(Buffer.from(val.replaceAll('-', ''), 'hex'), Binary.SUBTYPE_UUID);
47
+ static uuid(value: string): Binary {
48
+ return new Binary(Buffer.from(value.replaceAll('-', ''), 'hex'), Binary.SUBTYPE_UUID);
49
49
  }
50
50
 
51
51
  static idToString(id: string | ObjectId | Binary): string {
@@ -66,84 +66,84 @@ export class MongoUtil {
66
66
  /**
67
67
  * Build mongo where clause
68
68
  */
69
- static extractWhereClause<T>(cls: Class<T>, o: WhereClause<T>): Record<string, unknown> {
70
- if (ModelQueryUtil.has$And(o)) {
71
- return { $and: o.$and.map(x => this.extractWhereClause<T>(cls, x)) };
72
- } else if (ModelQueryUtil.has$Or(o)) {
73
- return { $or: o.$or.map(x => this.extractWhereClause<T>(cls, x)) };
74
- } else if (ModelQueryUtil.has$Not(o)) {
75
- return { $nor: [this.extractWhereClause<T>(cls, o.$not)] };
69
+ static extractWhereClause<T>(cls: Class<T>, clause: WhereClause<T>): Record<string, unknown> {
70
+ if (ModelQueryUtil.has$And(clause)) {
71
+ return { $and: clause.$and.map(item => this.extractWhereClause<T>(cls, item)) };
72
+ } else if (ModelQueryUtil.has$Or(clause)) {
73
+ return { $or: clause.$or.map(item => this.extractWhereClause<T>(cls, item)) };
74
+ } else if (ModelQueryUtil.has$Not(clause)) {
75
+ return { $nor: [this.extractWhereClause<T>(cls, clause.$not)] };
76
76
  } else {
77
- return this.extractSimple(cls, o);
77
+ return this.extractSimple(cls, clause);
78
78
  }
79
79
  }
80
80
 
81
81
  /**/
82
- static extractSimple<T>(base: Class<T> | undefined, o: Record<string, unknown>, path: string = '', recursive: boolean = true): Record<string, unknown> {
82
+ static extractSimple<T>(base: Class<T> | undefined, item: Record<string, unknown>, path: string = '', recursive: boolean = true): Record<string, unknown> {
83
83
  const fields = base ? SchemaRegistryIndex.getOptional(base)?.getFields() : undefined;
84
84
  const out: Record<string, unknown> = {};
85
- const sub = o;
85
+ const sub = item;
86
86
  const keys = Object.keys(sub);
87
87
  for (const key of keys) {
88
88
  const subpath = `${path}${key}`;
89
- const v: Record<string, unknown> = castTo(sub[key]);
89
+ const value: Record<string, unknown> = castTo(sub[key]);
90
90
  const subField = fields?.[key];
91
91
 
92
- const isPlain = v && DataUtil.isPlainObject(v);
93
- const firstKey = isPlain ? Object.keys(v)[0] : '';
92
+ const isPlain = value && DataUtil.isPlainObject(value);
93
+ const firstKey = isPlain ? Object.keys(value)[0] : '';
94
94
 
95
95
  if (subpath === 'id') {
96
96
  if (!firstKey) {
97
- out._id = Array.isArray(v) ? v.map(x => this.uuid(x)) : this.uuid(`${v}`);
97
+ out._id = Array.isArray(value) ? value.map(subValue => this.uuid(subValue)) : this.uuid(`${value}`);
98
98
  } else if (firstKey === '$in' || firstKey === '$nin' || firstKey === '$eq' || firstKey === '$ne') {
99
- const temp = v[firstKey];
100
- out._id = { [firstKey]: Array.isArray(temp) ? temp.map(x => this.uuid(x)) : this.uuid(`${temp}`) };
99
+ const temp = value[firstKey];
100
+ out._id = { [firstKey]: Array.isArray(temp) ? temp.map(subValue => this.uuid(subValue)) : this.uuid(`${temp}`) };
101
101
  } else {
102
102
  throw new AppError('Invalid id query');
103
103
  }
104
- } else if ((isPlain && !firstKey.startsWith('$')) || v?.constructor?.Ⲑid) {
104
+ } else if ((isPlain && !firstKey.startsWith('$')) || value?.constructor?.Ⲑid) {
105
105
  if (recursive) {
106
- Object.assign(out, this.extractSimple(subField?.type, v, `${subpath}.`, recursive));
106
+ Object.assign(out, this.extractSimple(subField?.type, value, `${subpath}.`, recursive));
107
107
  } else {
108
- out[subpath] = v;
108
+ out[subpath] = value;
109
109
  }
110
110
  } else {
111
111
  if (firstKey === '$gt' || firstKey === '$lt' || firstKey === '$gte' || firstKey === '$lte') {
112
- for (const [sk, sv] of Object.entries(v)) {
113
- v[sk] = ModelQueryUtil.resolveComparator(sv);
112
+ for (const [sk, sv] of Object.entries(value)) {
113
+ value[sk] = ModelQueryUtil.resolveComparator(sv);
114
114
  }
115
115
  } else if (firstKey === '$exists' && subField?.array) {
116
- const exists = v.$exists;
116
+ const exists = value.$exists;
117
117
  if (!exists) {
118
- delete v.$exists;
119
- v.$in = [null, []];
118
+ delete value.$exists;
119
+ value.$in = [null, []];
120
120
  } else {
121
- v.$exists = true;
122
- v.$nin = [null, []];
121
+ value.$exists = true;
122
+ value.$nin = [null, []];
123
123
  }
124
124
  } else if (firstKey === '$regex') {
125
- v.$regex = DataUtil.toRegex(castTo(v.$regex));
126
- } else if (firstKey && '$near' in v) {
127
- const dist: number = castTo(v.$maxDistance);
128
- const distance = dist / RADIANS_TO[(castTo<DistanceUnit>(v.$unit) ?? 'km')];
129
- v.$maxDistance = distance;
130
- delete v.$unit;
131
- } else if (firstKey && '$geoWithin' in v) {
132
- const coords: [number, number][] = castTo(v.$geoWithin);
125
+ value.$regex = DataUtil.toRegex(castTo(value.$regex));
126
+ } else if (firstKey && '$near' in value) {
127
+ const dist: number = castTo(value.$maxDistance);
128
+ const distance = dist / RADIANS_TO[(castTo<DistanceUnit>(value.$unit) ?? 'km')];
129
+ value.$maxDistance = distance;
130
+ delete value.$unit;
131
+ } else if (firstKey && '$geoWithin' in value) {
132
+ const coords: [number, number][] = castTo(value.$geoWithin);
133
133
  const first = coords[0];
134
134
  const last = coords.at(-1)!;
135
135
  // Connect if not
136
136
  if (first[0] !== last[0] || first[1] !== last[1]) {
137
137
  coords.push(first);
138
138
  }
139
- v.$geoWithin = {
139
+ value.$geoWithin = {
140
140
  $geometry: {
141
141
  type: 'Polygon',
142
142
  coordinates: [coords]
143
143
  }
144
144
  };
145
145
  }
146
- out[subpath === 'id' ? '_id' : subpath] = v;
146
+ out[subpath === 'id' ? '_id' : subpath] = value;
147
147
  }
148
148
  }
149
149
  return out;
@@ -153,11 +153,11 @@ export class MongoUtil {
153
153
  const out: BasicIdx[] = [];
154
154
  const textFields: string[] = [];
155
155
  SchemaRegistryIndex.visitFields(cls, (field, path) => {
156
- if (field.type === PointImpl) {
157
- const name = [...path, field].map(x => x.name).join('.');
156
+ if (field.type === PointConcrete) {
157
+ const name = [...path, field].map(schema => schema.name).join('.');
158
158
  out.push({ [name]: '2d' });
159
159
  } else if (field.specifiers?.includes('text') && (field.specifiers?.includes('long') || field.specifiers.includes('search'))) {
160
- const name = [...path, field].map(x => x.name).join('.');
160
+ const name = [...path, field].map(schema => schema.name).join('.');
161
161
  textFields.push(name);
162
162
  }
163
163
  });
@@ -173,17 +173,17 @@ export class MongoUtil {
173
173
 
174
174
  static getPlainIndex(idx: IndexConfig<ModelType>): PlainIdx {
175
175
  let out: PlainIdx = {};
176
- for (const cfg of idx.fields.map(x => this.toIndex(x))) {
177
- out = Object.assign(out, cfg);
176
+ for (const config of idx.fields.map(value => this.toIndex(value))) {
177
+ out = Object.assign(out, config);
178
178
  }
179
179
  return out;
180
180
  }
181
181
 
182
- static getIndices<T extends ModelType>(cls: Class<T>, indices: IndexConfig<ModelType>[] = []): [BasicIdx, IdxCfg][] {
182
+ static getIndices<T extends ModelType>(cls: Class<T>, indices: IndexConfig<ModelType>[] = []): [BasicIdx, IdxConfig][] {
183
183
  return [
184
184
  ...indices.map(idx => [this.getPlainIndex(idx), (idx.type === 'unique' ? { unique: true } : {})] as const),
185
- ...this.getExtraIndices(cls).map((x) => [x, {}] as const)
186
- ].map(x => [...x]);
185
+ ...this.getExtraIndices(cls).map((idx) => [idx, {}] as const)
186
+ ].map(idx => [...idx]);
187
187
  }
188
188
 
189
189
  static prepareCursor<T extends ModelType>(cls: Class<T>, cursor: FindCursor<T | MongoWithId<T>>, query: PageableModelQuery<T>): FindCursor<T> {
@@ -201,7 +201,7 @@ export class MongoUtil {
201
201
  }
202
202
 
203
203
  if (query.sort) {
204
- cursor = cursor.sort(Object.assign({}, ...query.sort.map(x => this.extractSimple(cls, x))));
204
+ cursor = cursor.sort(Object.assign({}, ...query.sort.map(item => this.extractSimple(cls, item))));
205
205
  }
206
206
 
207
207
  cursor = cursor.limit(Math.trunc(query.limit ?? 200));
package/src/service.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
 
9
9
  import {
10
10
  ModelRegistryIndex, ModelType, OptionalId, ModelCrudSupport, ModelStorageSupport,
11
- ModelExpirySupport, ModelBulkSupport, ModelIndexedSupport, BulkOp, BulkResponse,
11
+ ModelExpirySupport, ModelBulkSupport, ModelIndexedSupport, BulkOperation, BulkResponse,
12
12
  NotFoundError, ExistsError, ModelBlobSupport,
13
13
  ModelCrudUtil, ModelIndexedUtil, ModelStorageUtil, ModelExpiryUtil, ModelBulkUtil, ModelBlobUtil,
14
14
  } from '@travetto/model';
@@ -131,8 +131,8 @@ export class MongoModelService implements
131
131
  const creating = MongoUtil.getIndices(cls, ModelRegistryIndex.getConfig(cls).indices);
132
132
  if (creating.length) {
133
133
  console.debug('Creating indexes', { indices: creating });
134
- for (const el of creating) {
135
- await col.createIndex(...el);
134
+ for (const toCreate of creating) {
135
+ await col.createIndex(...toCreate);
136
136
  }
137
137
  }
138
138
  }
@@ -208,11 +208,11 @@ export class MongoModelService implements
208
208
  { $set: cleaned },
209
209
  { upsert: true }
210
210
  );
211
- } catch (err) {
212
- if (err instanceof Error && err.message.includes('duplicate key error')) {
211
+ } catch (error) {
212
+ if (error instanceof Error && error.message.includes('duplicate key error')) {
213
213
  throw new ExistsError(cls, id);
214
214
  } else {
215
- throw err;
215
+ throw error;
216
216
  }
217
217
  }
218
218
  return this.postUpdate(cleaned, id);
@@ -226,13 +226,13 @@ export class MongoModelService implements
226
226
 
227
227
  const operation: Partial<T> = castTo(Object
228
228
  .entries(simple)
229
- .reduce<Partial<Record<'$unset' | '$set', Record<string, unknown>>>>((acc, [k, v]) => {
230
- if (v === null || v === undefined) {
231
- (acc.$unset ??= {})[k] = v;
229
+ .reduce<Partial<Record<'$unset' | '$set', Record<string, unknown>>>>((document, [key, value]) => {
230
+ if (value === null || value === undefined) {
231
+ (document.$unset ??= {})[key] = value;
232
232
  } else {
233
- (acc.$set ??= {})[k] = v;
233
+ (document.$set ??= {})[key] = value;
234
234
  }
235
- return acc;
235
+ return document;
236
236
  }, {}));
237
237
 
238
238
  const id = item.id;
@@ -261,12 +261,12 @@ export class MongoModelService implements
261
261
  async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
262
262
  const store = await this.getStore(cls);
263
263
  const cursor = store.find(this.getWhereFilter(cls, {}), { timeout: true }).batchSize(100);
264
- for await (const el of cursor) {
264
+ for await (const item of cursor) {
265
265
  try {
266
- yield await this.postLoad(cls, el);
267
- } catch (err) {
268
- if (!(err instanceof NotFoundError)) {
269
- throw err;
266
+ yield await this.postLoad(cls, item);
267
+ } catch (error) {
268
+ if (!(error instanceof NotFoundError)) {
269
+ throw error;
270
270
  }
271
271
  }
272
272
  }
@@ -313,7 +313,7 @@ export class MongoModelService implements
313
313
  }
314
314
 
315
315
  // Bulk
316
- async processBulk<T extends ModelType>(cls: Class<T>, operations: BulkOp<T>[]): Promise<BulkResponse<{ index: number }>> {
316
+ async processBulk<T extends ModelType>(cls: Class<T>, operations: BulkOperation<T>[]): Promise<BulkResponse<{ index: number }>> {
317
317
  const out: BulkResponse<{ index: number }> = {
318
318
  errors: [],
319
319
  counts: {
@@ -336,26 +336,26 @@ export class MongoModelService implements
336
336
 
337
337
  out.insertedIds = new Map([...upsertedIds.entries(), ...insertedIds.entries()]);
338
338
 
339
- for (const op of operations) {
340
- if (op.insert) {
341
- this.preUpdate(op.insert);
342
- bulk.insert(op.insert);
343
- } else if (op.upsert) {
344
- const id = this.preUpdate(op.upsert);
345
- bulk.find({ _id: MongoUtil.uuid(id!) }).upsert().updateOne({ $set: op.upsert });
346
- } else if (op.update) {
347
- const id = this.preUpdate(op.update);
348
- bulk.find({ _id: MongoUtil.uuid(id) }).update({ $set: op.update });
349
- } else if (op.delete) {
350
- bulk.find({ _id: MongoUtil.uuid(op.delete.id) }).deleteOne();
339
+ for (const operation of operations) {
340
+ if (operation.insert) {
341
+ this.preUpdate(operation.insert);
342
+ bulk.insert(operation.insert);
343
+ } else if (operation.upsert) {
344
+ const id = this.preUpdate(operation.upsert);
345
+ bulk.find({ _id: MongoUtil.uuid(id!) }).upsert().updateOne({ $set: operation.upsert });
346
+ } else if (operation.update) {
347
+ const id = this.preUpdate(operation.update);
348
+ bulk.find({ _id: MongoUtil.uuid(id) }).update({ $set: operation.update });
349
+ } else if (operation.delete) {
350
+ bulk.find({ _id: MongoUtil.uuid(operation.delete.id) }).deleteOne();
351
351
  }
352
352
  }
353
353
 
354
354
  const result = await bulk.execute({});
355
355
 
356
356
  // Restore all ids
357
- for (const op of operations) {
358
- const core = op.insert ?? op.upsert ?? op.update;
357
+ for (const operation of operations) {
358
+ const core = operation.insert ?? operation.upsert ?? operation.update;
359
359
  if (core) {
360
360
  this.postUpdate(asFull(core));
361
361
  }
@@ -367,17 +367,17 @@ export class MongoModelService implements
367
367
 
368
368
  if (out.counts) {
369
369
  out.counts.delete = result.deletedCount;
370
- out.counts.update = operations.filter(x => x.update).length;
370
+ out.counts.update = operations.filter(item => item.update).length;
371
371
  out.counts.insert = result.insertedCount;
372
- out.counts.upsert = operations.filter(x => x.upsert).length;
372
+ out.counts.upsert = operations.filter(item => item.upsert).length;
373
373
  }
374
374
 
375
375
  if (result.hasWriteErrors()) {
376
376
  out.errors = result.getWriteErrors();
377
- for (const err of out.errors) {
378
- const op = operations[err.index];
379
- const k = TypedObject.keys(op)[0];
380
- out.counts[k] -= 1;
377
+ for (const error of out.errors) {
378
+ const operation = operations[error.index];
379
+ const key = TypedObject.keys(operation)[0];
380
+ out.counts[key] -= 1;
381
381
  }
382
382
  out.counts.error = out.errors.length;
383
383
  }
@@ -427,18 +427,18 @@ export class MongoModelService implements
427
427
 
428
428
  async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body?: DeepPartial<T>): AsyncIterable<T> {
429
429
  const store = await this.getStore(cls);
430
- const idxCfg = ModelRegistryIndex.getIndex(cls, idx, ['sorted', 'unsorted']);
430
+ const idxConfig = ModelRegistryIndex.getIndex(cls, idx, ['sorted', 'unsorted']);
431
431
 
432
432
  const where = this.getWhereFilter(
433
433
  cls,
434
434
  castTo(ModelIndexedUtil.projectIndex(cls, idx, body, { emptySortValue: { $exists: true } }))
435
435
  );
436
436
 
437
- const sort = castTo<{ [ListIndexSymbol]: PlainIdx }>(idxCfg)[ListIndexSymbol] ??= MongoUtil.getPlainIndex(idxCfg);
437
+ const sort = castTo<{ [ListIndexSymbol]: PlainIdx }>(idxConfig)[ListIndexSymbol] ??= MongoUtil.getPlainIndex(idxConfig);
438
438
  const cursor = store.find(where, { timeout: true }).batchSize(100).sort(castTo(sort));
439
439
 
440
- for await (const el of cursor) {
441
- yield await this.postLoad(cls, el);
440
+ for await (const item of cursor) {
441
+ yield await this.postLoad(cls, item);
442
442
  }
443
443
  }
444
444
 
@@ -450,7 +450,7 @@ export class MongoModelService implements
450
450
  const filter = MongoUtil.extractWhereFilter(cls, query.where);
451
451
  const cursor = col.find(filter, {});
452
452
  const items = await MongoUtil.prepareCursor(cls, cursor, query).toArray();
453
- return await Promise.all(items.map(r => this.postLoad(cls, r)));
453
+ return await Promise.all(items.map(item => this.postLoad(cls, item)));
454
454
  }
455
455
 
456
456
  async queryCount<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number> {
@@ -500,13 +500,13 @@ export class MongoModelService implements
500
500
  const col = await this.getStore(cls);
501
501
  const items = MongoUtil.extractSimple(cls, item);
502
502
  const final = Object.entries(items).reduce<Partial<Record<'$unset' | '$set', Record<string, unknown>>>>(
503
- (acc, [k, v]) => {
504
- if (v === null || v === undefined) {
505
- (acc.$unset ??= {})[k] = v;
503
+ (document, [key, value]) => {
504
+ if (value === null || value === undefined) {
505
+ (document.$unset ??= {})[key] = value;
506
506
  } else {
507
- (acc.$set ??= {})[k] = v;
507
+ (document.$set ??= {})[key] = value;
508
508
  }
509
- return acc;
509
+ return document;
510
510
  }, {});
511
511
 
512
512
  const filter = MongoUtil.extractWhereFilter(cls, query.where);
@@ -523,14 +523,14 @@ export class MongoModelService implements
523
523
  await QueryVerifier.verify(cls, query);
524
524
  }
525
525
 
526
- let q: Record<string, unknown> = { [field]: { $exists: true } };
526
+ let queryObject: Record<string, unknown> = { [field]: { $exists: true } };
527
527
 
528
528
  if (query?.where) {
529
- q = { $and: [q, MongoUtil.extractWhereFilter(cls, query.where)] };
529
+ queryObject = { $and: [queryObject, MongoUtil.extractWhereFilter(cls, query.where)] };
530
530
  }
531
531
 
532
532
  const aggregations: object[] = [
533
- { $match: q },
533
+ { $match: queryObject },
534
534
  {
535
535
  $group: {
536
536
  _id: `$${field}`,
@@ -544,9 +544,9 @@ export class MongoModelService implements
544
544
  const result = await col.aggregate<{ _id: ObjectId, count: number }>(aggregations).toArray();
545
545
 
546
546
  return result
547
- .map(val => ({
548
- key: MongoUtil.idToString(val._id),
549
- count: val.count
547
+ .map(item => ({
548
+ key: MongoUtil.idToString(item._id),
549
+ count: item.count
550
550
  }))
551
551
  .toSorted((a, b) => b.count - a.count);
552
552
  }
@@ -554,15 +554,15 @@ export class MongoModelService implements
554
554
  // Suggest
555
555
  async suggestValues<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, prefix?: string, query?: PageableModelQuery<T>): Promise<string[]> {
556
556
  await QueryVerifier.verify(cls, query);
557
- const q = ModelQuerySuggestUtil.getSuggestFieldQuery<T>(cls, field, prefix, query);
558
- const results = await this.query<T>(cls, q);
557
+ const resolvedQuery = ModelQuerySuggestUtil.getSuggestFieldQuery<T>(cls, field, prefix, query);
558
+ const results = await this.query<T>(cls, resolvedQuery);
559
559
  return ModelQuerySuggestUtil.combineSuggestResults<T, string>(cls, field, prefix, results, (a) => a, query && query.limit);
560
560
  }
561
561
 
562
562
  async suggest<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, prefix?: string, query?: PageableModelQuery<T>): Promise<T[]> {
563
563
  await QueryVerifier.verify(cls, query);
564
- const q = ModelQuerySuggestUtil.getSuggestQuery<T>(cls, field, prefix, query);
565
- const results = await this.query<T>(cls, q);
564
+ const resolvedQuery = ModelQuerySuggestUtil.getSuggestQuery<T>(cls, field, prefix, query);
565
+ const results = await this.query<T>(cls, resolvedQuery);
566
566
  return ModelQuerySuggestUtil.combineSuggestResults(cls, field, prefix, results, (_, b) => b, query && query.limit);
567
567
  }
568
568
 
@@ -582,6 +582,6 @@ export class MongoModelService implements
582
582
 
583
583
  const cursor = col.find(castTo({ $and: [{ $text: search }, filter] }), {});
584
584
  const items = await MongoUtil.prepareCursor(cls, cursor, query).toArray();
585
- return await Promise.all(items.map(r => this.postLoad(cls, r)));
585
+ return await Promise.all(items.map(item => this.postLoad(cls, item)));
586
586
  }
587
587
  }