ueberdb2 4.0.10 → 4.0.15
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/.eslintignore +2 -0
- package/.eslintrc.cjs +44 -5
- package/databases/{cassandra_db.js → cassandra_db.ts} +45 -30
- package/databases/{couch_db.js → couch_db.ts} +78 -31
- package/databases/{dirty_db.js → dirty_db.ts} +19 -14
- package/databases/{dirty_git_db.js → dirty_git_db.ts} +19 -15
- package/databases/{elasticsearch_db.js → elasticsearch_db.ts} +30 -21
- package/databases/{memory_db.js → memory_db.ts} +8 -8
- package/databases/mock_db.ts +43 -0
- package/databases/{mongodb_db.js → mongodb_db.ts} +22 -16
- package/databases/{mssql_db.js → mssql_db.ts} +29 -21
- package/databases/{mysql_db.js → mysql_db.ts} +20 -15
- package/databases/{postgres_db.js → postgres_db.ts} +37 -22
- package/databases/{postgrespool_db.js → postgrespool_db.ts} +3 -3
- package/databases/redis_db.ts +129 -0
- package/databases/{rethink_db.js → rethink_db.ts} +35 -19
- package/databases/{sqlite_db.js → sqlite_db.ts} +37 -36
- package/docker-compose.yml +44 -0
- package/{index.js → index.ts} +76 -25
- package/lib/AbstractDatabase.ts +79 -0
- package/lib/{CacheAndBufferLayer.js → CacheAndBufferLayer.ts} +17 -16
- package/lib/{logging.js → logging.ts} +10 -6
- package/package.json +17 -3
- package/test/lib/{databases.js → databases.ts} +8 -5
- package/test/test.ts +328 -0
- package/test/test_bulk.ts +69 -0
- package/test/{test_elasticsearch.js → test_elasticsearch.ts} +48 -53
- package/test/{test_findKeys.js → test_findKeys.ts} +15 -17
- package/test/{test_flush.js → test_flush.ts} +16 -22
- package/test/test_getSub.ts +28 -0
- package/test/test_lru.ts +151 -0
- package/test/test_memory.ts +32 -0
- package/test/{test_metrics.js → test_metrics.ts} +73 -68
- package/test/{test_mysql.js → test_mysql.ts} +16 -22
- package/test/test_postgres.ts +16 -0
- package/test/{test_setSub.js → test_setSub.ts} +8 -12
- package/test/test_tojson.ts +34 -0
- package/databases/mock_db.js +0 -42
- package/databases/redis_db.js +0 -96
- package/lib/AbstractDatabase.js +0 -37
- package/test/test.js +0 -328
- package/test/test_bulk.js +0 -69
- package/test/test_getSub.js +0 -31
- package/test/test_lru.js +0 -145
- package/test/test_memory.js +0 -31
- package/test/test_postgres.js +0 -16
- package/test/test_tojson.js +0 -37
|
@@ -1,25 +1,22 @@
|
|
|
1
|
+
import logging from '../lib/logging';
|
|
2
|
+
import * as ueberdb from '../index';
|
|
1
3
|
'use strict';
|
|
2
|
-
|
|
3
|
-
const logging = require('../lib/logging');
|
|
4
|
-
const ueberdb = require('../index');
|
|
5
|
-
|
|
6
4
|
const logger = new logging.ConsoleLogger();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let
|
|
10
|
-
let mock = null;
|
|
5
|
+
describe(__filename, () => {
|
|
6
|
+
let db: any = null;
|
|
7
|
+
let mock: any = null;
|
|
11
8
|
const createDb = async (wrapperSettings = {}) => {
|
|
12
9
|
const settings = {};
|
|
13
10
|
db = new ueberdb.Database('mock', settings, {json: false, ...wrapperSettings}, logger);
|
|
11
|
+
// @ts-expect-error TS(2339): Property 'mock' does not exist on type '{}'.
|
|
14
12
|
mock = settings.mock;
|
|
15
|
-
mock.once('init', (cb) => cb());
|
|
13
|
+
mock.once('init', (cb: any) => cb());
|
|
16
14
|
await db.init();
|
|
17
15
|
};
|
|
18
|
-
|
|
19
|
-
afterEach(async function () {
|
|
16
|
+
afterEach(async () => {
|
|
20
17
|
if (mock != null) {
|
|
21
18
|
mock.removeAllListeners();
|
|
22
|
-
mock.once('close', (cb) => cb());
|
|
19
|
+
mock.once('close', (cb: any) => cb());
|
|
23
20
|
mock = null;
|
|
24
21
|
}
|
|
25
22
|
if (db != null) {
|
|
@@ -27,32 +24,29 @@ describe(__filename, function () {
|
|
|
27
24
|
db = null;
|
|
28
25
|
}
|
|
29
26
|
});
|
|
30
|
-
|
|
31
|
-
it('flush() immediately after set() sees the write operation', async function () {
|
|
27
|
+
it('flush() immediately after set() sees the write operation', async () => {
|
|
32
28
|
// Trigger a test timeout if flush() completes before the write operation is buffered.
|
|
33
29
|
await createDb({writeInterval: 1e9});
|
|
34
|
-
mock.on('set', (k, v, cb) => cb());
|
|
30
|
+
mock.on('set', (k: any, v: any, cb: any) => cb());
|
|
35
31
|
await Promise.all([
|
|
36
32
|
db.set('key', 'value'),
|
|
37
33
|
db.flush(),
|
|
38
34
|
]);
|
|
39
35
|
});
|
|
40
|
-
|
|
41
|
-
it('flush() immediately after setSub() sees the write operation', async function () {
|
|
36
|
+
it('flush() immediately after setSub() sees the write operation', async () => {
|
|
42
37
|
// Trigger a test timeout if flush() completes before the write operation is buffered.
|
|
43
38
|
await createDb({writeInterval: 1e9});
|
|
44
|
-
mock.on('get', (k, cb) => cb(null, {sub: 'oldvalue'}));
|
|
45
|
-
mock.on('set', (k, v, cb) => cb(null));
|
|
39
|
+
mock.on('get', (k: any, cb: any) => cb(null, {sub: 'oldvalue'}));
|
|
40
|
+
mock.on('set', (k: any, v: any, cb: any) => cb(null));
|
|
46
41
|
await Promise.all([
|
|
47
42
|
db.setSub('key', ['sub'], 'newvalue'),
|
|
48
43
|
db.flush(),
|
|
49
44
|
]);
|
|
50
45
|
});
|
|
51
|
-
|
|
52
|
-
it('flush() immediately after remove() sees the write operation', async function () {
|
|
46
|
+
it('flush() immediately after remove() sees the write operation', async () => {
|
|
53
47
|
// Trigger a test timeout if flush() completes before the write operation is buffered.
|
|
54
48
|
await createDb({writeInterval: 1e9});
|
|
55
|
-
mock.on('remove', (k, cb) => cb(null));
|
|
49
|
+
mock.on('remove', (k: any, cb: any) => cb(null));
|
|
56
50
|
await Promise.all([
|
|
57
51
|
db.remove('key'),
|
|
58
52
|
db.flush(),
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert$0 from 'assert';
|
|
2
|
+
import * as ueberdb from '../index';
|
|
3
|
+
'use strict';
|
|
4
|
+
const assert = assert$0.strict;
|
|
5
|
+
describe(__filename, () => {
|
|
6
|
+
let db: any;
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
db = new ueberdb.Database('memory', {}, {});
|
|
9
|
+
await db.init();
|
|
10
|
+
await db.set('k', {s: 'v'});
|
|
11
|
+
});
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
if (db != null) await db.close();
|
|
14
|
+
db = null;
|
|
15
|
+
});
|
|
16
|
+
it('getSub stops at non-objects', async () => {
|
|
17
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
18
|
+
assert((await db.getSub('k', ['s', 'length'])) == null);
|
|
19
|
+
});
|
|
20
|
+
it('getSub ignores non-own properties', async () => {
|
|
21
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
22
|
+
assert((await db.getSub('k', ['toString'])) == null);
|
|
23
|
+
});
|
|
24
|
+
it('getSub ignores __proto__', async () => {
|
|
25
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
26
|
+
assert((await db.getSub('k', ['__proto__'])) == null);
|
|
27
|
+
});
|
|
28
|
+
});
|
package/test/test_lru.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// @ts-expect-error TS(2306): File '/mnt/c/Users/samue/WebstormProjects/ueberDB/... Remove this comment to see the full error message
|
|
2
|
+
import {exportedForTesting} from '../lib/CacheAndBufferLayer';
|
|
3
|
+
import assert$0 from 'assert';
|
|
4
|
+
'use strict';
|
|
5
|
+
const LRU = {exportedForTesting}.exportedForTesting.LRU;
|
|
6
|
+
const assert = assert$0.strict;
|
|
7
|
+
describe(__filename, () => {
|
|
8
|
+
describe('capacity = 0', () => {
|
|
9
|
+
it('constructor does not throw', async () => {
|
|
10
|
+
new LRU(0);
|
|
11
|
+
});
|
|
12
|
+
describe('behavior when empty', () => {
|
|
13
|
+
it('get() returns nullish', async () => {
|
|
14
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
15
|
+
assert((new LRU(0)).get('k') == null);
|
|
16
|
+
});
|
|
17
|
+
it('empty iteration', async () => {
|
|
18
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
19
|
+
assert.equal([...(new LRU(0))].length, 0);
|
|
20
|
+
});
|
|
21
|
+
it('evictOld() does not throw', async () => {
|
|
22
|
+
(new LRU(0)).evictOld();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe('single entry with evictable = false', () => {
|
|
26
|
+
let evictable: any, lru: any, key: any, val: any;
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
evictable = false;
|
|
29
|
+
lru = new LRU(0, () => evictable);
|
|
30
|
+
key = 'k';
|
|
31
|
+
val = 'v';
|
|
32
|
+
lru.set(key, val);
|
|
33
|
+
});
|
|
34
|
+
it('get() works', async () => {
|
|
35
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
36
|
+
assert.equal(lru.get(key), val);
|
|
37
|
+
});
|
|
38
|
+
it('iterate works', async () => {
|
|
39
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
40
|
+
assert.deepEqual([...lru], [[key, val]]);
|
|
41
|
+
});
|
|
42
|
+
it('re-set() works', async () => {
|
|
43
|
+
const val2 = 'v2';
|
|
44
|
+
lru.set(key, val2);
|
|
45
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
46
|
+
assert.equal(lru.get(key), val2);
|
|
47
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
48
|
+
assert.deepEqual([...lru], [[key, val2]]);
|
|
49
|
+
});
|
|
50
|
+
it('evictOld() does not evict', async () => {
|
|
51
|
+
lru.evictOld();
|
|
52
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
53
|
+
assert.deepEqual([...lru], [[key, val]]);
|
|
54
|
+
});
|
|
55
|
+
it('evictOld() evicts after setting evictable = true', async () => {
|
|
56
|
+
evictable = true;
|
|
57
|
+
lru.evictOld();
|
|
58
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
59
|
+
assert.deepEqual([...lru], []);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('set immediately evicts if evictable', () => {
|
|
63
|
+
it('explicitly evictable', async () => {
|
|
64
|
+
const lru = new LRU(0, () => true);
|
|
65
|
+
lru.set('k', 'v');
|
|
66
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
67
|
+
assert(lru.get('k') == null);
|
|
68
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
69
|
+
assert.deepEqual([...lru], []);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('is evictable by default', async () => {
|
|
73
|
+
const lru = new LRU(0);
|
|
74
|
+
lru.set('k', 'v');
|
|
75
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
76
|
+
assert(lru.get('k') == null);
|
|
77
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
78
|
+
assert.deepEqual([...lru], []);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
describe('capacity = 2', () => {
|
|
83
|
+
let evictable: any, lru: any;
|
|
84
|
+
beforeEach(async () => {
|
|
85
|
+
evictable = () => false;
|
|
86
|
+
lru = new LRU(2, (k: any, v: any) => evictable(k, v));
|
|
87
|
+
});
|
|
88
|
+
it('iterates oldest first', async () => {
|
|
89
|
+
lru.set(0, '0');
|
|
90
|
+
lru.set(1, '1');
|
|
91
|
+
let i = 0;
|
|
92
|
+
for (const [k, v] of lru) {
|
|
93
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
94
|
+
assert.equal(k, i);
|
|
95
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
96
|
+
assert.equal(v, `${i}`);
|
|
97
|
+
i++;
|
|
98
|
+
}
|
|
99
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
100
|
+
assert.equal(i, 2);
|
|
101
|
+
});
|
|
102
|
+
it('get(k) updates recently used', async () => {
|
|
103
|
+
lru.set(0, '0');
|
|
104
|
+
lru.set(1, '1');
|
|
105
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
106
|
+
assert.equal(lru.get(0), '0');
|
|
107
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
108
|
+
assert.deepEqual([...lru], [[1, '1'], [0, '0']]);
|
|
109
|
+
});
|
|
110
|
+
it('get(k, false) does not update recently used', async () => {
|
|
111
|
+
lru.set(0, '0');
|
|
112
|
+
lru.set(1, '1');
|
|
113
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
114
|
+
assert.equal(lru.get(0, false), '0');
|
|
115
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
116
|
+
assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
|
|
117
|
+
});
|
|
118
|
+
it('re-set() updates recently used', async () => {
|
|
119
|
+
lru.set(0, '0');
|
|
120
|
+
lru.set(1, '1');
|
|
121
|
+
lru.set(0, '00');
|
|
122
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
123
|
+
assert.deepEqual([...lru], [[1, '1'], [0, '00']]);
|
|
124
|
+
});
|
|
125
|
+
it('evictOld() only evicts evictable entries', async () => {
|
|
126
|
+
evictable = () => false;
|
|
127
|
+
lru.set(0, '0');
|
|
128
|
+
lru.set(1, '1');
|
|
129
|
+
lru.set(2, '2');
|
|
130
|
+
lru.set(3, '3');
|
|
131
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
132
|
+
assert.deepEqual([...lru], [[0, '0'], [1, '1'], [2, '2'], [3, '3']]);
|
|
133
|
+
evictable = (k: any) => k >= 2;
|
|
134
|
+
lru.evictOld();
|
|
135
|
+
// The newer entries should be evicted because the older are dirty/writingInProgress.
|
|
136
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
137
|
+
assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
|
|
138
|
+
});
|
|
139
|
+
it('evictOld() does nothing if at or below capacity', async () => {
|
|
140
|
+
evictable = () => true;
|
|
141
|
+
lru.set(0, '0');
|
|
142
|
+
lru.evictOld();
|
|
143
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
144
|
+
assert.deepEqual([...lru], [[0, '0']]);
|
|
145
|
+
lru.set(1, '1');
|
|
146
|
+
lru.evictOld();
|
|
147
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
148
|
+
assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert$0 from 'assert';
|
|
2
|
+
import * as memory from '../databases/memory_db';
|
|
3
|
+
'use strict';
|
|
4
|
+
const assert = assert$0.strict;
|
|
5
|
+
|
|
6
|
+
describe(__filename, () => {
|
|
7
|
+
describe('data option', () => {
|
|
8
|
+
it('uses existing records from data option', async () => {
|
|
9
|
+
const db = new memory.Database({data: new Map([['foo', 'bar']])});
|
|
10
|
+
await db.init();
|
|
11
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
12
|
+
assert.equal(await db.get('foo'), 'bar');
|
|
13
|
+
});
|
|
14
|
+
it('updates existing map', async () => {
|
|
15
|
+
const data = new Map();
|
|
16
|
+
const db = new memory.Database({data});
|
|
17
|
+
await db.init();
|
|
18
|
+
await db.set('foo', 'bar');
|
|
19
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
20
|
+
assert.equal(data.get('foo'), 'bar');
|
|
21
|
+
});
|
|
22
|
+
it('does not clear map on close', async () => {
|
|
23
|
+
const data = new Map();
|
|
24
|
+
const db = new memory.Database({data});
|
|
25
|
+
await db.init();
|
|
26
|
+
await db.set('foo', 'bar');
|
|
27
|
+
await db.close();
|
|
28
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
29
|
+
assert.equal(data.get('foo'), 'bar');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -1,74 +1,76 @@
|
|
|
1
|
+
import assert$0 from 'assert';
|
|
2
|
+
import * as ueberdb from '../index';
|
|
1
3
|
'use strict';
|
|
2
|
-
|
|
3
|
-
const assert = require('assert').strict;
|
|
4
|
-
const ueberdb = require('../index');
|
|
5
|
-
|
|
4
|
+
const assert = assert$0.strict;
|
|
6
5
|
// Gate is a normal Promise that resolves when its open() method is called.
|
|
6
|
+
// @ts-expect-error TS(2508): No base constructor has the specified number of ty... Remove this comment to see the full error message
|
|
7
7
|
class Gate extends Promise {
|
|
8
|
+
open: any;
|
|
8
9
|
constructor(executor = null) {
|
|
9
10
|
let open;
|
|
10
|
-
super((resolve, reject) => {
|
|
11
|
+
super((resolve: any, reject: any) => {
|
|
11
12
|
open = resolve;
|
|
12
|
-
if (executor != null)
|
|
13
|
+
if (executor != null)
|
|
14
|
+
// @ts-expect-error TS(2349): This expression is not callable.
|
|
15
|
+
{ executor(resolve, reject); }
|
|
13
16
|
});
|
|
14
17
|
this.open = open;
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
|
-
|
|
18
|
-
const diffMetrics = (before, after) => {
|
|
20
|
+
const diffMetrics = (before: any, after: any) => {
|
|
19
21
|
const diff = {};
|
|
22
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
20
23
|
assert.equal(Object.keys(before).length, Object.keys(after).length);
|
|
21
24
|
for (const [k, bv] of Object.entries(before)) {
|
|
25
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
22
26
|
assert(bv != null);
|
|
23
27
|
const av = after[k];
|
|
28
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
24
29
|
assert(av != null);
|
|
25
|
-
|
|
30
|
+
// @ts-expect-error TS(2571): Object is of type 'unknown'.
|
|
31
|
+
if (av - bv > 0)
|
|
32
|
+
// @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
|
33
|
+
{ diff[k] = av - bv; }
|
|
26
34
|
}
|
|
27
35
|
return diff;
|
|
28
36
|
};
|
|
29
|
-
|
|
30
|
-
const assertMetricsDelta = (before, after, wantDelta) => {
|
|
37
|
+
const assertMetricsDelta = (before: any, after: any, wantDelta: any) => {
|
|
31
38
|
wantDelta = {...wantDelta};
|
|
32
39
|
for (const [k, v] of Object.entries(wantDelta)) {
|
|
33
40
|
if (v === 0) delete wantDelta[k];
|
|
34
41
|
}
|
|
42
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
35
43
|
assert.deepEqual(diffMetrics(before, after), wantDelta);
|
|
36
44
|
};
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
let
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
before(async function () {
|
|
45
|
+
describe(__filename, () => {
|
|
46
|
+
let db: any;
|
|
47
|
+
let key: any;
|
|
48
|
+
let mock: any;
|
|
49
|
+
before(async () => {
|
|
44
50
|
const settings = {};
|
|
45
51
|
db = new ueberdb.Database('mock', settings);
|
|
52
|
+
// @ts-expect-error TS(2339): Property 'mock' does not exist on type '{}'.
|
|
46
53
|
mock = settings.mock;
|
|
47
|
-
mock.once('init', (cb) => cb());
|
|
54
|
+
mock.once('init', (cb: any) => cb());
|
|
48
55
|
await db.init();
|
|
49
56
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
mock.once('close', (cb) => cb());
|
|
57
|
+
after(async () => {
|
|
58
|
+
mock.once('close', (cb: any) => cb());
|
|
53
59
|
await db.close();
|
|
54
60
|
});
|
|
55
|
-
|
|
56
|
-
beforeEach(async function () {
|
|
61
|
+
beforeEach(async function (this: any) {
|
|
57
62
|
key = this.currentTest.fullTitle(); // Use test title to avoid collisions with other tests.
|
|
58
63
|
});
|
|
59
|
-
|
|
60
|
-
afterEach(async function () {
|
|
64
|
+
afterEach(async () => {
|
|
61
65
|
mock.removeAllListeners();
|
|
62
66
|
});
|
|
63
|
-
|
|
64
|
-
describe('reads', function () {
|
|
67
|
+
describe('reads', () => {
|
|
65
68
|
const tcs = [
|
|
66
|
-
{name: 'get', f: (key) => db.get(key)},
|
|
67
|
-
{name: 'getSub', f: (key) => db.getSub(key, ['s'])},
|
|
69
|
+
{name: 'get', f: (key: any) => db.get(key)},
|
|
70
|
+
{name: 'getSub', f: (key: any) => db.getSub(key, ['s'])},
|
|
68
71
|
];
|
|
69
|
-
|
|
70
72
|
for (const tc of tcs) {
|
|
71
|
-
describe(tc.name,
|
|
73
|
+
describe(tc.name, () => {
|
|
72
74
|
const subtcs = [
|
|
73
75
|
{
|
|
74
76
|
name: 'cache miss',
|
|
@@ -114,17 +116,18 @@ describe(__filename, function () {
|
|
|
114
116
|
},
|
|
115
117
|
},
|
|
116
118
|
];
|
|
117
|
-
|
|
118
119
|
for (const subtc of subtcs) {
|
|
119
|
-
it(subtc.name, async
|
|
120
|
+
it(subtc.name, async () => {
|
|
120
121
|
if (subtc.cacheHit) {
|
|
121
|
-
mock.once('get', (key, cb) => { cb(null, subtc.val); });
|
|
122
|
+
mock.once('get', (key: any, cb: any) => { cb(null, subtc.val); });
|
|
122
123
|
await tc.f(key);
|
|
123
124
|
}
|
|
124
125
|
let finishDbRead;
|
|
125
126
|
const dbReadStarted = new Promise((resolve) => {
|
|
126
|
-
mock.once('get', (key, cb) => {
|
|
127
|
+
mock.once('get', (key: any, cb: any) => {
|
|
128
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
127
129
|
assert(!subtc.cacheHit, 'value should have been cached');
|
|
130
|
+
// @ts-expect-error TS(2794): Expected 1 arguments, but got 0. Did you forget to... Remove this comment to see the full error message
|
|
128
131
|
resolve();
|
|
129
132
|
new Promise((resolve) => { finishDbRead = resolve; })
|
|
130
133
|
.then(() => cb(subtc.err, subtc.val));
|
|
@@ -140,6 +143,7 @@ describe(__filename, function () {
|
|
|
140
143
|
readsFromDb: 1,
|
|
141
144
|
});
|
|
142
145
|
before = {...db.metrics};
|
|
146
|
+
// @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
|
143
147
|
finishDbRead();
|
|
144
148
|
}
|
|
145
149
|
if (subtc.err) readFinished = assert.rejects(readFinished, subtc.err);
|
|
@@ -148,11 +152,11 @@ describe(__filename, function () {
|
|
|
148
152
|
assertMetricsDelta(before, db.metrics, subtc.wantMetrics);
|
|
149
153
|
});
|
|
150
154
|
}
|
|
151
|
-
|
|
152
|
-
it('read of in-progress write', async function () {
|
|
155
|
+
it('read of in-progress write', async () => {
|
|
153
156
|
let finishWrite;
|
|
154
157
|
const writeStarted = new Promise((resolve) => {
|
|
155
|
-
mock.once('set', (key, val, cb) => {
|
|
158
|
+
mock.once('set', (key: any, val: any, cb: any) => {
|
|
159
|
+
// @ts-expect-error TS(2794): Expected 1 arguments, but got 0. Did you forget to... Remove this comment to see the full error message
|
|
156
160
|
resolve();
|
|
157
161
|
new Promise((resolve) => { finishWrite = resolve; }).then(() => cb());
|
|
158
162
|
});
|
|
@@ -160,7 +164,7 @@ describe(__filename, function () {
|
|
|
160
164
|
const writeFinished = db.set(key, {s: 'v'});
|
|
161
165
|
const flushed = db.flush(); // Speed up the tests.
|
|
162
166
|
await writeStarted;
|
|
163
|
-
mock.once('get', (key, cb) => { assert.fail('value should be cached'); });
|
|
167
|
+
mock.once('get', (key: any, cb: any) => { assert.fail('value should be cached'); });
|
|
164
168
|
const before = {...db.metrics};
|
|
165
169
|
await tc.f(key);
|
|
166
170
|
assertMetricsDelta(before, db.metrics, {
|
|
@@ -170,6 +174,7 @@ describe(__filename, function () {
|
|
|
170
174
|
readsFinished: 1,
|
|
171
175
|
readsFromCache: 1,
|
|
172
176
|
});
|
|
177
|
+
// @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
|
173
178
|
finishWrite();
|
|
174
179
|
await writeFinished;
|
|
175
180
|
await flushed;
|
|
@@ -177,8 +182,7 @@ describe(__filename, function () {
|
|
|
177
182
|
});
|
|
178
183
|
}
|
|
179
184
|
});
|
|
180
|
-
|
|
181
|
-
describe('writes', function () {
|
|
185
|
+
describe('writes', () => {
|
|
182
186
|
const tcs = [
|
|
183
187
|
{
|
|
184
188
|
name: 'remove ok',
|
|
@@ -270,7 +274,7 @@ describe(__filename, function () {
|
|
|
270
274
|
},
|
|
271
275
|
{
|
|
272
276
|
name: 'set json error',
|
|
273
|
-
action: async () => await db.set(key, BigInt(1)),
|
|
277
|
+
action: async () => await db.set(key, BigInt(1)),
|
|
274
278
|
wantOps: [],
|
|
275
279
|
wantErr: {name: 'TypeError'},
|
|
276
280
|
wantMetricsDelta: {
|
|
@@ -422,7 +426,7 @@ describe(__filename, function () {
|
|
|
422
426
|
},
|
|
423
427
|
{
|
|
424
428
|
name: 'setSub json write error',
|
|
425
|
-
action: async () => await db.setSub(key, ['s'], BigInt(1)),
|
|
429
|
+
action: async () => await db.setSub(key, ['s'], BigInt(1)),
|
|
426
430
|
wantOps: [
|
|
427
431
|
{
|
|
428
432
|
wantFns: ['get'],
|
|
@@ -545,7 +549,7 @@ describe(__filename, function () {
|
|
|
545
549
|
cbArgs: [[new Error('test1')], [new Error('test2')]],
|
|
546
550
|
},
|
|
547
551
|
],
|
|
548
|
-
wantErr: (err) => ['test1', 'test2'].includes(err.message),
|
|
552
|
+
wantErr: (err: any) => ['test1', 'test2'].includes(err.message),
|
|
549
553
|
wantMetricsDelta: {
|
|
550
554
|
writesFailed: 2,
|
|
551
555
|
writesFinished: 2,
|
|
@@ -602,12 +606,11 @@ describe(__filename, function () {
|
|
|
602
606
|
},
|
|
603
607
|
},
|
|
604
608
|
];
|
|
605
|
-
|
|
606
609
|
for (const tc of tcs) {
|
|
607
|
-
it(tc.name, async
|
|
608
|
-
const opStarts = [];
|
|
610
|
+
it(tc.name, async () => {
|
|
611
|
+
const opStarts: any = [];
|
|
609
612
|
for (const fn of ['doBulk', 'get', 'remove', 'set']) {
|
|
610
|
-
mock.on(fn, (...args) => {
|
|
613
|
+
mock.on(fn, (...args: any[]) => {
|
|
611
614
|
const opStart = opStarts.shift();
|
|
612
615
|
const cb = args.pop();
|
|
613
616
|
opStart.open([fn, cb]);
|
|
@@ -626,82 +629,82 @@ describe(__filename, function () {
|
|
|
626
629
|
// Gate resolves to [fn, cb] where fn is the name of the mocked database method and cb is
|
|
627
630
|
// the mocked database method's callback.
|
|
628
631
|
for (let i = 0; i < ops.wantFns.length; ++i) opStarts.push(new Gate());
|
|
629
|
-
|
|
630
632
|
// Trigger the call(s) to the mock database method(s). This is scheduled to run in the
|
|
631
633
|
// future to ensure that advance() does not empty the opStarts array until after the
|
|
632
634
|
// Promise.all() call below has a chance to see all of the Promises in opStarts.
|
|
633
635
|
setImmediate(advance);
|
|
634
|
-
|
|
635
636
|
// Wait until the expected number of parallel database method calls have started.
|
|
636
637
|
const gotOps = await Promise.all(opStarts);
|
|
637
|
-
|
|
638
638
|
assertMetricsDelta(before, db.metrics, ops.wantMetricsDelta);
|
|
639
639
|
before = {...db.metrics};
|
|
640
|
-
|
|
641
|
-
const advanceFns = [];
|
|
640
|
+
const advanceFns: any = [];
|
|
642
641
|
for (const [gotFn, cb] of gotOps) {
|
|
643
642
|
const i = ops.wantFns.indexOf(gotFn);
|
|
643
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
644
644
|
assert(i >= 0, `unexpected mock database method call: ${gotFn}`);
|
|
645
645
|
ops.wantFns.splice(i, 1);
|
|
646
646
|
const [cbArgs] = ops.cbArgs.splice(i, 1);
|
|
647
647
|
advanceFns.push(() => cb(...cbArgs));
|
|
648
648
|
}
|
|
649
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
649
650
|
assert.equal(ops.wantFns.length, 0, `missing call(s): ${ops.wantFns.join(', ')}`);
|
|
651
|
+
// @ts-expect-error TS(7006): Parameter 'f' implicitly has an 'any' type.
|
|
650
652
|
advance = () => advanceFns.forEach((f) => f());
|
|
651
653
|
}
|
|
652
654
|
advance();
|
|
655
|
+
// @ts-expect-error TS(2769): No overload matches this call.
|
|
653
656
|
await (tc.wantErr ? assert.rejects(actionDone, tc.wantErr) : actionDone);
|
|
654
657
|
assertMetricsDelta(before, db.metrics, tc.wantMetricsDelta);
|
|
655
658
|
});
|
|
656
659
|
}
|
|
657
660
|
});
|
|
658
|
-
|
|
659
|
-
describe('lock contention', function () {
|
|
661
|
+
describe('lock contention', () => {
|
|
660
662
|
const tcs = [
|
|
661
663
|
{
|
|
662
664
|
name: 'get',
|
|
663
|
-
f: (key) => db.get(key),
|
|
665
|
+
f: (key: any) => db.get(key),
|
|
664
666
|
wantMetrics: {lockAwaits: 1},
|
|
665
667
|
},
|
|
666
668
|
{
|
|
667
669
|
name: 'getSub',
|
|
668
670
|
fn: 'get',
|
|
669
|
-
f: (key) => db.getSub(key, ['s']),
|
|
671
|
+
f: (key: any) => db.getSub(key, ['s']),
|
|
670
672
|
wantMetrics: {lockAwaits: 1},
|
|
671
673
|
},
|
|
672
674
|
{
|
|
673
675
|
name: 'remove',
|
|
674
|
-
f: (key) => db.remove(key),
|
|
676
|
+
f: (key: any) => db.remove(key),
|
|
675
677
|
wantMetrics: {lockAwaits: 1},
|
|
676
678
|
},
|
|
677
679
|
{
|
|
678
680
|
name: 'set',
|
|
679
|
-
f: (key) => db.set(key, 'v'),
|
|
681
|
+
f: (key: any) => db.set(key, 'v'),
|
|
680
682
|
wantMetrics: {lockAwaits: 1},
|
|
681
683
|
},
|
|
682
684
|
{
|
|
683
685
|
name: 'setSub',
|
|
684
686
|
fn: 'set',
|
|
685
|
-
f: (key) => db.setSub(key, ['s'], 'v'),
|
|
687
|
+
f: (key: any) => db.setSub(key, ['s'], 'v'),
|
|
686
688
|
wantMetrics: {lockAwaits: 1},
|
|
687
689
|
},
|
|
688
690
|
{
|
|
689
691
|
name: 'doBulk',
|
|
690
|
-
f: (key) => Promise.all([
|
|
692
|
+
f: (key: any) => Promise.all([
|
|
691
693
|
db.set(key, 'v'),
|
|
692
694
|
db.set(`${key} second op`, 'v'),
|
|
693
695
|
]),
|
|
694
696
|
wantMetrics: {lockAcquires: 1, lockAwaits: 1},
|
|
695
697
|
},
|
|
696
698
|
];
|
|
697
|
-
|
|
698
699
|
for (const tc of tcs) {
|
|
699
|
-
if (tc.fn == null)
|
|
700
|
-
|
|
701
|
-
|
|
700
|
+
if (tc.fn == null)
|
|
701
|
+
// @ts-expect-error TS(2322): Type 'string' is not assignable to type 'undefined... Remove this comment to see the full error message
|
|
702
|
+
{ tc.fn = tc.name; }
|
|
703
|
+
it(tc.name, async () => {
|
|
702
704
|
let finishRead;
|
|
703
705
|
const readStarted = new Promise((resolve) => {
|
|
704
|
-
mock.once('get', (key, cb) => {
|
|
706
|
+
mock.once('get', (key: any, cb: any) => {
|
|
707
|
+
// @ts-expect-error TS(2794): Expected 1 arguments, but got 0. Did you forget to... Remove this comment to see the full error message
|
|
705
708
|
resolve();
|
|
706
709
|
const val = '{"s": "v"}';
|
|
707
710
|
new Promise((resolve) => { finishRead = resolve; }).then(() => cb(null, val));
|
|
@@ -711,7 +714,8 @@ describe(__filename, function () {
|
|
|
711
714
|
// the record's key.
|
|
712
715
|
const getP = db.get(key);
|
|
713
716
|
await readStarted;
|
|
714
|
-
mock.once(tc.fn, (...args) => {
|
|
717
|
+
mock.once(tc.fn, (...args: any[]) => {
|
|
718
|
+
// @ts-expect-error TS(2775): Assertions require every name in the call target t... Remove this comment to see the full error message
|
|
715
719
|
assert(tc.fn !== 'get', 'value should have been cached');
|
|
716
720
|
args.pop()();
|
|
717
721
|
});
|
|
@@ -719,6 +723,7 @@ describe(__filename, function () {
|
|
|
719
723
|
const opFinished = tc.f(key);
|
|
720
724
|
const flushed = db.flush(); // Speed up tests.
|
|
721
725
|
assertMetricsDelta(before, db.metrics, tc.wantMetrics);
|
|
726
|
+
// @ts-expect-error TS(2722): Cannot invoke an object which is possibly 'undefin... Remove this comment to see the full error message
|
|
722
727
|
finishRead();
|
|
723
728
|
await getP;
|
|
724
729
|
await opFinished;
|