datastore-api 6.2.0 → 6.2.1

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.
@@ -5,26 +5,26 @@
5
5
  * Copyright (c) 2021, 2023 Dr. Maximilian Dornseif
6
6
  */
7
7
  // @ts-nocheck
8
- import { Datastore, Key } from '@google-cloud/datastore';
9
- import { assert, describe, expect, test } from 'vitest';
8
+ import { Datastore, Key } from '@google-cloud/datastore'
9
+ import { assert, describe, expect, test } from 'vitest'
10
10
 
11
- import { Dstore } from './dstore-api';
11
+ import { Dstore } from './dstore-api'
12
12
 
13
13
  function getDstore() {
14
- return new Dstore(new Datastore({ namespace: 'test', projectId: 'hdmashup-hrd' }));
14
+ return new Dstore(new Datastore({ namespace: 'test', projectId: 'hdmashup-hrd' }))
15
15
  }
16
16
 
17
17
  test('keySerialize', async () => {
18
- const kvStore = getDstore();
19
- assert.deepEqual(kvStore.key(['testYodel', 123]).path, ['testYodel', 123]);
18
+ const kvStore = getDstore()
19
+ assert.deepEqual(kvStore.key(['testYodel', 123]).path, ['testYodel', 123])
20
20
  assert.deepEqual(JSON.parse(JSON.stringify(kvStore.key(['testYodel', 123]))), {
21
21
  id: 123 as any, // typing in inconclusive here
22
22
  kind: 'testYodel',
23
23
  namespace: 'test',
24
24
  path: ['testYodel', 123],
25
- } as any);
26
- const ser = kvStore.keySerialize(kvStore.key(['testYodel', 123]));
27
- expect(ser).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBh7DKIBBHRlc3Q"');
25
+ } as any)
26
+ const ser = kvStore.keySerialize(kvStore.key(['testYodel', 123]))
27
+ expect(ser).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBh7DKIBBHRlc3Q"')
28
28
  expect(JSON.parse(JSON.stringify(kvStore.keyFromSerialized(ser)))).toMatchInlineSnapshot(`
29
29
  {
30
30
  "id": "123",
@@ -35,39 +35,39 @@ test('keySerialize', async () => {
35
35
  "123",
36
36
  ],
37
37
  }
38
- `);
39
- });
38
+ `)
39
+ })
40
40
 
41
41
  describe('Allocation', () => {
42
42
  test('allocateIds', async () => {
43
- const kvStore = getDstore();
44
- const keys = await kvStore.datastore.allocateIds(kvStore.datastore.key(['testYodel']), 2);
45
- expect(Array.isArray(keys)).toBeTruthy();
46
- expect(keys[0].length).toBe(2);
47
- expect(keys[0][0].kind).toBe('testYodel');
48
- expect(keys[0][0].id).toMatch(/\d+/);
49
- expect(keys?.[1]?.keys?.length).toBe(2);
50
- expect(keys[1].keys[0].partitionId.namespaceId).toMatchInlineSnapshot('"test"');
51
- expect(keys[1].keys[0].path[0].idType).toMatchInlineSnapshot('"id"');
52
- expect(keys[1].keys[0].path[0].kind).toMatchInlineSnapshot('"testYodel"');
53
- });
43
+ const kvStore = getDstore()
44
+ const keys = await kvStore.datastore.allocateIds(kvStore.datastore.key(['testYodel']), 2)
45
+ expect(Array.isArray(keys)).toBeTruthy()
46
+ expect(keys[0].length).toBe(2)
47
+ expect(keys[0][0].kind).toBe('testYodel')
48
+ expect(keys[0][0].id).toMatch(/\d+/)
49
+ expect(keys?.[1]?.keys?.length).toBe(2)
50
+ expect(keys[1].keys[0].partitionId.namespaceId).toMatchInlineSnapshot('"test"')
51
+ expect(keys[1].keys[0].path[0].idType).toMatchInlineSnapshot('"id"')
52
+ expect(keys[1].keys[0].path[0].kind).toMatchInlineSnapshot('"testYodel"')
53
+ })
54
54
 
55
55
  test('allocateOneId', async () => {
56
- const kvStore = getDstore();
57
- const id = await kvStore.allocateOneId();
58
- expect(id).toMatch(/\d+/);
59
- });
60
- });
56
+ const kvStore = getDstore()
57
+ const id = await kvStore.allocateOneId()
58
+ expect(id).toMatch(/\d+/)
59
+ })
60
+ })
61
61
 
62
62
  describe('Read', () => {
63
63
  test('get num_id', async () => {
64
- const kvStore = getDstore();
65
- const entity = { key: kvStore.key(['testYodel', 2]), data: { foo: 'bar' } };
64
+ const kvStore = getDstore()
65
+ const entity = { key: kvStore.key(['testYodel', 2]), data: { foo: 'bar' } }
66
66
  const entity2 = {
67
67
  key: kvStore.key(['testYodel', 3]),
68
68
  data: { foo: 'bar' },
69
- };
70
- const commitResponse = await kvStore.save([entity, entity2]);
69
+ }
70
+ const commitResponse = await kvStore.save([entity, entity2])
71
71
  // expect(isNumber(commitResponse?.[0]?.indexUpdates)).toBeTruthy();
72
72
  // expect(commitResponse).toMatchInlineSnapshot(`
