@travetto/model-firestore 8.0.0-alpha.16 → 8.0.0-alpha.19

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
@@ -17,7 +17,7 @@ This module provides an [Firestore](https://firebase.google.com/docs/firestore)-
17
17
 
18
18
  Supported features:
19
19
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L11)
20
- * [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L15)
20
+ * [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L16)
21
21
 
22
22
  Out of the box, by installing the module, everything should be wired up by default.If you need to customize any aspect of the source or config, you can override and register it with the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") module.
23
23
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-firestore",
3
- "version": "8.0.0-alpha.16",
3
+ "version": "8.0.0-alpha.19",
4
4
  "description": "Firestore backing for the travetto model module.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -25,14 +25,14 @@
25
25
  "directory": "module/model-firestore"
26
26
  },
27
27
  "dependencies": {
28
- "@google-cloud/firestore": "^8.5.0",
29
- "@travetto/config": "^8.0.0-alpha.14",
30
- "@travetto/model": "^8.0.0-alpha.14",
31
- "@travetto/model-indexed": "^8.0.0-alpha.16",
32
- "@travetto/runtime": "^8.0.0-alpha.13"
28
+ "@google-cloud/firestore": "^8.6.0",
29
+ "@travetto/config": "^8.0.0-alpha.17",
30
+ "@travetto/model": "^8.0.0-alpha.17",
31
+ "@travetto/model-indexed": "^8.0.0-alpha.19",
32
+ "@travetto/runtime": "^8.0.0-alpha.16"
33
33
  },
34
34
  "peerDependencies": {
35
- "@travetto/cli": "^8.0.0-alpha.19"
35
+ "@travetto/cli": "^8.0.0-alpha.22"
36
36
  },
37
37
  "peerDependenciesMeta": {
38
38
  "@travetto/cli": {
package/src/service.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type DocumentData, FieldValue, Firestore, type Query } from '@google-cloud/firestore';
2
2
 
3
- import { castTo, JSONUtil, ShutdownManager, type Class } from '@travetto/runtime';
3
+ import { castTo, JSONUtil, ShutdownManager, type Class, RuntimeError } from '@travetto/runtime';
4
4
  import { Injectable, PostConstruct } from '@travetto/di';
5
5
  import {
6
6
  type ModelCrudSupport, ModelRegistryIndex, type ModelStorageSupport, type ModelType, NotFoundError, type OptionalId, ModelCrudUtil,
@@ -9,7 +9,8 @@ import {
9
9
  import {
10
10
  type ModelIndexedSupport, type KeyedIndexSelection, type KeyedIndexBody, type ModelPageOptions, ModelIndexedUtil,
11
11
  type SingleItemIndex, type SortedIndexSelection, type ModelPageResult, type SortedIndex, type FullKeyedIndexBody,
12
- type FullKeyedIndexWithPartialBody, ModelIndexedComputedIndex, warnIfIndexedUniqueIndex, warnIfNonIndexedIndex
12
+ type FullKeyedIndexWithPartialBody, ModelIndexedComputedIndex, warnIfIndexedUniqueIndex, warnIfNonIndexedIndex,
13
+ type ModelIndexedSearchOptions, type SortedIndexSelectionType
13
14
  } from '@travetto/model-indexed';
14
15
 
15
16
  import type { FirestoreModelConfig } from './config.ts';
@@ -58,14 +59,13 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
58
59
  if (!item || item.empty) {
59
60
  throw new NotFoundError(`${cls.name} Index=${idx}`, computed.getKey());
60
61
  }
61
- return item.docs[0].id;
62
+ if (item.size > 1) {
63
+ throw new RuntimeError(`Multiple items found for ${cls.name} Index=${idx}`);
64
+ }
65
+ return item.docs[0].data().id;
62
66
  }
63
67
 
64
- #buildIndexQuery<
65
- T extends ModelType,
66
- K extends KeyedIndexSelection<T>,
67
- S extends SortedIndexSelection<T>
68
- >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>): Query {
68
+ #buildIndexQuery<T extends ModelType>(cls: Class<T>, idx: SortedIndex<T>, body: KeyedIndexBody<T>): Query {
69
69
  ModelCrudUtil.ensureNotSubType(cls);
70
70
  const computed = ModelIndexedComputedIndex.get(idx, body).validate();
71
71
 
@@ -92,19 +92,17 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
92
92
  while (!(options?.abort?.aborted) && produced < limit) {
93
93
  const query = queryBuilder().limit(batchSize).offset(offset);
94
94
 
95
- let { docs } = await query.get();
96
- if (docs.length === 0) {
95
+ const { docs, size } = await query.get();
96
+ if (size === 0) {
97
97
  break;
98
98
  }
99
99
 
100
- if (produced + docs.length > limit) {
101
- docs = docs.slice(0, limit - produced);
102
- }
100
+ const remaining = (produced + size > limit) ? docs.slice(0, limit - produced) : docs;
103
101
 
104
- offset += docs.length;
102
+ offset += size;
105
103
 
106
104
  const items = await ModelCrudUtil.filterOutNotFound(
107
- docs.map(item => ModelCrudUtil.load(cls, item.data()!)));
105
+ remaining.map(item => ModelCrudUtil.load(cls, item.data()!)));
108
106
  produced += items.length;
109
107
 
110
108
  yield { items, nextOffset: offset };
@@ -113,7 +111,6 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
113
111
 
114
112
  @PostConstruct()
115
113
  async initializeClient(): Promise<void> {
116
- globalThis.devProcessWarningExclusions?.push((_, category) => category === 'MetadataLookupWarning');
117
114
  this.client = new Firestore({ ...this.config, useBigInt: true });
118
115
  ShutdownManager.signal.addEventListener('abort', () => this.client.terminate());
119
116
  }
@@ -269,4 +266,26 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
269
266
  yield items;
270
267
  }
271
268
  }
269
+
270
+ async suggestByIndex<
271
+ T extends ModelType,
272
+ S extends SortedIndexSelection<T>,
273
+ K extends KeyedIndexSelection<T>,
274
+ B extends SortedIndexSelectionType<T, S> & string
275
+ >(cls: Class<T>, idx: SortedIndex<T, K, S>, body: KeyedIndexBody<T, K>, prefix: B, options?: ModelIndexedSearchOptions): Promise<T[]> {
276
+ const results: T[] = [];
277
+
278
+ const field = idx.sortTemplate[0].path.join('.');
279
+
280
+ for await (const { items } of this.#scanCollection(cls,
281
+ () => this.#buildIndexQuery(cls, idx, body)
282
+ .where(field, '>=', prefix)
283
+ .where(field, '<', `${prefix}\uf8ff`),
284
+ { limit: 10, ...options })
285
+ ) {
286
+ results.push(...items);
287
+ }
288
+
289
+ return results;
290
+ }
272
291
  }