datastore-api 4.0.0 → 6.0.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.
@@ -2,6 +2,7 @@
2
2
  * dstore.ts - Datastore Compatibility layer
3
3
  * Try to get a smoother api for transactions and such.
4
4
  * A little bit inspired by the Python2 ndb interface.
5
+ * But without the ORM bits.
5
6
  *
6
7
  * In future https://github.com/graphql/dataloader might be used for batching.
7
8
  *
@@ -9,13 +10,13 @@
9
10
  * Copyright (c) 2021, 2022, 2023 Dr. Maximillian Dornseif
10
11
  */
11
12
 
12
- import { AsyncLocalStorage } from 'async_hooks'
13
- import { setImmediate } from 'timers/promises'
13
+ import { AsyncLocalStorage } from 'async_hooks';
14
+ import { setImmediate } from 'timers/promises';
14
15
 
15
- import { Datastore, Key, PathType, Query, Transaction } from '@google-cloud/datastore'
16
- import { Entity, entity } from '@google-cloud/datastore/build/src/entity'
17
- import { Operator, RunQueryInfo, RunQueryResponse } from '@google-cloud/datastore/build/src/query'
18
- import { CommitResponse } from '@google-cloud/datastore/build/src/request'
16
+ import { Datastore, Key, PathType, Query, Transaction, PropertyFilter } from '@google-cloud/datastore';
17
+ import { Entity, entity } from '@google-cloud/datastore/build/src/entity';
18
+ import { Operator, RunQueryInfo, RunQueryResponse } from '@google-cloud/datastore/build/src/query';
19
+ import { CommitResponse } from '@google-cloud/datastore/build/src/request';
19
20
  import {
20
21
  assert,
21
22
  assertIsArray,
@@ -23,44 +24,44 @@ import {
23
24
  assertIsNumber,
24
25
  assertIsObject,
25
26
  assertIsString,
26
- } from 'assertate-debug'
27
- import Debug from 'debug'
28
- import promClient from 'prom-client'
29
- import { Writable } from 'ts-essentials'
27
+ } from 'assertate-debug';
28
+ import Debug from 'debug';
29
+ import promClient from 'prom-client';
30
+ import { Writable } from 'ts-essentials';
30
31
 
31
32
  /** @ignore */
32
- export { Datastore, Key, PathType, Query, Transaction } from '@google-cloud/datastore'
33
+ export { Datastore, Key, PathType, Query, Transaction } from '@google-cloud/datastore';
33
34
 
34
35
  /** @ignore */
35
- const debug = Debug('ds:api')
36
+ const debug = Debug('ds:api');
36
37
 
37
38
  /** @ignore */
38
- const transactionAsyncLocalStorage = new AsyncLocalStorage()
39
+ const transactionAsyncLocalStorage = new AsyncLocalStorage();
39
40
 
40
41
  /** @ignore */
41
42
  const metricHistogram = new promClient.Histogram({
42
43
  name: 'dstore_requests_seconds',
43
44
  help: 'How long did Datastore operations take?',
44
45
  labelNames: ['operation'],
45
- })
46
+ });
46
47
  const metricFailureCounter = new promClient.Counter({
47
48
  name: 'dstore_failures_total',
48
49
  help: 'How many Datastore operations failed?',
49
50
  labelNames: ['operation'],
50
- })
51
+ });
51
52
 
52
53
  /** Use instead of Datastore.KEY
53
54
  *
54
55
  * Even better: use `_key` instead.
55
56
  */
56
- export const KEYSYM = Datastore.KEY
57
+ export const KEYSYM = Datastore.KEY;
57
58
 
58
- export type IGqlFilterTypes = boolean | string | number
59
+ export type IGqlFilterTypes = boolean | string | number;
59
60
 
60
61
  export type IGqlFilterSpec = {
61
- readonly eq: IGqlFilterTypes
62
- }
63
- export type TGqlFilterList = Array<[string, Operator, DstorePropertyValues]>
62
+ readonly eq: IGqlFilterTypes;
63
+ };
64
+ export type TGqlFilterList = Array<[string, Operator, DstorePropertyValues]>;
64
65
 
65
66
  /** Define what can be written into the Datastore */
66
67
  export type DstorePropertyValues =
