@naturalcycles/firestore-lib 1.2.2 → 1.4.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.
@@ -12,16 +12,15 @@ export interface FirestoreDBSaveOptions<ROW extends Partial<ObjectWithId> = AnyO
12
12
  export declare class FirestoreDB extends BaseCommonDB implements CommonDB {
13
13
  cfg: FirestoreDBCfg;
14
14
  constructor(cfg: FirestoreDBCfg);
15
- getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], opt?: FirestoreDBOptions): Promise<ROW[]>;
16
- getById<ROW extends ObjectWithId>(table: string, id: ROW['id'], _opt?: FirestoreDBOptions): Promise<ROW | null>;
15
+ getByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: FirestoreDBOptions): Promise<ROW[]>;
17
16
  runQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: FirestoreDBOptions): Promise<RunQueryResult<ROW>>;
18
17
  runFirestoreQuery<ROW extends ObjectWithId>(q: Query, _opt?: FirestoreDBOptions): Promise<ROW[]>;
19
- runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: FirestoreDBOptions): Promise<number>;
18
+ runQueryCount<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: FirestoreDBOptions): Promise<number>;
20
19
  streamQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, _opt?: CommonDBStreamOptions): ReadableTyped<ROW>;
21
20
  saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: FirestoreDBSaveOptions<ROW>): Promise<void>;
22
21
  deleteByQuery<ROW extends ObjectWithId>(q: DBQuery<ROW>, opt?: FirestoreDBOptions): Promise<number>;
23
22
  deleteByIds<ROW extends ObjectWithId>(table: string, ids: ROW['id'][], _opt?: FirestoreDBOptions): Promise<number>;
24
23
  private querySnapshotToArray;
25
- commitTransaction(_tx: DBTransaction, _opt?: CommonDBSaveOptions): Promise<void>;
24
+ commitTransaction(tx: DBTransaction, _opt?: CommonDBSaveOptions): Promise<void>;
26
25
  ping(): Promise<void>;
27
26
  }
@@ -17,20 +17,27 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
17
17
  this.cfg = cfg;
18
18
  }
19
19
  // GET
20
- async getByIds(table, ids, opt) {
20
+ async getByIds(table, ids, _opt) {
21
21
  // Oj, doesn't look like a very optimal implementation!
22
22
  // TODO: check if we can query by keys or smth
23
- return (await Promise.all(ids.map(id => this.getById(table, id, opt)))).filter(Boolean);
24
- }
25
- async getById(table, id, _opt) {
26
- const doc = await this.cfg.firestore.collection(table).doc((0, firestore_util_1.escapeDocId)(id)).get();
27
- const data = doc.data();
28
- if (data === undefined)
29
- return null;
30
- return {
31
- id,
32
- ...data,
33
- };
23
+ // return (await Promise.all(ids.map(id => this.getById<ROW>(table, id, opt)))).filter(
24
+ // Boolean,
25
+ // ) as ROW[]
26
+ if (!ids.length)
27
+ return [];
28
+ const { firestore } = this.cfg;
29
+ const col = firestore.collection(table);
30
+ return (await firestore.getAll(...ids.map(id => col.doc((0, firestore_util_1.escapeDocId)(id)))))
31
+ .map(doc => {
32
+ const data = doc.data();
33
+ if (data === undefined)
34
+ return;
35
+ return {
36
+ id: (0, firestore_util_1.unescapeDocId)(doc.id),
37
+ ...data,
38
+ };
39
+ })
40
+ .filter(js_lib_1._isTruthy);
34
41
  }
35
42
  // QUERY
36
43
  async runQuery(q, opt) {
@@ -45,9 +52,10 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
45
52
  async runFirestoreQuery(q, _opt) {
46
53
  return this.querySnapshotToArray(await q.get());
47
54
  }
48
- async runQueryCount(q, opt) {
49
- const { rows } = await this.runQuery(q.select([]), opt);
50
- return rows.length;
55
+ async runQueryCount(q, _opt) {
56
+ const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q, this.cfg.firestore.collection(q.table));
57
+ const r = await firestoreQuery.count().get();
58
+ return r.data().count;
51
59
  }
52
60
  streamQuery(q, _opt) {
53
61
  const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q, this.cfg.firestore.collection(q.table));
@@ -98,8 +106,25 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
98
106
  });
99
107
  return rows;
100
108
  }