73
73
  // Array [
@@ -109,22 +109,22 @@ describe('Read', () => {
109
109
  ],
110
110
  },
111
111
  }
112
- `);
112
+ `)
113
113
 
114
- const result = await kvStore.get(entity.key);
114
+ const result = await kvStore.get(entity.key)
115
115
  // get returns a single Entity
116
- expect(Array.isArray(result)).toBeFalsy();
117
- expect(result).toMatchInlineSnapshot('null');
116
+ expect(Array.isArray(result)).toBeFalsy()
117
+ expect(result).toMatchInlineSnapshot('null')
118
118
  // expect(kvStore.readKey(result)).toBeInstanceOf(Key);
119
119
 
120
- const result2 = await kvStore.getMulti([entity.key]);
120
+ const result2 = await kvStore.getMulti([entity.key])
121
121
  // getMulti returns a Array even for single keys
122
122
  expect(result2).toMatchInlineSnapshot(`
123
123
  [
124
124
  null,
125
125
  ]
126
- `);
127
- const result3 = await kvStore.getMulti([entity.key, kvStore.key(['testYodel', 3])]);
126
+ `)
127
+ const result3 = await kvStore.getMulti([entity.key, kvStore.key(['testYodel', 3])])
128
128
  // getMulti returns a Array with multiple keys
129
129
  // expect(Array.isArray(result)).toBeTruthy();
130
130
  expect(result3).toMatchInlineSnapshot(`
@@ -132,8 +132,8 @@ describe('Read', () => {
132
132
  null,
133
133
  null,
134
134
  ]
135
- `);
136
- const result4 = await kvStore.getMulti([entity.key, entity.key]);
135
+ `)
136
+ const result4 = await kvStore.getMulti([entity.key, entity.key])
137
137
  // getMulti returns a Array but collapses duplicate keys
138
138
  // expect(Array.isArray(result)).toBeTruthy();
139
139
  // Firestore in Datastore returns the entity once
@@ -144,9 +144,9 @@ describe('Read', () => {
144
144
  null,
145
145
  null,
146
146
  ]
147
- `);
147
+ `)
148
148
 
149
- const result5 = await kvStore.getMulti([entity.key, kvStore.key(['YodelNotThere', 3])]);
149
+ const result5 = await kvStore.getMulti([entity.key, kvStore.key(['YodelNotThere', 3])])
150
150
  // getMulti returns a Array but omits unknown keys
151
151
  // expect(Array.isArray(result)).toBeTruthy();
