@luvio/adapter-test-library 0.62.3 → 0.63.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/dist/es/es2018/durableStore.d.ts +4 -4
- package/dist/es/es2018/durableStorePersistence.d.ts +11 -0
- package/dist/es/es2018/main.d.ts +1 -0
- package/dist/es/es2018/test-library.js +52 -41
- package/dist/umd/es2018/durableStore.d.ts +4 -4
- package/dist/umd/es2018/durableStorePersistence.d.ts +11 -0
- package/dist/umd/es2018/main.d.ts +1 -0
- package/dist/umd/es2018/test-library.js +62 -47
- package/dist/umd/es5/durableStore.d.ts +4 -4
- package/dist/umd/es5/durableStorePersistence.d.ts +11 -0
- package/dist/umd/es5/main.d.ts +1 -0
- package/dist/umd/es5/test-library.js +177 -64
- package/package.json +3 -3
- package/src/durableStore.ts +44 -42
- package/src/durableStorePersistence.ts +21 -0
- package/src/main.ts +1 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DurableStore, DurableStoreEntries, OnDurableStoreChangedListener, DurableStoreOperation, DurableStoreChange } from '@luvio/environments';
|
|
2
|
+
import { DurableStorePersistence } from './durableStorePersistence';
|
|
2
3
|
export declare class MockDurableStore implements DurableStore {
|
|
3
4
|
listeners: Set<OnDurableStoreChangedListener>;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
5
|
+
persistence: DurableStorePersistence;
|
|
6
|
+
constructor(persistence?: DurableStorePersistence);
|
|
7
7
|
getEntries<T>(entryIds: string[], segment: string): Promise<DurableStoreEntries<T> | undefined>;
|
|
8
|
-
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T
|
|
8
|
+
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T>>;
|
|
9
9
|
setEntries<T>(entries: DurableStoreEntries<T>, segment: string): Promise<void>;
|
|
10
10
|
evictEntries(ids: string[], segment: string): Promise<void>;
|
|
11
11
|
registerOnChangedListener(listener: OnDurableStoreChangedListener): () => Promise<void>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DurableStorePersistence {
|
|
2
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
3
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
4
|
+
delete(key: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare class MemoryDurableStorePersistence implements DurableStorePersistence {
|
|
7
|
+
private store;
|
|
8
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
9
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
}
|
package/dist/es/es2018/main.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { verifyImmutable, isImmutable } from './verification';
|
|
|
3
3
|
export { getMockLuvioWithFulfilledSnapshot, getMockFulfilledSnapshot } from './mocks';
|
|
4
4
|
export { stripProperties } from './utils';
|
|
5
5
|
export { MockDurableStore } from './durableStore';
|
|
6
|
+
export { MemoryDurableStorePersistence, DurableStorePersistence } from './durableStorePersistence';
|
|
@@ -277,35 +277,51 @@ function getMockFulfilledSnapshot() {
|
|
|
277
277
|
return mockFulfilledSnapshot;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
class
|
|
280
|
+
class MemoryDurableStorePersistence {
|
|
281
281
|
constructor() {
|
|
282
|
+
this.store = {};
|
|
283
|
+
}
|
|
284
|
+
async get(key) {
|
|
285
|
+
return this.store[key];
|
|
286
|
+
}
|
|
287
|
+
async set(key, value) {
|
|
288
|
+
this.store[key] = value;
|
|
289
|
+
}
|
|
290
|
+
async delete(key) {
|
|
291
|
+
delete this.store[key];
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
class MockDurableStore {
|
|
296
|
+
constructor(persistence) {
|
|
297
|
+
// NOTE: This mock class doesn't enforce read/write synchronization
|
|
282
298
|
this.listeners = new Set();
|
|
283
|
-
this.
|
|
299
|
+
this.persistence = persistence || new MemoryDurableStorePersistence();
|
|
284
300
|
}
|
|
285
301
|
getEntries(entryIds, segment) {
|
|
286
302
|
const returnSource = Object.create(null);
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
for (const entryId of entryIds) {
|
|
292
|
-
const entry = entries[entryId];
|
|
293
|
-
if (entry !== undefined) {
|
|
294
|
-
returnSource[entryId] = clone(entry);
|
|
303
|
+
return this.persistence.get(segment).then((entries) => {
|
|
304
|
+
if (entries === undefined) {
|
|
305
|
+
return undefined;
|
|
295
306
|
}
|
|
296
|
-
|
|
297
|
-
|
|
307
|
+
for (const entryId of entryIds) {
|
|
308
|
+
const entry = entries[entryId];
|
|
309
|
+
if (entry !== undefined) {
|
|
310
|
+
returnSource[entryId] = clone(entry);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return returnSource;
|
|
314
|
+
});
|
|
298
315
|
}
|
|
299
316
|
getAllEntries(segment) {
|
|
300
317
|
const returnSource = Object.create(null);
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
entries
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
returnSource
|
|
307
|
-
}
|
|
308
|
-
return Promise.resolve(returnSource);
|
|
318
|
+
return this.persistence.get(segment).then((rawEntries) => {
|
|
319
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
320
|
+
for (const key of Object.keys(entries)) {
|
|
321
|
+
returnSource[key] = clone(entries[key]);
|
|
322
|
+
}
|
|
323
|
+
return returnSource;
|
|
324
|
+
});
|
|
309
325
|
}
|
|
310
326
|
setEntries(entries, segment) {
|
|
311
327
|
return this.batchOperations([
|
|
@@ -324,41 +340,36 @@ class MockDurableStore {
|
|
|
324
340
|
return Promise.resolve();
|
|
325
341
|
};
|
|
326
342
|
}
|
|
327
|
-
batchOperations(operations) {
|
|
328
|
-
const
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
this.listeners.forEach((listener) => {
|
|
335
|
-
listener(changes);
|
|
336
|
-
});
|
|
343
|
+
async batchOperations(operations) {
|
|
344
|
+
const changes = [];
|
|
345
|
+
for (let i = 0; i < operations.length; i++) {
|
|
346
|
+
changes.push(await this.performOperation(operations[i]));
|
|
347
|
+
}
|
|
348
|
+
this.listeners.forEach((listener) => {
|
|
349
|
+
listener(changes);
|
|
337
350
|
});
|
|
338
351
|
}
|
|
339
|
-
performOperation(operation) {
|
|
352
|
+
async performOperation(operation) {
|
|
340
353
|
const segment = operation.segment;
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
let ids;
|
|
354
|
+
const rawEntries = await this.persistence.get(segment);
|
|
355
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
356
|
+
let ids = [];
|
|
346
357
|
switch (operation.type) {
|
|
347
358
|
case DurableStoreOperationType.SetEntries:
|
|
348
359
|
ids = Object.keys(operation.entries);
|
|
349
360
|
ids.forEach((id) => {
|
|
350
|
-
|
|
361
|
+
entries[id] = clone(operation.entries[id]);
|
|
351
362
|
});
|
|
352
363
|
break;
|
|
353
364
|
case DurableStoreOperationType.EvictEntries:
|
|
354
365
|
ids = operation.ids;
|
|
355
366
|
ids.forEach((id) => {
|
|
356
|
-
delete
|
|
367
|
+
delete entries[id];
|
|
357
368
|
});
|
|
358
369
|
}
|
|
359
|
-
this.
|
|
360
|
-
return
|
|
370
|
+
await this.persistence.set(operation.segment, entries);
|
|
371
|
+
return { ids, segment, type: operation.type };
|
|
361
372
|
}
|
|
362
373
|
}
|
|
363
374
|
|
|
364
|
-
export { ConnectivityState, MockDurableStore, buildErrorMockPayload, buildFetchResponse, buildMockNetworkAdapter, buildSuccessMockPayload, getMockFulfilledSnapshot, getMockLuvioWithFulfilledSnapshot, getMockNetworkAdapterCallCount, isImmutable, overrideMockNetworkResponses, resetMockNetworkAdapter, setMockNetworkPayloads, setNetworkConnectivity, stripProperties, verifyImmutable };
|
|
375
|
+
export { ConnectivityState, MemoryDurableStorePersistence, MockDurableStore, buildErrorMockPayload, buildFetchResponse, buildMockNetworkAdapter, buildSuccessMockPayload, getMockFulfilledSnapshot, getMockLuvioWithFulfilledSnapshot, getMockNetworkAdapterCallCount, isImmutable, overrideMockNetworkResponses, resetMockNetworkAdapter, setMockNetworkPayloads, setNetworkConnectivity, stripProperties, verifyImmutable };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DurableStore, DurableStoreEntries, OnDurableStoreChangedListener, DurableStoreOperation, DurableStoreChange } from '@luvio/environments';
|
|
2
|
+
import { DurableStorePersistence } from './durableStorePersistence';
|
|
2
3
|
export declare class MockDurableStore implements DurableStore {
|
|
3
4
|
listeners: Set<OnDurableStoreChangedListener>;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
5
|
+
persistence: DurableStorePersistence;
|
|
6
|
+
constructor(persistence?: DurableStorePersistence);
|
|
7
7
|
getEntries<T>(entryIds: string[], segment: string): Promise<DurableStoreEntries<T> | undefined>;
|
|
8
|
-
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T
|
|
8
|
+
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T>>;
|
|
9
9
|
setEntries<T>(entries: DurableStoreEntries<T>, segment: string): Promise<void>;
|
|
10
10
|
evictEntries(ids: string[], segment: string): Promise<void>;
|
|
11
11
|
registerOnChangedListener(listener: OnDurableStoreChangedListener): () => Promise<void>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DurableStorePersistence {
|
|
2
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
3
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
4
|
+
delete(key: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare class MemoryDurableStorePersistence implements DurableStorePersistence {
|
|
7
|
+
private store;
|
|
8
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
9
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
}
|
|
@@ -3,3 +3,4 @@ export { verifyImmutable, isImmutable } from './verification';
|
|
|
3
3
|
export { getMockLuvioWithFulfilledSnapshot, getMockFulfilledSnapshot } from './mocks';
|
|
4
4
|
export { stripProperties } from './utils';
|
|
5
5
|
export { MockDurableStore } from './durableStore';
|
|
6
|
+
export { MemoryDurableStorePersistence, DurableStorePersistence } from './durableStorePersistence';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
2
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('sinon'), require('@luvio/environments')) :
|
|
3
3
|
typeof define === 'function' && define.amd ? define(['exports', 'sinon', '@luvio/environments'], factory) :
|
|
4
|
-
(global = global || self, factory(global.luvioAdapterTestLibrary = {}, global.sinon, global.environments));
|
|
5
|
-
}(this, (function (exports, sinon, environments) { 'use strict';
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.luvioAdapterTestLibrary = {}, global.sinon, global.environments));
|
|
5
|
+
})(this, (function (exports, sinon, environments) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
var sinon__default = /*#__PURE__*/_interopDefaultLegacy(sinon);
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Clone an object
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
const networkConnectivityStateMap = new WeakMap();
|
|
62
|
+
exports.ConnectivityState = void 0;
|
|
60
63
|
(function (ConnectivityState) {
|
|
61
64
|
ConnectivityState[ConnectivityState["Online"] = 0] = "Online";
|
|
62
65
|
ConnectivityState[ConnectivityState["Offline"] = 1] = "Offline";
|
|
@@ -100,7 +103,7 @@
|
|
|
100
103
|
}
|
|
101
104
|
function buildMockNetworkAdapter(mockPayloads) {
|
|
102
105
|
// any endpoints not setup with a fake will return a rejected promise
|
|
103
|
-
const networkAdapter =
|
|
106
|
+
const networkAdapter = sinon__default["default"].stub().rejects(buildMockSetupError());
|
|
104
107
|
callCountMap.set(networkAdapter, 0);
|
|
105
108
|
mockPayloadsMap.set(networkAdapter, mockPayloads);
|
|
106
109
|
setMockNetworkPayloads(networkAdapter, mockPayloads);
|
|
@@ -136,7 +139,7 @@
|
|
|
136
139
|
// sort mock payloads so least-specific network args are registered first
|
|
137
140
|
mockPayloads.sort(sortPayloads).forEach((mockPayload) => {
|
|
138
141
|
const { networkArgs, response } = mockPayload;
|
|
139
|
-
const args =
|
|
142
|
+
const args = sinon__default["default"].match(networkArgs);
|
|
140
143
|
stub.withArgs(args).callsFake(() => {
|
|
141
144
|
return onNetworkStubCalled(stub, response);
|
|
142
145
|
});
|
|
@@ -158,7 +161,7 @@
|
|
|
158
161
|
function overrideMockNetworkResponses(mockNetworkAdapter, responses) {
|
|
159
162
|
const stub = mockNetworkAdapter;
|
|
160
163
|
let index = 0;
|
|
161
|
-
stub.withArgs(
|
|
164
|
+
stub.withArgs(sinon__default["default"].match.any).callsFake(() => {
|
|
162
165
|
const response = responses[index++];
|
|
163
166
|
if (response === undefined) {
|
|
164
167
|
// if they have more requests than expected
|
|
@@ -281,35 +284,51 @@
|
|
|
281
284
|
return mockFulfilledSnapshot;
|
|
282
285
|
}
|
|
283
286
|
|
|
284
|
-
class
|
|
287
|
+
class MemoryDurableStorePersistence {
|
|
285
288
|
constructor() {
|
|
289
|
+
this.store = {};
|
|
290
|
+
}
|
|
291
|
+
async get(key) {
|
|
292
|
+
return this.store[key];
|
|
293
|
+
}
|
|
294
|
+
async set(key, value) {
|
|
295
|
+
this.store[key] = value;
|
|
296
|
+
}
|
|
297
|
+
async delete(key) {
|
|
298
|
+
delete this.store[key];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
class MockDurableStore {
|
|
303
|
+
constructor(persistence) {
|
|
304
|
+
// NOTE: This mock class doesn't enforce read/write synchronization
|
|
286
305
|
this.listeners = new Set();
|
|
287
|
-
this.
|
|
306
|
+
this.persistence = persistence || new MemoryDurableStorePersistence();
|
|
288
307
|
}
|
|
289
308
|
getEntries(entryIds, segment) {
|
|
290
309
|
const returnSource = Object.create(null);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
for (const entryId of entryIds) {
|
|
296
|
-
const entry = entries[entryId];
|
|
297
|
-
if (entry !== undefined) {
|
|
298
|
-
returnSource[entryId] = clone(entry);
|
|
310
|
+
return this.persistence.get(segment).then((entries) => {
|
|
311
|
+
if (entries === undefined) {
|
|
312
|
+
return undefined;
|
|
299
313
|
}
|
|
300
|
-
|
|
301
|
-
|
|
314
|
+
for (const entryId of entryIds) {
|
|
315
|
+
const entry = entries[entryId];
|
|
316
|
+
if (entry !== undefined) {
|
|
317
|
+
returnSource[entryId] = clone(entry);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return returnSource;
|
|
321
|
+
});
|
|
302
322
|
}
|
|
303
323
|
getAllEntries(segment) {
|
|
304
324
|
const returnSource = Object.create(null);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
entries
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
returnSource
|
|
311
|
-
}
|
|
312
|
-
return Promise.resolve(returnSource);
|
|
325
|
+
return this.persistence.get(segment).then((rawEntries) => {
|
|
326
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
327
|
+
for (const key of Object.keys(entries)) {
|
|
328
|
+
returnSource[key] = clone(entries[key]);
|
|
329
|
+
}
|
|
330
|
+
return returnSource;
|
|
331
|
+
});
|
|
313
332
|
}
|
|
314
333
|
setEntries(entries, segment) {
|
|
315
334
|
return this.batchOperations([
|
|
@@ -328,43 +347,39 @@
|
|
|
328
347
|
return Promise.resolve();
|
|
329
348
|
};
|
|
330
349
|
}
|
|
331
|
-
batchOperations(operations) {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
this.listeners.forEach((listener) => {
|
|
339
|
-
listener(changes);
|
|
340
|
-
});
|
|
350
|
+
async batchOperations(operations) {
|
|
351
|
+
const changes = [];
|
|
352
|
+
for (let i = 0; i < operations.length; i++) {
|
|
353
|
+
changes.push(await this.performOperation(operations[i]));
|
|
354
|
+
}
|
|
355
|
+
this.listeners.forEach((listener) => {
|
|
356
|
+
listener(changes);
|
|
341
357
|
});
|
|
342
358
|
}
|
|
343
|
-
performOperation(operation) {
|
|
359
|
+
async performOperation(operation) {
|
|
344
360
|
const segment = operation.segment;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
let ids;
|
|
361
|
+
const rawEntries = await this.persistence.get(segment);
|
|
362
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
363
|
+
let ids = [];
|
|
350
364
|
switch (operation.type) {
|
|
351
365
|
case environments.DurableStoreOperationType.SetEntries:
|
|
352
366
|
ids = Object.keys(operation.entries);
|
|
353
367
|
ids.forEach((id) => {
|
|
354
|
-
|
|
368
|
+
entries[id] = clone(operation.entries[id]);
|
|
355
369
|
});
|
|
356
370
|
break;
|
|
357
371
|
case environments.DurableStoreOperationType.EvictEntries:
|
|
358
372
|
ids = operation.ids;
|
|
359
373
|
ids.forEach((id) => {
|
|
360
|
-
delete
|
|
374
|
+
delete entries[id];
|
|
361
375
|
});
|
|
362
376
|
}
|
|
363
|
-
this.
|
|
364
|
-
return
|
|
377
|
+
await this.persistence.set(operation.segment, entries);
|
|
378
|
+
return { ids, segment, type: operation.type };
|
|
365
379
|
}
|
|
366
380
|
}
|
|
367
381
|
|
|
382
|
+
exports.MemoryDurableStorePersistence = MemoryDurableStorePersistence;
|
|
368
383
|
exports.MockDurableStore = MockDurableStore;
|
|
369
384
|
exports.buildErrorMockPayload = buildErrorMockPayload;
|
|
370
385
|
exports.buildFetchResponse = buildFetchResponse;
|
|
@@ -383,4 +398,4 @@
|
|
|
383
398
|
|
|
384
399
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
385
400
|
|
|
386
|
-
}))
|
|
401
|
+
}));
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { DurableStore, DurableStoreEntries, OnDurableStoreChangedListener, DurableStoreOperation, DurableStoreChange } from '@luvio/environments';
|
|
2
|
+
import { DurableStorePersistence } from './durableStorePersistence';
|
|
2
3
|
export declare class MockDurableStore implements DurableStore {
|
|
3
4
|
listeners: Set<OnDurableStoreChangedListener>;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
5
|
+
persistence: DurableStorePersistence;
|
|
6
|
+
constructor(persistence?: DurableStorePersistence);
|
|
7
7
|
getEntries<T>(entryIds: string[], segment: string): Promise<DurableStoreEntries<T> | undefined>;
|
|
8
|
-
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T
|
|
8
|
+
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T>>;
|
|
9
9
|
setEntries<T>(entries: DurableStoreEntries<T>, segment: string): Promise<void>;
|
|
10
10
|
evictEntries(ids: string[], segment: string): Promise<void>;
|
|
11
11
|
registerOnChangedListener(listener: OnDurableStoreChangedListener): () => Promise<void>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface DurableStorePersistence {
|
|
2
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
3
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
4
|
+
delete(key: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export declare class MemoryDurableStorePersistence implements DurableStorePersistence {
|
|
7
|
+
private store;
|
|
8
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
9
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
10
|
+
delete(key: string): Promise<void>;
|
|
11
|
+
}
|
package/dist/umd/es5/main.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export { verifyImmutable, isImmutable } from './verification';
|
|
|
3
3
|
export { getMockLuvioWithFulfilledSnapshot, getMockFulfilledSnapshot } from './mocks';
|
|
4
4
|
export { stripProperties } from './utils';
|
|
5
5
|
export { MockDurableStore } from './durableStore';
|
|
6
|
+
export { MemoryDurableStorePersistence, DurableStorePersistence } from './durableStorePersistence';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
2
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('sinon'), require('@luvio/environments')) :
|
|
3
3
|
typeof define === 'function' && define.amd ? define(['exports', 'sinon', '@luvio/environments'], factory) :
|
|
4
|
-
(global = global || self, factory(global.luvioAdapterTestLibrary = {}, global.sinon, global.environments));
|
|
5
|
-
}(this, (function (exports, sinon, environments) { 'use strict';
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.luvioAdapterTestLibrary = {}, global.sinon, global.environments));
|
|
5
|
+
})(this, (function (exports, sinon, environments) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
var sinon__default = /*#__PURE__*/_interopDefaultLegacy(sinon);
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Clone an object
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
var networkConnectivityStateMap = new WeakMap();
|
|
62
|
+
exports.ConnectivityState = void 0;
|
|
60
63
|
(function (ConnectivityState) {
|
|
61
64
|
ConnectivityState[ConnectivityState["Online"] = 0] = "Online";
|
|
62
65
|
ConnectivityState[ConnectivityState["Offline"] = 1] = "Offline";
|
|
@@ -100,7 +103,7 @@
|
|
|
100
103
|
}
|
|
101
104
|
function buildMockNetworkAdapter(mockPayloads) {
|
|
102
105
|
// any endpoints not setup with a fake will return a rejected promise
|
|
103
|
-
var networkAdapter =
|
|
106
|
+
var networkAdapter = sinon__default["default"].stub().rejects(buildMockSetupError());
|
|
104
107
|
callCountMap.set(networkAdapter, 0);
|
|
105
108
|
mockPayloadsMap.set(networkAdapter, mockPayloads);
|
|
106
109
|
setMockNetworkPayloads(networkAdapter, mockPayloads);
|
|
@@ -136,7 +139,7 @@
|
|
|
136
139
|
// sort mock payloads so least-specific network args are registered first
|
|
137
140
|
mockPayloads.sort(sortPayloads).forEach(function (mockPayload) {
|
|
138
141
|
var networkArgs = mockPayload.networkArgs, response = mockPayload.response;
|
|
139
|
-
var args =
|
|
142
|
+
var args = sinon__default["default"].match(networkArgs);
|
|
140
143
|
stub.withArgs(args).callsFake(function () {
|
|
141
144
|
return onNetworkStubCalled(stub, response);
|
|
142
145
|
});
|
|
@@ -158,7 +161,7 @@
|
|
|
158
161
|
function overrideMockNetworkResponses(mockNetworkAdapter, responses) {
|
|
159
162
|
var stub = mockNetworkAdapter;
|
|
160
163
|
var index = 0;
|
|
161
|
-
stub.withArgs(
|
|
164
|
+
stub.withArgs(sinon__default["default"].match.any).callsFake(function () {
|
|
162
165
|
var response = responses[index++];
|
|
163
166
|
if (response === undefined) {
|
|
164
167
|
// if they have more requests than expected
|
|
@@ -230,10 +233,10 @@
|
|
|
230
233
|
throw new Error('IE11 does not throw when mutating a frozen object');
|
|
231
234
|
}
|
|
232
235
|
}) === false) {
|
|
233
|
-
throw new Error("Unexpected mutable property found at "
|
|
236
|
+
throw new Error("Unexpected mutable property found at ".concat(path, ": Array is extensible!"));
|
|
234
237
|
}
|
|
235
238
|
value.forEach(function (item, index) {
|
|
236
|
-
verifyImmutable(item, path
|
|
239
|
+
verifyImmutable(item, "".concat(path, ".").concat(index));
|
|
237
240
|
});
|
|
238
241
|
return;
|
|
239
242
|
}
|
|
@@ -243,7 +246,7 @@
|
|
|
243
246
|
throw new Error('IE11 does not throw when mutating a frozen object');
|
|
244
247
|
}
|
|
245
248
|
}) === false) {
|
|
246
|
-
throw new Error("Unexpected mutable property found at "
|
|
249
|
+
throw new Error("Unexpected mutable property found at ".concat(path, ": Object is extensible!"));
|
|
247
250
|
}
|
|
248
251
|
Object.keys(value).forEach(function (key) {
|
|
249
252
|
if (doesThrow(function () {
|
|
@@ -253,9 +256,9 @@
|
|
|
253
256
|
throw new Error('IE11 does not throw when mutating a frozen object');
|
|
254
257
|
}
|
|
255
258
|
}) === false) {
|
|
256
|
-
throw new Error("Unexpected mutable property found at "
|
|
259
|
+
throw new Error("Unexpected mutable property found at ".concat(path, ": \"").concat(path, ".").concat(key, "\" is mutable!"));
|
|
257
260
|
}
|
|
258
|
-
verifyImmutable(value[key], path
|
|
261
|
+
verifyImmutable(value[key], "".concat(path, ".").concat(key));
|
|
259
262
|
});
|
|
260
263
|
}
|
|
261
264
|
|
|
@@ -286,37 +289,121 @@
|
|
|
286
289
|
return mockFulfilledSnapshot;
|
|
287
290
|
}
|
|
288
291
|
|
|
292
|
+
/*! *****************************************************************************
|
|
293
|
+
Copyright (c) Microsoft Corporation.
|
|
294
|
+
|
|
295
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
296
|
+
purpose with or without fee is hereby granted.
|
|
297
|
+
|
|
298
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
299
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
300
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
301
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
302
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
303
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
304
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
305
|
+
***************************************************************************** */
|
|
306
|
+
|
|
307
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
308
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
309
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
310
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
311
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
312
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
313
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function __generator(thisArg, body) {
|
|
318
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
319
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
320
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
321
|
+
function step(op) {
|
|
322
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
323
|
+
while (_) try {
|
|
324
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
325
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
326
|
+
switch (op[0]) {
|
|
327
|
+
case 0: case 1: t = op; break;
|
|
328
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
329
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
330
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
331
|
+
default:
|
|
332
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
333
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
334
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
335
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
336
|
+
if (t[2]) _.ops.pop();
|
|
337
|
+
_.trys.pop(); continue;
|
|
338
|
+
}
|
|
339
|
+
op = body.call(thisArg, _);
|
|
340
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
341
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
var MemoryDurableStorePersistence = /** @class */ (function () {
|
|
346
|
+
function MemoryDurableStorePersistence() {
|
|
347
|
+
this.store = {};
|
|
348
|
+
}
|
|
349
|
+
MemoryDurableStorePersistence.prototype.get = function (key) {
|
|
350
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
351
|
+
return __generator(this, function (_a) {
|
|
352
|
+
return [2 /*return*/, this.store[key]];
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
MemoryDurableStorePersistence.prototype.set = function (key, value) {
|
|
357
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
358
|
+
return __generator(this, function (_a) {
|
|
359
|
+
this.store[key] = value;
|
|
360
|
+
return [2 /*return*/];
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
};
|
|
364
|
+
MemoryDurableStorePersistence.prototype.delete = function (key) {
|
|
365
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
366
|
+
return __generator(this, function (_a) {
|
|
367
|
+
delete this.store[key];
|
|
368
|
+
return [2 /*return*/];
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
return MemoryDurableStorePersistence;
|
|
373
|
+
}());
|
|
374
|
+
|
|
289
375
|
var MockDurableStore = /** @class */ (function () {
|
|
290
|
-
function MockDurableStore() {
|
|
376
|
+
function MockDurableStore(persistence) {
|
|
377
|
+
// NOTE: This mock class doesn't enforce read/write synchronization
|
|
291
378
|
this.listeners = new Set();
|
|
292
|
-
this.
|
|
379
|
+
this.persistence = persistence || new MemoryDurableStorePersistence();
|
|
293
380
|
}
|
|
294
381
|
MockDurableStore.prototype.getEntries = function (entryIds, segment) {
|
|
295
382
|
var returnSource = Object.create(null);
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
300
|
-
for (var _i = 0, entryIds_1 = entryIds; _i < entryIds_1.length; _i++) {
|
|
301
|
-
var entryId = entryIds_1[_i];
|
|
302
|
-
var entry = entries[entryId];
|
|
303
|
-
if (entry !== undefined) {
|
|
304
|
-
returnSource[entryId] = clone(entry);
|
|
383
|
+
return this.persistence.get(segment).then(function (entries) {
|
|
384
|
+
if (entries === undefined) {
|
|
385
|
+
return undefined;
|
|
305
386
|
}
|
|
306
|
-
|
|
307
|
-
|
|
387
|
+
for (var _i = 0, entryIds_1 = entryIds; _i < entryIds_1.length; _i++) {
|
|
388
|
+
var entryId = entryIds_1[_i];
|
|
389
|
+
var entry = entries[entryId];
|
|
390
|
+
if (entry !== undefined) {
|
|
391
|
+
returnSource[entryId] = clone(entry);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return returnSource;
|
|
395
|
+
});
|
|
308
396
|
};
|
|
309
397
|
MockDurableStore.prototype.getAllEntries = function (segment) {
|
|
310
398
|
var returnSource = Object.create(null);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
returnSource
|
|
318
|
-
}
|
|
319
|
-
return Promise.resolve(returnSource);
|
|
399
|
+
return this.persistence.get(segment).then(function (rawEntries) {
|
|
400
|
+
var entries = rawEntries === undefined ? {} : rawEntries;
|
|
401
|
+
for (var _i = 0, _a = Object.keys(entries); _i < _a.length; _i++) {
|
|
402
|
+
var key = _a[_i];
|
|
403
|
+
returnSource[key] = clone(entries[key]);
|
|
404
|
+
}
|
|
405
|
+
return returnSource;
|
|
406
|
+
});
|
|
320
407
|
};
|
|
321
408
|
MockDurableStore.prototype.setEntries = function (entries, segment) {
|
|
322
409
|
return this.batchOperations([
|
|
@@ -337,44 +424,70 @@
|
|
|
337
424
|
};
|
|
338
425
|
};
|
|
339
426
|
MockDurableStore.prototype.batchOperations = function (operations) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
427
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
428
|
+
var changes, i, _a, _b;
|
|
429
|
+
return __generator(this, function (_c) {
|
|
430
|
+
switch (_c.label) {
|
|
431
|
+
case 0:
|
|
432
|
+
changes = [];
|
|
433
|
+
i = 0;
|
|
434
|
+
_c.label = 1;
|
|
435
|
+
case 1:
|
|
436
|
+
if (!(i < operations.length)) return [3 /*break*/, 4];
|
|
437
|
+
_b = (_a = changes).push;
|
|
438
|
+
return [4 /*yield*/, this.performOperation(operations[i])];
|
|
439
|
+
case 2:
|
|
440
|
+
_b.apply(_a, [_c.sent()]);
|
|
441
|
+
_c.label = 3;
|
|
442
|
+
case 3:
|
|
443
|
+
i++;
|
|
444
|
+
return [3 /*break*/, 1];
|
|
445
|
+
case 4:
|
|
446
|
+
this.listeners.forEach(function (listener) {
|
|
447
|
+
listener(changes);
|
|
448
|
+
});
|
|
449
|
+
return [2 /*return*/];
|
|
450
|
+
}
|
|
349
451
|
});
|
|
350
452
|
});
|
|
351
453
|
};
|
|
352
454
|
MockDurableStore.prototype.performOperation = function (operation) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
455
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
456
|
+
var segment, rawEntries, entries, ids;
|
|
457
|
+
return __generator(this, function (_a) {
|
|
458
|
+
switch (_a.label) {
|
|
459
|
+
case 0:
|
|
460
|
+
segment = operation.segment;
|
|
461
|
+
return [4 /*yield*/, this.persistence.get(segment)];
|
|
462
|
+
case 1:
|
|
463
|
+
rawEntries = _a.sent();
|
|
464
|
+
entries = rawEntries === undefined ? {} : rawEntries;
|
|
465
|
+
ids = [];
|
|
466
|
+
switch (operation.type) {
|
|
467
|
+
case environments.DurableStoreOperationType.SetEntries:
|
|
468
|
+
ids = Object.keys(operation.entries);
|
|
469
|
+
ids.forEach(function (id) {
|
|
470
|
+
entries[id] = clone(operation.entries[id]);
|
|
471
|
+
});
|
|
472
|
+
break;
|
|
473
|
+
case environments.DurableStoreOperationType.EvictEntries:
|
|
474
|
+
ids = operation.ids;
|
|
475
|
+
ids.forEach(function (id) {
|
|
476
|
+
delete entries[id];
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
return [4 /*yield*/, this.persistence.set(operation.segment, entries)];
|
|
480
|
+
case 2:
|
|
481
|
+
_a.sent();
|
|
482
|
+
return [2 /*return*/, { ids: ids, segment: segment, type: operation.type }];
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
});
|
|
374
486
|
};
|
|
375
487
|
return MockDurableStore;
|
|
376
488
|
}());
|
|
377
489
|
|
|
490
|
+
exports.MemoryDurableStorePersistence = MemoryDurableStorePersistence;
|
|
378
491
|
exports.MockDurableStore = MockDurableStore;
|
|
379
492
|
exports.buildErrorMockPayload = buildErrorMockPayload;
|
|
380
493
|
exports.buildFetchResponse = buildFetchResponse;
|
|
@@ -393,4 +506,4 @@
|
|
|
393
506
|
|
|
394
507
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
395
508
|
|
|
396
|
-
}))
|
|
509
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/adapter-test-library",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.63.2",
|
|
4
4
|
"description": "Test library for luvio adapters",
|
|
5
5
|
"main": "dist/umd/es2018/test-library.js",
|
|
6
6
|
"module": "dist/es/es2018/test-library.js",
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"test": "jest"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@luvio/engine": "0.
|
|
17
|
-
"@luvio/environments": "0.
|
|
16
|
+
"@luvio/engine": "0.63.2",
|
|
17
|
+
"@luvio/environments": "0.63.2",
|
|
18
18
|
"@types/sinon": "^7.5.2"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
package/src/durableStore.ts
CHANGED
|
@@ -7,40 +7,48 @@ import {
|
|
|
7
7
|
DurableStoreChange,
|
|
8
8
|
} from '@luvio/environments';
|
|
9
9
|
import { clone } from './utils';
|
|
10
|
+
import { DurableStorePersistence, MemoryDurableStorePersistence } from './durableStorePersistence';
|
|
10
11
|
export class MockDurableStore implements DurableStore {
|
|
12
|
+
// NOTE: This mock class doesn't enforce read/write synchronization
|
|
13
|
+
|
|
11
14
|
listeners = new Set<OnDurableStoreChangedListener>();
|
|
12
|
-
|
|
15
|
+
persistence: DurableStorePersistence;
|
|
16
|
+
|
|
17
|
+
constructor(persistence?: DurableStorePersistence) {
|
|
18
|
+
this.persistence = persistence || new MemoryDurableStorePersistence();
|
|
19
|
+
}
|
|
13
20
|
|
|
14
21
|
getEntries<T>(
|
|
15
22
|
entryIds: string[],
|
|
16
23
|
segment: string
|
|
17
24
|
): Promise<DurableStoreEntries<T> | undefined> {
|
|
18
25
|
const returnSource = Object.create(null);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
26
|
+
return this.persistence.get<DurableStoreEntries<T>>(segment).then((entries) => {
|
|
27
|
+
if (entries === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
for (const entryId of entryIds) {
|
|
32
|
+
const entry = entries[entryId];
|
|
33
|
+
if (entry !== undefined) {
|
|
34
|
+
returnSource[entryId] = clone(entry);
|
|
35
|
+
}
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
return returnSource;
|
|
38
|
+
});
|
|
32
39
|
}
|
|
33
40
|
|
|
34
|
-
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T
|
|
41
|
+
getAllEntries<T>(segment: string): Promise<DurableStoreEntries<T>> {
|
|
35
42
|
const returnSource = Object.create(null);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
entries = {};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
|
|
44
|
+
return this.persistence.get<DurableStoreEntries<T>>(segment).then((rawEntries) => {
|
|
45
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
46
|
+
|
|
47
|
+
for (const key of Object.keys(entries)) {
|
|
48
|
+
returnSource[key] = clone(entries[key]);
|
|
49
|
+
}
|
|
50
|
+
return returnSource;
|
|
51
|
+
});
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
setEntries<T>(entries: DurableStoreEntries<T>, segment: string): Promise<void> {
|
|
@@ -63,43 +71,37 @@ export class MockDurableStore implements DurableStore {
|
|
|
63
71
|
};
|
|
64
72
|
}
|
|
65
73
|
|
|
66
|
-
batchOperations<T>(operations: DurableStoreOperation<T>[]): Promise<void> {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
async batchOperations<T>(operations: DurableStoreOperation<T>[]): Promise<void> {
|
|
75
|
+
const changes: DurableStoreChange[] = [];
|
|
76
|
+
for (let i = 0; i < operations.length; i++) {
|
|
77
|
+
changes.push(await this.performOperation(operations[i]));
|
|
78
|
+
}
|
|
70
79
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// tick
|
|
74
|
-
this.listeners.forEach((listener) => {
|
|
75
|
-
listener(changes);
|
|
76
|
-
});
|
|
80
|
+
this.listeners.forEach((listener) => {
|
|
81
|
+
listener(changes);
|
|
77
82
|
});
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
performOperation<T>(operation: DurableStoreOperation<T>): Promise<DurableStoreChange> {
|
|
85
|
+
async performOperation<T>(operation: DurableStoreOperation<T>): Promise<DurableStoreChange> {
|
|
81
86
|
const segment = operation.segment;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let ids: string[];
|
|
87
|
+
const rawEntries = await this.persistence.get<DurableStoreEntries<T>>(segment);
|
|
88
|
+
const entries = rawEntries === undefined ? {} : rawEntries;
|
|
89
|
+
let ids: string[] = [];
|
|
88
90
|
switch (operation.type) {
|
|
89
91
|
case DurableStoreOperationType.SetEntries:
|
|
90
92
|
ids = Object.keys(operation.entries);
|
|
91
93
|
ids.forEach((id) => {
|
|
92
|
-
|
|
94
|
+
entries[id] = clone(operation.entries[id]);
|
|
93
95
|
});
|
|
94
96
|
break;
|
|
95
97
|
case DurableStoreOperationType.EvictEntries:
|
|
96
98
|
ids = operation.ids;
|
|
97
99
|
ids.forEach((id) => {
|
|
98
|
-
delete
|
|
100
|
+
delete entries[id];
|
|
99
101
|
});
|
|
100
102
|
}
|
|
101
103
|
|
|
102
|
-
this.
|
|
103
|
-
return
|
|
104
|
+
await this.persistence.set(operation.segment, entries);
|
|
105
|
+
return { ids, segment, type: operation.type };
|
|
104
106
|
}
|
|
105
107
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface DurableStorePersistence {
|
|
2
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
3
|
+
set<T>(key: string, value: T): Promise<void>;
|
|
4
|
+
delete(key: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class MemoryDurableStorePersistence implements DurableStorePersistence {
|
|
8
|
+
private store: Record<string, any> = {};
|
|
9
|
+
|
|
10
|
+
async get<T>(key: string): Promise<T | undefined> {
|
|
11
|
+
return this.store[key];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async set<T>(key: string, value: T): Promise<void> {
|
|
15
|
+
this.store[key] = value;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async delete(key: string): Promise<void> {
|
|
19
|
+
delete this.store[key];
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/main.ts
CHANGED
|
@@ -15,3 +15,4 @@ export { verifyImmutable, isImmutable } from './verification';
|
|
|
15
15
|
export { getMockLuvioWithFulfilledSnapshot, getMockFulfilledSnapshot } from './mocks';
|
|
16
16
|
export { stripProperties } from './utils';
|
|
17
17
|
export { MockDurableStore } from './durableStore';
|
|
18
|
+
export { MemoryDurableStorePersistence, DurableStorePersistence } from './durableStorePersistence';
|