@naturalcycles/datastore-lib 3.16.5 → 3.18.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.
@@ -1,10 +1,12 @@
1
1
  /// <reference types="node" />
2
2
  import { Readable } from 'stream';
3
3
  import { Query } from '@google-cloud/datastore';
4
+ import { CommonLogger } from '@naturalcycles/js-lib';
4
5
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
5
6
  import type { DatastoreDBStreamOptions } from './datastore.model';
6
7
  export declare class DatastoreStreamReadable<T = any> extends Readable implements ReadableTyped<T> {
7
8
  private q;
9
+ private logger;
8
10
  private originalLimit;
9
11
  private rowsRetrieved;
10
12
  private endCursor?;
@@ -12,9 +14,8 @@ export declare class DatastoreStreamReadable<T = any> extends Readable implement
12
14
  private done;
13
15
  private lastQueryDone?;
14
16
  private totalWait;
15
- private log;
16
17
  private opt;
17
- constructor(q: Query, opt: DatastoreDBStreamOptions);
18
+ constructor(q: Query, opt: DatastoreDBStreamOptions, logger: CommonLogger);
18
19
  private runNextQuery;
19
20
  count: number;
20
21
  _read(): void;
@@ -4,25 +4,22 @@ exports.DatastoreStreamReadable = void 0;
4
4
  const stream_1 = require("stream");
5
5
  const js_lib_1 = require("@naturalcycles/js-lib");
6
6
  class DatastoreStreamReadable extends stream_1.Readable {
7
- constructor(q, opt) {
7
+ constructor(q, opt, logger) {
8
8
  super({ objectMode: true });
9
9
  this.q = q;
10
+ this.logger = logger;
10
11
  this.rowsRetrieved = 0;
11
12
  this.running = false;
12
13
  this.done = false;
13
14
  this.totalWait = 0;
14
- // private log = (...args: any[]): void => console.log(...args)
15
- this.log = console.log.bind(console);
16
15
  this.count = 0; // use for debugging
17
16
  this.opt = {
18
17
  rssLimitMB: 1000,
19
18
  batchSize: 1000,
20
19
  ...opt,
21
20
  };
22
- if (!opt.debug)
23
- this.log = () => { };
24
21
  this.originalLimit = q.limitVal;
25
- console.log(`!! using experimentalCursorStream !! batchSize: ${opt.batchSize}`);
22
+ logger.log(`!! using experimentalCursorStream !! batchSize: ${opt.batchSize}`);
26
23
  }
27
24
  async runNextQuery() {
28
25
  if (this.done)
@@ -45,7 +42,7 @@ class DatastoreStreamReadable extends stream_1.Readable {
45
42
  try {
46
43
  const [rows, info] = await q.run();
47
44
  this.rowsRetrieved += rows.length;
48
- this.log(`got ${rows.length} rows, ${this.rowsRetrieved} rowsRetrieved, totalWait: ${(0, js_lib_1._ms)(this.totalWait)}`, info.moreResults);
45
+ this.logger.log(`got ${rows.length} rows, ${this.rowsRetrieved} rowsRetrieved, totalWait: ${(0, js_lib_1._ms)(this.totalWait)}`, info.moreResults);
49
46
  this.endCursor = info.endCursor;
50
47
  this.running = false; // ready to take more _reads
51
48
  this.lastQueryDone = Date.now();
@@ -53,7 +50,7 @@ class DatastoreStreamReadable extends stream_1.Readable {
53
50
  if (!info.endCursor ||
54
51
  info.moreResults === 'NO_MORE_RESULTS' ||
55
52
  (this.originalLimit && this.rowsRetrieved >= this.originalLimit)) {
56
- this.log(`!!!! DONE! ${this.rowsRetrieved} rowsRetrieved, totalWait: ${(0, js_lib_1._ms)(this.totalWait)}`);
53
+ this.logger.log(`!!!! DONE! ${this.rowsRetrieved} rowsRetrieved, totalWait: ${(0, js_lib_1._ms)(this.totalWait)}`);
57
54
  this.push(null);
58
55
  this.done = true;
59
56
  }
@@ -63,7 +60,7 @@ class DatastoreStreamReadable extends stream_1.Readable {
63
60
  void this.runNextQuery();
64
61
  }
65
62
  else {
66
- this.log(`rssLimitMB reached ${rssMB} > ${this.opt.rssLimitMB}, pausing stream`);
63
+ this.logger.log(`rssLimitMB reached ${rssMB} > ${this.opt.rssLimitMB}, pausing stream`);
67
64
  }
68
65
  }
69
66
  }
@@ -76,10 +73,10 @@ class DatastoreStreamReadable extends stream_1.Readable {
76
73
  // console.log(`_read called ${++this.count}, wasRunning: ${this.running}`) // debugging
77
74
  this.count++;
78
75
  if (this.running) {
79
- this.log(`_read ${this.count}, wasRunning: true`);
76
+ this.logger.log(`_read ${this.count}, wasRunning: true`);
80
77
  }
81
78
  if (this.done) {
82
- console.warn(`!!! _read was called, but done==true`);
79
+ this.logger.warn(`!!! _read was called, but done==true`);
83
80
  return;
84
81
  }
85
82
  if (!this.running) {
@@ -1,6 +1,6 @@
1
1
  import type { Datastore, Key, Query } from '@google-cloud/datastore';
2
2
  import { BaseCommonDB, CommonDB, DBQuery, DBTransaction, RunQueryResult } from '@naturalcycles/db-lib';
3
- import { ObjectWithId, JsonSchemaRootObject } from '@naturalcycles/js-lib';
3
+ import { ObjectWithId, JsonSchemaRootObject, CommonLogger } from '@naturalcycles/js-lib';
4
4
  import { ReadableTyped } from '@naturalcycles/nodejs-lib';
5
5
  import { DatastoreDBCfg, DatastoreDBOptions, DatastoreDBSaveOptions, DatastoreDBStreamOptions, DatastorePayload, DatastorePropertyStats, DatastoreStats } from './datastore.model';
6
6
  /**
@@ -9,8 +9,10 @@ import { DatastoreDBCfg, DatastoreDBOptions, DatastoreDBSaveOptions, DatastoreDB
9
9
  * https://cloud.google.com/datastore/docs/datastore-api-tutorial
10
10
  */
11
11
  export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
12
- cfg: DatastoreDBCfg;
13
12
  constructor(cfg?: DatastoreDBCfg);
13
+ cfg: DatastoreDBCfg & {
14
+ logger: CommonLogger;
15
+ };
14
16
  private cachedDatastore?;
15
17
  /**
16
18
  * Datastore.KEY
@@ -21,27 +21,27 @@ const RETRY_ON = ['GOAWAY', 'UNAVAILABLE', 'UNKNOWN'];
21
21
  class DatastoreDB extends db_lib_1.BaseCommonDB {
22
22
  constructor(cfg = {}) {
23
23
  super();
24
- this.cfg = cfg;
24
+ this.cfg = {
25
+ logger: console,
26
+ ...cfg,
27
+ };
25
28
  }
26
29
  // @memo() // not used to be able to connect to many DBs in the same server instance
27
30
  ds() {
31
+ var _a;
28
32
  if (!this.cachedDatastore) {
29
- if (process.env['APP_ENV'] === 'test') {
30
- throw new Error('DatastoreDB cannot be used in Test env, please use InMemoryDB');
31
- }
33
+ (0, js_lib_1._assert)(process.env['APP_ENV'] !== 'test', 'DatastoreDB cannot be used in Test env, please use InMemoryDB');
32
34
  // Lazy-loading
33
35
  const datastoreLib = require('@google-cloud/datastore');
34
36
  const DS = datastoreLib.Datastore;
35
- this.cfg.projectId =
36
- this.cfg.projectId ||
37
- this.cfg.credentials?.project_id ||
38
- process.env['GOOGLE_CLOUD_PROJECT'];
39
- console.log(`DatastoreDB connected to ${(0, colors_1.boldWhite)(this.cfg.projectId)}`);
37
+ (_a = this.cfg).projectId || (_a.projectId = this.cfg.credentials?.project_id || process.env['GOOGLE_CLOUD_PROJECT']);
38
+ (0, js_lib_1._assert)(this.cfg.projectId, '"projectId" is not set for DatastoreDB');
39
+ this.cfg.logger.log(`DatastoreDB connected to ${(0, colors_1.boldWhite)(this.cfg.projectId)}`);
40
40
  if (this.cfg.useLegacyGRPC) {
41
41
  this.cfg.grpc = require('grpc');
42
42
  }
43
43
  if (this.cfg.grpc) {
44
- console.log('!!! DatastoreDB using custom grpc !!!');
44
+ this.cfg.logger.log('!!! DatastoreDB using custom grpc !!!');
45
45
  }
46
46
  this.cachedDatastore = new DS(this.cfg);
47
47
  this.KEY = this.cachedDatastore.KEY;
@@ -55,9 +55,20 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
55
55
  if (!ids.length)
56
56
  return [];
57
57
  const keys = ids.map(id => this.key(table, id));
58
- const [entities] = await this.ds().get(keys);
59
- return (entities
60
- .map(e => this.mapId(e))
58
+ let rows;
59
+ try {
60
+ rows = (await this.ds().get(keys))[0];
61
+ }
62
+ catch (err) {
63
+ this.cfg.logger.log('datastore recreated on error');
64
+ // This is to debug "GCP Datastore Timeout issue"
65
+ const datastoreLib = require('@google-cloud/datastore');
66
+ const DS = datastoreLib.Datastore;
67
+ this.cachedDatastore = new DS(this.cfg);
68
+ throw err;
69
+ }
70
+ return (rows
71
+ .map(r => this.mapId(r))
61
72
  // Seems like datastore .get() method doesn't return items properly sorted by input ids, so we gonna sort them here
62
73
  // same ids are not expected here
63
74
  .sort((a, b) => (a.id > b.id ? 1 : -1)));
@@ -95,7 +106,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
95
106
  ..._opt,
96
107
  };
97
108
  return (opt.experimentalCursorStream
98
- ? new DatastoreStreamReadable_1.DatastoreStreamReadable(q, opt)
109
+ ? new DatastoreStreamReadable_1.DatastoreStreamReadable(q, opt, (0, js_lib_1.commonLoggerMinLevel)(this.cfg.logger, opt.debug ? 'log' : 'warn'))
99
110
  : this.ds().runQueryStream(q)).pipe(new stream_1.Transform({
100
111
  objectMode: true,
101
112
  transform: (chunk, _enc, cb) => {
@@ -119,19 +130,21 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
119
130
  // Here we retry the GOAWAY errors that are somewhat common for Datastore
120
131
  // Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
121
132
  predicate: err => RETRY_ON.some(s => err?.message.includes(s)),
133
+ name: `DatastoreLib.saveBatch(${table})`,
122
134
  maxAttempts: 5,
123
135
  delay: 5000,
124
136
  delayMultiplier: 2,
125
137
  logFirstAttempt: false,
126
138
  logFailures: true,
127
139
  // logAll: true,
140
+ logger: this.cfg.logger,
128
141
  });
129
142
  try {
130
143
  await (0, js_lib_1.pMap)((0, js_lib_1._chunk)(entities, MAX_ITEMS), async (batch) => await save(batch));
131
144
  }
132
145
  catch (err) {
133
146
  // console.log(`datastore.save ${kind}`, { obj, entity })
134
- console.error(`error in datastore.save for ${table}`, err);
147
+ this.cfg.logger.error(`error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`, err);
135
148
  // don't throw, because datastore SDK makes it in separate thread, so exception will be unhandled otherwise
136
149
  return await Promise.reject(err);
137
150
  }
@@ -1,6 +1,6 @@
1
1
  import type { DatastoreOptions, Key, Transaction } from '@google-cloud/datastore';
2
2
  import { CommonDBOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib';
3
- import { AnyObjectWithId, ObjectWithId } from '@naturalcycles/js-lib';
3
+ import { AnyObjectWithId, CommonLogger, ObjectWithId } from '@naturalcycles/js-lib';
4
4
  export interface DatastorePayload<T = any> {
5
5
  key: Key;
6
6
  data: T;
@@ -30,6 +30,10 @@ export interface DatastoreDBCfg extends DatastoreOptions {
30
30
  * e.g you can globally enable `experimentalCursorStream` here, set the batchSize, etc.
31
31
  */
32
32
  streamOptions?: DatastoreDBStreamOptions;
33
+ /**
34
+ * Default to `console`
35
+ */
36
+ logger?: CommonLogger;
33
37
  }
34
38
  export interface DatastoreCredentials {
35
39
  type?: string;
@@ -17,4 +17,5 @@ export declare class DatastoreKeyValueDB implements CommonKeyValueDB {
17
17
  streamIds(table: string, limit?: number): ReadableTyped<string>;
18
18
  streamValues(table: string, limit?: number): ReadableTyped<Buffer>;
19
19
  streamEntries(table: string, limit?: number): ReadableTyped<KeyValueDBTuple>;
20
+ count(_table: string): Promise<number>;
20
21
  }
@@ -47,5 +47,9 @@ class DatastoreKeyValueDB {
47
47
  errorMode: js_lib_1.ErrorMode.SUPPRESS, // cause .pipe() cannot propagate errors
48
48
  }));
49
49
  }
50
+ async count(_table) {
51
+ this.db.cfg.logger.warn(`DatastoreKeyValueDB.count is not supported`);
52
+ return 0;
53
+ }
50
54
  }
51
55
  exports.DatastoreKeyValueDB = DatastoreKeyValueDB;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/datastore-lib",
3
- "version": "3.16.5",
3
+ "version": "3.18.0",
4
4
  "description": "Opinionated library to work with Google Datastore",
5
5
  "scripts": {
6
6
  "prepare": "husky install"
@@ -17,7 +17,7 @@
17
17
  "devDependencies": {
18
18
  "@google-cloud/datastore": "^6.0.0",
19
19
  "@naturalcycles/dev-lib": "^12.0.1",
20
- "@types/node": "^16.0.0",
20
+ "@types/node": "^17.0.8",
21
21
  "jest": "^27.0.4"
22
22
  },
23
23
  "files": [
@@ -1,6 +1,6 @@
1
1
  import { Readable } from 'stream'
2
2
  import { Query } from '@google-cloud/datastore'
3
- import { _ms } from '@naturalcycles/js-lib'
3
+ import { _ms, CommonLogger } from '@naturalcycles/js-lib'
4
4
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
5
5
  import type { DatastoreDBStreamOptions } from './datastore.model'
6
6
 
@@ -13,12 +13,9 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
13
13
  private lastQueryDone?: number
14
14
  private totalWait = 0
15
15
 
16
- // private log = (...args: any[]): void => console.log(...args)
17
- private log = console.log.bind(console)
18
-
19
16
  private opt: DatastoreDBStreamOptions & { batchSize: number }
20
17
 
21
- constructor(private q: Query, opt: DatastoreDBStreamOptions) {
18
+ constructor(private q: Query, opt: DatastoreDBStreamOptions, private logger: CommonLogger) {
22
19
  super({ objectMode: true })
23
20
 
24
21
  this.opt = {
@@ -27,11 +24,9 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
27
24
  ...opt,
28
25
  }
29
26
 
30
- if (!opt.debug) this.log = () => {}
31
-
32
27
  this.originalLimit = q.limitVal
33
28
 
34
- console.log(`!! using experimentalCursorStream !! batchSize: ${opt.batchSize}`)
29
+ logger.log(`!! using experimentalCursorStream !! batchSize: ${opt.batchSize}`)
35
30
  }
36
31
 
37
32
  private async runNextQuery(): Promise<void> {
@@ -61,7 +56,7 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
61
56
  const [rows, info] = await q.run()
62
57
 
63
58
  this.rowsRetrieved += rows.length
64
- this.log(
59
+ this.logger.log(
65
60
  `got ${rows.length} rows, ${this.rowsRetrieved} rowsRetrieved, totalWait: ${_ms(
66
61
  this.totalWait,
67
62
  )}`,
@@ -79,7 +74,7 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
79
74
  info.moreResults === 'NO_MORE_RESULTS' ||
80
75
  (this.originalLimit && this.rowsRetrieved >= this.originalLimit)
81
76
  ) {
82
- this.log(
77
+ this.logger.log(
83
78
  `!!!! DONE! ${this.rowsRetrieved} rowsRetrieved, totalWait: ${_ms(this.totalWait)}`,
84
79
  )
85
80
  this.push(null)
@@ -90,7 +85,7 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
90
85
  if (rssMB <= this.opt.rssLimitMB) {
91
86
  void this.runNextQuery()
92
87
  } else {
93
- this.log(`rssLimitMB reached ${rssMB} > ${this.opt.rssLimitMB}, pausing stream`)
88
+ this.logger.log(`rssLimitMB reached ${rssMB} > ${this.opt.rssLimitMB}, pausing stream`)
94
89
  }
95
90
  }
96
91
  } catch (err) {
@@ -105,11 +100,11 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
105
100
  // console.log(`_read called ${++this.count}, wasRunning: ${this.running}`) // debugging
106
101
  this.count++
107
102
  if (this.running) {
108
- this.log(`_read ${this.count}, wasRunning: true`)
103
+ this.logger.log(`_read ${this.count}, wasRunning: true`)
109
104
  }
110
105
 
111
106
  if (this.done) {
112
- console.warn(`!!! _read was called, but done==true`)
107
+ this.logger.warn(`!!! _read was called, but done==true`)
113
108
  return
114
109
  }
115
110
 
@@ -22,6 +22,8 @@ import {
22
22
  _chunk,
23
23
  _omit,
24
24
  JsonSchemaRootObject,
25
+ CommonLogger,
26
+ commonLoggerMinLevel,
25
27
  } from '@naturalcycles/js-lib'
26
28
  import { ReadableTyped } from '@naturalcycles/nodejs-lib'
27
29
  import { boldWhite } from '@naturalcycles/nodejs-lib/dist/colors'
@@ -51,10 +53,16 @@ const RETRY_ON = ['GOAWAY', 'UNAVAILABLE', 'UNKNOWN']
51
53
  * https://cloud.google.com/datastore/docs/datastore-api-tutorial
52
54
  */
53
55
  export class DatastoreDB extends BaseCommonDB implements CommonDB {
54
- constructor(public cfg: DatastoreDBCfg = {}) {
56
+ constructor(cfg: DatastoreDBCfg = {}) {
55
57
  super()
58
+ this.cfg = {
59
+ logger: console,
60
+ ...cfg,
61
+ }
56
62
  }
57
63
 
64
+ public cfg: DatastoreDBCfg & { logger: CommonLogger }
65
+
58
66
  private cachedDatastore?: Datastore
59
67
 
60
68
  /**
@@ -65,26 +73,26 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
65
73
  // @memo() // not used to be able to connect to many DBs in the same server instance
66
74
  ds(): Datastore {
67
75
  if (!this.cachedDatastore) {
68
- if (process.env['APP_ENV'] === 'test') {
69
- throw new Error('DatastoreDB cannot be used in Test env, please use InMemoryDB')
70
- }
76
+ _assert(
77
+ process.env['APP_ENV'] !== 'test',
78
+ 'DatastoreDB cannot be used in Test env, please use InMemoryDB',
79
+ )
71
80
 
72
81
  // Lazy-loading
73
82
  const datastoreLib = require('@google-cloud/datastore')
74
83
  const DS = datastoreLib.Datastore as typeof Datastore
75
- this.cfg.projectId =
76
- this.cfg.projectId ||
77
- this.cfg.credentials?.project_id ||
78
- process.env['GOOGLE_CLOUD_PROJECT']!
84
+ this.cfg.projectId ||= this.cfg.credentials?.project_id || process.env['GOOGLE_CLOUD_PROJECT']
85
+
86
+ _assert(this.cfg.projectId, '"projectId" is not set for DatastoreDB')
79
87
 
80
- console.log(`DatastoreDB connected to ${boldWhite(this.cfg.projectId)}`)
88
+ this.cfg.logger.log(`DatastoreDB connected to ${boldWhite(this.cfg.projectId)}`)
81
89
 
82
90
  if (this.cfg.useLegacyGRPC) {
83
91
  this.cfg.grpc = require('grpc')
84
92
  }
85
93
 
86
94
  if (this.cfg.grpc) {
87
- console.log('!!! DatastoreDB using custom grpc !!!')
95
+ this.cfg.logger.log('!!! DatastoreDB using custom grpc !!!')
88
96
  }
89
97
 
90
98
  this.cachedDatastore = new DS(this.cfg)
@@ -105,11 +113,24 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
105
113
  ): Promise<ROW[]> {
106
114
  if (!ids.length) return []
107
115
  const keys = ids.map(id => this.key(table, id))
108
- const [entities] = await this.ds().get(keys)
116
+ let rows: any[]
117
+
118
+ try {
119
+ rows = (await this.ds().get(keys))[0]
120
+ } catch (err) {
121
+ this.cfg.logger.log('datastore recreated on error')
122
+
123
+ // This is to debug "GCP Datastore Timeout issue"
124
+ const datastoreLib = require('@google-cloud/datastore')
125
+ const DS = datastoreLib.Datastore as typeof Datastore
126
+ this.cachedDatastore = new DS(this.cfg)
127
+
128
+ throw err
129
+ }
109
130
 
110
131
  return (
111
- (entities as any[])
112
- .map(e => this.mapId<ROW>(e))
132
+ rows
133
+ .map(r => this.mapId<ROW>(r))
113
134
  // Seems like datastore .get() method doesn't return items properly sorted by input ids, so we gonna sort them here
114
135
  // same ids are not expected here
115
136
  .sort((a, b) => (a.id > b.id ? 1 : -1))
@@ -167,7 +188,11 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
167
188
 
168
189
  return (
169
190
  opt.experimentalCursorStream
170
- ? new DatastoreStreamReadable(q, opt)
191
+ ? new DatastoreStreamReadable(
192
+ q,
193
+ opt,
194
+ commonLoggerMinLevel(this.cfg.logger, opt.debug ? 'log' : 'warn'),
195
+ )
171
196
  : this.ds().runQueryStream(q)
172
197
  ).pipe(
173
198
  new Transform({
@@ -209,12 +234,14 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
209
234
  // Here we retry the GOAWAY errors that are somewhat common for Datastore
210
235
  // Currently only retrying them here in .saveBatch(), cause probably they're only thrown when saving
211
236
  predicate: err => RETRY_ON.some(s => (err as Error)?.message.includes(s)),
237
+ name: `DatastoreLib.saveBatch(${table})`,
212
238
  maxAttempts: 5,
213
239
  delay: 5000,
214
240
  delayMultiplier: 2,
215
241
  logFirstAttempt: false,
216
242
  logFailures: true,
217
243
  // logAll: true,
244
+ logger: this.cfg.logger,
218
245
  },
219
246
  )
220
247
 
@@ -222,7 +249,10 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
222
249
  await pMap(_chunk(entities, MAX_ITEMS), async batch => await save(batch))
223
250
  } catch (err) {
224
251
  // console.log(`datastore.save ${kind}`, { obj, entity })
225
- console.error(`error in datastore.save for ${table}`, err)
252
+ this.cfg.logger.error(
253
+ `error in DatastoreLib.saveBatch for ${table} (${rows.length} rows)`,
254
+ err,
255
+ )
226
256
  // don't throw, because datastore SDK makes it in separate thread, so exception will be unhandled otherwise
227
257
  return await Promise.reject(err)
228
258
  }
@@ -1,6 +1,6 @@
1
1
  import type { DatastoreOptions, Key, Transaction } from '@google-cloud/datastore'
2
2
  import { CommonDBOptions, CommonDBSaveOptions } from '@naturalcycles/db-lib'
3
- import { AnyObjectWithId, ObjectWithId } from '@naturalcycles/js-lib'
3
+ import { AnyObjectWithId, CommonLogger, ObjectWithId } from '@naturalcycles/js-lib'
4
4
 
5
5
  export interface DatastorePayload<T = any> {
6
6
  key: Key
@@ -36,6 +36,11 @@ export interface DatastoreDBCfg extends DatastoreOptions {
36
36
  * e.g you can globally enable `experimentalCursorStream` here, set the batchSize, etc.
37
37
  */
38
38
  streamOptions?: DatastoreDBStreamOptions
39
+
40
+ /**
41
+ * Default to `console`
42
+ */
43
+ logger?: CommonLogger
39
44
  }
40
45
 
41
46
  export interface DatastoreCredentials {
@@ -76,4 +76,9 @@ export class DatastoreKeyValueDB implements CommonKeyValueDB {
76
76
  }),
77
77
  )
78
78
  }
79
+
80
+ async count(_table: string): Promise<number> {
81
+ this.db.cfg.logger.warn(`DatastoreKeyValueDB.count is not supported`)
82
+ return 0
83
+ }
79
84
  }