@travetto/model-firestore 2.1.3 → 2.2.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/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @travetto/model-firestore
10
10
 
11
11
  This module provides an [Firestore](https://firebase.google.com/docs/firestore)-based implementation of the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations."). This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [Firestore](https://firebase.google.com/docs/firestore).
12
12
 
13
- Supported featrues:
13
+ Supported features:
14
14
 
15
15
  * [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/service/crud.ts#L11)
16
16
  * [Indexed](https://github.com/travetto/travetto/tree/main/module/model/src/service/indexed.ts#L12)
@@ -57,7 +57,7 @@ export class FirestoreModelConfig {
57
57
  private_key: string;
58
58
  };
59
59
 
60
- async postConstruct() {
60
+ async postConstruct(): Promise<void> {
61
61
  if (this.emulator) {
62
62
  process.env.FIRESTORE_EMULATOR_HOST = this.emulator;
63
63
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@travetto/model-firestore",
3
3
  "displayName": "Firestore Model Support",
4
- "version": "2.1.3",
4
+ "version": "2.2.0",
5
5
  "description": "Firestore backing for the travetto model module.",
6
6
  "keywords": [
7
7
  "typescript",
@@ -26,8 +26,8 @@
26
26
  "directory": "module/model-firestore"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/config": "^2.1.3",
30
- "@travetto/model": "^2.1.3",
29
+ "@travetto/config": "^2.2.0",
30
+ "@travetto/model": "^2.2.0",
31
31
  "@google-cloud/firestore": "^5.0.2"
32
32
  },
33
33
  "private": false,
package/src/config.ts CHANGED
@@ -16,7 +16,7 @@ export class FirestoreModelConfig {
16
16
  private_key: string;
17
17
  };
18
18
 
19
- async postConstruct() {
19
+ async postConstruct(): Promise<void> {
20
20
  if (this.emulator) {
21
21
  process.env.FIRESTORE_EMULATOR_HOST = this.emulator;
22
22
  }
package/src/service.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { FieldValue, Firestore, Precondition, Query } from '@google-cloud/firestore';
1
+ import { DocumentData, FieldValue, Firestore, PartialWithFieldValue, Query, UpdateData } from '@google-cloud/firestore';
2
2
 
3
3
  import { ShutdownManager, Util, Class } from '@travetto/base';
4
4
  import { DeepPartial } from '@travetto/schema';
@@ -13,9 +13,9 @@ import { ModelIndexedUtil } from '@travetto/model/src/internal/service/indexed';
13
13
 
14
14
  import { FirestoreModelConfig } from './config';
15
15
 
16
- const clone = <T>(inp: T) => JSON.parse(JSON.stringify(inp));
16
+ const clone = <T>(inp: T): T => JSON.parse(JSON.stringify(inp));
17
17
 
18
- const toSimpleObj = <T>(inp: T, missingValue: unknown = null) =>
18
+ const toSimpleObj = <T>(inp: T, missingValue: unknown = null): PartialWithFieldValue<DocumentData> =>
19
19
  JSON.parse(JSON.stringify(inp, (_, v) => v ?? null), (_, v) => v ?? missingValue);
20
20
 
21
21
  /**
@@ -28,7 +28,7 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
28
28
 
29
29
  constructor(public readonly config: FirestoreModelConfig) { }
30
30
 
31
- #resolveTable(cls: Class) {
31
+ #resolveTable(cls: Class): string {
32
32
  let table = ModelRegistry.getStore(cls);
33
33
  if (this.config.namespace) {
34
34
  table = `${this.config.namespace}_${table}`;
@@ -36,20 +36,20 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
36
36
  return table;
37
37
  }
38
38
 
39
- #getCollection(cls: Class) {
39
+ #getCollection(cls: Class): FirebaseFirestore.CollectionReference<DocumentData> {
40
40
  return this.client.collection(this.#resolveTable(cls));
41
41
  }
42
42
 
43
- async postConstruct() {
43
+ async postConstruct(): Promise<void> {
44
44
  this.client = new Firestore(this.config);
45
45
  ShutdownManager.onShutdown(this.constructor.ᚕid, () => this.client.terminate());
46
46
  }
47
47
 
48
48
  // Storage
49
- async createStorage() { }
50
- async deleteStorage() { }
49
+ async createStorage(): Promise<void> { }
50
+ async deleteStorage(): Promise<void> { }
51
51
 
52
- async deleteModel(cls: Class) {
52
+ async deleteModel(cls: Class): Promise<void> {
53
53
  for await (const el of this.list(cls)) {
54
54
  await this.delete(cls, el.id);
55
55
  }
@@ -60,7 +60,7 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
60
60
  return Util.uuid();
61
61
  }
62
62
 
63
- async get<T extends ModelType>(cls: Class<T>, id: string) {
63
+ async get<T extends ModelType>(cls: Class<T>, id: string): Promise<T> {
64
64
  const res = await this.#getCollection(cls).doc(id).get();
65
65
 
66
66
  if (res && res.exists) {
@@ -69,67 +69,70 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
69
69
  throw new NotFoundError(cls, id);
70
70
  }
71
71
 
72
- async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>) {
72
+ async create<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
73
73
  const prepped = await ModelCrudUtil.preStore(cls, item, this);
74
74
  await this.#getCollection(cls).doc(prepped.id).create(clone(prepped));
75
75
  return prepped;
76
76
  }
77
77
 
78
- async update<T extends ModelType>(cls: Class<T>, item: T) {
78
+ async update<T extends ModelType>(cls: Class<T>, item: T): Promise<T> {
79
79
  ModelCrudUtil.ensureNotSubType(cls);
80
- item = await ModelCrudUtil.preStore(cls, item, this);
81
- await this.#getCollection(cls).doc(item.id).update(clone(item));
80
+ const prepped = await ModelCrudUtil.preStore(cls, item, this);
81
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
82
+ await this.#getCollection(cls).doc(item.id).update(clone(prepped) as unknown as UpdateData<DocumentData>);
82
83
  return item;
83
84
  }
84
85
 
85
- async upsert<T extends ModelType>(cls: Class<T>, item: OptionalId<T>) {
86
+ async upsert<T extends ModelType>(cls: Class<T>, item: OptionalId<T>): Promise<T> {
86
87
  ModelCrudUtil.ensureNotSubType(cls);
87
88
  const prepped = await ModelCrudUtil.preStore(cls, item, this);
88
89
  await this.#getCollection(cls).doc(prepped.id).set(clone(prepped));
89
90
  return prepped;
90
91
  }
91
92
 
92
- async updatePartial<T extends ModelType>(cls: Class<T>, item: Partial<T> & { id: string }, view?: string) {
93
+ async updatePartial<T extends ModelType>(cls: Class<T>, item: Partial<T> & { id: string }, view?: string): Promise<T> {
93
94
  ModelCrudUtil.ensureNotSubType(cls);
94
95
  const id = item.id;
96
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
95
97
  item = await ModelCrudUtil.naivePartialUpdate(cls, item, view, async () => ({} as unknown as T));
96
98
  const cleaned = toSimpleObj(item, FieldValue.delete());
97
99
  await this.#getCollection(cls).doc(id).set(cleaned, { merge: true });
98
100
  return this.get(cls, id);
99
101
  }
100
102
 
101
- async delete<T extends ModelType>(cls: Class<T>, id: string) {
103
+ async delete<T extends ModelType>(cls: Class<T>, id: string): Promise<void> {
102
104
  ModelCrudUtil.ensureNotSubType(cls);
103
105
  try {
104
- await this.#getCollection(cls).doc(id).delete({ exists: true } as unknown as Precondition);
106
+ await this.#getCollection(cls).doc(id).delete({ exists: true });
105
107
  } catch (err) {
106
- if (`${err.message}`.includes('NOT_FOUND')) {
108
+ if (err && err instanceof Error && err.message.includes('NOT_FOUND')) {
107
109
  throw new NotFoundError(cls, id);
108
110
  }
109
111
  throw err;
110
112
  }
111
113
  }
112
114
 
113
- async * list<T extends ModelType>(cls: Class<T>) {
115
+ async * list<T extends ModelType>(cls: Class<T>): AsyncIterable<T> {
114
116
  const batch = await this.#getCollection(cls).select().get();
115
117
  for (const el of batch.docs) {
116
118
  try {
117
119
  yield await this.get(cls, el.id);
118
- } catch (e) {
119
- if (!(e instanceof NotFoundError)) {
120
- throw e;
120
+ } catch (err) {
121
+ if (!(err instanceof NotFoundError)) {
122
+ throw err;
121
123
  }
122
124
  }
123
125
  }
124
126
  }
125
127
 
126
128
  // Indexed
127
- async #getIdByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
129
+ async #getIdByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<string> {
128
130
  ModelCrudUtil.ensureNotSubType(cls);
129
131
 
130
132
  const { fields } = ModelIndexedUtil.computeIndexParts(cls, idx, body);
131
- const query = fields.reduce((q, { path, value }) => q.where(path.join('.'), '==', value),
132
- this.#getCollection(cls) as Query
133
+ const query = fields.reduce<Query>(
134
+ (q, { path, value }) => q.where(path.join('.'), '==', value),
135
+ this.#getCollection(cls)
133
136
  );
134
137
 
135
138
  const item = await query.get();
@@ -140,11 +143,11 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
140
143
  throw new NotFoundError(`${cls.name} Index=${idx}`, ModelIndexedUtil.computeIndexKey(cls, idx, body, { sep: '; ' })?.key);
141
144
  }
142
145
 
143
- async getByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
146
+ async getByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<T> {
144
147
  return this.get(cls, await this.#getIdByIndex(cls, idx, body));
145
148
  }
146
149
 
147
- async deleteByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
150
+ async deleteByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): Promise<void> {
148
151
  return this.delete(cls, await this.#getIdByIndex(cls, idx, body));
149
152
  }
150
153
 
@@ -152,12 +155,12 @@ export class FirestoreModelService implements ModelCrudSupport, ModelStorageSupp
152
155
  return ModelIndexedUtil.naiveUpsert(this, cls, idx, body);
153
156
  }
154
157
 
155
- async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>) {
158
+ async * listByIndex<T extends ModelType>(cls: Class<T>, idx: string, body: DeepPartial<T>): AsyncIterable<T> {
156
159
  ModelCrudUtil.ensureNotSubType(cls);
157
160
 
158
161
  const { fields, sorted } = ModelIndexedUtil.computeIndexParts(cls, idx, body, { emptySortValue: null });
159
- let query = fields.reduce((q, { path, value }) =>
160
- q.where(path.join('.'), '==', value), this.#getCollection(cls) as Query);
162
+ let query = fields.reduce<Query>((q, { path, value }) =>
163
+ q.where(path.join('.'), '==', value), this.#getCollection(cls));
161
164
 
162
165
  if (sorted) {
163
166
  query = query.orderBy(sorted.path.join('.'), sorted.dir === 1 ? 'asc' : 'desc');