datastore-api 6.2.3 → 6.4.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.
@@ -6,30 +6,43 @@
6
6
  */
7
7
  // @ts-nocheck
8
8
  // import { Datastore, Key } from '@google-cloud/datastore';
9
- import { afterAll, assert, beforeAll, describe, expect, test } from 'vitest';
9
+ import { afterAll, assert, beforeAll, describe, expect, test } from 'vitest'
10
10
 
11
- import { Datastore } from '../mock';
11
+ import { Datastore } from '../mock'
12
12
 
13
- import { Dstore } from './dstore-api';
13
+ import { Dstore } from './dstore-api'
14
14
 
15
- process.env.GCLOUD_PROJECT = 'project-id'; // Set the datastore project Id globally
16
- let emulator;
15
+ process.env.GCLOUD_PROJECT = 'project-id' // Set the datastore project Id globally
16
+ let emulator, entity, saveResult
17
+
18
+ beforeAll(async () => {
19
+ // Data for the query tests
20
+ const kvStore = getDstore()
21
+ entity = {
22
+ key: kvStore.key(['testYodel', '3']),
23
+ data: { foo: 'bar', baz: 'baz' },
24
+ }
25
+
26
+ saveResult = await kvStore.save([entity])
27
+ // Give Datastore time to become consistent
28
+ do { } while ((await kvStore.get(entity.key)) === null)
29
+ })
17
30
 
18
31
  function getDstore() {
19
- return new Dstore(new Datastore({ namespace: 'test', projectId: process.env.GCLOUD_PROJECT }));
32
+ return new Dstore(new Datastore({ namespace: 'test', projectId: process.env.GCLOUD_PROJECT }))
20
33
  }
21
34
 
22
35
  test('keySerialize', async () => {
23
- const kvStore = getDstore();
24
- assert.deepEqual(kvStore.key(['testYodel', 123]).path, ['testYodel', 123]);
36
+ const kvStore = getDstore()
37
+ assert.deepEqual(kvStore.key(['testYodel', 123]).path, ['testYodel', 123])
25
38
  assert.deepEqual(JSON.parse(JSON.stringify(kvStore.key(['testYodel', 123]))), {
26
39
  id: 123 as any, // typing in inconclusive here
27
40
  kind: 'testYodel',
28
41
  namespace: 'test',
29
42
  path: ['testYodel', 123],
30
- } as any);
31
- const ser = kvStore.keySerialize(kvStore.key(['testYodel', 123]));
32
- expect(ser).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBh7DKIBBHRlc3Q"');
43
+ } as any)
44
+ const ser = kvStore.keySerialize(kvStore.key(['testYodel', 123]))
45
+ expect(ser).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBh7DKIBBHRlc3Q"')
33
46
  expect(JSON.parse(JSON.stringify(kvStore.keyFromSerialized(ser)))).toMatchInlineSnapshot(`
34
47
  {
35
48
  "id": "123",
@@ -40,18 +53,18 @@ test('keySerialize', async () => {
40
53
  "123",
41
54
  ],
42
55
  }
43
- `);
44
- });
56
+ `)
57
+ })
45
58
  test('keyFromLegacyUrlsafe', async () => {
46
- const kvStore = getDstore();
47
- const ser = await kvStore.datastore.keyToLegacyUrlSafe(kvStore.key(['testYodel', 123]));
59
+ const kvStore = getDstore()
60
+ const ser = await kvStore.datastore.keyToLegacyUrlSafe(kvStore.key(['testYodel', 123]))
48
61
  expect(ser).toMatchInlineSnapshot(`
49
62
  [
50
63
  "agpwcm9qZWN0LWlkcg8LEgl0ZXN0WW9kZWwYewyiAQR0ZXN0",
51
64
  ]
52
- `);
65
+ `)
53
66
 
