datastore-api 2.0.0 → 2.1.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.
- package/README.md +12 -2
- package/dist/datastore-api.cjs.development.js +1427 -0
- package/dist/datastore-api.cjs.development.js.map +1 -0
- package/dist/datastore-api.cjs.production.min.js +2 -0
- package/dist/datastore-api.cjs.production.min.js.map +1 -0
- package/dist/datastore-api.esm.js +1406 -0
- package/dist/datastore-api.esm.js.map +1 -0
- package/dist/index.js +8 -0
- package/{build/module → dist}/lib/dstore-api.d.ts +31 -15
- package/dist/mock/index.d.ts +106 -0
- package/dist/mock/operators.d.ts +8 -0
- package/package.json +98 -82
- package/src/index.ts +1 -0
- package/src/lib/dstore-api-cloud.spec.ts +435 -0
- package/src/lib/dstore-api-emulator.spec.ts +440 -0
- package/src/lib/dstore-api-simulator.spec.ts +412 -0
- package/src/lib/dstore-api.ts +703 -0
- package/src/mock/index.ts +639 -0
- package/src/mock/operators.ts +20 -0
- package/CHANGELOG.md +0 -105
- package/build/main/index.js +0 -14
- package/build/main/lib/dstore-api.d.ts +0 -332
- package/build/main/lib/dstore-api.js +0 -567
- package/build/main/lib/dstore-api.spec.d.ts +0 -1
- package/build/main/lib/dstore-api.spec.js +0 -377
- package/build/module/index.d.ts +0 -1
- package/build/module/index.js +0 -2
- package/build/module/lib/dstore-api.js +0 -557
- package/build/module/lib/dstore-api.spec.d.ts +0 -1
- package/build/module/lib/dstore-api.spec.js +0 -368
- /package/{build/main → dist}/index.d.ts +0 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* dstore-api-simulator.spec.ts - test against the in-process-datastore simulator
|
|
3
|
+
*
|
|
4
|
+
* Created by Dr. Maximilian Dornseif 2021-12-10 in huwawi3backend 11.10.0
|
|
5
|
+
* Copyright (c) 2021, 2023 Dr. Maximilian Dornseif
|
|
6
|
+
*/
|
|
7
|
+
// @ts-nocheck
|
|
8
|
+
// import { Datastore, Key } from '@google-cloud/datastore';
|
|
9
|
+
import { afterAll, assert, beforeAll, describe, expect, test } from 'vitest'
|
|
10
|
+
|
|
11
|
+
import { Datastore } from '../mock'
|
|
12
|
+
|
|
13
|
+
import { Dstore } from './dstore-api'
|
|
14
|
+
|
|
15
|
+
process.env.GCLOUD_PROJECT = 'project-id' // Set the datastore project Id globally
|
|
16
|
+
let emulator
|
|
17
|
+
|
|
18
|
+
function getDstore() {
|
|
19
|
+
return new Dstore(new Datastore({ namespace: 'test', projectId: process.env.GCLOUD_PROJECT }))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test('keySerialize', async () => {
|
|
23
|
+
const kvStore = getDstore()
|
|
24
|
+
assert.deepEqual(kvStore.key(['testYodel', 123]).path, ['testYodel', 123])
|
|
25
|
+
assert.deepEqual(JSON.parse(JSON.stringify(kvStore.key(['testYodel', 123]))), {
|
|
26
|
+
id: 123 as any, // typing in inconclusive here
|
|
27
|
+
kind: 'testYodel',
|
|
28
|
+
namespace: 'test',
|
|
29
|
+
path: ['testYodel', 123],
|
|
30
|
+
} as any)
|
|
31
|
+
const ser = kvStore.keySerialize(kvStore.key(['testYodel', 123]))
|
|
32
|
+
expect(ser).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBh7DKIBBHRlc3Q"')
|
|
33
|
+
expect(JSON.parse(JSON.stringify(kvStore.keyFromSerialized(ser)))).toMatchInlineSnapshot(`
|
|
34
|
+
{
|
|
35
|
+
"id": "123",
|
|
36
|
+
"kind": "testYodel",
|
|
37
|
+
"namespace": "test",
|
|
38
|
+
"path": [
|
|
39
|
+
"testYodel",
|
|
40
|
+
"123",
|
|
41
|
+
],
|
|
42
|
+
}
|
|
43
|
+
`)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('Allocation', () => {
|
|
47
|
+
test('allocateIds', async () => {
|
|
48
|
+
const kvStore = getDstore()
|
|
49
|
+
const keys = await kvStore.datastore.allocateIds(kvStore.datastore.key(['testYodel']), 2)
|
|
50
|
+
expect(Array.isArray(keys)).toBeTruthy()
|
|
51
|
+
expect(keys[0].length).toBe(2)
|
|
52
|
+
expect(keys[0][0].kind).toBe('testYodel')
|
|
53
|
+
expect(keys[0][0].id).toMatch(/\d+/)
|
|
54
|
+
expect(keys?.[1]?.keys?.length).toBe(2)
|
|
55
|
+
expect(keys[1].keys[0].partitionId.namespaceId).toMatchInlineSnapshot('"test"')
|
|
56
|
+
expect(keys[1].keys[0].path[0].idType).toMatchInlineSnapshot('"id"')
|
|
57
|
+
expect(keys[1].keys[0].path[0].kind).toMatchInlineSnapshot('"testYodel"')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('allocateOneId', async () => {
|
|
61
|
+
const kvStore = getDstore()
|
|
62
|
+
const id = await kvStore.allocateOneId()
|
|
63
|
+
expect(id).toMatch(/\d+/)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe('Read', () => {
|
|
68
|
+
test('get num_id', async () => {
|
|
69
|
+
const kvStore = getDstore()
|
|
70
|
+
const entity = { key: kvStore.key(['testYodel', 2]), data: { foo: 'bar' } }
|
|
71
|
+
const entity2 = {
|
|
72
|
+
key: kvStore.key(['testYodel', 3]),
|
|
73
|
+
data: { foo: 'bar' },
|
|
74
|
+
}
|
|
75
|
+
const commitResponse = await kvStore.save([entity, entity2])
|
|
76
|
+
// expect(isNumber(commitResponse?.[0]?.indexUpdates)).toBeTruthy();
|
|
77
|
+
// expect(commitResponse).toMatchInlineSnapshot(`
|
|
78
|
+
// Array [
|
|
79
|
+
// Object {
|
|
80
|
+
// "indexUpdates": 0,
|
|
81
|
+
// "mutationResults": Array [
|
|
82
|
+
// Object {
|
|
83
|
+
// "conflictDetected": false,
|
|
84
|
+
// "key": null,
|
|
85
|
+
// "version": "1234567890123456",
|
|
86
|
+
// },
|
|
87
|
+
// ],
|
|
88
|
+
// },
|
|
89
|
+
// ]
|
|
90
|
+
// `);
|
|
91
|
+
expect(entity).toMatchInlineSnapshot(`
|
|
92
|
+
{
|
|
93
|
+
"data": {
|
|
94
|
+
"_keyStr": "agByDwsSCXRlc3RZb2RlbBgCDKIBBHRlc3Q",
|
|
95
|
+
"foo": "bar",
|
|
96
|
+
Symbol(KEY): Key {
|
|
97
|
+
"id": 2,
|
|
98
|
+
"kind": "testYodel",
|
|
99
|
+
"namespace": "test",
|
|
100
|
+
"path": [
|
|
101
|
+
"testYodel",
|
|
102
|
+
2,
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
"excludeLargeProperties": true,
|
|
107
|
+
"key": Key {
|
|
108
|
+
"id": 2,
|
|
109
|
+
"kind": "testYodel",
|
|
110
|
+
"namespace": "test",
|
|
111
|
+
"path": [
|
|
112
|
+
"testYodel",
|
|
113
|
+
2,
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
`)
|
|
118
|
+
|
|
119
|
+
const result = await kvStore.get(entity.key)
|
|
120
|
+
// get returns a single Entity
|
|
121
|
+
expect(Array.isArray(result)).toBeFalsy()
|
|
122
|
+
expect(result).toMatchInlineSnapshot('null')
|
|
123
|
+
// expect(kvStore.readKey(result)).toBeInstanceOf(Key);
|
|
124
|
+
|
|
125
|
+
const result2 = await kvStore.getMulti([entity.key])
|
|
126
|
+
// getMulti returns a Array even for single keys
|
|
127
|
+
expect(result2).toMatchInlineSnapshot(`
|
|
128
|
+
[
|
|
129
|
+
null,
|
|
130
|
+
]
|
|
131
|
+
`)
|
|
132
|
+
const result3 = await kvStore.getMulti([entity.key, kvStore.key(['testYodel', 3])])
|
|
133
|
+
// getMulti returns a Array with multiple keys
|
|
134
|
+
// expect(Array.isArray(result)).toBeTruthy();
|
|
135
|
+
expect(result3).toMatchInlineSnapshot(`
|
|
136
|
+
[
|
|
137
|
+
null,
|
|
138
|
+
null,
|
|
139
|
+
]
|
|
140
|
+
`)
|
|
141
|
+
const result4 = await kvStore.getMulti([entity.key, entity.key])
|
|
142
|
+
// getMulti returns a Array but collapses duplicate keys
|
|
143
|
+
// expect(Array.isArray(result)).toBeTruthy();
|
|
144
|
+
// Firestore in Datastore returns the entity once
|
|
145
|
+
// Datastore Emulator returns the Entity twice
|
|
146
|
+
// kvStore should normalize that.
|
|
147
|
+
expect(result4).toMatchInlineSnapshot(`
|
|
148
|
+
[
|
|
149
|
+
null,
|
|
150
|
+
null,
|
|
151
|
+
]
|
|
152
|
+
`)
|
|
153
|
+
|
|
154
|
+
const result5 = await kvStore.getMulti([entity.key, kvStore.key(['YodelNotThere', 3])])
|
|
155
|
+
// getMulti returns a Array but omits unknown keys
|
|
156
|
+
// expect(Array.isArray(result)).toBeTruthy();
|
|
157
|
+
expect(result5).toMatchInlineSnapshot(`
|
|
158
|
+
[
|
|
159
|
+
null,
|
|
160
|
+
null,
|
|
161
|
+
]
|
|
162
|
+
`)
|
|
163
|
+
const result6 = await kvStore.getMulti([])
|
|
164
|
+
// getMulti returns a empty Array for an empty array
|
|
165
|
+
// expect(Array.isArray(result)).toBeTruthy();
|
|
166
|
+
expect(result6).toMatchInlineSnapshot('[]')
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('get name', async (t) => {
|
|
171
|
+
const kvStore = getDstore()
|
|
172
|
+
const entity = {
|
|
173
|
+
key: kvStore.key(['testYodel', 'two']),
|
|
174
|
+
data: { foo: 'bar' },
|
|
175
|
+
}
|
|
176
|
+
await kvStore.save([entity])
|
|
177
|
+
const result = await kvStore.get(entity.key)
|
|
178
|
+
expect(result?._keyStr).toMatchInlineSnapshot('"agByEgsSCXRlc3RZb2RlbCIDdHdvDKIBBHRlc3Q"')
|
|
179
|
+
expect(result?.foo).toBe('bar')
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
describe('query', async () => {
|
|
183
|
+
test.skip('raw', async () => {
|
|
184
|
+
const kvStore = getDstore()
|
|
185
|
+
const entity = {
|
|
186
|
+
key: kvStore.key(['testYodel', '3']),
|
|
187
|
+
data: { foo: 'bar', baz: 'baz' },
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
await kvStore.save([entity])
|
|
191
|
+
const query = kvStore.datastore.createQuery('testYodel')
|
|
192
|
+
query.limit(1)
|
|
193
|
+
const [entities, runQueryInfo] = await kvStore.datastore.runQuery(query)
|
|
194
|
+
expect(entities.length).toBe(1)
|
|
195
|
+
expect(entities).toMatchInlineSnapshot(`
|
|
196
|
+
[
|
|
197
|
+
{
|
|
198
|
+
"foo": "bar",
|
|
199
|
+
Symbol(KEY): Key {
|
|
200
|
+
"id": "2",
|
|
201
|
+
"kind": "testYodel",
|
|
202
|
+
"namespace": "test",
|
|
203
|
+
"path": [
|
|
204
|
+
"testYodel",
|
|
205
|
+
"2",
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
]
|
|
210
|
+
`)
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test.skip('query', async () => {
|
|
214
|
+
const kvStore = getDstore()
|
|
215
|
+
const entity = {
|
|
216
|
+
key: kvStore.key(['testYodel', '3']),
|
|
217
|
+
data: { foo: 'bar', baz: 'baz' },
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const saveResult = await kvStore.save([entity])
|
|
221
|
+
expect(saveResult).toMatchInlineSnapshot(`
|
|
222
|
+
[
|
|
223
|
+
{
|
|
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
|
+
`)
|
|
243
|
+
expect(await kvStore.get(entity.key)).toMatchInlineSnapshot(`
|
|
244
|
+
{
|
|
245
|
+
"_keyStr": "agByEAsSCXRlc3RZb2RlbCIBMwyiAQR0ZXN0",
|
|
246
|
+
"baz": "baz",
|
|
247
|
+
"foo": "bar",
|
|
248
|
+
Symbol(KEY): Key {
|
|
249
|
+
"kind": "testYodel",
|
|
250
|
+
"name": "3",
|
|
251
|
+
"namespace": "test",
|
|
252
|
+
"path": [
|
|
253
|
+
"testYodel",
|
|
254
|
+
"3",
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
`)
|
|
259
|
+
|
|
260
|
+
// Give Datastore time to become consistent
|
|
261
|
+
do {} while ((await kvStore.get(entity.key)) === null)
|
|
262
|
+
|
|
263
|
+
const query = kvStore.createQuery('testYodel')
|
|
264
|
+
query.limit(1)
|
|
265
|
+
const [entities, runQueryInfo] = await kvStore.runQuery(query)
|
|
266
|
+
// expect(entities.length).toBe(1)
|
|
267
|
+
expect(entities).toMatchInlineSnapshot()
|
|
268
|
+
expect(runQueryInfo).toMatchInlineSnapshot()
|
|
269
|
+
expect(entities?.[0]?.foo).toBe('bar')
|
|
270
|
+
expect(entities?.[0]?.[Datastore.KEY]?.kind).toBe('testYodel')
|
|
271
|
+
expect(runQueryInfo?.moreResults).toBe('MORE_RESULTS_AFTER_LIMIT')
|
|
272
|
+
|
|
273
|
+
// modern interface
|
|
274
|
+
const [result2] = await kvStore.query('testYodel', [], 1, [], ['baz'])
|
|
275
|
+
expect(result2.length).toBe(1)
|
|
276
|
+
// foo is removed by selection
|
|
277
|
+
expect(JSON.parse(JSON.stringify(result2?.[0]))).toMatchInlineSnapshot()
|
|
278
|
+
|
|
279
|
+
const key = kvStore.readKey(result2?.[0])
|
|
280
|
+
expect(key.id).toBe(entity.key.id)
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
test('set', async () => {
|
|
285
|
+
// expect.assertions(2);
|
|
286
|
+
const kvStore = getDstore()
|
|
287
|
+
const result = await kvStore.set(kvStore.key(['testYodel', '5e7']), {
|
|
288
|
+
foo: 'bar',
|
|
289
|
+
})
|
|
290
|
+
expect(result.name).toBe('5e7')
|
|
291
|
+
expect(result.kind).toBe('testYodel')
|
|
292
|
+
|
|
293
|
+
// autogenerate key
|
|
294
|
+
const result2 = await kvStore.set(kvStore.key(['testYodel']), { foo: 'bar' })
|
|
295
|
+
expect(result2.kind).toBe('testYodel')
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
test('save / upsert', async () => {
|
|
299
|
+
// expect.assertions(2);
|
|
300
|
+
const kvStore = getDstore()
|
|
301
|
+
const entity = {
|
|
302
|
+
key: kvStore.key(['testYodel', 3]),
|
|
303
|
+
data: { foo: 'bar' } as any,
|
|
304
|
+
}
|
|
305
|
+
const result = await kvStore.save([entity])
|
|
306
|
+
// const result2 = await kvStore.upsert([entity]);
|
|
307
|
+
expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
|
|
308
|
+
expect(entity.data._keyStr).toMatchInlineSnapshot('"agByDwsSCXRlc3RZb2RlbBgDDKIBBHRlc3Q"')
|
|
309
|
+
expect(entity.data.foo).toBe('bar')
|
|
310
|
+
expect(entity.data[Datastore.KEY].kind).toBe('testYodel')
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
test('update', async (t) => {
|
|
314
|
+
// expect.assertions(3);
|
|
315
|
+
const kvStore = getDstore()
|
|
316
|
+
const keyName = `4insert${Math.random()}`
|
|
317
|
+
const entity = {
|
|
318
|
+
key: kvStore.key(['testYodel', keyName]),
|
|
319
|
+
data: { foo: 'bar' },
|
|
320
|
+
}
|
|
321
|
+
// const request = kvStore.update([entity]);
|
|
322
|
+
// await expect(request).rejects.toThrowError(Error);
|
|
323
|
+
|
|
324
|
+
await kvStore.save([entity])
|
|
325
|
+
const result = await kvStore.update([entity])
|
|
326
|
+
expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
|
|
327
|
+
expect(result?.[0]?.mutationResults?.[0]?.key).toBe(null)
|
|
328
|
+
// expect(result?.[0]?.indexUpdates).toBe(2);
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
test('insert / delete', async (t) => {
|
|
332
|
+
// expect.assertions(2);
|
|
333
|
+
const kvStore = getDstore()
|
|
334
|
+
const testkey = kvStore.key(['testYodel', 4])
|
|
335
|
+
await kvStore.delete([testkey])
|
|
336
|
+
const entity = {
|
|
337
|
+
key: testkey,
|
|
338
|
+
data: { foo: 'bar' } as any,
|
|
339
|
+
}
|
|
340
|
+
const result = await kvStore.insert([entity])
|
|
341
|
+
|
|
342
|
+
expect(result?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
|
|
343
|
+
expect(result?.[0]?.mutationResults?.[0]?.version).toMatch(/\d+/)
|
|
344
|
+
expect(entity.data.foo).toBe('bar')
|
|
345
|
+
expect(entity.key.path[0]).toBe('testYodel')
|
|
346
|
+
// expect(result?.[0]?.indexUpdates).toBe(3);
|
|
347
|
+
|
|
348
|
+
const result2 = await kvStore.delete([entity.key])
|
|
349
|
+
expect(result2?.[0]?.mutationResults?.[0]?.conflictDetected).toBe(false)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
test('exception', async () => {
|
|
353
|
+
// expect.assertions(2);
|
|
354
|
+
const kvStore = getDstore()
|
|
355
|
+
try {
|
|
356
|
+
const result = await kvStore.set(kvStore.key(['testYodel', NaN]), {
|
|
357
|
+
foo: 'bar',
|
|
358
|
+
})
|
|
359
|
+
} catch (e) {
|
|
360
|
+
expect(e.stack).toMatch(/Dstore\.set/)
|
|
361
|
+
}
|
|
362
|
+
})
|
|
363
|
+
// describe("Transactions", () => {
|
|
364
|
+
// it("simple", async () => {
|
|
365
|
+
// expect.assertions(2);
|
|
366
|
+
// const kvStore = getDstore("huwawi3Datastore");
|
|
367
|
+
// const outerResult = await kvStore.runInTransaction<any>(async () => {
|
|
368
|
+
// // write inside the transaction
|
|
369
|
+
// const entity = { key: kvStore.key(["testYodel", 6]), data: { foo: "foobar" } };
|
|
370
|
+
// const innerResult = await kvStore.save([entity]);
|
|
371
|
+
// // save does not return anything within transactions
|
|
372
|
+
// expect(innerResult).toMatchInlineSnapshot(`undefined`);
|
|
373
|
+
// return 123;
|
|
374
|
+
// });
|
|
375
|
+
// expect(outerResult).toMatchInlineSnapshot(`123`);
|
|
376
|
+
|
|
377
|
+
// // this fails in the Datastore Emulator
|
|
378
|
+
// const entitiey = await kvStore.get(kvStore.key(["testYodel", 6]));
|
|
379
|
+
// // expect(entitiey).toMatchInlineSnapshot(`
|
|
380
|
+
// // Object {
|
|
381
|
+
// // "foo": "foobar",
|
|
382
|
+
// // Symbol(KEY): Key {
|
|
383
|
+
// // "id": "6",
|
|
384
|
+
// // "kind": "testYodel",
|
|
385
|
+
// // "namespace": "test",
|
|
386
|
+
// // "path": Array [
|
|
387
|
+
// // "testYodel",
|
|
388
|
+
// // "6",
|
|
389
|
+
// // ],
|
|
390
|
+
// // },
|
|
391
|
+
// // }
|
|
392
|
+
// // `);
|
|
393
|
+
// });
|
|
394
|
+
|
|
395
|
+
// it("throws", async () => {
|
|
396
|
+
// expect.assertions(1);
|
|
397
|
+
// const kvStore = getDstore("huwawi3Datastore");
|
|
398
|
+
// const request = kvStore.runInTransaction<any>(async () => {
|
|
399
|
+
// throw new DstoreError("TestError", undefined);
|
|
400
|
+
// });
|
|
401
|
+
// await expect(request).rejects.toThrowError(DstoreError);
|
|
402
|
+
// });
|
|
403
|
+
// });
|
|
404
|
+
|
|
405
|
+
// describe('Exceptions', () => {
|
|
406
|
+
// it('simple', async () => {
|
|
407
|
+
// const t = () => {
|
|
408
|
+
// throw new DstoreError('bla', undefined);
|
|
409
|
+
// };
|
|
410
|
+
// expect(t).toThrow(DstoreError);
|
|
411
|
+
// });
|
|
412
|
+
// });
|