@naturalcycles/firestore-lib 1.8.0 → 2.0.1

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.
@@ -1,7 +1,8 @@
1
- import { Firestore, Query, Transaction } from '@google-cloud/firestore';
2
- import { BaseCommonDB, CommonDB, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBSupport, CommonDBTransactionOptions, DBQuery, DBTransaction, DBTransactionFn, RunQueryResult } from '@naturalcycles/db-lib';
3
- import { ObjectWithId, StringMap } from '@naturalcycles/js-lib';
4
- import { ReadableTyped } from '@naturalcycles/nodejs-lib';
1
+ import type { Firestore, Query, Transaction } from '@google-cloud/firestore';
2
+ import type { CommonDB, CommonDBOptions, CommonDBSaveOptions, CommonDBStreamOptions, CommonDBSupport, CommonDBTransactionOptions, DBQuery, DBTransaction, DBTransactionFn, RunQueryResult } from '@naturalcycles/db-lib';
3
+ import { BaseCommonDB } from '@naturalcycles/db-lib';
4
+ import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib';
5
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
5
6
  export interface FirestoreDBCfg {
6
7
  firestore: Firestore;
7
8
  }
@@ -40,6 +41,7 @@ export declare class FirestoreDBTransaction implements DBTransaction {
40
41
  db: FirestoreDB;
41
42
  tx: Transaction;
42
43
  constructor(db: FirestoreDB, tx: Transaction);
44
+ commit(): Promise<void>;
43
45
  rollback(): Promise<void>;
44
46
  getByIds<ROW extends ObjectWithId>(table: string, ids: string[], opt?: CommonDBOptions): Promise<ROW[]>;
45
47
  saveBatch<ROW extends ObjectWithId>(table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW>): Promise<void>;
@@ -1,49 +1,46 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FirestoreDBTransaction = exports.FirestoreDB = exports.RollbackError = void 0;
4
- const firestore_1 = require("@google-cloud/firestore");
5
- const db_lib_1 = require("@naturalcycles/db-lib");
6
- const js_lib_1 = require("@naturalcycles/js-lib");
7
- const firestore_util_1 = require("./firestore.util");
8
- const query_util_1 = require("./query.util");
1
+ import { FieldValue } from '@google-cloud/firestore';
2
+ import { BaseCommonDB, commonDBFullSupport } from '@naturalcycles/db-lib';
3
+ import { _assert, _chunk, _filterUndefinedValues, _isTruthy, _omit, _stringMapEntries, pMap, } from '@naturalcycles/js-lib';
4
+ import { escapeDocId, unescapeDocId } from './firestore.util.js';
5
+ import { dbQueryToFirestoreQuery } from './query.util.js';
9
6
  const methodMap = {
10
7
  insert: 'create',
11
8
  update: 'update',
12
9
  upsert: 'set',
13
10
  };
14
- class RollbackError extends Error {
11
+ export class RollbackError extends Error {
15
12
  constructor() {
16
13
  super('rollback');
17
14
  }
18
15
  }
19
- exports.RollbackError = RollbackError;
20
- class FirestoreDB extends db_lib_1.BaseCommonDB {
16
+ export class FirestoreDB extends BaseCommonDB {
17
+ cfg;
21
18
  constructor(cfg) {
22
19
  super();
23
20
  this.cfg = cfg;
24
- this.support = {
25
- ...db_lib_1.commonDBFullSupport,
26
- patchByQuery: false, // todo: can be implemented
27
- tableSchemas: false,
28
- };
29
21
  }
22
+ support = {
23
+ ...commonDBFullSupport,
24
+ patchByQuery: false, // todo: can be implemented
25
+ tableSchemas: false,
26
+ };
30
27
  // GET
31
28
  async getByIds(table, ids, opt = {}) {
32
29
  if (!ids.length)
33
30
  return [];
34
31
  const { firestore } = this.cfg;
35
32
  const col = firestore.collection(table);
36
- return (await (opt.tx?.tx || firestore).getAll(...ids.map(id => col.doc((0, firestore_util_1.escapeDocId)(id)))))
33
+ return (await (opt.tx?.tx || firestore).getAll(...ids.map(id => col.doc(escapeDocId(id)))))
37
34
  .map(doc => {
38
35
  const data = doc.data();
39
36
  if (data === undefined)
40
37
  return;
41
38
  return {
42
- id: (0, firestore_util_1.unescapeDocId)(doc.id),
39
+ id: unescapeDocId(doc.id),
43
40
  ...data,
44
41
  };
45
42
  })
46
- .filter(js_lib_1._isTruthy);
43
+ .filter(_isTruthy);
47
44
  }
48
45
  // QUERY
49
46
  async runQuery(q, opt) {
@@ -54,11 +51,11 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
54
51
  rows: await this.getByIds(q.table, ids, opt),
55
52
  };
56
53
  }
57
- const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q, this.cfg.firestore.collection(q.table));
54
+ const firestoreQuery = dbQueryToFirestoreQuery(q, this.cfg.firestore.collection(q.table));
58
55
  let rows = await this.runFirestoreQuery(firestoreQuery, opt);
59
56
  // Special case when projection query didn't specify 'id'
60
57
  if (q._selectedFieldNames && !q._selectedFieldNames.includes('id')) {
61
- rows = rows.map(r => (0, js_lib_1._omit)(r, ['id']));
58
+ rows = rows.map(r => _omit(r, ['id']));
62
59
  }
63
60
  return { rows };
64
61
  }
@@ -66,15 +63,15 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
66
63
  return this.querySnapshotToArray(await q.get());
67
64
  }