@@ -73,53 +74,51 @@ export type DstorePropertyValues =
73
74
  | Buffer
74
75
  | Key
75
76
  | DstorePropertyValues[]
76
- | { [key: string]: DstorePropertyValues }
77
+ | { [key: string]: DstorePropertyValues };
77
78
 
78
79
  export interface IDstoreEntryWithoutKey {
79
80
  /** All User Data stored in the Datastore */
80
- [key: string]: DstorePropertyValues
81
+ [key: string]: DstorePropertyValues;
81
82
  }
82
83
 
83
84
  /** Represents what is actually stored inside the Datastore, called "Entity" by Google
84
85
  [@google-cloud/datastore](https://github.com/googleapis/nodejs-datastore#readme) adds `[Datastore.KEY]`. Using ES6 Symbols presents all kinds of hurdles, especially when you try to serialize into a cache. So we add the property _keyStr which contains the encoded key. It is automatically used to reconstruct `[Datastore.KEY]`, if you use [[Dstore.readKey]].
85
86
  */
86
87
  export interface IDstoreEntry extends IDstoreEntryWithoutKey {
87
- /* Datastore key provided by [@google-cloud/datastore](https://github.com/googleapis/nodejs-datastore#readme) */
88
- readonly [Datastore.KEY]?: Key
88
+ /* Datastore Key provided by [@google-cloud/datastore](https://github.com/googleapis/nodejs-datastore#readme) */
89
+ readonly [Datastore.KEY]?: Key;
89
90
  /** [Datastore.KEY] key */
90
- _keyStr: string
91
- /** All User Data stored in the Datastore */
92
- [key: string]: DstorePropertyValues
91
+ _keyStr: string;
93
92
  }
94
93
 
95
94
  /** Represents the thing you pass to the save method. Also called "Entity" by Google */
96
95
  export type DstoreSaveEntity = {
97
- key: Key
96
+ key: Key;
98
97
  data: Omit<IDstoreEntry, '_keyStr' | Datastore['KEY']> &
99
98
  Partial<{
100
- _keyStr: string
101
- [Datastore.KEY]: Key
102
- }>
103
- method?: 'insert' | 'update' | 'upsert'
104
- excludeLargeProperties?: boolean
105
- excludeFromIndexes?: readonly string[]
106
- }
99
+ _keyStr: string|undefined;
100
+ [Datastore.KEY]: Key;
101
+ }>;
102
+ method?: 'insert' | 'update' | 'upsert';
103
+ excludeLargeProperties?: boolean;
104
+ excludeFromIndexes?: readonly string[];
105
+ };
107
106
 
108
107
  type IDstore = {
109
108
  /** Accessible by Users of the library. Keep in mind that you will access outside transactions created by [[runInTransaction]]. */
110
- readonly datastore: Datastore
111
- key: (path: ReadonlyArray<PathType>) => Key
112
- keyFromSerialized: (text: string) => Key
113
- keySerialize: (key: Key) => string
114
- readKey: (entry: IDstoreEntry) => Key
115
- get: (key: Key) => Promise<IDstoreEntry | null>
116
- getMulti: (keys: ReadonlyArray<Key>) => Promise<ReadonlyArray<IDstoreEntry | null>>
117
- set: (key: Key, entry: IDstoreEntry) => Promise<Key>
118
- save: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>
119
- insert: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>
120
- update: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>
121
- delete: (keys: readonly Key[]) => Promise<CommitResponse | undefined>
122
- createQuery: (kind: string) => Query
109
+ readonly datastore: Datastore;
110
+ key: (path: ReadonlyArray<PathType>) => Key;
111
+ keyFromSerialized: (text: string) => Key;
112
+ keySerialize: (key: Key) => string;
113
+ readKey: (entry: IDstoreEntry) => Key;
114
+ get: (key: Key) => Promise<IDstoreEntry | null>;
115
+ getMulti: (keys: ReadonlyArray<Key>) => Promise<ReadonlyArray<IDstoreEntry | null>>;
116
+ set: (key: Key, entry: IDstoreEntry) => Promise<Key>;
117
+ save: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>;
118
+ insert: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>;
119
+ update: (entities: readonly DstoreSaveEntity[]) => Promise<CommitResponse | undefined>;
120
+ delete: (keys: readonly Key[]) => Promise<CommitResponse | undefined>;
121
+ createQuery: (kind: string) => Query;
123
122
  query: (
124
123
  kind: string,
125
124
  filters?: TGqlFilterList,
@@ -127,11 +126,11 @@ type IDstore = {
127
126
  ordering?: readonly string[],
128
127
  selection?: readonly string[],
129
128
  cursor?: string
130
- ) => Promise<RunQueryResponse>
131
- runQuery: (query: Query | Omit<Query, 'run'>) => Promise<RunQueryResponse>
132
- allocateOneId: (kindName: string) => Promise<string>
133
- runInTransaction: <T>(func: { (): Promise<T>; (): T }) => Promise<T>
134
- }
129
+ ) => Promise<RunQueryResponse>;
130
+ runQuery: (query: Query | Omit<Query, 'run'>) => Promise<RunQueryResponse>;
131
+ allocateOneId: (kindName: string) => Promise<string>;
132
+ runInTransaction: <T>(func: { (): Promise<T>; (): T }) => Promise<T>;
133
+ };
135
134
 