54
- const key = kvStore.datastore.keyFromLegacyUrlsafe(ser[0]);
67
+ const key = kvStore.datastore.keyFromLegacyUrlsafe(ser[0])
55
68
  expect(key).toMatchInlineSnapshot(`
56
69
  Key {
57
70
  "id": "123",
@@ -62,40 +75,40 @@ test('keyFromLegacyUrlsafe', async () => {
62
75
  "123",
63
76
  ],
64
77
  }
65
- `);
66
- expect(kvStore.datastore.isKey(key)).toBeTruthy();
67
- });
78
+ `)
79
+ expect(kvStore.datastore.isKey(key)).toBeTruthy()
80
+ })
68
81
 
69
82
  describe('Allocation', () => {
70
83
  test('allocateIds', async () => {
71
- const kvStore = getDstore();
72
- const keys = await kvStore.datastore.allocateIds(kvStore.datastore.key(['testYodel']), 2);
73
- expect(Array.isArray(keys)).toBeTruthy();
74
- expect(keys[0].length).toBe(2);
75
- expect(keys[0][0].kind).toBe('testYodel');
76
- expect(keys[0][0].id).toMatch(/\d+/);
77
- expect(keys?.[1]?.keys?.length).toBe(2);
78
- expect(keys[1].keys[0].partitionId.namespaceId).toMatchInlineSnapshot('"test"');
79
- expect(keys[1].keys[0].path[0].idType).toMatchInlineSnapshot('"id"');
80
- expect(keys[1].keys[0].path[0].kind).toMatchInlineSnapshot('"testYodel"');
81
- });
84
+ const kvStore = getDstore()
85
+ const keys = await kvStore.datastore.allocateIds(kvStore.datastore.key(['testYodel']), 2)
86
+ expect(Array.isArray(keys)).toBeTruthy()
87
+ expect(keys[0].length).toBe(2)
88
+ expect(keys[0][0].kind).toBe('testYodel')
89
+ expect(keys[0][0].id).toMatch(/\d+/)
90
+ expect(keys?.[1]?.keys?.length).toBe(2)
91
+ expect(keys[1].keys[0].partitionId.namespaceId).toMatchInlineSnapshot('"test"')
92
+ expect(keys[1].keys[0].path[0].idType).toMatchInlineSnapshot('"id"')
93
+ expect(keys[1].keys[0].path[0].kind).toMatchInlineSnapshot('"testYodel"')
94
+ })
82
95
 
83
96
  test('allocateOneId', async () => {
84
- const kvStore = getDstore();
85
- const id = await kvStore.allocateOneId();
86
- expect(id).toMatch(/\d+/);
87
- });
88
- });
97
+ const kvStore = getDstore()
98
+ const id = await kvStore.allocateOneId()
99
+ expect(id).toMatch(/\d+/)
100
+ })
101
+ })
89
102
 
90
103
  describe('Read', () => {
91
104
  test('get num_id', async () => {
92
- const kvStore = getDstore();
93
- const entity = { key: kvStore.key(['testYodel', 2]), data: { foo: 'bar' } };
105
+ const kvStore = getDstore()
106
+ const entity = { key: kvStore.key(['testYodel', 2]), data: { foo: 'bar' } }
94
107
  const entity2 = {
95
108
  key: kvStore.key(['testYodel', 3]),
96
109
  data: { foo: 'bar' },
97
- };
98
- const commitResponse = await kvStore.save([entity, entity2]);
110
+ }
111
+ const commitResponse = await kvStore.save([entity, entity2])
99
112
  // expect(isNumber(commitResponse?.[0]?.indexUpdates)).toBeTruthy();
100
113
  // expect(commitResponse).toMatchInlineSnapshot(`
101
114
  // Array [
@@ -137,22 +150,22 @@ describe('Read', () => {
137
150
  ],
138
151
  },
139
152
  }
140
- `);
153
+ `)
141
154
 
142
- const result = await kvStore.get(entity.key);
155
+ const result = await kvStore.get(entity.key)
143
156
  // get returns a single Entity
144
- expect(Array.isArray(result)).toBeFalsy();
145
- expect(result).toMatchInlineSnapshot('null');
157
+ expect(Array.isArray(result)).toBeFalsy()
158
+ expect(result).toMatchInlineSnapshot('null')
146
159
  // expect(kvStore.readKey(result)).toBeInstanceOf(Key);