152
152
  expect(result5).toMatchInlineSnapshot(`
@@ -154,39 +154,39 @@ describe('Read', () => {
154
154
  null,
155
155
  null,
156
156
  ]
157
- `);
158
- const result6 = await kvStore.getMulti([]);
157
+ `)
158
+ const result6 = await kvStore.getMulti([])
159
159
  // getMulti returns a empty Array for an empty array
160
160
  // expect(Array.isArray(result)).toBeTruthy();
161
- expect(result6).toMatchInlineSnapshot('[]');
162
- });
163
- });
161
+ expect(result6).toMatchInlineSnapshot('[]')
162
+ })
163
+ })
164
164
 
165
165
  test('get name', async (t) => {
166
- const kvStore = getDstore();
166
+ const kvStore = getDstore()
167
167
  const entity = {
168
168
  key: kvStore.key(['testYodel', 'two']),
169
169
  data: { foo: 'bar' },
170
- };
171
- await kvStore.save([entity]);
172
- const result = await kvStore.get(entity.key);
173
- expect(result?._keyStr).toMatchInlineSnapshot('"agByEgsSCXRlc3RZb2RlbCIDdHdvDKIBBHRlc3Q"');
174
- expect(result?.foo).toBe('bar');
175
- });
170
+ }
171
+ await kvStore.save([entity])
172
+ const result = await kvStore.get(entity.key)
173
+ expect(result?._keyStr).toMatchInlineSnapshot('"agByEgsSCXRlc3RZb2RlbCIDdHdvDKIBBHRlc3Q"')
174
+ expect(result?.foo).toBe('bar')
175
+ })
176
176
 
177
177
  describe('query', async () => {
178
178
  test('raw', async () => {
179
- const kvStore = getDstore();
179
+ const kvStore = getDstore()
180
180
  const entity = {
181
181
  key: kvStore.key(['testYodel', '3']),
182
182
  data: { foo: 'bar', baz: 'baz' },
183
- };
183
+ }
184
184
 
185
- await kvStore.save([entity]);
186
- const query = kvStore.datastore.createQuery('testYodel');
187
- query.limit(1);
188
- const [entities, runQueryInfo] = await kvStore.datastore.runQuery(query);
189
- expect(entities.length).toBe(1);
185
+ await kvStore.save([entity])
186
+ const query = kvStore.datastore.createQuery('testYodel')
187
+ query.limit(1)
188
+ const [entities, runQueryInfo] = await kvStore.datastore.runQuery(query)
189
+ expect(entities.length).toBe(1)
190
190
  expect(entities).toMatchInlineSnapshot(`
191
191
  [
192
192
  {
@@ -202,18 +202,18 @@ describe('query', async () => {
202
202
  },
203
203
  },
204
204
  ]
205
- `);
206
- });
205
+ `)
206
+ })
207
207
 
208
208
  test('query', async () => {
209
- const kvStore = getDstore();
209
+ const kvStore = getDstore()
210
210
  const entity = {
211
211
  key: kvStore.key(['testYodel', '3']),
212
212
  data: { foo: 'bar', baz: 'baz' },
213
- };
213
+ }
214
214
 
215
- const saveResult = await kvStore.save([entity]);
216
- expect(saveResult?.[0]?.mutationResults?.key).toMatchInlineSnapshot('undefined');
215
+ const saveResult = await kvStore.save([entity])
216
+ expect(saveResult?.[0]?.mutationResults?.key).toMatchInlineSnapshot('undefined')
217
217
 
218
218
  // expect(saveResult).toMatchInlineSnapshot(`
219
219
  // [
@@ -253,13 +253,13 @@ describe('query', async () => {
253
253
  ],
254
254
  },
255
255
  }
256
- `);
256
+ `)
257
257
  // Give Datastore time to become consistent
258
- do {} while ((await kvStore.get(entity.key)) === null);
258
+ do { } while ((await kvStore.get(entity.key)) === null)
259
259
 
260
- const query = kvStore.createQuery('testYodel');
261
- query.limit(1);
262
- const [entities, runQueryInfo] = await kvStore.runQuery(query);
260
+ const query = kvStore.createQuery('testYodel')
261
+ query.limit(1)
262
+ const [entities, runQueryInfo] = await kvStore.runQuery(query)
263
263
  // expect(entities.length).toBe(1)
264
264
  expect(entities).toMatchInlineSnapshot(`
265
265
  [
@@ -277,112 +277,112 @@ describe('query', async () => {
277
277
  },
278
278
  },
279
279
  ]
280
- `);
280
+ `)
281
281
  expect(runQueryInfo).toMatchInlineSnapshot(`
282
282
  {
283
283
  "endCursor": "Ci4SKGoOc35oZG1hc2h1cC1ocmRyDwsSCXRlc3RZb2RlbBgCDKIBBHRlc3QYACAA",
284
284
  "moreResults": "MORE_RESULTS_AFTER_LIMIT",
285
285
  }
286
- `);
287
- expect(entities?.[0]?.foo).toBe('bar');
288
- expect(entities?.[0]?.[Datastore.KEY]?.kind).toBe('testYodel');
289
- expect(runQueryInfo?.moreResults).toBe('MORE_RESULTS_AFTER_LIMIT');
286
+ `)
287
+ expect(entities?.[0]?.foo).toBe('bar')
288
+ expect(entities?.[0]?.[Datastore.KEY]?.kind).toBe('testYodel')
289
+ expect(runQueryInfo?.moreResults).toBe('MORE_RESULTS_AFTER_LIMIT')
290
290
 
291
291
  // modern interface