136
135
  /** Dstore implements a slightly more accessible version of the [Google Cloud Datastore: Node.js Client](https://cloud.google.com/nodejs/docs/reference/datastore/latest)
137
136
 
@@ -157,9 +156,9 @@ Main differences:
157
156
  This documentation also tries to document the little known idiosyncrasies of the [@google-cloud/datastore](https://github.com/googleapis/nodejs-datastore) library. See the corresponding functions.
158
157
  */
159
158
  export class Dstore implements IDstore {
160
- engine = 'Dstore'
161
- engines: string[] = []
162
- private readonly urlSaveKey = new entity.URLSafeKey()
159
+ engine = 'Dstore';
160
+ engines: string[] = [];
161
+ private readonly urlSaveKey = new entity.URLSafeKey();
163
162
 
164
163
  /** Generate a Dstore instance for a specific [[Datastore]] instance.
165
164
 
@@ -177,13 +176,13 @@ export class Dstore implements IDstore {
177
176
  ```
178
177
  */
179
178
  constructor(readonly datastore: Datastore, readonly projectId?: string, readonly logger?: string) {
180
- assertIsObject(datastore)
181
- this.engines.push(this.engine)
179
+ assertIsObject(datastore);
180
+ this.engines.push(this.engine);
182
181
  }
183
182
 
184
183
  /** Gets the Datastore or the current Transaction. */
185
184
  private getDoT(): Transaction | Datastore {
186
- return (transactionAsyncLocalStorage.getStore() as Transaction) || this.datastore
185
+ return (transactionAsyncLocalStorage.getStore() as Transaction) || this.datastore;
187
186
  }
188
187
 
189
188
  /** `key()` creates a [[Key]] Object from a path.
@@ -195,7 +194,7 @@ export class Dstore implements IDstore {
195
194
  * @category Datastore Drop-In
196
195
  */
197
196
  key(path: readonly PathType[]): Key {
198
- return this.datastore.key(path as Writable<typeof path>)
197
+ return this.datastore.key(path as Writable<typeof path>);
199
198
  }
200
199
 
201
200
  /** `keyFromSerialized()` serializes [[Key]] to a string.
@@ -207,7 +206,7 @@ export class Dstore implements IDstore {
207
206
  * @category Datastore Drop-In
208
207
  */
209
208
  keySerialize(key: Key): string {
210
- return key ? this.urlSaveKey.legacyEncode(this.projectId ?? '', key) : ''
209
+ return key ? this.urlSaveKey.legacyEncode(this.projectId ?? '', key) : '';
211
210
  }
212
211
 
213
212
  /** `keyFromSerialized()` deserializes a string created with [[keySerialize]] to a [[Key]].
@@ -217,7 +216,7 @@ export class Dstore implements IDstore {
217
216
  * @category Datastore Drop-In
218
217
  */
219
218
  keyFromSerialized(text: string): Key {
220
- return this.urlSaveKey.legacyDecode(text)
219
+ return this.urlSaveKey.legacyDecode(text);
221
220
  }
222
221
 
223
222
  /** `readKey()` extracts the [[Key]] from an [[IDstoreEntry]].
@@ -228,17 +227,17 @@ export class Dstore implements IDstore {
228
227
  * @category Additional
229
228
  */
230
229
  readKey(ent: IDstoreEntry): Key {
231
- assertIsObject(ent)
232
- let ret = ent[Datastore.KEY]
230
+ assertIsObject(ent);
231
+ let ret = ent[Datastore.KEY];
233
232
  if (ent._keyStr && !ret) {
234
- ret = this.keyFromSerialized(ent._keyStr)
233
+ ret = this.keyFromSerialized(ent._keyStr);
235
234
  }
236
235
  assertIsObject(
237
236
  ret,
238
237
  'entity[Datastore.KEY]/entity._keyStr',
239
238
  `Entity is missing the datastore Key: ${JSON.stringify(ent)}`
240
- )
241
- return ret
239
+ );
240
+ return ret;
242
241
  }