147
160
 
148
- const result2 = await kvStore.getMulti([entity.key]);
161
+ const result2 = await kvStore.getMulti([entity.key])
149
162
  // getMulti returns a Array even for single keys
150
163
  expect(result2).toMatchInlineSnapshot(`
151
164
  [
152
165
  null,
153
166
  ]
154
- `);
155
- const result3 = await kvStore.getMulti([entity.key, kvStore.key(['testYodel', 3])]);
167
+ `)
168
+ const result3 = await kvStore.getMulti([entity.key, kvStore.key(['testYodel', 3])])
156
169
  // getMulti returns a Array with multiple keys
157
170
  // expect(Array.isArray(result)).toBeTruthy();
158
171
  expect(result3).toMatchInlineSnapshot(`
@@ -160,8 +173,8 @@ describe('Read', () => {
160
173
  null,
161
174
  null,
162
175
  ]
163
- `);
164
- const result4 = await kvStore.getMulti([entity.key, entity.key]);
176
+ `)
177
+ const result4 = await kvStore.getMulti([entity.key, entity.key])
165
178
  // getMulti returns a Array but collapses duplicate keys
166
179
  // expect(Array.isArray(result)).toBeTruthy();
167
180
  // Firestore in Datastore returns the entity once
@@ -172,9 +185,9 @@ describe('Read', () => {
172
185
  null,
173
186
  null,
174
187
  ]
175
- `);
188
+ `)
176
189
 
177
- const result5 = await kvStore.getMulti([entity.key, kvStore.key(['YodelNotThere', 3])]);
190
+ const result5 = await kvStore.getMulti([entity.key, kvStore.key(['YodelNotThere', 3])])
178
191
  // getMulti returns a Array but omits unknown keys
179
192
  // expect(Array.isArray(result)).toBeTruthy();
180
193
  expect(result5).toMatchInlineSnapshot(`
@@ -182,233 +195,195 @@ describe('Read', () => {
182
195
  null,
183
196
  null,
184
197
  ]
185
- `);
186
- const result6 = await kvStore.getMulti([]);
198
+ `)
199
+ const result6 = await kvStore.getMulti([])
187
200
  // getMulti returns a empty Array for an empty array
188
201
  // expect(Array.isArray(result)).toBeTruthy();
189
- expect(result6).toMatchInlineSnapshot('[]');
190
- });
202
+ expect(result6).toMatchInlineSnapshot('[]')
203
+ })
191
204
 
192
205
  test('get name', async (t) => {
193
- const kvStore = getDstore();
206
+ const kvStore = getDstore()
194
207
  const entity = {
195
208
  key: kvStore.key(['testYodel', 'two']),
196
209
  data: { foo: 'bar' },
197
- };
198
- await kvStore.save([entity]);
199
- const result = await kvStore.get(entity.key);
200
- expect(result?._keyStr).toMatchInlineSnapshot('"agByEgsSCXRlc3RZb2RlbCIDdHdvDKIBBHRlc3Q"');
201
- expect(result?.foo).toBe('bar');
202
- });
203
- });
204
- describe('query', async () => {
205
- test.skip('raw', async () => {
206
- const kvStore = getDstore();
207
- const entity = {
208
- key: kvStore.key(['testYodel', '3']),
209
- data: { foo: 'bar', baz: 'baz' },
210
- };
211
-
212
- await kvStore.save([entity]);
213
- const query = kvStore.datastore.createQuery('testYodel');
214
- query.limit(1);
215
- const [entities, runQueryInfo] = await kvStore.datastore.runQuery(query);
216
- expect(entities.length).toBe(1);
217
- expect(entities).toMatchInlineSnapshot(`
218
- [
219
- {
220
- "foo": "bar",
221
- Symbol(KEY): Key {
222
- "id": "2",
223
- "kind": "testYodel",
224
- "namespace": "test",
225
- "path": [
226
- "testYodel",
227
- "2",
228
- ],
229
- },
230
- },
231
- ]
232
- `);
233
- });
234
-
235
- test('query', async () => {
236
- const kvStore = getDstore();
237
- const entity = {
238
- key: kvStore.key(['testYodel', '3']),
239
- data: { foo: 'bar', baz: 'baz' },
240
- };
241
-
242
- const saveResult = await kvStore.save([entity]);
210
+ }
211
+ await kvStore.save([entity])
212
+ const result = await kvStore.get(entity.key)
213
+ expect(result?._keyStr).toMatchInlineSnapshot('"agByEgsSCXRlc3RZb2RlbCIDdHdvDKIBBHRlc3Q"')
214
+ expect(result?.foo).toBe('bar')
215
+ })
216
+ })
217
+
218
+ describe('queryies', async () => {
219
+ test('sanity check', async () => {
220
+ const kvStore = getDstore()
243
221
  expect(saveResult).toMatchInlineSnapshot(`
