@travetto/model-sql 8.0.0-alpha.23 → 8.0.0-alpha.25

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/src/service.ts CHANGED
@@ -1,31 +1,64 @@
1
+ import type { AsyncContext } from '@travetto/context';
2
+ import { Injectable, PostConstruct } from '@travetto/di';
1
3
  import {
2
- type ModelType,
3
- type BulkOperation, type BulkResponse, type ModelCrudSupport, type ModelStorageSupport, type ModelBulkSupport, NotFoundError,
4
- ModelRegistryIndex, ExistsError, type OptionalId, type ModelIdSource, ModelExpiryUtil, ModelCrudUtil, ModelStorageUtil, ModelBulkUtil,
4
+ type BulkOperation,
5
+ type BulkResponse,
6
+ ExistsError,
7
+ type ModelBulkSupport,
8
+ ModelBulkUtil,
9
+ type ModelCrudSupport,
10
+ ModelCrudUtil,
11
+ ModelExpiryUtil,
12
+ type ModelIdSource,
5
13
  type ModelListOptions,
14
+ ModelRegistryIndex,
15
+ type ModelStorageSupport,
16
+ ModelStorageUtil,
17
+ type ModelType,
18
+ NotFoundError,
19
+ type OptionalId
6
20
  } from '@travetto/model';
7
21
  import {
8
- type ModelIndexedSupport, type KeyedIndexSelection, type KeyedIndexBody, type ModelPageOptions, ModelIndexedUtil,
9
- type SingleItemIndex, type SortedIndexSelection, type ModelPageResult, type SortedIndex, type FullKeyedIndexBody,
10
- type FullKeyedIndexWithPartialBody, ModelIndexedComputedIndex, type ModelIndexedSearchOptions, type SortedIndexSelectionType
22
+ type FullKeyedIndexBody,
23
+ type FullKeyedIndexWithPartialBody,
24
+ type KeyedIndexBody,
25
+ type KeyedIndexSelection,
26
+ ModelIndexedComputedIndex,
27
+ type ModelIndexedSearchOptions,
28
+ type ModelIndexedSupport,
29
+ ModelIndexedUtil,
30
+ type ModelPageOptions,
31
+ type ModelPageResult,
32
+ type SingleItemIndex,
33
+ type SortedIndex,
34
+ type SortedIndexSelection,
35
+ type SortedIndexSelectionType
11
36
  } from '@travetto/model-indexed';
12
- import { castTo, type Class, JSONUtil } from '@travetto/runtime';
13
- import { DataUtil } from '@travetto/schema';
14
- import type { AsyncContext } from '@travetto/context';
15
- import { Injectable, PostConstruct } from '@travetto/di';
16
37
  import {
17
- type ModelQuery, type ModelQueryCrudSupport, type ModelQueryFacetSupport, type ModelQuerySupport,
18
- type PageableModelQuery, type ValidStringFields, type WhereClauseRaw, QueryVerifier, type ModelQuerySuggestSupport,
19
- ModelQueryUtil, ModelQuerySuggestUtil, ModelQueryCrudUtil, type ModelQueryFacet,
38
+ type ModelQuery,
39
+ type ModelQueryCrudSupport,
40
+ ModelQueryCrudUtil,
41
+ type ModelQueryFacet,
42
+ type ModelQueryFacetSupport,
43
+ type ModelQuerySuggestSupport,
44
+ ModelQuerySuggestUtil,
45
+ type ModelQuerySupport,
46
+ ModelQueryUtil,
47
+ type PageableModelQuery,
48
+ QueryVerifier,
49
+ type ValidStringFields,
50
+ type WhereClauseRaw
20
51
  } from '@travetto/model-query';
52
+ import { type Class, castTo, JSONUtil } from '@travetto/runtime';
53
+ import { DataUtil } from '@travetto/schema';
21
54
 
22
55
  import type { SQLModelConfig } from './config.ts';
56
+ import type { Connection } from './connection/base.ts';
23
57
  import { Connected, ConnectedIterator, Transactional } from './connection/decorator.ts';
24
- import { SQLModelUtil } from './util.ts';
25
58
  import type { SQLDialect } from './dialect/base.ts';