243
242
 
244
243
  /** `fixKeys()` is called for all [[IDstoreEntry]]sa returned from [[Dstore]].
@@ -252,13 +251,13 @@ export class Dstore implements IDstore {
252
251
  ): Array<IDstoreEntry | undefined> {
253
252
  entities.forEach((x) => {
254
253
  if (!!x?.[Datastore.KEY] && x[Datastore.KEY]) {
255
- assertIsDefined(x[Datastore.KEY])
256
- assertIsObject(x[Datastore.KEY])
254
+ assertIsDefined(x[Datastore.KEY]);
255
+ assertIsObject(x[Datastore.KEY]);
257
256
  // Old TypesScript has problems with symbols as a property
258
- x._keyStr = this.keySerialize(x[Datastore.KEY] as Key)
257
+ x._keyStr = this.keySerialize(x[Datastore.KEY] as Key);
259
258
  }
260
- })
261
- return entities as Array<IDstoreEntry | undefined>
259
+ });
260
+ return entities as Array<IDstoreEntry | undefined>;
262
261
  }
263
262
 
264
263
  /** `get()` reads a [[IDstoreEntry]] from the Datastore.
@@ -277,11 +276,11 @@ export class Dstore implements IDstore {
277
276
  * @category Datastore Drop-In
278
277
  */
279
278
  async get(key: Key): Promise<IDstoreEntry | null> {
280
- assertIsObject(key)
281
- assert(!Array.isArray(key))
282
- assert(key.path.length % 2 == 0, `key.path must be complete: ${JSON.stringify(key.path)}`)
283
- const result = await this.getMulti([key])
284
- return result?.[0] || null
279
+ assertIsObject(key);
280
+ assert(!Array.isArray(key));
281
+ assert(key.path.length % 2 == 0, `key.path must be complete: ${JSON.stringify(key.path)}`);
282
+ const result = await this.getMulti([key]);
283
+ return result?.[0] || null;
285
284
  }
286
285
 
287
286
  /** `getMulti()` reads several [[IDstoreEntry]]s from the Datastore.
@@ -303,28 +302,28 @@ export class Dstore implements IDstore {
303
302
  */
304
303
  async getMulti(keys: readonly Key[]): Promise<Array<IDstoreEntry | null>> {
305
304
  // assertIsArray(keys);
306
- let results: (IDstoreEntry | null | undefined)[]
307
- const metricEnd = metricHistogram.startTimer()
305
+ let results: (IDstoreEntry | null | undefined)[];
306
+ const metricEnd = metricHistogram.startTimer();
308
307
  try {
309
308
  results = this.fixKeys(
310
309
  keys.length > 0 ? (await this.getDoT().get(keys as Writable<typeof keys>))?.[0] : []
311
- )
310
+ );
312
311
  } catch (error) {
313
- metricFailureCounter.inc({ operation: 'get' })
314
- await setImmediate()
315
- throw new DstoreError('datastore.getMulti error', error as Error, { keys })
312
+ metricFailureCounter.inc({ operation: 'get' });
313
+ await setImmediate();
314
+ throw new DstoreError('datastore.getMulti error', error as Error, { keys });
316
315
  } finally {
317
- metricEnd({ operation: 'get' })
316
+ metricEnd({ operation: 'get' });
318
317
  }
319
318
 
320
319
  // Sort resulting entities by the keys they were requested with.