244
- [
245
- {
246
- "indexUpdates": 1,
247
- "mutationResults": [
248
- {
249
- "conflictDetected": false,
250
- "createTime": {
251
- "nanos": 1,
252
- "seconds": 2,
253
- },
254
- "key": null,
255
- "updateTime": {
256
- "nanos": 3,
257
- "seconds": 4,
258
- },
259
- "version": 1,
260
- },
261
- ],
262
- },
263
- ]
264
- `);
265
- expect(await kvStore.get(entity.key)).toMatchInlineSnapshot(`
222
+ [
266
223
  {
267
- "_keyStr": "agByEAsSCXRlc3RZb2RlbCIBMwyiAQR0ZXN0",
268
- "baz": "baz",
269
- "foo": "bar",
270
- Symbol(KEY): Key {
271
- "kind": "testYodel",
272
- "name": "3",
273
- "namespace": "test",
274
- "path": [
275
- "testYodel",
276
- "3",
277
- ],
278
- },
279
- }
280
- `);
224
+ "indexUpdates": 1,
225
+ "mutationResults": [
226
+ {
227
+ "conflictDetected": false,
228
+ "createTime": {
229
+ "nanos": 1,
230
+ "seconds": 2,
231
+ },
232
+ "key": null,
233
+ "updateTime": {
234
+ "nanos": 3,
235
+ "seconds": 4,
236
+ },
237
+ "version": 1,
238
+ },
239
+ ],
240
+ },
241
+ ]
242
+ `)
281
243
 
282
- // Give Datastore time to become consistent
283
- do {} while ((await kvStore.get(entity.key)) === null);
244
+ expect(await kvStore.get(entity.key)).toMatchInlineSnapshot(`null`)
245
+ })
284
246
 
