@naturalcycles/datastore-lib 3.31.0 → 3.32.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,6 +1,6 @@
1
1
  import { Transaction } from '@google-cloud/datastore';
2
2
  import type { Datastore, Key, Query } from '@google-cloud/datastore';
3
- import { BaseCommonDB, CommonDB, CommonDBSupport, DBQuery, DBTransaction, RunQueryResult } from '@naturalcycles/db-lib';
3
+ import { BaseCommonDB, CommonDB, CommonDBOptions, CommonDBSaveOptions, CommonDBSupport, DBQuery, DBTransaction, DBTransactionFn, RunQueryResult, CommonDBTransactionOptions } from '@naturalcycles/db-lib';
4
4
  import { ObjectWithId, JsonSchemaObject, JsonSchemaRootObject, CommonLogger } from '@naturalcycles/js-lib';
5
5
  import { ReadableTyped } from '@naturalcycles/nodejs-lib';
6
6
  import { DatastoreDBCfg, DatastoreDBOptions, DatastoreDBSaveOptions, DatastoreDBStreamOptions, DatastorePayload, DatastorePropertyStats, DatastoreStats } from './datastore.model';
@@ -22,7 +22,7 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
22
22
  protected KEY: symbol;
23
23
  ds(): Datastore;
24
24
  ping(): Promise<void>;
25
- getByIds<ROW extends ObjectWithId>(table: string, ids: string[], _opt?: DatastoreDBOptions): Promise<ROW[]>;
25
+ getByIds<ROW extends ObjectWithId>(table: string, ids: string[], opt?: DatastoreDBOptions): Promise<ROW[]>;
26
26
  runQuery<ROW extends ObjectWithId>(dbQuery: DBQuery<ROW>, _opt?: DatastoreDBOptions): Promise<RunQueryResult<ROW>>;
27
27
  runQueryCount<ROW extends ObjectWithId>(dbQuery: DBQuery<ROW>, _opt?: DatastoreDBOptions): Promise<number>;
28
28
  runDatastoreQuery<ROW extends ObjectWithId>(q: Query): Promise<RunQueryResult<ROW>>;
@@ -38,7 +38,7 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
38
38
  * regardless if they were actually deleted or not.
39
39
  */
40
40
  deleteByIds(table: string, ids: string[], opt?: DatastoreDBOptions): Promise<number>;
41
- createTransaction(): Promise<DatastoreDBTransaction>;
41
+ runInTransaction(fn: DBTransactionFn, opt?: CommonDBTransactionOptions): Promise<void>;
42
42
  getAllStats(): Promise<DatastoreStats[]>;