321
- assertIsArray(results)
322
- const entities = results as IDstoreEntry[]
323
- const entitiesByKey: Record<string, IDstoreEntry> = {}
320
+ assertIsArray(results);
321
+ const entities = results as IDstoreEntry[];
322
+ const entitiesByKey: Record<string, IDstoreEntry> = {};
324
323
  entities.forEach((entity) => {
325
- entitiesByKey[JSON.stringify(entity[Datastore.KEY])] = entity
326
- })
327
- return keys.map((key) => entitiesByKey[JSON.stringify(key)] || null)
324
+ entitiesByKey[JSON.stringify(entity[Datastore.KEY])] = entity;
325
+ });
326
+ return keys.map((key) => entitiesByKey[JSON.stringify(key)] || null);
328
327
  }
329
328
 
330
329
  /** `set()` is addition to [[Datastore]]. It provides a classic Key-value Interface.
@@ -344,11 +343,11 @@ export class Dstore implements IDstore {
344
343
  * @category Additional
345
344
  */
346
345
  async set(key: Key, data: IDstoreEntryWithoutKey): Promise<Key> {
347
- assertIsObject(key)
348
- assertIsObject(data)
349
- const saveEntity = { key, data }
350
- await this.save([saveEntity])
351
- return saveEntity.key
346
+ assertIsObject(key);
347
+ assertIsObject(data);
348
+ const saveEntity = { key, data };
349
+ await this.save([saveEntity]);
350
+ return saveEntity.key;
352
351
  }
353
352
 
354
353
  /** `save()` is compatible to [Datastore.save()](https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/datastore#_google_cloud_datastore_Datastore_save_member_1_).
@@ -385,32 +384,32 @@ export class Dstore implements IDstore {
385
384
  * @category Datastore Drop-In
386
385
  */
387
386
  async save(entities: readonly DstoreSaveEntity[]): Promise<CommitResponse | undefined> {
388
- assertIsArray(entities)
389
- let ret: CommitResponse | undefined
390
- const metricEnd = metricHistogram.startTimer()
387
+ assertIsArray(entities);
388
+ let ret: CommitResponse | undefined;
389
+ const metricEnd = metricHistogram.startTimer();
391
390
  try {
392
391
  // Within Transaction we don't get any answer here!
393
392
  // [ { mutationResults: [ [Object], [Object] ], indexUpdates: 51 } ]
394
393
  for (const e of entities) {
395
- assertIsObject(e.key)
396
- assertIsObject(e.data)
397
- this.fixKeys([e.data])
398
- e.excludeLargeProperties = e.excludeLargeProperties === undefined ? true : e.excludeLargeProperties
399
- e.data = { ...e.data, _keyStr: undefined }
394
+ assertIsObject(e.key);
395
+ assertIsObject(e.data);
396
+ this.fixKeys([e.data]);
397
+ e.excludeLargeProperties = e.excludeLargeProperties === undefined ? true : e.excludeLargeProperties;
398
+ e.data = { ...e.data, _keyStr: undefined };
400
399
  }
401
- ret = (await this.getDoT().save(entities)) || undefined
400
+ ret = (await this.getDoT().save(entities)) || undefined;
402
401
  for (const e of entities) {
403
- e.data[Datastore.KEY] = e.key
404
- this.fixKeys([e.data])
402
+ e.data[Datastore.KEY] = e.key;
403
+ this.fixKeys([e.data]);
405
404
  }
406
405
  } catch (error) {
407
- metricFailureCounter.inc({ operation: 'save' })
408
- await setImmediate()
409
- throw new DstoreError('datastore.save error', error as Error)
406
+ metricFailureCounter.inc({ operation: 'save' });
407
+ await setImmediate();
408
+ throw new DstoreError('datastore.save error', error as Error);
410
409
  } finally {
411
- metricEnd({ operation: 'save' })
410
+ metricEnd({ operation: 'save' });
412
411
  }
413
- return ret
412
+ return ret;
414
413
  }
415
414
 
416
415
  /** `insert()` is compatible to [Datastore.insert()](https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/datastore#_google_cloud_datastore_Datastore_insert_member_1_).
@@ -432,20 +431,20 @@ export class Dstore implements IDstore {
432
431
  * @category Datastore Drop-In
433
432
  */