26
- import { TableManager } from './table-manager.ts';
27
- import type { Connection } from './connection/base.ts';
28
59
  import type { InsertWrapper } from './internal/types.ts';
60
+ import { TableManager } from './table-manager.ts';
61
+ import { SQLModelUtil } from './util.ts';
29
62
 
30
63
  /**
31
64
  * Core for SQL Model Source. Should not have any direct queries,
@@ -33,13 +66,17 @@ import type { InsertWrapper } from './internal/types.ts';
33
66
  * as needed.
34
67
  */
35
68
  @Injectable()
36
- export class SQLModelService implements
37
- ModelCrudSupport, ModelStorageSupport,
38
- ModelBulkSupport, ModelQuerySupport,
39
- ModelQueryCrudSupport, ModelQueryFacetSupport,
40
- ModelIndexedSupport,
41
- ModelQuerySuggestSupport {
42
-
69
+ export class SQLModelService
70
+ implements
71
+ ModelCrudSupport,
72
+ ModelStorageSupport,
73
+ ModelBulkSupport,
74
+ ModelQuerySupport,
75
+ ModelQueryCrudSupport,
76
+ ModelQueryFacetSupport,
77
+ ModelIndexedSupport,
78
+ ModelQuerySuggestSupport
79
+ {
43
80
  #manager: TableManager;
44
81
  #context: AsyncContext;
45
82
  #dialect: SQLDialect;
@@ -51,11 +88,7 @@ export class SQLModelService implements
51
88
  return this.#dialect;
52
89
  }
53
90
 
54
- constructor(
55
- context: AsyncContext,
56
- config: SQLModelConfig,
57
- dialect: SQLDialect
58
- ) {
91
+ constructor(context: AsyncContext, config: SQLModelConfig, dialect: SQLDialect) {
59
92
  this.#context = context;
60
93
  this.#dialect = dialect;
61
94
  this.config = config;
@@ -70,17 +103,19 @@ export class SQLModelService implements
70
103
  toCheck: Map<string, number>
71
104
  ): Promise<Map<number, string>> {
72
105
  // Get all upsert ids
73
- const all = toCheck.size ?
74
- (await this.#exec<ModelType>(
75
- this.#dialect.getSelectRowsByIdsSQL(
76
- SQLModelUtil.classToStack(cls), [...toCheck.keys()], [this.#dialect.idField]
77
- )
78
- )).records : [];
106
+ const all = toCheck.size
107
+ ? (
108
+ await this.#exec<ModelType>(
109
+ this.#dialect.getSelectRowsByIdsSQL(SQLModelUtil.classToStack(cls), [...toCheck.keys()], [this.#dialect.idField])
110
+ )
111
+ ).records
112
+ : [];
79
113
 
80
114
  const allIds = new Set(all.map(type => type.id));
81
115
 
82
116
  for (const [id, idx] of toCheck.entries()) {
83
- if (!allIds.has(id)) { // If not found
117
+ if (!allIds.has(id)) {
118
+ // If not found
84
119
  addedIds.set(idx, id);
85
120
  }
86
121
  }
@@ -88,12 +123,12 @@ export class SQLModelService implements
88
123
  return addedIds;
89
124
  }
90
125
 
91
- #exec<T = unknown>(sql: string): Promise<{ records: T[], count: number }> {
126
+ #exec<T = unknown>(sql: string): Promise<{ records: T[]; count: number }> {
92
127
  return this.#dialect.executeSQL<T>(sql);
93
128
  }
94
129
 
95
130
  async #deleteRaw<T extends ModelType>(cls: Class<T>, id: string, where?: WhereClauseRaw<T>, checkExpiry = true): Promise<void> {
96
- castTo<WhereClauseRaw<ModelType>>(where ??= {}).id = id;
131
+ castTo<WhereClauseRaw<ModelType>>((where ??= {})).id = id;
97
132
 
98
133
  const count = await this.#dialect.deleteAndGetCount<ModelType>(cls, {
99
134
  where: ModelQueryUtil.getWhereClause(cls, where, checkExpiry)