43
43
  /**
44
44
  * Returns undefined e.g when Table is non-existing
@@ -64,8 +64,9 @@ export declare class DatastoreDB extends BaseCommonDB implements CommonDB {
64
64
  export declare class DatastoreDBTransaction implements DBTransaction {
65
65
  db: DatastoreDB;
66
66
  tx: Transaction;
67
- private constructor();
68
- static create(db: DatastoreDB): Promise<DatastoreDBTransaction>;
69
- commit(): Promise<void>;
67
+ constructor(db: DatastoreDB, tx: Transaction);
70
68
  rollback(): Promise<void>;
69
+ getByIds<ROW extends ObjectWithId>(table: string, ids: string[], opt?: CommonDBOptions | undefined): Promise<ROW[]>;
70
+ saveBatch<ROW extends Partial<ObjectWithId>>(table: string, rows: ROW[], opt?: CommonDBSaveOptions<ROW> | undefined): Promise<void>;
71
+ deleteByIds(table: string, ids: string[], opt?: CommonDBOptions | undefined): Promise<number>;
71
72
  }
@@ -69,7 +69,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
69
69
  async ping() {
70
70
  await this.getAllStats();
71
71
  }
72
- async getByIds(table, ids, _opt) {
72
+ async getByIds(table, ids, opt = {}) {
73
73
  if (!ids.length)
74
74
  return [];
75
75
  const keys = ids.map(id => this.key(table, id));
@@ -77,7 +77,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
77
77
  if (this.cfg.timeout) {
78
78
  // First try
79
79
  try {
80
- const r = await (0, js_lib_1.pTimeout)(() => this.ds().get(keys), {
80
+ const r = await (0, js_lib_1.pTimeout)(() => (opt.tx?.tx || this.ds()).get(keys), {
81
81
  timeout: this.cfg.timeout,
82
82
  name: `datastore.getByIds(${table})`,
83
83
  });
@@ -90,7 +90,7 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
90
90
  const DS = datastoreLib.Datastore;
91
91
  this.cachedDatastore = new DS(this.cfg);
92
92
  // Second try (will throw)
93
- const r = await (0, js_lib_1.pRetry)(() => this.ds().get(keys), {
93
+ const r = await (0, js_lib_1.pRetry)(() => (opt.tx?.tx || this.ds()).get(keys), {
94
94
  ...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
95
95
  maxAttempts: 3,
96
96
  timeout: this.cfg.timeout,
@@ -214,8 +214,21 @@ class DatastoreDB extends db_lib_1.BaseCommonDB {
214
214
  async (batch) => await (opt.tx?.tx || this.ds()).delete(batch));
215
215
  return ids.length;
216
216
  }
217
- async createTransaction() {
218
- return await DatastoreDBTransaction.create(this);
217
+ async runInTransaction(fn, opt = {}) {
218
+ const { readOnly } = opt;
219
+ const datastoreTx = this.ds().transaction({
220
+ readOnly,
221
+ });
222
+ try {
223
+ await datastoreTx.run();
224
+ const tx = new DatastoreDBTransaction(this, datastoreTx);
225
+ await fn(tx);
226
+ await datastoreTx.commit();
227
+ }
228
+ catch (err) {
229
+ await datastoreTx.rollback();
230
+ throw err;
231
+ }
219
232
  }
220
233
  async getAllStats() {
221
234
  const q = this.ds().createQuery('__Stat_Kind__');
@@ -379,16 +392,17 @@ class DatastoreDBTransaction {
379
392
  this.db = db;
380
393
  this.tx = tx;
381
394
  }
382
- static async create(db) {
383
- const tx = db.ds().transaction();
384
- await tx.run();
385
- return new DatastoreDBTransaction(db, tx);
386
- }
387
- async commit() {
388
- await this.tx.commit();
389
- }
390
395
  async rollback() {
391
396
  await this.tx.rollback();
392
397
  }
398
+ async getByIds(table, ids, opt) {
399
+ return await this.db.getByIds(table, ids, { ...opt, tx: this });
400
+ }
401
+ async saveBatch(table, rows, opt) {
402
+ await this.db.saveBatch(table, rows, { ...opt, tx: this });
403
+ }
404
+ async deleteByIds(table, ids, opt) {
405
+ return await this.db.deleteByIds(table, ids, { ...opt, tx: this });
406
+ }
393
407
  }
394
408
  exports.DatastoreDBTransaction = DatastoreDBTransaction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/datastore-lib",
3
- "version": "3.31.0",
3
+ "version": "3.32.0",
4
4
  "description": "Opinionated library to work with Google Datastore",
5
5
  "scripts": {
6
6
  "prepare": "husky install"
@@ -5,11 +5,15 @@ import {
5
5
  BaseCommonDB,
6
6
  CommonDB,
7
7
  commonDBFullSupport,
8
+ CommonDBOptions,
8
9
  CommonDBSaveMethod,
10
+ CommonDBSaveOptions,
9
11
  CommonDBSupport,
10
12
  DBQuery,
11
13
  DBTransaction,
14
+ DBTransactionFn,
12
15
  RunQueryResult,
16
+ CommonDBTransactionOptions,
13
17
  } from '@naturalcycles/db-lib'
14
18
  import {
15
19
  ObjectWithId,
@@ -132,7 +136,7 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
132
136
  override async getByIds<ROW extends ObjectWithId>(
133
137
  table: string,
134
138
  ids: string[],
135
- _opt?: DatastoreDBOptions,
139
+ opt: DatastoreDBOptions = {},
136
140
  ): Promise<ROW[]> {
137
141
  if (!ids.length) return []
138
142
  const keys = ids.map(id => this.key(table, id))
@@ -141,10 +145,13 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
141
145
  if (this.cfg.timeout) {
142
146
  // First try
143
147
  try {
144
- const r = await pTimeout(() => this.ds().get(keys), {
145
- timeout: this.cfg.timeout,
146
- name: `datastore.getByIds(${table})`,
147
- })
148
+ const r = await pTimeout(
149
+ () => ((opt.tx as DatastoreDBTransaction)?.tx || this.ds()).get(keys),
150
+ {
151
+ timeout: this.cfg.timeout,
152
+ name: `datastore.getByIds(${table})`,
153
+ },
154
+ )
148
155
  rows = r[0]
149
156
  } catch {
150
157
  this.cfg.logger.log('datastore recreated on error')
@@ -155,15 +162,18 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
155
162
  this.cachedDatastore = new DS(this.cfg)
156
163
 
157
164
  // Second try (will throw)
158
- const r = await pRetry(() => this.ds().get(keys), {
159
- ...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
160
- maxAttempts: 3,
161
- timeout: this.cfg.timeout,
162
- errorData: {
163
- // This error will be grouped ACROSS all endpoints and usages
164
- fingerprint: [DATASTORE_TIMEOUT],
165
+ const r = await pRetry(
166
+ () => ((opt.tx as DatastoreDBTransaction)?.tx || this.ds()).get(keys),
167
+ {
168
+ ...this.getPRetryOptions(`datastore.getByIds(${table}) second try`),
169
+ maxAttempts: 3,
170
+ timeout: this.cfg.timeout,
171
+ errorData: {
172
+ // This error will be grouped ACROSS all endpoints and usages
173
+ fingerprint: [DATASTORE_TIMEOUT],
174
+ },
165
175
  },
166
- })
176
+ )
167
177
  rows = r[0]
168
178
  }
169
179
  } else {
@@ -352,8 +362,24 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
352
362
  return ids.length
353
363
  }
354
364
 
355
- override async createTransaction(): Promise<DatastoreDBTransaction> {
356
- return await DatastoreDBTransaction.create(this)
365
+ override async runInTransaction(
366
+ fn: DBTransactionFn,
367
+ opt: CommonDBTransactionOptions = {},
368
+ ): Promise<void> {
369
+ const { readOnly } = opt
370
+ const datastoreTx = this.ds().transaction({
371
+ readOnly,
372
+ })
373
+
374
+ try {
375
+ await datastoreTx.run()
376
+ const tx = new DatastoreDBTransaction(this, datastoreTx)
377
+ await fn(tx)
378
+ await datastoreTx.commit()
379
+ } catch (err) {
380
+ await datastoreTx.rollback()
381
+ throw err
382
+ }
357
383
  }
358
384
 
359
385
  async getAllStats(): Promise<DatastoreStats[]> {
@@ -532,21 +558,36 @@ export class DatastoreDB extends BaseCommonDB implements CommonDB {
532
558
  * https://cloud.google.com/datastore/docs/concepts/transactions#datastore-datastore-transactional-update-nodejs
533
559
  */