434
433
  async insert(entities: readonly DstoreSaveEntity[]): Promise<CommitResponse | undefined> {
435
- assertIsArray(entities)
436
- let ret: CommitResponse | undefined
437
- const metricEnd = metricHistogram.startTimer()
434
+ assertIsArray(entities);
435
+ let ret: CommitResponse | undefined;
436
+ const metricEnd = metricHistogram.startTimer();
438
437
  try {
439
- ret = (await this.getDoT().insert(entities)) || undefined
438
+ ret = (await this.getDoT().insert(entities)) || undefined;
440
439
  } catch (error) {
441
440
  // console.error(error)
442
- metricFailureCounter.inc({ operation: 'insert' })
443
- await setImmediate()
444
- throw new DstoreError('datastore.insert error', error as Error)
441
+ metricFailureCounter.inc({ operation: 'insert' });
442
+ await setImmediate();
443
+ throw new DstoreError('datastore.insert error', error as Error);
445
444
  } finally {
446
- metricEnd({ operation: 'insert' })
445
+ metricEnd({ operation: 'insert' });
447
446
  }
448
- return ret
447
+ return ret;
449
448
  }
450
449
 
451
450
  /** `update()` is compatible to [Datastore.update()](https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/datastore#_google_cloud_datastore_Datastore_update_member_1_).
@@ -467,29 +466,29 @@ export class Dstore implements IDstore {
467
466
  * @category Datastore Drop-In
468
467
  */
469
468
  async update(entities: readonly DstoreSaveEntity[]): Promise<CommitResponse | undefined> {
470
- assertIsArray(entities)
469
+ assertIsArray(entities);
471
470
 
472
- entities.forEach((entity) => assertIsObject(entity.key))
471
+ entities.forEach((entity) => assertIsObject(entity.key));
473
472
  entities.forEach((entity) =>
474
473
  assert(
475
474
  entity.key.path.length % 2 == 0,
476
475
  `entity.key.path must be complete: ${JSON.stringify([entity.key.path, entity])}`
477
476
  )
478
- )
479
- let ret: CommitResponse | undefined
480
- const metricEnd = metricHistogram.startTimer()
477
+ );
478
+ let ret: CommitResponse | undefined;
479
+ const metricEnd = metricHistogram.startTimer();
481
480
 
482
481
  try {
483
- ret = (await this.getDoT().update(entities)) || undefined
482
+ ret = (await this.getDoT().update(entities)) || undefined;
484
483
  } catch (error) {
485
484
  // console.error(error)
486
- metricFailureCounter.inc({ operation: 'update' })
487
- await setImmediate()
488
- throw new DstoreError('datastore.update error', error as Error)
485
+ metricFailureCounter.inc({ operation: 'update' });
486
+ await setImmediate();
487
+ throw new DstoreError('datastore.update error', error as Error);
489
488
  } finally {
490
- metricEnd({ operation: 'update' })
489
+ metricEnd({ operation: 'update' });
491
490
  }
492
- return ret
491
+ return ret;
493
492
  }
494
493
 
495
494
  /** `delete()` is compatible to [Datastore.delete()].
@@ -506,23 +505,23 @@ export class Dstore implements IDstore {
506
505
  * @category Datastore Drop-In
507
506
  */
508
507
  async delete(keys: readonly Key[]): Promise<CommitResponse | undefined> {
509
- assertIsArray(keys)
510
- keys.forEach((key) => assertIsObject(key))
508
+ assertIsArray(keys);
509
+ keys.forEach((key) => assertIsObject(key));
511
510
  keys.forEach((key) =>
512
511
  assert(key.path.length % 2 == 0, `key.path must be complete: ${JSON.stringify(key.path)}`)
513
- )
514
- let ret
515
- const metricEnd = metricHistogram.startTimer()
512
+ );
513
+ let ret;
514
+ const metricEnd = metricHistogram.startTimer();
516
515
  try {
517
- ret = (await this.getDoT().delete(keys)) || undefined
516
+ ret = (await this.getDoT().delete(keys)) || undefined;
518
517
  } catch (error) {
519
- metricFailureCounter.inc({ operation: 'delete' })
520
- await setImmediate()
521
- throw new DstoreError('datastore.delete error', error as Error)
518
+ metricFailureCounter.inc({ operation: 'delete' });
519
+ await setImmediate();
520
+ throw new DstoreError('datastore.delete error', error as Error);
522
521
  } finally {
523
- metricEnd({ operation: 'delete' })
522
+ metricEnd({ operation: 'delete' });
524
523
  }
