datastore-api 6.2.0 → 6.2.2
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.
- package/README.md +2 -1
- package/dist/datastore-api.cjs.development.js +136 -109
- package/dist/datastore-api.cjs.development.js.map +1 -1
- package/dist/datastore-api.cjs.production.min.js +1 -1
- package/dist/datastore-api.cjs.production.min.js.map +1 -1
- package/dist/datastore-api.esm.js +137 -110
- package/dist/datastore-api.esm.js.map +1 -1
- package/dist/lib/assert.d.ts +1 -1
- package/dist/lib/dstore-api.d.ts +26 -2
- package/package.json +1 -1
- package/src/lib/assert.ts +1 -1
- package/src/lib/dstore-api-cloud.spec.ts +123 -123
- package/src/lib/dstore-api.ts +57 -16
|
@@ -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);
|
package/src/lib/dstore-api.ts
CHANGED
|
@@ -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
|
|
@@ -138,7 +148,7 @@ type IDstore = {
|
|
|
138
148
|
selection?: readonly string[],
|
|
139
149
|
cursor?: string
|
|
140
150
|
) => Promise<RunQueryResponse>
|
|
141
|
-
iterate: (options: IIterateParams) => AsyncIterable<
|
|
151
|
+
iterate: (options: IIterateParams) => AsyncIterable<IDstoreEntryWithKey>
|
|
142
152
|
allocateOneId: (kindName: string) => Promise<string>
|
|
143
153
|
runInTransaction: <T>(func: { (): Promise<T>; (): T }) => Promise<T>
|
|
144
154
|
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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({
|
|
@@ -638,7 +678,7 @@ export class Dstore implements IDstore {
|
|
|
638
678
|
limit = 2500,
|
|
639
679
|
ordering = [],
|
|
640
680
|
selection = [],
|
|
641
|
-
}: IIterateParams): AsyncIterable<
|
|
681
|
+
}: IIterateParams): AsyncIterable<IDstoreEntryWithKey> {
|
|
642
682
|
assertIsString(kindName)
|
|
643
683
|
assertIsArray(filters)
|
|
644
684
|
assertIsNumber(limit)
|
|
@@ -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
|
|
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
|
-
|
|
704
|
+
assertIsKey(ret[Datastore.KEY])
|
|
705
|
+
yield ret as IDstoreEntryWithKey
|
|
665
706
|
}
|
|
666
707
|
} catch (error) {
|
|
667
708
|
await setImmediate()
|