534
560
  export class DatastoreDBTransaction implements DBTransaction {
535
- private constructor(
561
+ constructor(
536
562
  public db: DatastoreDB,
537
563
  public tx: Transaction,
538
564
  ) {}
539
565
 
540
- static async create(db: DatastoreDB): Promise<DatastoreDBTransaction> {
541
- const tx = db.ds().transaction()
542
- await tx.run()
543
- return new DatastoreDBTransaction(db, tx)
566
+ async rollback(): Promise<void> {
567
+ await this.tx.rollback()
544
568
  }
545
569
 
546
- async commit(): Promise<void> {
547
- await this.tx.commit()
570
+ async getByIds<ROW extends ObjectWithId>(
571
+ table: string,
572
+ ids: string[],
573
+ opt?: CommonDBOptions | undefined,
574
+ ): Promise<ROW[]> {
575
+ return await this.db.getByIds(table, ids, { ...opt, tx: this })
548
576
  }
549
- async rollback(): Promise<void> {
550
- await this.tx.rollback()
577
+
578
+ async saveBatch<ROW extends Partial<ObjectWithId>>(
579
+ table: string,
580
+ rows: ROW[],
581
+ opt?: CommonDBSaveOptions<ROW> | undefined,
582
+ ): Promise<void> {
583
+ await this.db.saveBatch(table, rows, { ...opt, tx: this })
584
+ }
585
+
586
+ async deleteByIds(
587
+ table: string,
588
+ ids: string[],
589
+ opt?: CommonDBOptions | undefined,
590
+ ): Promise<number> {
591
+ return await this.db.deleteByIds(table, ids, { ...opt, tx: this })
551
592
  }
552
593
  }