@@ -103,17 +138,17 @@ export class SQLModelService implements
103
138
  }
104
139
  }
105
140
 
106
- async * #scanTable<T extends ModelType>(
141
+ async *#scanTable<T extends ModelType>(
107
142
  cls: Class<T>,
108
143
  buildQuery: () => PageableModelQuery<T>,
109
144
  options?: ModelListOptions & ModelPageOptions<number>
110
- ): AsyncIterable<{ items: T[], nextOffset?: number }> {
145
+ ): AsyncIterable<{ items: T[]; nextOffset?: number }> {
111
146
  const batchSize = options?.batchSizeHint ?? 100;
112
147
  const maxCount = options?.limit ?? Number.MAX_SAFE_INTEGER;
113
148
  let offset = options?.offset ?? 0;
114
149
  let lastOffset = -1;
115
150
  let produced = 0;
116
- while (offset !== lastOffset && produced < maxCount && !(options?.abort?.aborted)) {
151
+ while (offset !== lastOffset && produced < maxCount && !options?.abort?.aborted) {
117
152
  const limit = Math.min(batchSize, maxCount - produced);
118
153
  lastOffset = offset;
119
154
  const items = await this.query<T>(cls, {
@@ -158,8 +193,8 @@ export class SQLModelService implements
158
193
  await this.#manager.truncateTables(cls);
159
194
  }
160
195
 
161
- async createStorage(): Promise<void> { }
162
- async deleteStorage(): Promise<void> { }
196
+ async createStorage(): Promise<void> {}
197
+ async deleteStorage(): Promise<void> {}
163
198
 
164
199
  @Transactional()
165
200
  async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
@@ -215,7 +250,7 @@ export class SQLModelService implements
215
250
  }
216
251
 
217
252
  @ConnectedIterator()
218
- async * list<T extends ModelType>(cls: Class<T>, options?: ModelListOptions): AsyncIterable<T[]> {
253
+ async *list<T extends ModelType>(cls: Class<T>, options?: ModelListOptions): AsyncIterable<T[]> {
219
254
  for await (const { items } of this.#scanTable(cls, () => ({}), options)) {
220
255
  yield items;
221
256
  }
@@ -228,15 +263,11 @@ export class SQLModelService implements
228
263
 
229
264
  @Transactional()
230
265
  async processBulk<T extends ModelType>(cls: Class<T>, operations: BulkOperation<T>[]): Promise<BulkResponse> {
231
-
232
266
  const { insertedIds, upsertedIds, existingUpsertedIds } = await ModelBulkUtil.preStore(cls, operations, this);
233
267
 
234
268
  const addedIds = new Map([...insertedIds.entries(), ...upsertedIds.entries()]);
235
269
 
236
- await this.#checkUpsertedIds(cls,
237
- addedIds,
238
- new Map([...existingUpsertedIds.entries()].map(([key, value]) => [value, key]))
239
- );
270
+ await this.#checkUpsertedIds(cls, addedIds, new Map([...existingUpsertedIds.entries()].map(([key, value]) => [value, key])));
240
271
 
241
272
  const get = <K extends keyof BulkOperation<T>>(key: K): Required<BulkOperation<T>>[K][] =>
242
273
  operations.map(item => item[key]).filter((item): item is Required<BulkOperation<T>>[K] => !!item);
@@ -244,14 +275,11 @@ export class SQLModelService implements
244
275
  const getStatements = async (key: keyof BulkOperation<T>): Promise<InsertWrapper[]> =>
245
276
  (await SQLModelUtil.getInserts(cls, get(key))).filter(wrapper => !!wrapper.records.length);
246
277
 
247
- const deletes = [{ stack: SQLModelUtil.classToStack(cls), ids: get('delete').map(wrapper => wrapper.id) }]
248
- .filter(wrapper => !!wrapper.ids.length);
278
+ const deletes = [{ stack: SQLModelUtil.classToStack(cls), ids: get('delete').map(wrapper => wrapper.id) }].filter(
279
+ wrapper => !!wrapper.ids.length
280
+ );
249
281
 
250
- const [inserts, upserts, updates] = await Promise.all([
251
- getStatements('insert'),
252
- getStatements('upsert'),
253
- getStatements('update')
254
- ]);
282
+ const [inserts, upserts, updates] = await Promise.all([getStatements('insert'), getStatements('upsert'), getStatements('update')]);
255
283
 
256
284
  const result = await this.#dialect.bulkProcess(deletes, inserts, upserts, updates);
257
285
  result.insertedIds = addedIds;
@@ -269,7 +297,7 @@ export class SQLModelService implements
269
297
  await QueryVerifier.verify(cls, query);
270
298
  const { records } = await this.#exec<T>(this.#dialect.getQuerySQL(cls, query, ModelQueryUtil.getWhereClause(cls, query.where)));
271
299
  if (ModelRegistryIndex.has(cls)) {
272
- await this.#dialect.fetchDependents(cls, records, query && query.select);
300
+ await this.#dialect.fetchDependents(cls, records, query?.select);
273
301
  }
274
302
 
275
303
  const cleaned = SQLModelUtil.cleanResults<T>(this.#dialect, records);
@@ -303,7 +331,9 @@ export class SQLModelService implements
303
331
  async updatePartialByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>, data: Partial<T>): Promise<number> {
304
332
  await QueryVerifier.verify(cls, query);
305
333
  const item = await ModelCrudUtil.prePartialUpdate(cls, data);
306
- const { count } = await this.#exec(this.#dialect.getUpdateSQL(SQLModelUtil.classToStack(cls), item, ModelQueryUtil.getWhereClause(cls, query.where)));
334
+ const { count } = await this.#exec(
335
+ this.#dialect.getUpdateSQL(SQLModelUtil.classToStack(cls), item, ModelQueryUtil.getWhereClause(cls, query.where))
336
+ );
307
337
  return count;
308
338
  }
309
339
 
@@ -311,12 +341,19 @@ export class SQLModelService implements
311
341
  @Transactional()
312
342
  async deleteByQuery<T extends ModelType>(cls: Class<T>, query: ModelQuery<T>): Promise<number> {
313
343
  await QueryVerifier.verify(cls, query);
314
- const { count } = await this.#exec(this.#dialect.getDeleteSQL(SQLModelUtil.classToStack(cls), ModelQueryUtil.getWhereClause(cls, query.where, false)));
344
+ const { count } = await this.#exec(
345
+ this.#dialect.getDeleteSQL(SQLModelUtil.classToStack(cls), ModelQueryUtil.getWhereClause(cls, query.where, false))
346
+ );
315
347
  return count;
316
348
  }
317
349
 
318
350
  @Connected()
319
- async suggestByQuery<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, prefix?: string, query?: PageableModelQuery<T>): Promise<T[]> {
351
+ async suggestByQuery<T extends ModelType>(
352
+ cls: Class<T>,
353
+ field: ValidStringFields<T>,
354
+ prefix?: string,
355
+ query?: PageableModelQuery<T>
356
+ ): Promise<T[]> {
320
357
  await QueryVerifier.verify(cls, query);
321
358
  const resolvedQuery = ModelQuerySuggestUtil.getSuggestQuery<T>(cls, field, prefix, query);
322
359
  const results = await this.query<T>(cls, resolvedQuery);
@@ -324,7 +361,12 @@ export class SQLModelService implements
324
361
  }
325
362
 
326
363
  @Connected()
327
- async suggestValuesByQuery<T extends ModelType>(cls: Class<T>, field: ValidStringFields<T>, prefix?: string, query?: PageableModelQuery<T>): Promise<string[]> {
364
+ async suggestValuesByQuery<T extends ModelType>(
365
+ cls: Class<T>,
366
+ field: ValidStringFields<T>,
367
+ prefix?: string,
368
+ query?: PageableModelQuery<T>
369
+ ): Promise<string[]> {
328
370
  await QueryVerifier.verify(cls, query);
329
371
  const resolvedQuery = ModelQuerySuggestUtil.getSuggestFieldQuery(cls, field, prefix, query);
330
372
  const results = await this.query(cls, resolvedQuery);
@@ -339,19 +381,11 @@ export class SQLModelService implements
339
381
  const col = this.#dialect.identifier(field);
340
382
  const ttl = this.#dialect.identifier('count');
341
383
  const key = this.#dialect.identifier('key');
342
- const sql = [
343
- `SELECT ${col} as ${key}, COUNT(${col}) as ${ttl}`,
344
- this.#dialect.getFromSQL(cls),
345
- ];
346
- sql.push(
347
- this.#dialect.getWhereSQL(cls, ModelQueryUtil.getWhereClause(cls, query?.where))
348
- );
349
- sql.push(
350
- `GROUP BY ${col}`,
351
- `ORDER BY ${ttl} DESC`
352
- );
384
+ const sql = [`SELECT ${col} as ${key}, COUNT(${col}) as ${ttl}`, this.#dialect.getFromSQL(cls)];
385
+ sql.push(this.#dialect.getWhereSQL(cls, ModelQueryUtil.getWhereClause(cls, query?.where)));
386
+ sql.push(`GROUP BY ${col}`, `ORDER BY ${ttl} DESC`);
353
387
 
354
- const results = await this.#exec<{ key: string, count: number }>(sql.join('\n'));
388
+ const results = await this.#exec<{ key: string; count: number }>(sql.join('\n'));
355
389
  return results.records.map(result => {
356
390
  result.count = DataUtil.coerceType(result.count, Number);
357
391
  return result;
@@ -360,11 +394,11 @@ export class SQLModelService implements
360
394
 
361
395
  // Indexed support
362
396
  @Connected()
363
- async getByIndex<
364
- T extends ModelType,
365
- K extends KeyedIndexSelection<T>,
366
- S extends SortedIndexSelection<T>
367
- >(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: FullKeyedIndexBody<T, K, S>): Promise<T> {
397
+ async getByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
398
+ cls: Class<T>,
399
+ idx: SingleItemIndex<T, K, S>,
400
+ body: FullKeyedIndexBody<T, K, S>
401
+ ): Promise<T> {
368
402
  const computed = ModelIndexedComputedIndex.get(idx, body).validate({ sort: true });
369
403
  const results = await this.query(cls, castTo({ where: computed.project({ sort: true, includeId: true }) }));
370
404
  if (results.length !== 1) {
@@ -375,11 +409,11 @@ export class SQLModelService implements
375
409
 
376
410
  @Connected()
377
411
  @Transactional()
378
- async deleteByIndex<
379
- T extends ModelType,
380
- K extends KeyedIndexSelection<T>,
381
- S extends SortedIndexSelection<T>
382
- >(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: FullKeyedIndexBody<T, K, S>): Promise<void> {
412
+ async deleteByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
413
+ cls: Class<T>,
414
+ idx: SingleItemIndex<T, K, S>,
415
+ body: FullKeyedIndexBody<T, K, S>
416
+ ): Promise<void> {
383
417
  const computed = ModelIndexedComputedIndex.get(idx, body).validate({ sort: true });
384
418
  const count = await this.deleteByQuery(cls, castTo({ where: computed.project({ sort: true, includeId: true }) }));
385
419
  if (count === 0) {
@@ -389,41 +423,37 @@ export class SQLModelService implements
389
423
 
390
424
  @Connected()
391
425
  @Transactional()
392
- upsertByIndex<
393
- T extends ModelType,
394
- K extends KeyedIndexSelection<T>,
395
- S extends SortedIndexSelection<T>
396
- >(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: OptionalId<T>): Promise<T> {
426
+ upsertByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
427
+ cls: Class<T>,
428
+ idx: SingleItemIndex<T, K, S>,
429
+ body: OptionalId<T>
430
+ ): Promise<T> {
397
431
  return ModelIndexedUtil.naiveUpsert(this, cls, idx, body);
398
432
  }
399
433
 
400
434
  @Connected()
401
435
  @Transactional()
402
- updateByIndex<
403
- T extends ModelType,
404
- K extends KeyedIndexSelection<T>,
405
- S extends SortedIndexSelection<T>
406
- >(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: T): Promise<T> {
436
+ updateByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
437
+ cls: Class<T>,
438
+ idx: SingleItemIndex<T, K, S>,
439
+ body: T
440
+ ): Promise<T> {
407
441
  return ModelIndexedUtil.naiveUpdate(this, cls, idx, body);
408
442
  }
409
443
 
410
444
  @Connected()
411
445
  @Transactional()
412
- async updatePartialByIndex<
413
- T extends ModelType,
414
- K extends KeyedIndexSelection<T>,
415
- S extends SortedIndexSelection<T>
416
- >(cls: Class<T>, idx: SingleItemIndex<T, K, S>, body: FullKeyedIndexWithPartialBody<T, K, S>): Promise<T> {
446
+ async updatePartialByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
447
+ cls: Class<T>,
448
+ idx: SingleItemIndex<T, K, S>,
449
+ body: FullKeyedIndexWithPartialBody<T, K, S>
450
+ ): Promise<T> {
417
451
  const item = await ModelCrudUtil.naivePartialUpdate(cls, () => this.getByIndex(cls, idx, castTo(body)), castTo(body));
418
452
  return this.update(cls, item);
419
453
  }
420
454
 
421
455
  @Connected()
422
- async pageByIndex<
423
- T extends ModelType,
424
- K extends KeyedIndexSelection<T>,
425
- S extends SortedIndexSelection<T>
426
- >(
456
+ async pageByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
427
457
  cls: Class<T>,
428
458
  idx: SortedIndex<T, K, S>,
429
459
  body: KeyedIndexBody<T, K>,
@@ -434,7 +464,7 @@ export class SQLModelService implements
434
464
 
435
465
  const baseQuery = castTo<ModelQuery<T>>({
436
466
  where: computed.project(),
437
- sort: idx.sortTemplate.map(part => ({ [part.path.join('.')]: part.value })),
467
+ sort: idx.sortTemplate.map(part => ({ [part.path.join('.')]: part.value }))
438
468
  });
439
469
 
440
470
  const items: T[] = [];
@@ -447,11 +477,7 @@ export class SQLModelService implements
447
477
  }
448
478
 
449
479
  @ConnectedIterator()
450
- async * listByIndex<
451
- T extends ModelType,
452
- K extends KeyedIndexSelection<T>,
453
- S extends SortedIndexSelection<T>
454
- >(
480
+ async *listByIndex<T extends ModelType, K extends KeyedIndexSelection<T>, S extends SortedIndexSelection<T>>(
455
481
  cls: Class<T>,
456
482
  idx: SortedIndex<T, K, S>,
457
483
  body: KeyedIndexBody<T, K>,
@@ -460,7 +486,7 @@ export class SQLModelService implements
460
486
  const computed = ModelIndexedComputedIndex.get(idx, body).validate();
461
487
  const baseQuery = castTo<ModelQuery<T>>({
462
488
  where: computed.project(),
463
- sort: idx.sortTemplate.map(part => ({ [part.path.join('.')]: part.value })),
489
+ sort: idx.sortTemplate.map(part => ({ [part.path.join('.')]: part.value }))
464
490
  });
465
491
  for await (const { items } of this.#scanTable<T>(cls, () => baseQuery, options)) {
466
492
  yield items;
@@ -479,17 +505,14 @@ export class SQLModelService implements
479
505
  const nested: Record<string, unknown> = {};
480
506
  let current = nested;
481
507
  for (const key of idx.sortTemplate[0].path.slice(0, -1)) {
482
- current = (current[key] = {});
508
+ current = current[key] = {};
483
509
  }
484
510
  current[idx.sortTemplate[0].path.at(-1)!] = { $regex: ModelIndexedUtil.getSuggestRegex(prefix) };
485
511
 
486
512
  const baseQuery = castTo<ModelQuery<T>>({
487
513
  where: {
488
- $and: [
489
- computed.project(),
490
- nested
491
- ]
492
- },
514
+ $and: [computed.project(), nested]
515
+ }
493
516
  });
494
517
 
495
518
  for await (const batch of this.#scanTable<T>(cls, () => baseQuery, { limit: 10, ...options })) {
@@ -498,4 +521,4 @@ export class SQLModelService implements
498
521
 
499
522
  return items;
500
523
  }
501
- }
524
+ }
@@ -1,15 +1,15 @@
1
1
  import { type AsyncContext, WithAsyncContext } from '@travetto/context';
2
2
  import { ModelRegistryIndex } from '@travetto/model';
3
- import { type Class } from '@travetto/runtime';
4
- import { SchemaRegistryIndex, type SchemaFieldConfig } from '@travetto/schema';
3
+ import type { Class } from '@travetto/runtime';
4
+ import { type SchemaFieldConfig, SchemaRegistryIndex } from '@travetto/schema';
5
5
 
6
+ import type { Connection } from './connection/base.ts';
6
7
  import { Connected, Transactional } from './connection/decorator.ts';
7
8
  import type { SQLDialect } from './dialect/base.ts';
8
- import { SQLModelUtil } from './util.ts';
9
- import type { Connection } from './connection/base.ts';
10
9
  import type { VisitStack } from './types.ts';
10
+ import { SQLModelUtil } from './util.ts';
11
11
 
12
- type UpsertStructure = { dropIndex: string[], createIndex: string[], table: string[] };
12
+ type UpsertStructure = { dropIndex: string[]; createIndex: string[]; table: string[] };
13
13
  const isSimpleField = (input: VisitStack | undefined): input is SchemaFieldConfig =>
14
14
  !!input && (!('type' in input) || (input.type && !SchemaRegistryIndex.has(input.type)));
15
15
 
@@ -17,7 +17,6 @@ const isSimpleField = (input: VisitStack | undefined): input is SchemaFieldConfi
17
17
  * Manage creation/updating of all tables
18
18
  */
19
19
  export class TableManager {
20
-
21
20
  #dialect: SQLDialect;
22
21
  context: AsyncContext;
23
22
 
@@ -26,7 +25,7 @@ export class TableManager {
26
25
  this.context = context;
27
26
  }
28
27
 
29
- #exec<T = unknown>(sql: string): Promise<{ records: T[], count: number }> {
28
+ #exec<T = unknown>(sql: string): Promise<{ records: T[]; count: number }> {
30
29
  return this.#dialect.executeSQL<T>(sql);
31
30
  }
32
31
 
@@ -70,7 +69,8 @@ export class TableManager {
70
69
  // Manage fields
71
70
  if (!existingFields.size) {
72
71
  sqlCommands.table.push(this.#dialect.getCreateTableSQL(path));
73
- } else { // Existing
72
+ } else {
73
+ // Existing
74
74
  // Fields
75
75
  const requestedFields = new Map(fields.map(field => [field.name, field]));
76
76
  const top = path.at(-1);
@@ -121,9 +121,17 @@ export class TableManager {
121
121
 
122
122
  const schema = SchemaRegistryIndex.getConfig(cls);
123
123
  await SQLModelUtil.visitSchema(schema, {
124
- onRoot: async ({ config, path, fields, descend }) => { await onVisit(config.class, fields, path); return descend(); },
125
- onSub: async ({ config, path, fields, descend }) => { await onVisit(config.type, fields, path); return descend(); },
126
- onSimple: async ({ config, path, fields }) => { await onVisit(config.type, fields, path); }
124
+ onRoot: async ({ config, path, fields, descend }) => {
125
+ await onVisit(config.class, fields, path);
126
+ return descend();
127
+ },
128
+ onSub: async ({ config, path, fields, descend }) => {
129
+ await onVisit(config.type, fields, path);
130
+ return descend();
131
+ },
132
+ onSimple: async ({ config, path, fields }) => {
133
+ await onVisit(config.type, fields, path);
134
+ }
127
135
  });
128
136
  return sqlCommands;
129
137
  }
@@ -166,4 +174,4 @@ export class TableManager {
166
174
  await this.#exec(command);
167
175
  }
168
176
  }
169
- }
177
+ }
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Class } from '@travetto/runtime';
1
+ import type { Class } from '@travetto/runtime';
2
2
 
3
3
  export const TableSymbol = Symbol.for('@travetto/model-sql:table');
4
4