68
65
  async runQueryCount(q, _opt) {
69
- const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q, this.cfg.firestore.collection(q.table));
66
+ const firestoreQuery = dbQueryToFirestoreQuery(q, this.cfg.firestore.collection(q.table));
70
67
  const r = await firestoreQuery.count().get();
71
68
  return r.data().count;
72
69
  }
73
70
  streamQuery(q, _opt) {
74
- const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q, this.cfg.firestore.collection(q.table));
71
+ const firestoreQuery = dbQueryToFirestoreQuery(q, this.cfg.firestore.collection(q.table));
75
72
  return firestoreQuery.stream().map(doc => {
76
73
  return {
77
- id: (0, firestore_util_1.unescapeDocId)(doc.id),
74
+ id: unescapeDocId(doc.id),
78
75
  ...doc.data(),
79
76
  };
80
77
  });
@@ -87,17 +84,17 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
87
84
  if (opt.tx) {
88
85
  const { tx } = opt.tx;
89
86
  rows.forEach(row => {
90
- (0, js_lib_1._assert)(row.id, `firestore-db doesn't support id auto-generation, but empty id was provided in saveBatch`);
91
- tx[method](col.doc((0, firestore_util_1.escapeDocId)(row.id)), (0, js_lib_1._filterUndefinedValues)(row));
87
+ _assert(row.id, `firestore-db doesn't support id auto-generation, but empty id was provided in saveBatch`);
88
+ tx[method](col.doc(escapeDocId(row.id)), _filterUndefinedValues(row));
92
89
  });
93
90
  return;
94
91
  }
95
92
  // Firestore allows max 500 items in one batch