525
- return ret
524
+ return ret;
526
525
  }
527
526
 
528
527
  /** `createQuery()` creates an "empty" [[Query]] Object.
@@ -535,25 +534,25 @@ export class Dstore implements IDstore {
535
534
  */
536
535
  createQuery(kindName: string): Query {
537
536
  try {
538
- return this.getDoT().createQuery(kindName)
537
+ return this.getDoT().createQuery(kindName);
539
538
  } catch (error) {
540
- throw new DstoreError('datastore.createQuery error', error as Error)
539
+ throw new DstoreError('datastore.createQuery error', error as Error);
541
540
  }
542
541
  }
543
542
 
544
543
  async runQuery(query: Query | Omit<Query, 'run'>): Promise<RunQueryResponse> {
545
- let ret
546
- const metricEnd = metricHistogram.startTimer()
544
+ let ret;
545
+ const metricEnd = metricHistogram.startTimer();
547
546
  try {
548
- const [entities, info]: [Entity[], RunQueryInfo] = await this.getDoT().runQuery(query as Query)
549
- ret = [this.fixKeys(entities), info]
547
+ const [entities, info]: [Entity[], RunQueryInfo] = await this.getDoT().runQuery(query as Query);
548
+ ret = [this.fixKeys(entities), info];
550
549
  } catch (error) {
551
- await setImmediate()
552
- throw new DstoreError('datastore.runQuery error', error as Error)
550
+ await setImmediate();
551
+ throw new DstoreError('datastore.runQuery error', error as Error);
553
552
  } finally {
554
- metricEnd({ operation: 'query' })
553
+ metricEnd({ operation: 'query' });
555
554
  }
556
- return ret as RunQueryResponse
555
+ return ret as RunQueryResponse;
557
556
  }
558
557
 
559
558
  /** `query()` combined [[createQuery]] and [[runQuery]] in a single call.
@@ -576,34 +575,34 @@ export class Dstore implements IDstore {
576
575
  selection: readonly string[] = [],
577
576
  cursor?: string
578
577
  ): Promise<RunQueryResponse> {
579
- assertIsString(kindName)
580
- assertIsArray(filters)
581
- assertIsNumber(limit)
578
+ assertIsString(kindName);
579
+ assertIsArray(filters);
580
+ assertIsNumber(limit);
582
581
  try {
583
- const q = this.createQuery(kindName)
582
+ const q = this.createQuery(kindName);
584
583
  for (const filterSpec of filters) {
585
- assertIsObject(filterSpec)
584
+ assertIsObject(filterSpec);
586
585
  // @ts-ignore
587
- q.filter(...filterSpec)
586
+ q.filter(new PropertyFilter(...filterSpec));
588
587
  }
589
588
  for (const orderField of ordering) {
590
- q.order(orderField)
589
+ q.order(orderField);
591
590
  }
592
591
  if (limit > 0) {
593
- q.limit(limit)
592
+ q.limit(limit);
594
593
  }
595
594
  if (selection.length > 0) {
596
- q.select(selection as any)
595
+ q.select(selection as any);
597
596
  }
598
- return await this.runQuery(q)
597
+ return await this.runQuery(q);
599
598
  } catch (error) {
600
- await setImmediate()
599
+ await setImmediate();
601
600
  throw new DstoreError('datastore.query error', error as Error, {
602
601
  kindName,
603
602
  filters,
604
603
  limit,
605
604
  ordering,
606
- })
605
+ });
607
606
  }
608
607
  }
609
608
 
@@ -619,10 +618,10 @@ export class Dstore implements IDstore {
619
618
  * In fact the generated ID is namespaced via an incomplete [[Key]] of the given Kind.
620
619
  */
621
620
  async allocateOneId(kindName = 'Numbering'): Promise<string> {
622
- assertIsString(kindName)
623
- const ret = (await this.datastore.allocateIds(this.key([kindName]), 1))[0][0].id
624
- assertIsString(ret)
625
- return ret
621
+ assertIsString(kindName);
622
+ const ret = (await this.datastore.allocateIds(this.key([kindName]), 1))[0][0].id;
623
+ assertIsString(ret);
624
+ return ret;
626
625
  }
