@naturalcycles/datastore-lib 4.18.2 → 4.18.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.
@@ -66,7 +66,6 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
66
66
  * It may happen that transaction is already committed/rolled back, so we don't want to throw an error here.
67
67
  */
68
68
  private rollback;
69
- private getRunQueryOptions;
70
69
  }
71
70
  /**
72
71
  * https://cloud.google.com/datastore/docs/concepts/transactions#datastore-datastore-transactional-update-nodejs
@@ -1,6 +1,5 @@
1
1
  import { Datastore, PropertyFilter } from '@google-cloud/datastore';
2
2
  import { BaseCommonDB, commonDBFullSupport } from '@naturalcycles/db-lib';
3
- import { _round } from '@naturalcycles/js-lib';
4
3
  import { _chunk } from '@naturalcycles/js-lib/array/array.util.js';
5
4
  import { _ms } from '@naturalcycles/js-lib/datetime/time.util.js';
6
5
  import { _assert } from '@naturalcycles/js-lib/error/assert.js';
@@ -14,7 +13,7 @@ import { boldWhite } from '@naturalcycles/nodejs-lib/colors';
14
13
  import { Pipeline } from '@naturalcycles/nodejs-lib/stream';
15
14
  import { DatastoreType } from './datastore.model.js';
16
15
  import { DatastoreStreamReadable } from './datastoreStreamReadable.js';
17
- import { dbQueryToDatastoreQuery } from './query.util.js';
16
+ import { dbQueryToDatastoreQuery, getRunQueryOptions } from './query.util.js';
18
17
  // Datastore (also Firestore and other Google APIs) supports max 500 of items when saving/deleting, etc.
19
18
  const MAX_ITEMS = 500;
20
19
  // It's an empyrical value, but anything less than infinity is better than infinity
@@ -90,7 +89,7 @@ export class DatastoreDB extends BaseCommonDB {
90
89
  let ds = this.ds();
91
90
  const keys = ids.map(id => this.key(ds, table, id));
92
91
  let rows;
93
- const dsOpt = this.getRunQueryOptions(opt);
92
+ const dsOpt = getRunQueryOptions(opt);
94
93
  if (this.cfg.timeout) {
95
94
  // First try
96
95
  try {
@@ -141,7 +140,7 @@ export class DatastoreDB extends BaseCommonDB {
141
140
  async multiGet(map, opt = {}) {
142
141
  const result = {};
143
142
  const ds = this.ds();
144
- const dsOpt = this.getRunQueryOptions(opt);
143
+ const dsOpt = getRunQueryOptions(opt);
145
144
  const keys = [];
146
145
  for (const [table, ids] of _stringMapEntries(map)) {
147
146
  result[table] = [];
@@ -174,7 +173,7 @@ export class DatastoreDB extends BaseCommonDB {
174
173
  }
175
174
  const ds = this.ds();
176
175
  const q = dbQueryToDatastoreQuery(dbQuery, ds.createQuery(dbQuery.table));
177
- const dsOpt = this.getRunQueryOptions(opt);
176
+ const dsOpt = getRunQueryOptions(opt);
178
177
  const qr = await this.runDatastoreQuery(q, dsOpt);
179
178
  // Special case when projection query didn't specify 'id'
180
179
  if (dbQuery._selectedFieldNames && !dbQuery._selectedFieldNames.includes('id')) {
@@ -186,7 +185,7 @@ export class DatastoreDB extends BaseCommonDB {
186
185
  const ds = this.ds();
187
186
  const q = dbQueryToDatastoreQuery(dbQuery, ds.createQuery(dbQuery.table));
188
187
  const aq = ds.createAggregationQuery(q).count('count');
189
- const dsOpt = this.getRunQueryOptions(opt);
188
+ const dsOpt = getRunQueryOptions(opt);
190
189
  const [entities] = await ds.runAggregationQuery(aq, dsOpt);
191
190
  return entities[0]?.count;
192
191
  }
@@ -209,7 +208,7 @@ export class DatastoreDB extends BaseCommonDB {
209
208
  };
210
209
  const readable = opt.experimentalCursorStream
211
210
  ? new DatastoreStreamReadable(q, opt)
212
- : ds.runQueryStream(q, this.getRunQueryOptions(opt));
211
+ : ds.runQueryStream(q, getRunQueryOptions(opt));
213
212
  return Pipeline.from(readable).mapSync(r => this.mapId(r));
214
213
  }
215
214
  // https://github.com/GoogleCloudPlatform/nodejs-getting-started/blob/master/2-structured-data/books/model-datastore.js
@@ -255,7 +254,7 @@ export class DatastoreDB extends BaseCommonDB {
255
254
  }
256
255
  const ds = this.ds();
257
256
  const datastoreQuery = dbQueryToDatastoreQuery(q.select([]), ds.createQuery(q.table));
258
- const dsOpt = this.getRunQueryOptions(opt);
257
+ const dsOpt = getRunQueryOptions(opt);
259
258
  const { rows } = await this.runDatastoreQuery(datastoreQuery, dsOpt);
260
259
  return await this.deleteByIds(q.table, rows.map(obj => obj.id), opt);
261
260
  }
@@ -500,15 +499,6 @@ export class DatastoreDB extends BaseCommonDB {
500
499
  this.cfg.logger.error(err);
501
500
  }
502
501
  }
503
- getRunQueryOptions(opt) {
504
- if (!opt.readAt)
505
- return {};
506
- return {
507
- // Datastore expects UnixTimestamp in milliseconds
508
- // Datastore requires the timestamp to be rounded to the whole minutes
509
- readTime: _round(opt.readAt, 60) * 1000,
510
- };
511
- }
512
502
  }
513
503
  /**
514
504
  * https://cloud.google.com/datastore/docs/concepts/transactions#datastore-datastore-transactional-update-nodejs
@@ -3,6 +3,7 @@ import { localTime } from '@naturalcycles/js-lib/datetime/localTime.js';
3
3
  import { _ms } from '@naturalcycles/js-lib/datetime/time.util.js';
4
4
  import { createCommonLoggerAtLevel } from '@naturalcycles/js-lib/log';
5
5
  import { pRetry } from '@naturalcycles/js-lib/promise/pRetry.js';
6
+ import { getRunQueryOptions } from './query.util.js';
6
7
  export class DatastoreStreamReadable extends Readable {
7
8
  q;
8
9
  table;
@@ -39,11 +40,7 @@ export class DatastoreStreamReadable extends Readable {
39
40
  batchSize,
40
41
  highWaterMark,
41
42
  };
42
- this.dsOpt = {};
43
- if (opt.readAt) {
44
- // Datastore expects UnixTimestamp in milliseconds
45
- this.dsOpt.readTime = opt.readAt * 1000;
46
- }
43
+ this.dsOpt = getRunQueryOptions(opt);
47
44
  const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel);
48
45
  this.logger = logger;
49
46
  this.originalLimit = q.limitVal;
@@ -177,7 +174,6 @@ export class DatastoreStreamReadable extends Readable {
177
174
  }, err);
178
175
  clearInterval(this.maxWaitInterval);
179
176
  this.destroy(err);
180
- return;
181
177
  }
182
178
  }
183
179
  }
@@ -1,4 +1,7 @@
1
1
  import { type Query } from '@google-cloud/datastore';
2
+ import type { RunQueryOptions } from '@google-cloud/datastore/build/src/query.js';
2
3
  import type { DBQuery } from '@naturalcycles/db-lib';
3
4
  import type { ObjectWithId } from '@naturalcycles/js-lib/types';
5
+ import type { DatastoreDBReadOptions } from './datastore.model.js';
4
6
  export declare function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(dbQuery: Readonly<DBQuery<ROW>>, emptyQuery: Query): Query;
7
+ export declare function getRunQueryOptions(opt: DatastoreDBReadOptions): RunQueryOptions;
@@ -1,4 +1,5 @@
1
1
  import { PropertyFilter } from '@google-cloud/datastore';
2
+ import { _round } from '@naturalcycles/js-lib';
2
3
  const FNAME_MAP = {
3
4
  id: '__key__',
4
5
  };
@@ -47,3 +48,15 @@ export function dbQueryToDatastoreQuery(dbQuery, emptyQuery) {
47
48
  }
48
49
  return q;
49
50
  }
51
+ export function getRunQueryOptions(opt) {
52
+ if (!opt.readAt)
53
+ return {};
54
+ // Datastore expects UnixTimestamp in milliseconds
55
+ // Datastore requires the timestamp to be rounded to the whole minutes
56
+ let readTime = _round(opt.readAt, 60) * 1000;
57
+ if (readTime >= Date.now() - 1000) {
58
+ // To avoid the error of: The requested 'read_time' cannot be in the future
59
+ readTime -= 60_000;
60
+ }
61
+ return { readTime };
62
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/datastore-lib",
3
3
  "type": "module",
4
- "version": "4.18.2",
4
+ "version": "4.18.4",
5
5
  "description": "Opinionated library to work with Google Datastore, implements CommonDB",
6
6
  "dependencies": {
7
7
  "@google-cloud/datastore": "^10",
@@ -10,8 +10,8 @@
10
10
  "@naturalcycles/nodejs-lib": "^15"
11
11
  },
12
12
  "devDependencies": {
13
- "@types/node": "^24",
14
- "@naturalcycles/dev-lib": "20.12.10"
13
+ "@types/node": "^25",
14
+ "@naturalcycles/dev-lib": "18.4.2"
15
15
  },
16
16
  "exports": {
17
17
  ".": "./dist/index.js"
@@ -15,7 +15,6 @@ import type {
15
15
  RunQueryResult,
16
16
  } from '@naturalcycles/db-lib'
17
17
  import { BaseCommonDB, commonDBFullSupport } from '@naturalcycles/db-lib'
18
- import { _round } from '@naturalcycles/js-lib'
19
18
  import { _chunk } from '@naturalcycles/js-lib/array/array.util.js'
20
19
  import { _ms } from '@naturalcycles/js-lib/datetime/time.util.js'
21
20
  import { _assert } from '@naturalcycles/js-lib/error/assert.js'
@@ -47,7 +46,7 @@ import type {
47
46
  } from './datastore.model.js'
48
47
  import { DatastoreType } from './datastore.model.js'
49
48
  import { DatastoreStreamReadable } from './datastoreStreamReadable.js'
50
- import { dbQueryToDatastoreQuery } from './query.util.js'
49
+ import { dbQueryToDatastoreQuery, getRunQueryOptions } from './query.util.js'
51
50
 
52
51
  // Datastore (also Firestore and other Google APIs) supports max 500 of items when saving/deleting, etc.
53
52
  const MAX_ITEMS = 500
@@ -146,7 +145,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
146
145
  const keys = ids.map(id => this.key(ds, table, id))
147
146
  let rows: any[]
148
147
 
149
- const dsOpt = this.getRunQueryOptions(opt)
148
+ const dsOpt = getRunQueryOptions(opt)
150
149
 
151
150
  if (this.cfg.timeout) {
152
151
  // First try
@@ -216,7 +215,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
216
215
  ): Promise<StringMap<ROW[]>> {
217
216
  const result: StringMap<ROW[]> = {}
218
217
  const ds = this.ds()
219
- const dsOpt = this.getRunQueryOptions(opt)
218
+ const dsOpt = getRunQueryOptions(opt)
220
219
  const keys: Key[] = []
221
220
  for (const [table, ids] of _stringMapEntries(map)) {
222
221
  result[table] = []
@@ -260,7 +259,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
260
259
 
261
260
  const ds = this.ds()
262
261
  const q = dbQueryToDatastoreQuery(dbQuery, ds.createQuery(dbQuery.table))
263
- const dsOpt = this.getRunQueryOptions(opt)
262
+ const dsOpt = getRunQueryOptions(opt)
264
263
  const qr = await this.runDatastoreQuery<ROW>(q, dsOpt)
265
264
 
266
265
  // Special case when projection query didn't specify 'id'
@@ -278,7 +277,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
278
277
  const ds = this.ds()
279
278
  const q = dbQueryToDatastoreQuery(dbQuery, ds.createQuery(dbQuery.table))
280
279
  const aq = ds.createAggregationQuery(q).count('count')
281
- const dsOpt = this.getRunQueryOptions(opt)
280
+ const dsOpt = getRunQueryOptions(opt)
282
281
  const [entities] = await ds.runAggregationQuery(aq, dsOpt)
283
282
  return entities[0]?.count
284
283
  }
@@ -313,7 +312,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
313
312
 
314
313
  const readable = opt.experimentalCursorStream
315
314
  ? new DatastoreStreamReadable<ROW>(q, opt)
316
- : ds.runQueryStream(q, this.getRunQueryOptions(opt))
315
+ : ds.runQueryStream(q, getRunQueryOptions(opt))
317
316
 
318
317
  return Pipeline.from<ROW>(readable).mapSync(r => this.mapId<ROW>(r))
319
318
  }
@@ -383,7 +382,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
383
382
 
384
383
  const ds = this.ds()
385
384
  const datastoreQuery = dbQueryToDatastoreQuery(q.select([]), ds.createQuery(q.table))
386
- const dsOpt = this.getRunQueryOptions(opt)
385
+ const dsOpt = getRunQueryOptions(opt)
387
386
  const { rows } = await this.runDatastoreQuery<ObjectWithId>(datastoreQuery, dsOpt)
388
387
  return await this.deleteByIds(
389
388
  q.table,
@@ -680,16 +679,6 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
680
679
  this.cfg.logger.error(err)
681
680
  }
682
681
  }
683
-
684
- private getRunQueryOptions(opt: DatastoreDBReadOptions): RunQueryOptions {
685
- if (!opt.readAt) return {}
686
-
687
- return {
688
- // Datastore expects UnixTimestamp in milliseconds
689
- // Datastore requires the timestamp to be rounded to the whole minutes
690
- readTime: _round(opt.readAt, 60) * 1000,
691
- }
692
- }
693
682
  }
694
683
 
695
684
  /**
@@ -12,6 +12,7 @@ import { pRetry } from '@naturalcycles/js-lib/promise/pRetry.js'
12
12
  import type { UnixTimestampMillis } from '@naturalcycles/js-lib/types'
13
13
  import type { ReadableTyped } from '@naturalcycles/nodejs-lib/stream'
14
14
  import type { DatastoreDBStreamOptions } from './datastore.model.js'
15
+ import { getRunQueryOptions } from './query.util.js'
15
16
 
16
17
  export class DatastoreStreamReadable<T = any> extends Readable implements ReadableTyped<T> {
17
18
  private readonly table: string
@@ -53,12 +54,7 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
53
54
  batchSize,
54
55
  highWaterMark,
55
56
  }
56
- this.dsOpt = {}
57
- if (opt.readAt) {
58
- // Datastore expects UnixTimestamp in milliseconds
59
- this.dsOpt.readTime = opt.readAt * 1000
60
- }
61
-
57
+ this.dsOpt = getRunQueryOptions(opt)
62
58
  const logger = createCommonLoggerAtLevel(opt.logger, opt.logLevel)
63
59
  this.logger = logger
64
60
  this.originalLimit = q.limitVal
@@ -236,7 +232,6 @@ export class DatastoreStreamReadable<T = any> extends Readable implements Readab
236
232
  )
237
233
  clearInterval(this.maxWaitInterval)
238
234
  this.destroy(err as Error)
239
- return
240
235
  }
241
236
  }
242
237
  }
package/src/query.util.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import { PropertyFilter, type Query } from '@google-cloud/datastore'
2
+ import type { RunQueryOptions } from '@google-cloud/datastore/build/src/query.js'
2
3
  import type { DBQuery, DBQueryFilterOperator } from '@naturalcycles/db-lib'
4
+ import { _round } from '@naturalcycles/js-lib'
3
5
  import type { ObjectWithId, StringMap } from '@naturalcycles/js-lib/types'
6
+ import type { DatastoreDBReadOptions } from './datastore.model.js'
4
7
 
5
8
  const FNAME_MAP: StringMap = {
6
9
  id: '__key__',
@@ -64,3 +67,17 @@ export function dbQueryToDatastoreQuery<ROW extends ObjectWithId>(
64
67
 
65
68
  return q
66
69
  }
70
+
71
+ export function getRunQueryOptions(opt: DatastoreDBReadOptions): RunQueryOptions {
72
+ if (!opt.readAt) return {}
73
+
74
+ // Datastore expects UnixTimestamp in milliseconds
75
+ // Datastore requires the timestamp to be rounded to the whole minutes
76
+ let readTime = _round(opt.readAt, 60) * 1000
77
+ if (readTime >= Date.now() - 1000) {
78
+ // To avoid the error of: The requested 'read_time' cannot be in the future
79
+ readTime -= 60_000
80
+ }
81
+
82
+ return { readTime }
83
+ }