292
- const [result2] = await kvStore.query('testYodel', [], 1, [], ['baz']);
293
- expect(result2.length).toBe(1);
292
+ const [result2] = await kvStore.query('testYodel', [], 1, [], ['baz'])
293
+ expect(result2.length).toBe(1)
294
294
  // foo is removed by selection
295
295
  expect(JSON.parse(JSON.stringify(result2?.[0]))).toMatchInlineSnapshot(`
296
296
  {
297
297
  "_keyStr": "agByEAsSCXRlc3RZb2RlbCIBMwyiAQR0ZXN0",
298
298
  "baz": "baz",
299
299
  }
300
- `);
300
+ `)
301
301
 
302
- const key = kvStore.readKey(result2?.[0]);
303
- expect(key.id).toBe(entity.key.id);
304
- });
305
- });
302
+ const key = kvStore.readKey(result2?.[0])
303
+ expect(key.id).toBe(entity.key.id)
304
+ })
305
+ })
306
306
 
307
307
  test('set', async () => {
308
308
  // expect.assertions(2);
309
- const kvStore = getDstore();
309
+ const kvStore = getDstore()
310
310
  const result = await kvStore.set(kvStore.key(['testYodel', '5e7']), {
311
311
  foo: 'bar',
312
- });
313
- expect(result.name).toBe('5e7');
314
- expect(result.kind).toBe('testYodel');
312
+ })
313
+ expect(result.name).toBe('5e7')
314
+ expect(result.kind).toBe('testYodel')
315
315
 
316
316
  // autogenerate key
317
- const result2 = await kvStore.set(kvStore.key(['testYodel']), { foo: 'bar' });
318
- expect(result2.kind).toBe('testYodel');
319
- });
317
+ const result2 = await kvStore.set(kvStore.key(['testYodel']), { foo: 'bar' })
318
+ expect(result2.kind).toBe('testYodel')
319
+ })
320
320
 
321
321
  test('save / upsert', async () => {
322
322
  // expect.assertions(2);
323
- const kvStore = getDstore();
323
+ const kvStore = getDstore()
324
324
  const entity = {
325
325
  key: kvStore.key(['testYodel', 3]),
326
326
  data: { foo: 'bar' } as any,
327
- };
328
- const result = await kvStore.save([entity]);
327
+ }
328
+ const result = await kvStore.save([entity])
329
329
  // const result2 = await kvStore.upsert([entity]);
330
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
331
- expect(entity.data._keyStr).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBgDDKIBBHRlc3Q"');
332
- expect(entity.data.foo).toBe('bar');
333
- expect(entity.data[Datastore.KEY].kind).toBe('testYodel');
334
- });
330
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
331
+ expect(entity.data._keyStr).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBgDDKIBBHRlc3Q"')
332
+ expect(entity.data.foo).toBe('bar')
333
+ expect(entity.data[Datastore.KEY].kind).toBe('testYodel')
334
+ })
335
335
 
336
336
  test('update', async (t) => {
337
337
  // expect.assertions(3);
338
- const kvStore = getDstore();
339
- const keyName = `4insert${Math.random()}`;
338
+ const kvStore = getDstore()
339
+ const keyName = `4insert${Math.random()}`
340
340
  const entity = {
341
341
  key: kvStore.key(['testYodel', keyName]),
342
342
  data: { foo: 'bar' },
343
- };
343
+ }
344
344
  // const request = kvStore.update([entity]);
345
345
  // await expect(request).rejects.toThrowError(Error);
346
346
 
347
- await kvStore.save([entity]);
348
- const result = await kvStore.update([entity]);
349
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
350
- expect(result?.[0]?.mutationResults?.[0]?.key).toBe(null);
347
+ await kvStore.save([entity])
348
+ const result = await kvStore.update([entity])
349
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
350
+ expect(result?.[0]?.mutationResults?.[0]?.key).toBe(null)
351
351
  // expect(result?.[0]?.indexUpdates).toBe(2);
352
- });
352
+ })
353
353
 
354
354
  test('insert / delete', async (t) => {
355
355
  // expect.assertions(2);
356
- const kvStore = getDstore();
357
- const testkey = kvStore.key(['testYodel', 4]);
358
- await kvStore.delete([testkey]);
356
+ const kvStore = getDstore()
357
+ const testkey = kvStore.key(['testYodel', 4])
358
+ await kvStore.delete([testkey])
359
359
  const entity = {
360
360
  key: testkey,
361
361
  data: { foo: 'bar' } as any,
362
- };
363
- const result = await kvStore.insert([entity]);
362
+ }
363
+ const result = await kvStore.insert([entity])
364
364
 
365
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
366
- expect(result?.[0]?.mutationResults?.[0]?.version).toMatch(/\d+/);
367
- expect(entity.data.foo).toBe('bar');
368
- expect(entity.key.path[0]).toBe('testYodel');
365
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
366
+ expect(result?.[0]?.mutationResults?.[0]?.version).toMatch(/\d+/)
367
+ expect(entity.data.foo).toBe('bar')
368
+ expect(entity.key.path[0]).toBe('testYodel')
369
369
  // expect(result?.[0]?.indexUpdates).toBe(3);
370
370
 
371
- const result2 = await kvStore.delete([entity.key]);
372
- expect(result2?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
373
- });
371
+ const result2 = await kvStore.delete([entity.key])
372
+ expect(result2?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
373
+ })
374
374
 
375
375
  test('exception', async () => {
376
376
  // expect.assertions(2);
377
- const kvStore = getDstore();
377
+ const kvStore = getDstore()
378
378
  try {
379
379
  const result = await kvStore.set(kvStore.key(['testYodel', NaN]), {
380
380
  foo: 'bar',
381
- });
381
+ })
382
382
  } catch (e) {
383
- expect(e.stack).toMatch(/Dstore\.set/);
383
+ expect(e.stack).toMatch(/Dstore\.set/)
384
384
  }
385
- });
385
+ })
386
386
  // describe("Transactions", () => {
387
387
  // it("simple", async () => {
388
388
  // expect.assertions(2);
@@ -28,6 +28,7 @@ import {
28
28
  import Debug from 'debug'
29
29
  import promClient from 'prom-client'
30
30
  import { Writable } from 'ts-essentials'
31
+ import { assertIsKey } from './assert'
31
32
 
32
33
  /** @ignore */
33
34
  export { Datastore, Key, PathType, Query, Transaction } from '@google-cloud/datastore'
@@ -94,6 +95,15 @@ export interface IDstoreEntry extends IDstoreEntryWithoutKey {
94
95
  _keyStr: string
95
96
  }
96
97
 
98
+ /** Represents what is actually stored inside the Datastore, called "Entity" by Google
99
+ */
100
+ export interface IDstoreEntryWithKey extends IDstoreEntry {
101
+ /* Datastore Key provided by [@google-cloud/datastore](https://github.com/googleapis/nodejs-datastore#readme) */
102
+ readonly [Datastore.KEY]: Key
103
+ /** [Datastore.KEY] key */
104
+ _keyStr: string
105
+ }
106
+
97
107
  /** Represents the thing you pass to the save method. Also called "Entity" by Google */
98
108
  export type DstoreSaveEntity = {
99
109
  key: Key
@@ -271,6 +281,29 @@ export class Dstore implements IDstore {
271
281
  return entities as Array<IDstoreEntry | undefined>
272
282
  }
273
283
 
284
+ /** this is for save, insert, update and upsert and ensures _kkeyStr() handling.
285
+ *
286
+ */
287
+ private prepareEntitiesForDatastore(entities: readonly DstoreSaveEntity[]) {
288
+ for (const e of entities) {
289
+ assertIsObject(e.key)
290
+ assertIsObject(e.data)
291
+ this.fixKeys([e.data])
292
+ e.excludeLargeProperties = e.excludeLargeProperties === undefined ? true : e.excludeLargeProperties
293
+ e.data = { ...e.data, _keyStr: undefined }
294
+ }
295
+ }
296
+
297
+ /** this is for save, insert, update and upsert and ensures _kkeyStr() handling.
298
+ *
299
+ */
300
+ private prepareEntitiesFromDatastore(entities: readonly DstoreSaveEntity[] & unknown[]) {
301
+ for (const e of entities) {
302
+ e.data[Datastore.KEY] = e.key
303
+ this.fixKeys([e.data])
304
+ }
305
+ }
306
+
274
307
  /** `get()` reads a [[IDstoreEntry]] from the Datastore.
275
308
  *
276
309
  * It returns [[IDstoreEntry]] or `null` if not found.
@@ -399,20 +432,11 @@ export class Dstore implements IDstore {
399
432
  let ret: CommitResponse | undefined
400
433
  const metricEnd = metricHistogram.startTimer()
401
434
  try {
435
+ this.prepareEntitiesForDatastore(entities)
402
436
  // Within Transaction we don't get any answer here!
403
437
  // [ { mutationResults: [ [Object], [Object] ], indexUpdates: 51 } ]
404
- for (const e of entities) {
405
- assertIsObject(e.key)
406
- assertIsObject(e.data)
407
- this.fixKeys([e.data])
408
- e.excludeLargeProperties = e.excludeLargeProperties === undefined ? true : e.excludeLargeProperties
409
- e.data = { ...e.data, _keyStr: undefined }
410
- }
411
438
  ret = (await this.getDoT().save(entities)) || undefined
412
- for (const e of entities) {
413
- e.data[Datastore.KEY] = e.key
414
- this.fixKeys([e.data])
415
- }
439
+ this.prepareEntitiesFromDatastore(entities)
416
440
  } catch (error) {
417
441
  metricFailureCounter.inc({ operation: 'save' })
418
442
  await setImmediate()
@@ -423,6 +447,8 @@ export class Dstore implements IDstore {
423
447
  return ret
424
448
  }
425
449
 
450
+
451
+
426
452
  /** `insert()` is compatible to [Datastore.insert()](https://cloud.google.com/nodejs/docs/reference/datastore/latest/datastore/datastore#_google_cloud_datastore_Datastore_insert_member_1_).
427
453
  *
428
454
  * The single Parameter is a list of [[DstoreSaveEntity]]s.
@@ -446,7 +472,9 @@ export class Dstore implements IDstore {
446
472
  let ret: CommitResponse | undefined
447
473
  const metricEnd = metricHistogram.startTimer()
448
474
  try {
475
+ this.prepareEntitiesForDatastore(entities)
449
476
  ret = (await this.getDoT().insert(entities)) || undefined
477
+ this.prepareEntitiesFromDatastore(entities)
450
478
  } catch (error) {
451
479
  // console.error(error)
452
480
  metricFailureCounter.inc({ operation: 'insert' })
@@ -490,7 +518,9 @@ export class Dstore implements IDstore {
490
518
  const metricEnd = metricHistogram.startTimer()
491
519
 
492
520
  try {
521
+ this.prepareEntitiesForDatastore(entities)
493
522
  ret = (await this.getDoT().update(entities)) || undefined
523
+ this.prepareEntitiesFromDatastore(entities)
494
524
  } catch (error) {
495
525
  // console.error(error)
496
526
  metricFailureCounter.inc({ operation: 'update' })
@@ -606,7 +636,8 @@ export class Dstore implements IDstore {
606
636
  if (selection.length > 0) {
607
637
  q.select(selection as any)
608
638
  }
609
- return await this.runQuery(q)
639
+ const ret = await this.getDoT().runQuery(q)
640
+ return [this.fixKeys(ret[0]), ret[1]]
610
641
  } catch (error) {
611
642
  await setImmediate()
612
643
  throw new DstoreError('datastore.query error', error as Error, {
@@ -624,12 +655,21 @@ export class Dstore implements IDstore {
624
655
  * It takes a Parameter object and returns an AsyncIterable.
625
656
  * Entities returned have been processed by `fixKeys()`.
626
657
  *
658
+ * Can be used with `for await` loops like this:
659
+ *
660
+ * ```typescript
661
+ * for await (const entity of dstore.iterate({ kindName: 'p_ReservierungsAbruf', filters: [['verbucht', '=', true]]})) {
662
+ * console.log(entity)
663
+ * }
664
+ * ```
665
+ *
627
666
  * @param kindName Name of the [[Datastore]][Kind](https://cloud.google.com/datastore/docs/concepts/entities#kinds_and_identifiers) ("Table") which should be searched.
628
667
  * @param filters List of [[Query]] filter() calls.
629
668
  * @param limit Maximum Number of Results to return.
630
669
  * @param ordering List of [[Query]] order() calls.
631
670
  * @param selection selectionList of [[Query]] select() calls.
632
671
  *
672
+ * @throws [[DstoreError]]
633
673
  * @category Additional
634
674
  */
635
675
  async * iterate({
@@ -658,10 +698,11 @@ export class Dstore implements IDstore {
658
698
  if (selection.length > 0) {
659
699
  q.select(selection as any)
660
700
  }
661
- for await (const entity of this.getDoT().runStream(q)) {
701
+ for await (const entity of q.runStream()) {
662
702
  const ret = this.fixKeys([entity])[0]
663
703
  assertIsDefined(ret, 'datastore.iterate: entity is undefined')
664
- yield ret
704
+ assertIsKey(ret[Datastore.KEY])
705
+ yield ret as IDstoreEntryWithKey
665
706
  }
666
707
  } catch (error) {
667
708
  await setImmediate()