627
626
 
628
627
  /** This tries to give high level access to transactions.
@@ -640,27 +639,27 @@ export class Dstore implements IDstore {
640
639
  Most Applications today are running on "Firestore in Datastore Mode". Beware that the Datastore-Emulator fails with `error: 3 INVALID_ARGUMENT: Only ancestor queries are allowed inside transactions.` during [[runQuery]] while the Datastore on Google Infrastructure does not have such an restriction anymore as of 2022.
641
640
  */
642
641
  async runInTransaction<T>(func: () => Promise<T>): Promise<T> {
643
- let ret
644
- const transaction: Transaction = this.datastore.transaction()
642
+ let ret;
643
+ const transaction: Transaction = this.datastore.transaction();
645
644
  await transactionAsyncLocalStorage.run(transaction, async () => {
646
- const [transactionInfo, transactionRunApiResponse] = await transaction.run()
647
- let commitApiResponse
645
+ const [transactionInfo, transactionRunApiResponse] = await transaction.run();
646
+ let commitApiResponse;
648
647
  try {
649
- ret = await func()
648
+ ret = await func();
650
649
  } catch (error) {
651
- const rollbackInfo = await transaction.rollback()
650
+ const rollbackInfo = await transaction.rollback();
652
651
  debug(
653
652
  'Transaction failed, rollback initiated: %O %O %O %O',
654
653
  transactionInfo,
655
654
  transactionRunApiResponse,
656
655
  rollbackInfo,
657
656
  error
658
- )
659
- await setImmediate()
660
- throw new DstoreError('datastore.transaction execution error', error as Error)
657
+ );
658
+ await setImmediate();
659
+ throw new DstoreError('datastore.transaction execution error', error as Error);
661
660
  }
662
661
  try {
663
- commitApiResponse = (await transaction.commit())[0]
662
+ commitApiResponse = (await transaction.commit())[0];
664
663
  } catch (error) {
665
664
  debug(
666
665
  'Transaction commit failed: %O %O %O %O ret: %O',
@@ -669,36 +668,36 @@ export class Dstore implements IDstore {
669
668
  commitApiResponse,
670
669
  error,
671
670
  ret
672
- )
673
- await setImmediate()
674
- throw new DstoreError('datastore.transaction execution error', error as Error)
671
+ );
672
+ await setImmediate();
673
+ throw new DstoreError('datastore.transaction execution error', error as Error);
675
674
  }
676
- })
677
- return ret as T
675
+ });
676
+ return ret as T;
678
677
  }
679
678
  }
680
679
 
681
680
  export class DstoreError extends Error {
682
- public readonly extensions: Record<string, unknown>
681
+ public readonly extensions: Record<string, unknown>;
683
682
  public readonly originalError: Error | undefined;
684
- readonly [key: string]: unknown
683
+ readonly [key: string]: unknown;
685
684
 
686
685
  constructor(message: string, originalError: Error | undefined, extensions?: Record<string, unknown>) {
687
- super(`${message}: ${originalError?.message}`)
686
+ super(`${message}: ${originalError?.message}`);
688
687
 
689
688
  // if no name provided, use the default. defineProperty ensures that it stays non-enumerable
690
689
  if (!this.name) {
691
- Object.defineProperty(this, 'name', { value: 'DstoreError' })
690
+ Object.defineProperty(this, 'name', { value: 'DstoreError' });
692
691
  }
693
692
  // metadata: Metadata { internalRepr: Map(0) {}, options: {} },
694
- this.originalError = originalError
695
- this.extensions = { ...extensions }
693
+ this.originalError = originalError;
694
+ this.extensions = { ...extensions };
696
695
  this.stack =
697
696
  (this.stack?.split('\n')[0] || '') +
698
697
  '\n' +
699
698
  (originalError?.stack?.split('\n')?.slice(1)?.join('\n') || '') +
700
699
  '\n' +
701
- (this.stack?.split('\n')?.slice(1)?.join('\n') || '')
700
+ (this.stack?.split('\n')?.slice(1)?.join('\n') || '');
702
701
 
703
702
  // These are usually present on Datastore Errors
704
703
  // logger.error({ err: originalError, extensions }, message);