101
- async commitTransaction(_tx, _opt) {
102
- throw new Error('commitTransaction is not supported yet');
109
+ async commitTransaction(tx, _opt) {
110
+ const { firestore } = this.cfg;
111
+ await firestore.runTransaction(async (tr) => {
112
+ for (const op of tx.ops) {
113
+ if (op.type === 'saveBatch') {
114
+ op.rows.forEach(row => {
115
+ tr.set(firestore.collection(op.table).doc((0, firestore_util_1.escapeDocId)(row.id)), (0, js_lib_1._filterUndefinedValues)(row));
116
+ });
117
+ }
118
+ else if (op.type === 'deleteByIds') {
119
+ op.ids.forEach(id => {
120
+ tr.delete(firestore.collection(op.table).doc((0, firestore_util_1.escapeDocId)(id)));
121
+ });
122
+ }
123
+ else {
124
+ throw new Error(`DBOperation not supported: ${op.type}`);
125
+ }
126
+ }
127
+ });
103
128
  }
104
129
  async ping() {
105
130
  // no-op now
package/package.json CHANGED
@@ -37,7 +37,7 @@
37
37
  "engines": {
38
38
  "node": ">=14.15.0"
39
39
  },
40
- "version": "1.2.2",
40
+ "version": "1.4.0",
41
41
  "description": "Firestore implementation of CommonDB interface",
42
42
  "author": "Natural Cycles Team",
43
43
  "license": "MIT"
@@ -19,6 +19,7 @@ import {
19
19
  ObjectWithId,
20
20
  AnyObjectWithId,
21
21
  _assert,
22
+ _isTruthy,
22
23
  } from '@naturalcycles/js-lib'
23
24
  import { ReadableTyped, transformMapSimple } from '@naturalcycles/nodejs-lib'
24
25
  import { escapeDocId, unescapeDocId } from './firestore.util'
@@ -47,29 +48,28 @@ export class FirestoreDB extends BaseCommonDB implements CommonDB {
47
48
  override async getByIds<ROW extends ObjectWithId>(
48
49
  table: string,
49
50
  ids: ROW['id'][],
50
- opt?: FirestoreDBOptions,
51
+ _opt?: FirestoreDBOptions,
51
52
  ): Promise<ROW[]> {
52
53
  // Oj, doesn't look like a very optimal implementation!
53
54
  // TODO: check if we can query by keys or smth
54
- return (await Promise.all(ids.map(id => this.getById<ROW>(table, id, opt)))).filter(
55
- Boolean,
56
- ) as ROW[]
57
- }
58
-
59
- async getById<ROW extends ObjectWithId>(
60
- table: string,
61
- id: ROW['id'],
62
- _opt?: FirestoreDBOptions,
63
- ): Promise<ROW | null> {
64
- const doc = await this.cfg.firestore.collection(table).doc(escapeDocId(id)).get()
65
-
66
- const data = doc.data()
67
- if (data === undefined) return null
68
-
69
- return {
70
- id,
71
- ...(data as any),
72
- }
55
+ // return (await Promise.all(ids.map(id => this.getById<ROW>(table, id, opt)))).filter(
56
+ // Boolean,
57
+ // ) as ROW[]
58
+ if (!ids.length) return []
59
+
60
+ const { firestore } = this.cfg
61
+ const col = firestore.collection(table)
62
+
63
+ return (await firestore.getAll(...ids.map(id => col.doc(escapeDocId(id)))))
64
+ .map(doc => {
65
+ const data = doc.data()
66
+ if (data === undefined) return
67
+ return {
68
+ id: unescapeDocId(doc.id),
69
+ ...(data as any),
70
+ }
71
+ })
72
+ .filter(_isTruthy)
73
73
  }
74
74
 
75
75
  // QUERY
@@ -83,7 +83,7 @@ export class FirestoreDB extends BaseCommonDB implements CommonDB {
83
83
 
84
84
  // Special case when projection query didn't specify 'id'
85
85
  if (q._selectedFieldNames && !q._selectedFieldNames.includes('id')) {
86
- rows = rows.map(r => _omit(r as any, ['id']))
86
+ rows = rows.map(r => _omit(r, ['id']))
87
87
  }
88
88
 
89
89
  return { rows }
@@ -98,10 +98,11 @@ export class FirestoreDB extends BaseCommonDB implements CommonDB {
98
98
 
99
99
  override async runQueryCount<ROW extends ObjectWithId>(
100
100
  q: DBQuery<ROW>,
101
- opt?: FirestoreDBOptions,
101
+ _opt?: FirestoreDBOptions,
102
102
  ): Promise<number> {
103
- const { rows } = await this.runQuery(q.select([]), opt)
104
- return rows.length
103
+ const firestoreQuery = dbQueryToFirestoreQuery(q, this.cfg.firestore.collection(q.table))
104
+ const r = await firestoreQuery.count().get()
105
+ return r.data().count
105
106
  }
106
107
 
107
108
  override streamQuery<ROW extends ObjectWithId>(
@@ -201,8 +202,27 @@ export class FirestoreDB extends BaseCommonDB implements CommonDB {
201
202
  return rows
202
203
  }
203
204
 
204
- override async commitTransaction(_tx: DBTransaction, _opt?: CommonDBSaveOptions): Promise<void> {
205
- throw new Error('commitTransaction is not supported yet')
205
+ override async commitTransaction(tx: DBTransaction, _opt?: CommonDBSaveOptions): Promise<void> {
206
+ const { firestore } = this.cfg
207
+
208
+ await firestore.runTransaction(async tr => {
209
+ for (const op of tx.ops) {
210
+ if (op.type === 'saveBatch') {
211
+ op.rows.forEach(row => {
212
+ tr.set(
213
+ firestore.collection(op.table).doc(escapeDocId(row.id)),
214
+ _filterUndefinedValues(row),
215
+ )
216
+ })
217
+ } else if (op.type === 'deleteByIds') {
218
+ op.ids.forEach(id => {
219
+ tr.delete(firestore.collection(op.table).doc(escapeDocId(id)))
220
+ })
221
+ } else {
222
+ throw new Error(`DBOperation not supported: ${(op as any).type}`)
223
+ }
224
+ }
225
+ })
206
226
  }
207
227
 
208
228
  override async ping(): Promise<void> {