285
- const query = kvStore.createQuery('testYodel');
286
- query.limit(1);
287
- const [entities, runQueryInfo] = await kvStore.runQuery(query);
247
+ test('raw', async () => {
248
+ const kvStore = getDstore()
249
+ const query = kvStore.datastore.createQuery('testYodel')
250
+ query.limit(1)
251
+ const [entities, runQueryInfo] = await kvStore.datastore.runQuery(query)
288
252
  // expect(entities.length).toBe(1)
289
- expect(entities).toMatchInlineSnapshot(`
290
- [
291
- {
292
- "_keyStr": "agByEAsSCXRlc3RZb2RlbCIBMwyiAQR0ZXN0",
293
- "baz": "baz",
294
- "foo": "bar",
295
- Symbol(KEY): Key {
296
- "kind": "testYodel",
297
- "name": "3",
298
- "namespace": "test",
299
- "path": [
300
- "testYodel",
301
- "3",
302
- ],
303
- },
304
- },
305
- ]
306
- `);
253
+ expect(entities).toMatchInlineSnapshot(`[]`)
254
+ })
255
+
256
+ test('runQuery', async () => {
257
+ const kvStore = getDstore()
258
+ const query = kvStore.createQuery('testYodel')
259
+ query.limit(1)
260
+ const [entities, runQueryInfo] = await kvStore.runQuery(query)
261
+ // expect(entities.length).toBe(1)
262
+ expect(entities).toMatchInlineSnapshot(`[]`)
307
263
  expect(runQueryInfo).toMatchInlineSnapshot(`
308
264
  {
309
265
  "moreResults": "MORE_RESULTS_AFTER_LIMIT",
310
266
  }
311
- `);
312
- expect(entities?.[0]?.foo).toBe('bar');
313
- expect(entities?.[0]?.[Datastore.KEY]?.kind).toBe('testYodel');
314
- expect(runQueryInfo?.moreResults).toBe('MORE_RESULTS_AFTER_LIMIT');
267
+ `)
268
+ // expect(entities?.[0]?.foo).toBe('bar')
269
+ // expect(entities?.[0]?.[Datastore.KEY]?.kind).toBe('testYodel')
270
+ expect(runQueryInfo?.moreResults).toBe('MORE_RESULTS_AFTER_LIMIT')
271
+ })
315
272
 
273
+ test('query', async () => {
316
274
  // modern interface
317
- const [result2] = await kvStore.query('testYodel', [], 1, [], ['baz']);
318
- expect(result2.length).toBe(1);
275
+ const kvStore = getDstore()
276
+ const [result1] = await kvStore.query('testYodel')
277
+ expect(result1?.[0]).toMatchInlineSnapshot(`undefined`)
278
+ const [result2] = await kvStore.query('testYodel', [])
279
+ expect(result2?.[0]).toMatchInlineSnapshot(`undefined`)
280
+ const [result3] = await kvStore.query('testYodel', [], 1)
281
+ expect(result3?.[0]).toMatchInlineSnapshot(`undefined`)
282
+ const [result4] = await kvStore.query('testYodel', [], 1, [])
283
+ expect(result4?.[0]).toMatchInlineSnapshot(`undefined`)
284
+ // expect(result2.length).toBe(1)
319
285
  // foo is removed by selection
320
- expect(JSON.parse(JSON.stringify(result2?.[0]))).toMatchInlineSnapshot(`
321
- {
322
- "_keyStr": "agByEAsSCXRlc3RZb2RlbCIBMwyiAQR0ZXN0",
323
- "baz": "baz",
324
- "foo": "bar",
325
- }
326
- `);
286
+ const [result5] = await kvStore.query('testYodel', [], 1, [], ['baz'])
287
+ expect(result5?.[0]).toMatchInlineSnapshot(`undefined`)
288
+
289
+ // const key = kvStore.readKey(result2?.[0])
290
+ // expect(key.id).toBe(entity.key.id)
291
+ })
292
+
293
+ test.skip('iterate', async () => {
294
+ const kvStore = getDstore()
295
+ const result = await kvStore.iterate({ kindName: 'testYodel', limit: 1 })
296
+ for await (const entity of result) {
297
+ expect(entity).toMatchInlineSnapshot()
298
+ }
299
+ })
327
300
 
328
- const key = kvStore.readKey(result2?.[0]);
329
- expect(key.id).toBe(entity.key.id);
330
- });
331
- });
301
+ test.skip('list', async () => {
302
+ const kvStore = getDstore()
303
+ const result = await kvStore.list({ kindName: 'testYodel', limit: 1 })
304
+ expect(result).toMatchInlineSnapshot()
305
+ })
306
+ })
332
307
 
333
308
  test('set', async () => {
334
309
  // expect.assertions(2);
335
- const kvStore = getDstore();
310
+ const kvStore = getDstore()
336
311
  const result = await kvStore.set(kvStore.key(['testYodel', '5e7']), {
337
312
  foo: 'bar',
338
- });
339
- expect(result.name).toBe('5e7');
340
- expect(result.kind).toBe('testYodel');
313
+ })
314
+ expect(result.name).toBe('5e7')
315
+ expect(result.kind).toBe('testYodel')
341
316
 
342
317
  // autogenerate key
343
- const result2 = await kvStore.set(kvStore.key(['testYodel']), { foo: 'bar' });
344
- expect(result2.kind).toBe('testYodel');
345
- });
318
+ const result2 = await kvStore.set(kvStore.key(['testYodel']), { foo: 'bar' })
319
+ expect(result2.kind).toBe('testYodel')
320
+ })
346
321
 
347
322
  test('save / upsert', async () => {
348
323
  // expect.assertions(2);
349
- const kvStore = getDstore();
324
+ const kvStore = getDstore()
350
325
  const entity = {
351
326
  key: kvStore.key(['testYodel', 3]),
352
327
  data: { foo: 'bar' } as any,
353
- };
354
- const result = await kvStore.save([entity]);
328
+ }
329
+ const result = await kvStore.save([entity])
355
330
  // const result2 = await kvStore.upsert([entity]);
356
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
357
- expect(entity.data._keyStr).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBgDDKIBBHRlc3Q"');
358
- expect(entity.data.foo).toBe('bar');
359
- expect(entity.data[Datastore.KEY].kind).toBe('testYodel');
360
- });
331
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
332
+ expect(entity.data._keyStr).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBgDDKIBBHRlc3Q"')
333
+ expect(entity.data.foo).toBe('bar')
334
+ expect(entity.data[Datastore.KEY].kind).toBe('testYodel')
335
+ })
361
336
 
362
337
  test('update', async (t) => {
363
338
  // expect.assertions(3);
364
- const kvStore = getDstore();
365
- const keyName = `4insert${Math.random()}`;
339
+ const kvStore = getDstore()
340
+ const keyName = `4insert${Math.random()}`
366
341
  const entity = {
367
342
  key: kvStore.key(['testYodel', keyName]),
368
343
  data: { foo: 'bar' },
369
- };
344
+ }
370
345
  // const request = kvStore.update([entity]);
371
346
  // await expect(request).rejects.toThrowError(Error);
372
347
 
373
- await kvStore.save([entity]);
374
- const result = await kvStore.update([entity]);
375
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
376
- expect(result?.[0]?.mutationResults?.[0]?.key).toBe(null);
348
+ await kvStore.save([entity])
349
+ const result = await kvStore.update([entity])
350
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
351
+ expect(result?.[0]?.mutationResults?.[0]?.key).toBe(null)
377
352
  // expect(result?.[0]?.indexUpdates).toBe(2);
378
- });
353
+ })
379
354
 
380
355
  test('insert / delete', async (t) => {
381
356
  // expect.assertions(2);
382
- const kvStore = getDstore();
383
- const testkey = kvStore.key(['testYodel', 4]);
384
- await kvStore.delete([testkey]);
357
+ const kvStore = getDstore()
358
+ const testkey = kvStore.key(['testYodel', 4])
359
+ await kvStore.delete([testkey])
385
360
  const entity = {
386
361
  key: testkey,
387
362
  data: { foo: 'bar' } as any,
388
- };
389
- const result = await kvStore.insert([entity]);
363
+ }
364
+ const result = await kvStore.insert([entity])
390
365
 
391
- expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
392
- expect(result?.[0]?.mutationResults?.[0]?.version).toMatch(/\d+/);
393
- expect(entity.data.foo).toBe('bar');
394
- expect(entity.key.path[0]).toBe('testYodel');
366
+ expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
367
+ expect(result?.[0]?.mutationResults?.[0]?.version).toMatch(/\d+/)
368
+ expect(entity.data.foo).toBe('bar')
369
+ expect(entity.key.path[0]).toBe('testYodel')
395
370
  // expect(result?.[0]?.indexUpdates).toBe(3);
396
371
 
397
- const result2 = await kvStore.delete([entity.key]);
398
- expect(result2?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false);
399
- });
372
+ const result2 = await kvStore.delete([entity.key])
373
+ expect(result2?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
374
+ })
400
375
 
401
376
  test('exception', async () => {
402
377
  // expect.assertions(2);
403
- const kvStore = getDstore();
378
+ const kvStore = getDstore()
404
379
  try {
405
380
  const result = await kvStore.set(kvStore.key(['testYodel', NaN]), {
406
381
  foo: 'bar',
407
- });
382
+ })
408
383
  } catch (e) {
409
- expect(e.stack).toMatch(/Dstore\.set/);
384
+ expect(e.stack).toMatch(/Dstore\.set/)
410
385
  }
411
- });
386
+ })
412
387
  // describe("Transactions", () => {
413
388
  // it("simple", async () => {
414
389
  // expect.assertions(2);
@@ -148,7 +148,8 @@ type IDstore = {
148
148
  selection?: readonly string[],
149
149
  cursor?: string
150
150
  ) => Promise<RunQueryResponse>
151
- iterate: (options: IIterateParams) => AsyncIterable<IDstoreEntryWithKey>
151
+ iterate: <T = IDstoreEntryWithKey>(options: IIterateParams) => AsyncIterable<T>
152
+ list: <T = IDstoreEntryWithKey>(options: IIterateParams) => Promise<Array<T>>
152
153
  allocateOneId: (kindName: string) => Promise<string>
153
154
  runInTransaction: <T>(func: { (): Promise<T>; (): T }) => Promise<T>
154
155
  }
@@ -248,7 +249,7 @@ export class Dstore implements IDstore {
248
249
  * @category Additional
249
250
  */
250
251
  readKey(ent: IDstoreEntry): Key {
251
- assertIsObject(ent)
252
+ assertIsObject(ent, 'entity', 'readKey() wants to be provided an entity object')
252
253
  let ret = ent[Datastore.KEY]
253
254
  if (ent._keyStr && !ret) {
254
255
  ret = this.keyFromSerialized(ent._keyStr)
@@ -672,13 +673,13 @@ export class Dstore implements IDstore {
672
673
  * @throws [[DstoreError]]
673
674
  * @category Additional
674
675
  */
675
- async * iterate({
676
+ async * iterate<T = IDstoreEntryWithKey>({
676
677
  kindName,
677
678
  filters = [],
678
679
  limit = 0,
679
680
  ordering = [],
680
681
  selection = [],
681
- }: IIterateParams): AsyncIterable<IDstoreEntryWithKey> {
682
+ }: IIterateParams): AsyncIterable<T> {
682
683
  assertIsString(kindName)
683
684
  assertIsArray(filters)
684
685
  assertIsNumber(limit)
@@ -702,7 +703,7 @@ export class Dstore implements IDstore {
702
703
  const ret = this.fixKeys([entity])[0]
703
704
  assertIsDefined(ret, 'datastore.iterate: entity is undefined')
704
705
  assertIsKey(ret[Datastore.KEY])
705
- yield ret as IDstoreEntryWithKey
706
+ yield ret as T
706
707
  }
707
708
  } catch (error) {
708
709
  await setImmediate()
@@ -715,6 +716,33 @@ export class Dstore implements IDstore {
715
716
  }
716
717
  }
717
718
 
719
+ /** `list()` is a non iteratingversion of `iterate()`.
720
+ *
721
+ * @param kindName Name of the [[Datastore]][Kind](https://cloud.google.com/datastore/docs/concepts/entities#kinds_and_identifiers) ("Table") which should be searched.
722
+ * @param filters List of [[Query]] filter() calls.
723
+ * @param limit Maximum Number of Results to return.
724
+ * @param ordering List of [[Query]] order() calls.
725
+ * @param selection selectionList of [[Query]] select() calls.
726
+ *
727
+ * @throws [[DstoreError]]
728
+ * @category Additional
729
+ */
730
+ async list<T = IDstoreEntryWithKey>({
731
+ kindName,
732
+ filters = [],
733
+ limit = 0,
734
+ ordering = [],
735
+ selection = [],
736
+ }: IIterateParams): Array<T> {
737
+ const iterator = this.iterate<T>({ kindName, filters, limit, ordering, selection })
738
+ const entities: T[] = []
739
+ for await (const entity of iterator) {
740
+ entities.push(entity as T)
741
+ }
742
+ return entities
743
+ }
744
+
745
+
718
746
  /** Allocate one ID in the Datastore.
719
747
  *
720
748
  * Currently (late 2021) there is no documentation provided by Google for the underlying node function.