@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.
@@ -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> {
@@ -1,9 +1,9 @@
1
- import type { Datastore, Key } from '@google-cloud/datastore';
2
- import { Transaction } from '@google-cloud/datastore';
3
- import { BaseCommonDB, CommonDB, CommonDBOptions, CommonDBReadOptions, CommonDBSaveOptions, CommonDBSupport, CommonDBTransactionOptions, DBQuery, DBTransaction, DBTransactionFn, RunQueryResult } from '@naturalcycles/db-lib';
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>>;
@@ -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
- // Lazy-loading
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
- const r = await (0, js_lib_1.pRetry)(() => (opt.tx?.tx || this.ds()).get(keys, dsOpt), {
97
- ...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
98
- maxAttempts: 3,
99
- timeout: this.cfg.timeout,
100
- errorData: {
101
- // This error will be grouped ACROSS all endpoints and usages
102
- fingerprint: [DATASTORE_TIMEOUT],
103
- },
104
- });
105
- rows = r[0];
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 datastore_1.PropertyFilter('kind_name', '=', table))
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 datastore_1.PropertyFilter('kind_name', '=', table));
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
- errorData: {
383
- fingerprint: [DATASTORE_TIMEOUT],
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 { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB';
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 {
@@ -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;
@@ -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 datastore_1.PropertyFilter(f.name, OP_MAP[op] || op, val));
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.2",
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.0.0",
15
- "@naturalcycles/db-lib": "^9.0.0",
16
- "@naturalcycles/js-lib": "^14.116.0",
17
- "@naturalcycles/nodejs-lib": "^13.1.0"
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": "^15.2.0",
21
- "@types/node": "^22.0.0",
22
- "jest": "^29.0.3"
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": ">=20.13.0"
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 { _ms, CommonLogger, pRetry, UnixTimestampMillis } from '@naturalcycles/js-lib'
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
 
@@ -1,10 +1,7 @@
1
- import type { Datastore, Key, Query } from '@google-cloud/datastore'
2
- import { PropertyFilter, Transaction } from '@google-cloud/datastore'
3
- import { type RunQueryOptions } from '@google-cloud/datastore/build/src/query'
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
- _assert,
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 { boldWhite, ReadableTyped } from '@naturalcycles/nodejs-lib'
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
- // Lazy-loading
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
- const r = await pRetry(
173
- () => ((opt.tx as DatastoreDBTransaction)?.tx || this.ds()).get(keys, dsOpt),
174
- {
175
- ...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
176
- maxAttempts: 3,
177
- timeout: this.cfg.timeout,
178
- errorData: {
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
- rows = r[0]
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(dbQuery, this.ds().createQuery(dbQuery.table))
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(dbQuery.select([]), this.ds().createQuery(dbQuery.table))
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(dbQuery, this.ds().createQuery(dbQuery.table))
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(q.select([]), this.ds().createQuery(q.table))
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 PropertyFilter('kind_name', '=', table))
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
- errorData: {
560
- fingerprint: [DATASTORE_TIMEOUT],
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
 
@@ -1,6 +1,10 @@
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 {
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
- CommonKeyValueDB,
3
- commonKeyValueDBFullSupport,
4
- DBQuery,
5
- KeyValueDBTuple,
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 PropertyFilter(f.name as string, OP_MAP[op] || (op as any), val))
34
+ q = q.filter(new propertyFilterClass(f.name as string, OP_MAP[op] || (op as any), val))
34
35
  }
35
36
 
36
37
  // limit