@naturalcycles/datastore-lib 3.39.2 → 3.39.4
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/DatastoreStreamReadable.d.ts +2 -2
- package/dist/datastore.db.d.ts +8 -6
- package/dist/datastore.db.js +45 -24
- package/dist/datastore.model.d.ts +2 -2
- package/dist/datastoreKeyValueDB.d.ts +3 -4
- package/dist/query.util.d.ts +4 -4
- package/dist/query.util.js +2 -3
- package/package.json +11 -9
- package/src/DatastoreStreamReadable.ts +3 -2
- package/src/datastore.db.ts +84 -39
- package/src/datastore.model.ts +6 -2
- package/src/datastoreKeyValueDB.ts +6 -10
- package/src/query.util.ts +5 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
|
-
import { Query } from '@google-cloud/datastore';
|
|
3
|
-
import { CommonLogger } from '@naturalcycles/js-lib';
|
|
2
|
+
import type { Query } from '@google-cloud/datastore';
|
|
3
|
+
import type { CommonLogger } from '@naturalcycles/js-lib';
|
|
4
4
|
import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
5
5
|
import type { DatastoreDBStreamOptions } from './datastore.model';
|
|
6
6
|
export declare class DatastoreStreamReadable<T = any> extends Readable implements ReadableTyped<T> {
|
package/dist/datastore.db.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Datastore, Key } from '@google-cloud/datastore';
|
|
2
|
-
import {
|
|
3
|
-
import { BaseCommonDB
|
|
4
|
-
import { CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
5
|
-
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
6
|
-
import { DatastoreDBCfg, DatastoreDBOptions, DatastoreDBReadOptions, DatastoreDBSaveOptions, DatastoreDBStreamOptions, DatastorePropertyStats, DatastoreStats } from './datastore.model';
|
|
1
|
+
import type { Datastore, Key, Transaction } from '@google-cloud/datastore';
|
|
2
|
+
import type { CommonDB, CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions, CommonDBSupport, CommonDBTransactionOptions, DBQuery, DBTransaction, DBTransactionFn, RunQueryResult } from '@naturalcycles/db-lib';
|
|
3
|
+
import { BaseCommonDB } from '@naturalcycles/db-lib';
|
|
4
|
+
import type { CommonLogger, JsonSchemaObject, JsonSchemaRootObject, ObjectWithId } from '@naturalcycles/js-lib';
|
|
5
|
+
import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
6
|
+
import type { DatastoreDBCfg, DatastoreDBOptions, DatastoreDBReadOptions, DatastoreDBSaveOptions, DatastoreDBStreamOptions, DatastorePropertyStats, DatastoreStats } from './datastore.model';
|
|
7
7
|
/**
|
|
8
8
|
* Datastore API:
|
|
9
9
|
* https://googlecloudplatform.github.io/google-cloud-node/#/docs/datastore/1.0.3/datastore
|
|
@@ -21,6 +21,8 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
21
21
|
*/
|
|
22
22
|
protected KEY: symbol;
|
|
23
23
|
ds(): Datastore;
|
|
24
|
+
private getPropertyFilter;
|
|
25
|
+
private getDatastoreLib;
|
|
24
26
|
ping(): Promise<void>;
|
|
25
27
|
getByIds<ROW extends ObjectWithId>(table: string, ids: string[], opt?: DatastoreDBReadOptions): Promise<ROW[]>;
|
|
26
28
|
runQuery<ROW extends ObjectWithId>(dbQuery: DBQuery<ROW>, opt?: DatastoreDBReadOptions): Promise<RunQueryResult<ROW>>;
|
package/dist/datastore.db.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DatastoreDBTransaction = exports.DatastoreDB = void 0;
|
|
4
|
-
const datastore_1 = require("@google-cloud/datastore");
|
|
5
4
|
const db_lib_1 = require("@naturalcycles/db-lib");
|
|
6
5
|
const js_lib_1 = require("@naturalcycles/js-lib");
|
|
7
6
|
const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
|
|
@@ -50,9 +49,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
50
49
|
ds() {
|
|
51
50
|
if (!this.cachedDatastore) {
|
|
52
51
|
(0, js_lib_1._assert)(process.env['APP_ENV'] !== 'test', 'DatastoreDB cannot be used in Test env, please use InMemoryDB');
|
|
53
|
-
|
|
54
|
-
const datastoreLib = require('@google-cloud/datastore');
|
|
55
|
-
const DS = datastoreLib.Datastore;
|
|
52
|
+
const DS = this.getDatastoreLib().Datastore;
|
|
56
53
|
this.cfg.projectId ||= this.cfg.credentials?.project_id || process.env['GOOGLE_CLOUD_PROJECT'];
|
|
57
54
|
if (this.cfg.projectId) {
|
|
58
55
|
this.cfg.logger.log(`DatastoreDB connected to ${(0, nodejs_lib_1.boldWhite)(this.cfg.projectId)}`);
|
|
@@ -68,6 +65,13 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
68
65
|
}
|
|
69
66
|
return this.cachedDatastore;
|
|
70
67
|
}
|
|
68
|
+
getPropertyFilter() {
|
|
69
|
+
return this.getDatastoreLib().PropertyFilter;
|
|
70
|
+
}
|
|
71
|
+
getDatastoreLib() {
|
|
72
|
+
// Lazy-loading
|
|
73
|
+
return require('@google-cloud/datastore');
|
|
74
|
+
}
|
|
71
75
|
async ping() {
|
|
72
76
|
await this.getAllStats();
|
|
73
77
|
}
|
|
@@ -86,23 +90,33 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
86
90
|
});
|
|
87
91
|
rows = r[0];
|
|
88
92
|
}
|
|
89
|
-
catch {
|
|
93
|
+
catch (err) {
|
|
94
|
+
if (!(err instanceof js_lib_1.TimeoutError)) {
|
|
95
|
+
// Not a timeout error, re-throw
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
90
98
|
this.cfg.logger.log('datastore recreated on error');
|
|
91
99
|
// This is to debug "GCP Datastore Timeout issue"
|
|
92
100
|
const datastoreLib = require('@google-cloud/datastore');
|
|
93
101
|
const DS = datastoreLib.Datastore;
|
|
94
102
|
this.cachedDatastore = new DS(this.cfg);
|
|
95
103
|
// Second try (will throw)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
try {
|
|
105
|
+
const r = await (0, js_lib_1.pRetry)(() => (opt.tx?.tx || this.ds()).get(keys, dsOpt), {
|
|
106
|
+
...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
|
|
107
|
+
maxAttempts: 3,
|
|
108
|
+
timeout: this.cfg.timeout,
|
|
109
|
+
});
|
|
110
|
+
rows = r[0];
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
if (err instanceof js_lib_1.TimeoutError) {
|
|
114
|
+
(0, js_lib_1._errorDataAppend)(err, {
|
|
115
|
+
fingerprint: [DATASTORE_TIMEOUT],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
106
120
|
}
|
|
107
121
|
}
|
|
108
122
|
else {
|
|
@@ -128,7 +142,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
128
142
|
rows: await this.getByIds(dbQuery.table, ids, opt),
|
|
129
143
|
};
|
|
130
144
|
}
|
|
131
|
-
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery, this.ds().createQuery(dbQuery.table));
|
|
145
|
+
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery, this.ds().createQuery(dbQuery.table), this.getPropertyFilter());
|
|
132
146
|
const dsOpt = this.getRunQueryOptions(opt);
|
|
133
147
|
const qr = await this.runDatastoreQuery(q, dsOpt);
|
|
134
148
|
// Special case when projection query didn't specify 'id'
|
|
@@ -138,7 +152,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
138
152
|
return qr;
|
|
139
153
|
}
|
|
140
154
|
async runQueryCount(dbQuery, opt = {}) {
|
|
141
|
-
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery.select([]), this.ds().createQuery(dbQuery.table));
|
|
155
|
+
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery.select([]), this.ds().createQuery(dbQuery.table), this.getPropertyFilter());
|
|
142
156
|
const aq = this.ds().createAggregationQuery(q).count('count');
|
|
143
157
|
const dsOpt = this.getRunQueryOptions(opt);
|
|
144
158
|
const [entities] = await this.ds().runAggregationQuery(aq, dsOpt);
|
|
@@ -163,7 +177,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
163
177
|
: this.ds().runQueryStream(q, dsOpt)).map(chunk => this.mapId(chunk));
|
|
164
178
|
}
|
|
165
179
|
streamQuery(dbQuery, opt) {
|
|
166
|
-
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery, this.ds().createQuery(dbQuery.table));
|
|
180
|
+
const q = (0, query_util_1.dbQueryToDatastoreQuery)(dbQuery, this.ds().createQuery(dbQuery.table), this.getPropertyFilter());
|
|
167
181
|
return this.runQueryStream(q, opt);
|
|
168
182
|
}
|
|
169
183
|
// https://github.com/GoogleCloudPlatform/nodejs-getting-started/blob/master/2-structured-data/books/model-datastore.js
|
|
@@ -189,6 +203,11 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
189
203
|
}
|
|
190
204
|
}
|
|
191
205
|
catch (err) {
|
|
206
|
+
if (err instanceof js_lib_1.TimeoutError) {
|
|
207
|
+
(0, js_lib_1._errorDataAppend)(err, {
|
|
208
|
+
fingerprint: [DATASTORE_TIMEOUT],
|
|
209
|
+
});
|
|
210
|
+
}
|
|
192
211
|
// console.log(`datastore.save ${kind}`, { obj, entity })
|
|
193
212
|
this.cfg.logger.error(`error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`, err);
|
|
194
213
|
throw err;
|
|
@@ -200,7 +219,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
200
219
|
const ids = idFilter.op === '==' ? [idFilter.val] : idFilter.val;
|
|
201
220
|
return await this.deleteByIds(q.table, ids, opt);
|
|
202
221
|
}
|
|
203
|
-
const datastoreQuery = (0, query_util_1.dbQueryToDatastoreQuery)(q.select([]), this.ds().createQuery(q.table));
|
|
222
|
+
const datastoreQuery = (0, query_util_1.dbQueryToDatastoreQuery)(q.select([]), this.ds().createQuery(q.table), this.getPropertyFilter());
|
|
204
223
|
const dsOpt = this.getRunQueryOptions(opt);
|
|
205
224
|
const { rows } = await this.runDatastoreQuery(datastoreQuery, dsOpt);
|
|
206
225
|
return await this.deleteByIds(q.table, rows.map(obj => obj.id), opt);
|
|
@@ -241,10 +260,11 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
241
260
|
* Returns undefined e.g when Table is non-existing
|
|
242
261
|
*/
|
|
243
262
|
async getStats(table) {
|
|
263
|
+
const { PropertyFilter } = this.getDatastoreLib();
|
|
244
264
|
const q = this.ds()
|
|
245
265
|
.createQuery('__Stat_Kind__')
|
|
246
266
|
// .filter('kind_name', table)
|
|
247
|
-
.filter(new
|
|
267
|
+
.filter(new PropertyFilter('kind_name', '=', table))
|
|
248
268
|
.limit(1);
|
|
249
269
|
const [statsArray] = await this.ds().runQuery(q);
|
|
250
270
|
const [stats] = statsArray;
|
|
@@ -258,7 +278,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
258
278
|
const q = this.ds()
|
|
259
279
|
.createQuery('__Stat_PropertyType_PropertyName_Kind__')
|
|
260
280
|
// .filter('kind_name', table)
|
|
261
|
-
.filter(new
|
|
281
|
+
.filter(new (this.getPropertyFilter())('kind_name', '=', table));
|
|
262
282
|
const [stats] = await this.ds().runQuery(q);
|
|
263
283
|
return stats;
|
|
264
284
|
}
|
|
@@ -379,9 +399,10 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
|
|
|
379
399
|
logFailures: true,
|
|
380
400
|
// logAll: true,
|
|
381
401
|
logger: this.cfg.logger,
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
402
|
+
// not appending fingerprint here, otherwise it would just group all kinds of errors, not just Timeout errors
|
|
403
|
+
// errorData: {
|
|
404
|
+
// fingerprint: [DATASTORE_TIMEOUT],
|
|
405
|
+
// },
|
|
385
406
|
};
|
|
386
407
|
}
|
|
387
408
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DatastoreOptions, Key } from '@google-cloud/datastore';
|
|
2
|
-
import { CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib';
|
|
3
|
-
import { CommonLogger, NumberOfSeconds, ObjectWithId } from '@naturalcycles/js-lib';
|
|
2
|
+
import type { CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib';
|
|
3
|
+
import type { CommonLogger, NumberOfSeconds, ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
4
|
export interface DatastorePayload<T = any> {
|
|
5
5
|
key: Key;
|
|
6
6
|
data: T;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
|
|
2
|
-
import {
|
|
3
|
-
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
1
|
+
import type { CommonKeyValueDB, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib';
|
|
2
|
+
import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
4
3
|
import { DatastoreDB } from './datastore.db';
|
|
5
|
-
import { DatastoreDBCfg } from './datastore.model';
|
|
4
|
+
import type { DatastoreDBCfg } from './datastore.model';
|
|
6
5
|
export interface DatastoreKeyValueDBCfg extends DatastoreDBCfg {
|
|
7
6
|
}
|
|
8
7
|
export declare class DatastoreKeyValueDB implements CommonKeyValueDB {
|
package/dist/query.util.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Query } from '@google-cloud/datastore';
|
|
2
|
-
import { DBQuery } from '@naturalcycles/db-lib';
|
|
3
|
-
import { ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
|
-
export declare function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(dbQuery: Readonly<DBQuery<ROW>>, emptyQuery: Query): Query;
|
|
1
|
+
import type { PropertyFilter, Query } from '@google-cloud/datastore';
|
|
2
|
+
import type { DBQuery } from '@naturalcycles/db-lib';
|
|
3
|
+
import type { ObjectWithId } from '@naturalcycles/js-lib';
|
|
4
|
+
export declare function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(dbQuery: Readonly<DBQuery<ROW>>, emptyQuery: Query, propertyFilterClass: typeof PropertyFilter): Query;
|
package/dist/query.util.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.dbQueryToDatastoreQuery = dbQueryToDatastoreQuery;
|
|
4
|
-
const datastore_1 = require("@google-cloud/datastore");
|
|
5
4
|
const FNAME_MAP = {
|
|
6
5
|
id: '__key__',
|
|
7
6
|
};
|
|
@@ -10,7 +9,7 @@ const OP_MAP = {
|
|
|
10
9
|
in: 'IN',
|
|
11
10
|
'not-in': 'NOT_IN',
|
|
12
11
|
};
|
|
13
|
-
function dbQueryToDatastoreQuery(dbQuery, emptyQuery) {
|
|
12
|
+
function dbQueryToDatastoreQuery(dbQuery, emptyQuery, propertyFilterClass) {
|
|
14
13
|
let q = emptyQuery;
|
|
15
14
|
// filter
|
|
16
15
|
for (const f of dbQuery._filters) {
|
|
@@ -24,7 +23,7 @@ function dbQueryToDatastoreQuery(dbQuery, emptyQuery) {
|
|
|
24
23
|
let { op, val } = f;
|
|
25
24
|
if (val === undefined)
|
|
26
25
|
val = null;
|
|
27
|
-
q = q.filter(new
|
|
26
|
+
q = q.filter(new propertyFilterClass(f.name, OP_MAP[op] || op, val));
|
|
28
27
|
}
|
|
29
28
|
// limit
|
|
30
29
|
q = q.limit(dbQuery._limitValue || 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/datastore-lib",
|
|
3
|
-
"version": "3.39.
|
|
3
|
+
"version": "3.39.4",
|
|
4
4
|
"description": "Opinionated library to work with Google Datastore",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepare": "husky",
|
|
@@ -11,15 +11,17 @@
|
|
|
11
11
|
"lbt": "dev-lib lbt"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@google-cloud/datastore": "^9
|
|
15
|
-
"@naturalcycles/db-lib": "^
|
|
16
|
-
"@naturalcycles/js-lib": "^14
|
|
17
|
-
"@naturalcycles/nodejs-lib": "^13
|
|
14
|
+
"@google-cloud/datastore": "^9",
|
|
15
|
+
"@naturalcycles/db-lib": "^10",
|
|
16
|
+
"@naturalcycles/js-lib": "^14",
|
|
17
|
+
"@naturalcycles/nodejs-lib": "^13"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@naturalcycles/dev-lib": "^
|
|
21
|
-
"@types/node": "^22
|
|
22
|
-
"
|
|
20
|
+
"@naturalcycles/dev-lib": "^17",
|
|
21
|
+
"@types/node": "^22",
|
|
22
|
+
"@vitest/coverage-v8": "^3",
|
|
23
|
+
"tsx": "^4.19.3",
|
|
24
|
+
"vitest": "^3"
|
|
23
25
|
},
|
|
24
26
|
"files": [
|
|
25
27
|
"dist",
|
|
@@ -32,7 +34,7 @@
|
|
|
32
34
|
"main": "dist/index.js",
|
|
33
35
|
"types": "dist/index.d.ts",
|
|
34
36
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
37
|
+
"node": ">=22.12.0"
|
|
36
38
|
},
|
|
37
39
|
"publishConfig": {
|
|
38
40
|
"access": "public"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Readable } from 'node:stream'
|
|
2
|
-
import { Query } from '@google-cloud/datastore'
|
|
2
|
+
import type { Query } from '@google-cloud/datastore'
|
|
3
3
|
import type { RunQueryInfo, RunQueryOptions } from '@google-cloud/datastore/build/src/query'
|
|
4
|
-
import {
|
|
4
|
+
import type { CommonLogger, UnixTimestampMillis } from '@naturalcycles/js-lib'
|
|
5
|
+
import { _ms, pRetry } from '@naturalcycles/js-lib'
|
|
5
6
|
import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
6
7
|
import type { DatastoreDBStreamOptions } from './datastore.model'
|
|
7
8
|
|
package/src/datastore.db.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import type { Datastore, Key, Query } from '@google-cloud/datastore'
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
BaseCommonDB,
|
|
1
|
+
import type { Datastore, Key, PropertyFilter, Query, Transaction } from '@google-cloud/datastore'
|
|
2
|
+
import type { RunQueryOptions } from '@google-cloud/datastore/build/src/query'
|
|
3
|
+
import type {
|
|
6
4
|
CommonDB,
|
|
7
|
-
commonDBFullSupport,
|
|
8
5
|
CommonDBOptions,
|
|
9
6
|
CommonDBReadOptions,
|
|
10
7
|
CommonDBSaveMethod,
|
|
@@ -16,12 +13,9 @@ import {
|
|
|
16
13
|
DBTransactionFn,
|
|
17
14
|
RunQueryResult,
|
|
18
15
|
} from '@naturalcycles/db-lib'
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
_chunk,
|
|
22
|
-
_omit,
|
|
16
|
+
import { BaseCommonDB, commonDBFullSupport } from '@naturalcycles/db-lib'
|
|
17
|
+
import type {
|
|
23
18
|
CommonLogger,
|
|
24
|
-
commonLoggerMinLevel,
|
|
25
19
|
JsonSchemaAny,
|
|
26
20
|
JsonSchemaBoolean,
|
|
27
21
|
JsonSchemaNull,
|
|
@@ -30,14 +24,23 @@ import {
|
|
|
30
24
|
JsonSchemaRootObject,
|
|
31
25
|
JsonSchemaString,
|
|
32
26
|
ObjectWithId,
|
|
27
|
+
PRetryOptions,
|
|
28
|
+
} from '@naturalcycles/js-lib'
|
|
29
|
+
import {
|
|
30
|
+
_assert,
|
|
31
|
+
_chunk,
|
|
32
|
+
_errorDataAppend,
|
|
33
|
+
_omit,
|
|
34
|
+
commonLoggerMinLevel,
|
|
33
35
|
pMap,
|
|
34
36
|
pRetry,
|
|
35
37
|
pRetryFn,
|
|
36
|
-
PRetryOptions,
|
|
37
38
|
pTimeout,
|
|
39
|
+
TimeoutError,
|
|
38
40
|
} from '@naturalcycles/js-lib'
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
+
import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
42
|
+
import { boldWhite } from '@naturalcycles/nodejs-lib'
|
|
43
|
+
import type {
|
|
41
44
|
DatastoreDBCfg,
|
|
42
45
|
DatastoreDBOptions,
|
|
43
46
|
DatastoreDBReadOptions,
|
|
@@ -46,8 +49,8 @@ import {
|
|
|
46
49
|
DatastorePayload,
|
|
47
50
|
DatastorePropertyStats,
|
|
48
51
|
DatastoreStats,
|
|
49
|
-
DatastoreType,
|
|
50
52
|
} from './datastore.model'
|
|
53
|
+
import { DatastoreType } from './datastore.model'
|
|
51
54
|
import { DatastoreStreamReadable } from './DatastoreStreamReadable'
|
|
52
55
|
import { dbQueryToDatastoreQuery } from './query.util'
|
|
53
56
|
|
|
@@ -112,9 +115,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
112
115
|
'DatastoreDB cannot be used in Test env, please use InMemoryDB',
|
|
113
116
|
)
|
|
114
117
|
|
|
115
|
-
|
|
116
|
-
const datastoreLib = require('@google-cloud/datastore')
|
|
117
|
-
const DS = datastoreLib.Datastore as typeof Datastore
|
|
118
|
+
const DS = this.getDatastoreLib().Datastore as typeof Datastore
|
|
118
119
|
this.cfg.projectId ||= this.cfg.credentials?.project_id || process.env['GOOGLE_CLOUD_PROJECT']
|
|
119
120
|
|
|
120
121
|
if (this.cfg.projectId) {
|
|
@@ -134,6 +135,15 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
134
135
|
return this.cachedDatastore
|
|
135
136
|
}
|
|
136
137
|
|
|
138
|
+
private getPropertyFilter(): typeof PropertyFilter {
|
|
139
|
+
return this.getDatastoreLib().PropertyFilter
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private getDatastoreLib(): any {
|
|
143
|
+
// Lazy-loading
|
|
144
|
+
return require('@google-cloud/datastore')
|
|
145
|
+
}
|
|
146
|
+
|
|
137
147
|
override async ping(): Promise<void> {
|
|
138
148
|
await this.getAllStats()
|
|
139
149
|
}
|
|
@@ -160,7 +170,12 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
160
170
|
},
|
|
161
171
|
)
|
|
162
172
|
rows = r[0]
|
|
163
|
-
} catch {
|
|
173
|
+
} catch (err) {
|
|
174
|
+
if (!(err instanceof TimeoutError)) {
|
|
175
|
+
// Not a timeout error, re-throw
|
|
176
|
+
throw err
|
|
177
|
+
}
|
|
178
|
+
|
|
164
179
|
this.cfg.logger.log('datastore recreated on error')
|
|
165
180
|
|
|
166
181
|
// This is to debug "GCP Datastore Timeout issue"
|
|
@@ -169,19 +184,24 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
169
184
|
this.cachedDatastore = new DS(this.cfg)
|
|
170
185
|
|
|
171
186
|
// Second try (will throw)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// This error will be grouped ACROSS all endpoints and usages
|
|
180
|
-
fingerprint: [DATASTORE_TIMEOUT],
|
|
187
|
+
try {
|
|
188
|
+
const r = await pRetry(
|
|
189
|
+
() => ((opt.tx as DatastoreDBTransaction)?.tx || this.ds()).get(keys, dsOpt),
|
|
190
|
+
{
|
|
191
|
+
...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
|
|
192
|
+
maxAttempts: 3,
|
|
193
|
+
timeout: this.cfg.timeout,
|
|
181
194
|
},
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
195
|
+
)
|
|
196
|
+
rows = r[0]
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (err instanceof TimeoutError) {
|
|
199
|
+
_errorDataAppend(err, {
|
|
200
|
+
fingerprint: [DATASTORE_TIMEOUT],
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
throw err
|
|
204
|
+
}
|
|
185
205
|
}
|
|
186
206
|
} else {
|
|
187
207
|
rows = await pRetry(
|
|
@@ -219,7 +239,11 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
219
239
|
}
|
|
220
240
|
}
|
|
221
241
|
|
|
222
|
-
const q = dbQueryToDatastoreQuery(
|
|
242
|
+
const q = dbQueryToDatastoreQuery(
|
|
243
|
+
dbQuery,
|
|
244
|
+
this.ds().createQuery(dbQuery.table),
|
|
245
|
+
this.getPropertyFilter(),
|
|
246
|
+
)
|
|
223
247
|
const dsOpt = this.getRunQueryOptions(opt)
|
|
224
248
|
const qr = await this.runDatastoreQuery<ROW>(q, dsOpt)
|
|
225
249
|
|
|
@@ -235,7 +259,11 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
235
259
|
dbQuery: DBQuery<ROW>,
|
|
236
260
|
opt: DatastoreDBReadOptions = {},
|
|
237
261
|
): Promise<number> {
|
|
238
|
-
const q = dbQueryToDatastoreQuery(
|
|
262
|
+
const q = dbQueryToDatastoreQuery(
|
|
263
|
+
dbQuery.select([]),
|
|
264
|
+
this.ds().createQuery(dbQuery.table),
|
|
265
|
+
this.getPropertyFilter(),
|
|
266
|
+
)
|
|
239
267
|
const aq = this.ds().createAggregationQuery(q).count('count')
|
|
240
268
|
const dsOpt = this.getRunQueryOptions(opt)
|
|
241
269
|
const [entities] = await this.ds().runAggregationQuery(aq, dsOpt)
|
|
@@ -281,7 +309,11 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
281
309
|
dbQuery: DBQuery<ROW>,
|
|
282
310
|
opt?: DatastoreDBStreamOptions,
|
|
283
311
|
): ReadableTyped<ROW> {
|
|
284
|
-
const q = dbQueryToDatastoreQuery(
|
|
312
|
+
const q = dbQueryToDatastoreQuery(
|
|
313
|
+
dbQuery,
|
|
314
|
+
this.ds().createQuery(dbQuery.table),
|
|
315
|
+
this.getPropertyFilter(),
|
|
316
|
+
)
|
|
285
317
|
return this.runQueryStream(q, opt)
|
|
286
318
|
}
|
|
287
319
|
|
|
@@ -319,6 +351,12 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
319
351
|
})
|
|
320
352
|
}
|
|
321
353
|
} catch (err) {
|
|
354
|
+
if (err instanceof TimeoutError) {
|
|
355
|
+
_errorDataAppend(err, {
|
|
356
|
+
fingerprint: [DATASTORE_TIMEOUT],
|
|
357
|
+
})
|
|
358
|
+
}
|
|
359
|
+
|
|
322
360
|
// console.log(`datastore.save ${kind}`, { obj, entity })
|
|
323
361
|
this.cfg.logger.error(
|
|
324
362
|
`error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`,
|
|
@@ -339,7 +377,11 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
339
377
|
return await this.deleteByIds(q.table, ids, opt)
|
|
340
378
|
}
|
|
341
379
|
|
|
342
|
-
const datastoreQuery = dbQueryToDatastoreQuery(
|
|
380
|
+
const datastoreQuery = dbQueryToDatastoreQuery(
|
|
381
|
+
q.select([]),
|
|
382
|
+
this.ds().createQuery(q.table),
|
|
383
|
+
this.getPropertyFilter(),
|
|
384
|
+
)
|
|
343
385
|
const dsOpt = this.getRunQueryOptions(opt)
|
|
344
386
|
const { rows } = await this.runDatastoreQuery<ROW>(datastoreQuery, dsOpt)
|
|
345
387
|
return await this.deleteByIds(
|
|
@@ -401,6 +443,8 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
401
443
|
* Returns undefined e.g when Table is non-existing
|
|
402
444
|
*/
|
|
403
445
|
async getStats(table: string): Promise<DatastoreStats | undefined> {
|
|
446
|
+
const { PropertyFilter } = this.getDatastoreLib()
|
|
447
|
+
|
|
404
448
|
const q = this.ds()
|
|
405
449
|
.createQuery('__Stat_Kind__')
|
|
406
450
|
// .filter('kind_name', table)
|
|
@@ -420,7 +464,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
420
464
|
const q = this.ds()
|
|
421
465
|
.createQuery('__Stat_PropertyType_PropertyName_Kind__')
|
|
422
466
|
// .filter('kind_name', table)
|
|
423
|
-
.filter(new
|
|
467
|
+
.filter(new (this.getPropertyFilter())('kind_name', '=', table))
|
|
424
468
|
const [stats] = await this.ds().runQuery(q)
|
|
425
469
|
return stats
|
|
426
470
|
}
|
|
@@ -556,9 +600,10 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
|
|
|
556
600
|
logFailures: true,
|
|
557
601
|
// logAll: true,
|
|
558
602
|
logger: this.cfg.logger,
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
603
|
+
// not appending fingerprint here, otherwise it would just group all kinds of errors, not just Timeout errors
|
|
604
|
+
// errorData: {
|
|
605
|
+
// fingerprint: [DATASTORE_TIMEOUT],
|
|
606
|
+
// },
|
|
562
607
|
}
|
|
563
608
|
}
|
|
564
609
|
|
package/src/datastore.model.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { DatastoreOptions, Key } from '@google-cloud/datastore'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
CommonDBOptions,
|
|
4
|
+
CommonDBReadOptions,
|
|
5
|
+
CommonDBSaveOptions,
|
|
6
|
+
} from '@naturalcycles/db-lib'
|
|
7
|
+
import type { CommonLogger, NumberOfSeconds, ObjectWithId } from '@naturalcycles/js-lib'
|
|
4
8
|
|
|
5
9
|
export interface DatastorePayload<T = any> {
|
|
6
10
|
key: Key
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from '@naturalcycles/db-lib'
|
|
7
|
-
import { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB'
|
|
8
|
-
import { AppError, ObjectWithId } from '@naturalcycles/js-lib'
|
|
9
|
-
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
1
|
+
import type { CommonKeyValueDB, IncrementTuple, KeyValueDBTuple } from '@naturalcycles/db-lib'
|
|
2
|
+
import { commonKeyValueDBFullSupport, DBQuery } from '@naturalcycles/db-lib'
|
|
3
|
+
import type { ObjectWithId } from '@naturalcycles/js-lib'
|
|
4
|
+
import { AppError } from '@naturalcycles/js-lib'
|
|
5
|
+
import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
10
6
|
import { DatastoreDB } from './datastore.db'
|
|
11
|
-
import { DatastoreDBCfg } from './datastore.model'
|
|
7
|
+
import type { DatastoreDBCfg } from './datastore.model'
|
|
12
8
|
|
|
13
9
|
interface KVObject {
|
|
14
10
|
id: string
|
package/src/query.util.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { PropertyFilter, Query } from '@google-cloud/datastore'
|
|
2
|
-
import { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
|
|
3
|
-
import { ObjectWithId, StringMap } from '@naturalcycles/js-lib'
|
|
1
|
+
import type { PropertyFilter, Query } from '@google-cloud/datastore'
|
|
2
|
+
import type { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
|
|
3
|
+
import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib'
|
|
4
4
|
|
|
5
5
|
const FNAME_MAP: StringMap = {
|
|
6
6
|
id: '__key__',
|
|
@@ -15,6 +15,7 @@ const OP_MAP: Partial<Record<DBQueryFilterOperator, string>> = {
|
|
|
15
15
|
export function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(
|
|
16
16
|
dbQuery: Readonly<DBQuery<ROW>>,
|
|
17
17
|
emptyQuery: Query,
|
|
18
|
+
propertyFilterClass: typeof PropertyFilter,
|
|
18
19
|
): Query {
|
|
19
20
|
let q = emptyQuery
|
|
20
21
|
|
|
@@ -30,7 +31,7 @@ export function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(
|
|
|
30
31
|
// `a == null` will return just that - rows with null values
|
|
31
32
|
let { op, val } = f
|
|
32
33
|
if (val === undefined) val = null
|
|
33
|
-
q = q.filter(new
|
|
34
|
+
q = q.filter(new propertyFilterClass(f.name as string, OP_MAP[op] || (op as any), val))
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
// limit
|