@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.
- package/dist/firestore.db.d.ts +6 -4
- package/dist/firestore.db.js +41 -40
- package/dist/firestore.util.js +2 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -8
- package/dist/query.util.d.ts +3 -3
- package/dist/query.util.js +1 -4
- package/package.json +14 -12
- package/src/firestore.db.ts +13 -10
- package/src/index.ts +2 -2
- package/src/query.util.ts +3 -3
package/dist/firestore.db.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Firestore, Query, Transaction } from '@google-cloud/firestore';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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>;
|
package/dist/firestore.db.js
CHANGED
|
@@ -1,49 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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(
|
|
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:
|
|
39
|
+
id: unescapeDocId(doc.id),
|
|
43
40
|
...data,
|
|
44
41
|
};
|
|
45
42
|
})
|
|
46
|
-
.filter(
|
|
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 =
|
|
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 =>
|
|
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 =
|
|
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 =
|
|
71
|
+
const firestoreQuery = dbQueryToFirestoreQuery(q, this.cfg.firestore.collection(q.table));
|
|
75
72
|
return firestoreQuery.stream().map(doc => {
|
|
76
73
|
return {
|
|
77
|
-
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
|
-
|
|
91
|
-
tx[method](col.doc(
|
|
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
|
|
93
|
+
await pMap(_chunk(rows, 500), async (chunk) => {
|
|
97
94
|
const batch = firestore.batch();
|
|
98
95
|
chunk.forEach(row => {
|
|
99
|
-
|
|
100
|
-
batch[method](col.doc(
|
|
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 =
|
|
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(
|
|
122
|
+
tx.delete(col.doc(escapeDocId(id)));
|
|
126
123
|
});
|
|
127
124
|
return ids.length;
|
|
128
125
|
}
|
|
129
|
-
await
|
|
126
|
+
await pMap(_chunk(ids, 500), async (chunk) => {
|
|
130
127
|
const batch = firestore.batch();
|
|
131
128
|
chunk.forEach(id => {
|
|
132
|
-
batch.delete(col.doc(
|
|
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:
|
|
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
|
|
174
|
-
batch.set(col.doc(
|
|
175
|
-
|
|
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;
|
package/dist/firestore.util.js
CHANGED
|
@@ -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
package/dist/index.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 };
|
package/dist/query.util.d.ts
CHANGED
|
@@ -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;
|
package/dist/query.util.js
CHANGED
|
@@ -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
|
|
13
|
-
"@naturalcycles/db-lib": "^
|
|
14
|
-
"@naturalcycles/js-lib": "^
|
|
15
|
-
"@naturalcycles/nodejs-lib": "^
|
|
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": "^
|
|
19
|
-
"@
|
|
20
|
-
"@
|
|
21
|
-
"dotenv": "^16
|
|
22
|
-
"firebase-admin": "^
|
|
23
|
-
"
|
|
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": ">=
|
|
45
|
+
"node": ">=22.12.0"
|
|
44
46
|
},
|
|
45
|
-
"version": "
|
|
47
|
+
"version": "2.0.1",
|
|
46
48
|
"description": "Firestore implementation of CommonDB interface",
|
|
47
49
|
"author": "Natural Cycles Team",
|
|
48
50
|
"license": "MIT"
|
package/src/firestore.db.ts
CHANGED
|
@@ -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
|
-
|
|
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
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!
|