96
- await (0, js_lib_1.pMap)((0, js_lib_1._chunk)(rows, 500), async (chunk) => {
93
+ await pMap(_chunk(rows, 500), async (chunk) => {
97
94
  const batch = firestore.batch();
98
95
  chunk.forEach(row => {
99
- (0, js_lib_1._assert)(row.id, `firestore-db doesn't support id auto-generation, but empty id was provided in saveBatch`);
100
- batch[method](col.doc((0, firestore_util_1.escapeDocId)(row.id)), (0, js_lib_1._filterUndefinedValues)(row));
96
+ _assert(row.id, `firestore-db doesn't support id auto-generation, but empty id was provided in saveBatch`);
97
+ batch[method](col.doc(escapeDocId(row.id)), _filterUndefinedValues(row));
101
98
  });
102
99
  await batch.commit();
103
100
  }, { concurrency: 1 });
@@ -110,7 +107,7 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
110
107
  ids = Array.isArray(idFilter.val) ? idFilter.val : [idFilter.val];
111
108
  }
112
109
  else {
113
- const firestoreQuery = (0, query_util_1.dbQueryToFirestoreQuery)(q.select([]), this.cfg.firestore.collection(q.table));
110
+ const firestoreQuery = dbQueryToFirestoreQuery(q.select([]), this.cfg.firestore.collection(q.table));
114
111
  ids = (await this.runFirestoreQuery(firestoreQuery)).map(obj => obj.id);
115
112
  }
116
113
  await this.deleteByIds(q.table, ids, opt);
@@ -122,14 +119,14 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
122
119
  if (opt.tx) {
123
120
  const { tx } = opt.tx;
124
121
  ids.forEach(id => {
125
- tx.delete(col.doc((0, firestore_util_1.escapeDocId)(id)));
122
+ tx.delete(col.doc(escapeDocId(id)));
126
123
  });
127
124
  return ids.length;
128
125
  }
129
- await (0, js_lib_1.pMap)((0, js_lib_1._chunk)(ids, 500), async (chunk) => {
126
+ await pMap(_chunk(ids, 500), async (chunk) => {
130
127
  const batch = firestore.batch();
131
128
  chunk.forEach(id => {
132
- batch.delete(col.doc((0, firestore_util_1.escapeDocId)(id)));
129
+ batch.delete(col.doc(escapeDocId(id)));
133
130
  });
134
131
  await batch.commit();
135
132
  });
@@ -139,7 +136,7 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
139
136
  const rows = [];
140
137
  qs.forEach(doc => {
141
138
  rows.push({
142
- id: (0, firestore_util_1.unescapeDocId)(doc.id),
139
+ id: unescapeDocId(doc.id),
143
140
  ...doc.data(),
144
141
  });
145
142
  });
@@ -170,9 +167,10 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
170
167
  const { firestore } = this.cfg;
171
168
  const col = firestore.collection(table);
172
169
  const batch = firestore.batch();
173
- for (const [id, increment] of (0, js_lib_1._stringMapEntries)(incrementMap)) {
174
- batch.set(col.doc((0, firestore_util_1.escapeDocId)(id)), {
175
- [prop]: firestore_1.FieldValue.increment(increment),
170
+ for (const [id, increment] of _stringMapEntries(incrementMap)) {
171
+ batch.set(col.doc(escapeDocId(id)), {
172
+ // todo: lazy-load FieldValue
173
+ [prop]: FieldValue.increment(increment),
176
174
  }, { merge: true });
177
175
  }
178
176
  await batch.commit();
@@ -185,15 +183,19 @@ class FirestoreDB extends db_lib_1.BaseCommonDB {
185
183
  return [];
186
184
  }
187
185
  }
188
- exports.FirestoreDB = FirestoreDB;
189
186
  /**
190
187
  * https://firebase.google.com/docs/firestore/manage-data/transactions
191
188
  */
192
- class FirestoreDBTransaction {
189
+ export class FirestoreDBTransaction {
190
+ db;
191
+ tx;
193
192
  constructor(db, tx) {
194
193
  this.db = db;
195
194
  this.tx = tx;
196
195
  }
196
+ async commit() {
197
+ throw new Error('FirestoreDBTransaction.commit() is not implemented');
198
+ }
197
199
  async rollback() {
198
200
  throw new RollbackError();
199
201
  }
@@ -207,4 +209,3 @@ class FirestoreDBTransaction {
207
209
  return await this.db.deleteByIds(table, ids, { ...opt, tx: this });
208
210
  }
209
211
  }
210
- exports.FirestoreDBTransaction = FirestoreDBTransaction;
@@ -1,14 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.escapeDocId = escapeDocId;
4
- exports.unescapeDocId = unescapeDocId;
5
1
  const SLASH = '_SLASH_';
6
- function escapeDocId(docId) {
2
+ export function escapeDocId(docId) {
7
3
  if (typeof docId === 'number')
8
4
  return String(docId);
9
5
  return docId.replaceAll('/', SLASH);
10
6
  }
11
- function unescapeDocId(docId) {
7
+ export function unescapeDocId(docId) {
12
8
  // if (typeof docId === 'number') return docId
13
9
  return docId.replaceAll(SLASH, '/');
14
10
  }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Firestore } from '@google-cloud/firestore';
2
- export * from './firestore.db';
3
- export * from './query.util';
2
+ export * from './firestore.db.js';
3
+ export * from './query.util.js';
4
4
  export { Firestore };
package/dist/index.js CHANGED
@@ -1,8 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Firestore = void 0;
4
- const tslib_1 = require("tslib");
5
- const firestore_1 = require("@google-cloud/firestore");
6
- Object.defineProperty(exports, "Firestore", { enumerable: true, get: function () { return firestore_1.Firestore; } });
7
- tslib_1.__exportStar(require("./firestore.db"), exports);
8
- tslib_1.__exportStar(require("./query.util"), exports);
1
+ import { Firestore } from '@google-cloud/firestore';
2
+ export * from './firestore.db.js';
3
+ export * from './query.util.js';
4
+ export { Firestore };
@@ -1,4 +1,4 @@
1
- import { Query } from '@google-cloud/firestore';
2
- import { DBQuery } from '@naturalcycles/db-lib';
3
- import { ObjectWithId } from '@naturalcycles/js-lib';
1
+ import type { Query } from '@google-cloud/firestore';
2
+ import type { DBQuery } from '@naturalcycles/db-lib';
3
+ import type { ObjectWithId } from '@naturalcycles/js-lib';
4
4
  export declare function dbQueryToFirestoreQuery<ROW extends ObjectWithId>(dbQuery: DBQuery<ROW>, emptyQuery: Query): Query;
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dbQueryToFirestoreQuery = dbQueryToFirestoreQuery;
4
1
  // Map DBQueryFilterOp to WhereFilterOp
5
2
  // Currently it's fully aligned!
6
3
  const OP_MAP = {
7
4
  // '=': '==',
8
5
  // in: 'array-contains',
9
6
  };
10
- function dbQueryToFirestoreQuery(dbQuery, emptyQuery) {
7
+ export function dbQueryToFirestoreQuery(dbQuery, emptyQuery) {
11
8
  // filter
12
9
  // eslint-disable-next-line unicorn/no-array-reduce
13
10
  let q = dbQuery._filters.reduce((q, f) => {
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/firestore-lib",
3
+ "type": "module",
3
4
  "scripts": {
4
5
  "prepare": "husky",
5
6
  "build": "dev-lib build",
@@ -9,18 +10,19 @@
9
10
  "lbt": "dev-lib lbt"
10
11
  },
11
12
  "dependencies": {
12
- "@google-cloud/firestore": "^7.0.0",
13
- "@naturalcycles/db-lib": "^9.0.0",
14
- "@naturalcycles/js-lib": "^14.6.0",
15
- "@naturalcycles/nodejs-lib": "^13.1.0"
13
+ "@google-cloud/firestore": "^7",
14
+ "@naturalcycles/db-lib": "^10",
15
+ "@naturalcycles/js-lib": "^15",
16
+ "@naturalcycles/nodejs-lib": "^14"
16
17
  },
17
18
  "devDependencies": {
18
- "@naturalcycles/dev-lib": "^15.22.0",
19
- "@naturalcycles/test-lib": "^1.0.3",
20
- "@types/node": "^22.7.5",
21
- "dotenv": "^16.0.0",
22
- "firebase-admin": "^12.0.0",
23
- "jest": "^29.1.2"
19
+ "@naturalcycles/dev-lib": "^18",
20
+ "@types/node": "^22",
21
+ "@vitest/coverage-v8": "^3",
22
+ "dotenv": "^16",
23
+ "firebase-admin": "^13",
24
+ "tsx": "^4",
25
+ "vitest": "^3"
24
26
  },
25
27
  "files": [
26
28
  "dist",
@@ -40,9 +42,9 @@
40
42
  "url": "https://github.com/NaturalCycles/firestore-lib"
41
43
  },
42
44
  "engines": {
43
- "node": ">=18.12.0"
45
+ "node": ">=22.12.0"
44
46
  },
45
- "version": "1.8.0",
47
+ "version": "2.0.1",
46
48
  "description": "Firestore implementation of CommonDB interface",
47
49
  "author": "Natural Cycles Team",
48
50
  "license": "MIT"
@@ -1,15 +1,13 @@
1
- import {
2
- FieldValue,
1
+ import type {
3
2
  Firestore,
4
3
  Query,
5
4
  QueryDocumentSnapshot,
6
5
  QuerySnapshot,
7
6
  Transaction,
8
7
  } from '@google-cloud/firestore'
9
- import {
10
- BaseCommonDB,
8
+ import { FieldValue } from '@google-cloud/firestore'
9
+ import type {
11
10
  CommonDB,
12
- commonDBFullSupport,
13
11
  CommonDBOptions,
14
12
  CommonDBSaveMethod,
15
13
  CommonDBSaveOptions,
@@ -21,6 +19,8 @@ import {
21
19
  DBTransactionFn,
22
20
  RunQueryResult,
23
21
  } from '@naturalcycles/db-lib'
22
+ import { BaseCommonDB, commonDBFullSupport } from '@naturalcycles/db-lib'
23
+ import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib'
24
24
  import {
25
25
  _assert,
26
26
  _chunk,
@@ -28,13 +28,11 @@ import {
28
28
  _isTruthy,
29
29
  _omit,
30
30
  _stringMapEntries,
31
- ObjectWithId,
32
31
  pMap,
33
- StringMap,
34
32
  } from '@naturalcycles/js-lib'
35
- import { ReadableTyped } from '@naturalcycles/nodejs-lib'
36
- import { escapeDocId, unescapeDocId } from './firestore.util'
37
- import { dbQueryToFirestoreQuery } from './query.util'
33
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
34
+ import { escapeDocId, unescapeDocId } from './firestore.util.js'
35
+ import { dbQueryToFirestoreQuery } from './query.util.js'
38
36
 
39
37
  export interface FirestoreDBCfg {
40
38
  firestore: Firestore
@@ -306,6 +304,7 @@ export class FirestoreDB extends BaseCommonDB implements CommonDB {
306
304
  batch.set(
307
305
  col.doc(escapeDocId(id)),
308
306
  {
307
+ // todo: lazy-load FieldValue
309
308
  [prop]: FieldValue.increment(increment),
310
309
  },
311
310
  { merge: true },
@@ -334,6 +333,10 @@ export class FirestoreDBTransaction implements DBTransaction {
334
333
  public tx: Transaction,
335
334
  ) {}
336
335
 
336
+ async commit(): Promise<void> {
337
+ throw new Error('FirestoreDBTransaction.commit() is not implemented')
338
+ }
339
+
337
340
  async rollback(): Promise<void> {
338
341
  throw new RollbackError()
339
342
  }
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { Firestore } from '@google-cloud/firestore'
2
- export * from './firestore.db'
3
- export * from './query.util'
2
+ export * from './firestore.db.js'
3
+ export * from './query.util.js'
4
4
  export { Firestore }
package/src/query.util.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Query, WhereFilterOp } from '@google-cloud/firestore'
2
- import { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
3
- import { ObjectWithId } from '@naturalcycles/js-lib'
1
+ import type { Query, WhereFilterOp } from '@google-cloud/firestore'
2
+ import type { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
3
+ import type { ObjectWithId } from '@naturalcycles/js-lib'
4
4
 
5
5
  // Map DBQueryFilterOp to WhereFilterOp
6
6
  // Currently it's fully aligned!