ueberdb2 4.0.11 → 4.0.17

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.
Files changed (81) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.cjs +44 -5
  3. package/.github/workflows/npmpublish.yml +3 -3
  4. package/databases/{cassandra_db.js → cassandra_db.ts} +45 -30
  5. package/databases/{couch_db.js → couch_db.ts} +78 -31
  6. package/databases/{dirty_db.js → dirty_db.ts} +19 -14
  7. package/databases/{dirty_git_db.js → dirty_git_db.ts} +19 -15
  8. package/databases/{elasticsearch_db.js → elasticsearch_db.ts} +30 -21
  9. package/databases/{memory_db.js → memory_db.ts} +8 -8
  10. package/databases/mock_db.ts +43 -0
  11. package/databases/{mongodb_db.js → mongodb_db.ts} +22 -16
  12. package/databases/{mssql_db.js → mssql_db.ts} +29 -21
  13. package/databases/{mysql_db.js → mysql_db.ts} +20 -15
  14. package/databases/{postgres_db.js → postgres_db.ts} +37 -22
  15. package/databases/{postgrespool_db.js → postgrespool_db.ts} +3 -3
  16. package/databases/redis_db.ts +129 -0
  17. package/databases/{rethink_db.js → rethink_db.ts} +35 -19
  18. package/databases/{sqlite_db.js → sqlite_db.ts} +37 -36
  19. package/dist/databases/cassandra_db.js +237 -0
  20. package/dist/databases/couch_db.js +181 -0
  21. package/dist/databases/dirty_db.js +78 -0
  22. package/dist/databases/dirty_git_db.js +77 -0
  23. package/dist/databases/elasticsearch_db.js +251 -0
  24. package/dist/databases/memory_db.js +39 -0
  25. package/dist/databases/mock_db.js +40 -0
  26. package/dist/databases/mongodb_db.js +127 -0
  27. package/dist/databases/mssql_db.js +187 -0
  28. package/dist/databases/mysql_db.js +170 -0
  29. package/dist/databases/postgres_db.js +192 -0
  30. package/dist/databases/postgrespool_db.js +12 -0
  31. package/dist/databases/redis_db.js +105 -0
  32. package/dist/databases/rethink_db.js +123 -0
  33. package/dist/databases/sqlite_db.js +140 -0
  34. package/dist/index.js +215 -0
  35. package/dist/lib/AbstractDatabase.js +38 -0
  36. package/dist/lib/CacheAndBufferLayer.js +657 -0
  37. package/dist/lib/logging.js +34 -0
  38. package/dist/test/lib/databases.js +72 -0
  39. package/dist/test/test.js +373 -0
  40. package/dist/test/test_bulk.js +74 -0
  41. package/dist/test/test_elasticsearch.js +157 -0
  42. package/dist/test/test_findKeys.js +69 -0
  43. package/dist/test/test_flush.js +83 -0
  44. package/dist/test/test_getSub.js +57 -0
  45. package/dist/test/test_lru.js +155 -0
  46. package/dist/test/test_memory.js +59 -0
  47. package/dist/test/test_metrics.js +772 -0
  48. package/dist/test/test_mysql.js +91 -0
  49. package/dist/test/test_postgres.js +40 -0
  50. package/dist/test/test_setSub.js +48 -0
  51. package/dist/test/test_tojson.js +62 -0
  52. package/docker-compose.yml +44 -0
  53. package/{index.js → index.ts} +76 -25
  54. package/lib/AbstractDatabase.ts +79 -0
  55. package/lib/{CacheAndBufferLayer.js → CacheAndBufferLayer.ts} +17 -16
  56. package/lib/{logging.js → logging.ts} +10 -6
  57. package/package.json +18 -3
  58. package/test/lib/{databases.js → databases.ts} +8 -5
  59. package/test/test.ts +328 -0
  60. package/test/test_bulk.ts +69 -0
  61. package/test/{test_elasticsearch.js → test_elasticsearch.ts} +48 -53
  62. package/test/{test_findKeys.js → test_findKeys.ts} +15 -17
  63. package/test/{test_flush.js → test_flush.ts} +16 -22
  64. package/test/test_getSub.ts +28 -0
  65. package/test/test_lru.ts +151 -0
  66. package/test/test_memory.ts +32 -0
  67. package/test/{test_metrics.js → test_metrics.ts} +73 -68
  68. package/test/{test_mysql.js → test_mysql.ts} +16 -22
  69. package/test/test_postgres.ts +16 -0
  70. package/test/{test_setSub.js → test_setSub.ts} +8 -12
  71. package/test/test_tojson.ts +34 -0
  72. package/databases/mock_db.js +0 -42
  73. package/databases/redis_db.js +0 -96
  74. package/lib/AbstractDatabase.js +0 -37
  75. package/test/test.js +0 -328
  76. package/test/test_bulk.js +0 -69
  77. package/test/test_getSub.js +0 -31
  78. package/test/test_lru.js +0 -145
  79. package/test/test_memory.js +0 -31
  80. package/test/test_postgres.js +0 -16
  81. package/test/test_tojson.js +0 -37
@@ -1,37 +0,0 @@
1
- 'use strict';
2
-
3
- const logging = require('./logging');
4
-
5
- const nullLogger = logging.normalizeLogger(null);
6
-
7
- // Format: All characters match themselves except * matches any zero or more characters. No
8
- // backslash escaping is supported, so it is impossible to create a pattern that matches only the
9
- // '*' character.
10
- const simpleGlobToRegExp = (s) => s.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
11
-
12
- module.exports = class AbstractDatabase {
13
- constructor() {
14
- if (new.target === module.exports) {
15
- throw new TypeError('cannot instantiate Abstract Database directly');
16
- }
17
- for (const fn of ['init', 'close', 'get', 'findKeys', 'remove', 'set']) {
18
- if (typeof this[fn] !== 'function') throw new TypeError(`method ${fn} not defined`);
19
- }
20
- this.logger = nullLogger;
21
- }
22
-
23
- /**
24
- * For findKey regex. Used by document dbs like mongodb or dirty.
25
- */
26
- createFindRegex(key, notKey) {
27
- let regex = `^(?=${simpleGlobToRegExp(key)}$)`;
28
- if (notKey != null) regex += `(?!${simpleGlobToRegExp(notKey)}$)`;
29
- return new RegExp(regex);
30
- }
31
-
32
- doBulk(operations, cb) {
33
- throw new Error('the doBulk method must be implemented if write caching is enabled');
34
- }
35
-
36
- get isAsync() { return false; }
37
- };
package/test/test.js DELETED
@@ -1,328 +0,0 @@
1
- 'use strict';
2
-
3
- const wtfnode = require('wtfnode'); // This should be first so that it can instrument everything.
4
-
5
- const Clitable = require('cli-table');
6
- const Randexp = require('randexp');
7
- const assert = require('assert').strict;
8
- const databases = require('./lib/databases').databases;
9
- const fs = require('fs').promises;
10
- const logging = require('../lib/logging');
11
- const ueberdb = require('../index');
12
-
13
- const maxKeyLength = 100;
14
- const randomString = (length = maxKeyLength) => new Randexp(new RegExp(`.{${length}}`)).gen();
15
-
16
- // eslint-disable-next-line mocha/no-top-level-hooks
17
- after(async function () {
18
- // Add a timeout to forcibly exit if something is keeping node from exiting cleanly.
19
- // The timeout is unref()ed so that it doesn't prevent node from exiting when done.
20
- setTimeout(() => {
21
- console.error('node should have exited by now but something is keeping it open ' +
22
- 'such as an open connection or active timer');
23
- wtfnode.dump();
24
- process.exit(1); // eslint-disable-line n/no-process-exit
25
- }, 5000).unref();
26
- });
27
-
28
- describe(__filename, function () {
29
- let speedTable;
30
- let db;
31
-
32
- before(async function () {
33
- speedTable = new Clitable({
34
- head: [
35
- 'Database',
36
- 'read cache',
37
- 'write buffer',
38
- '#',
39
- 'ms/set',
40
- 'ms/get',
41
- 'ms/findKeys',
42
- 'ms/remove',
43
- 'total ms',
44
- 'total ms/#',
45
- ],
46
- colWidths: [15, 15, 15, 8, 13, 13, 13, 13, 13, 13],
47
- });
48
- });
49
-
50
- after(async function () {
51
- console.log(speedTable.toString());
52
- });
53
-
54
- for (const database of Object.keys(databases)) {
55
- const dbSettings = databases[database];
56
- describe(database, function () {
57
- for (const readCache of [false, true]) {
58
- describe(`${readCache ? '' : 'no '}read cache`, function () {
59
- for (const writeBuffer of [false, true]) {
60
- describe(`${writeBuffer ? '' : 'no '}write buffer`, function () {
61
- this.timeout(5000);
62
-
63
- before(async function () {
64
- if (dbSettings.filename) await fs.unlink(dbSettings.filename).catch(() => {});
65
- db = new ueberdb.Database(database, dbSettings, {
66
- ...(readCache ? {} : {cache: 0}),
67
- ...(writeBuffer ? {} : {writeInterval: 0}),
68
- }, new logging.ConsoleLogger());
69
- await db.init();
70
- });
71
-
72
- after(async function () {
73
- await db.close();
74
- if (dbSettings.filename) await fs.unlink(dbSettings.filename).catch(() => {});
75
- });
76
-
77
- describe('white space in key is not ignored', function () {
78
- for (const space of [false, true]) {
79
- describe(`key ${space ? 'has' : 'does not have'} a trailing space`, function () {
80
- let input;
81
- let key;
82
-
83
- before(async function () {
84
- input = {a: 1, b: new Randexp(/.+/).gen()};
85
- key = randomString(maxKeyLength - 1) + (space ? ' ' : '');
86
- await db.set(key, input);
87
- });
88
-
89
- it('get(key) -> record', async function () {
90
- const output = await db.get(key);
91
- assert.equal(JSON.stringify(output), JSON.stringify(input));
92
- });
93
-
94
- it('get(`${key} `) -> nullish', async function () {
95
- const output = await db.get(`${key} `);
96
- assert(output == null);
97
- });
98
-
99
- if (space) {
100
- it('get(key.slice(0, -1)) -> nullish', async function () {
101
- const output = await db.get(key.slice(0, -1));
102
- assert(output == null);
103
- });
104
- }
105
- });
106
- }
107
- });
108
-
109
- it('get of unknown key -> nullish', async function () {
110
- const key = randomString();
111
- assert(await db.get(key) == null);
112
- });
113
-
114
- it('set+get works', async function () {
115
- const input = {a: 1, b: new Randexp(/.+/).gen()};
116
- const key = randomString();
117
- await db.set(key, input);
118
- const output = await db.get(key);
119
- assert.equal(JSON.stringify(output), JSON.stringify(input));
120
- });
121
-
122
- it('set+get with random key/value works', async function () {
123
- const input = {testLongString: new Randexp(/[a-f0-9]{50000}/).gen()};
124
- const key = randomString();
125
- await db.set(key, input);
126
- const output = await db.get(key);
127
- assert.equal(JSON.stringify(output), JSON.stringify(input));
128
- });
129
-
130
- it('findKeys works', async function () {
131
- if (database === 'mongodb') this.skip(); // TODO: Fix mongodb.
132
- // TODO setting a key with non ascii chars
133
- const key = new Randexp(/([a-z]\w{0,20})foo\1/).gen();
134
- await Promise.all([
135
- db.set(key, true),
136
- db.set(`${key}a`, true),
137
- db.set(`nonmatching_${key}`, false),
138
- ]);
139
- const keys = await db.findKeys(`${key}*`, null);
140
- assert.deepEqual(keys.sort(), [key, `${key}a`]);
141
- });
142
-
143
- it('findKeys with exclusion works', async function () {
144
- if (database === 'mongodb') this.skip(); // TODO: Fix mongodb.
145
- const key = new Randexp(/([a-z]\w{0,20})foo\1/).gen();
146
- await Promise.all([
147
- db.set(key, true),
148
- db.set(`${key}a`, true),
149
- db.set(`${key}b`, false),
150
- db.set(`${key}b2`, false),
151
- db.set(`nonmatching_${key}`, false),
152
- ]);
153
- const keys = await db.findKeys(`${key}*`, `${key}b*`);
154
- assert.deepEqual(keys.sort(), [key, `${key}a`].sort());
155
- });
156
-
157
- it('findKeys with no matches works', async function () {
158
- const key = new Randexp(/([a-z]\w{0,20})foo\1/).gen();
159
- await db.set(key, true);
160
- const keys = await db.findKeys(`${key}_nomatch_*`, null);
161
- assert.deepEqual(keys, []);
162
- });
163
-
164
- it('findKeys with no wildcard works', async function () {
165
- const key = new Randexp(/([a-z]\w{0,20})foo\1/).gen();
166
- await db.set(key, true);
167
- const keys = await db.findKeys(key, null);
168
- assert.deepEqual(keys, [key]);
169
- });
170
-
171
- it('remove works', async function () {
172
- const input = {a: 1, b: new Randexp(/.+/).gen()};
173
- const key = randomString();
174
- await db.set(key, input);
175
- assert.equal(JSON.stringify(await db.get(key)), JSON.stringify(input));
176
- await db.remove(key);
177
- assert(await db.get(key) == null);
178
- });
179
-
180
- it('getSub of existing property works', async function () {
181
- await db.set('k', {sub1: {sub2: 'v'}});
182
- assert.equal(await db.getSub('k', ['sub1', 'sub2']), 'v');
183
- assert.deepEqual(await db.getSub('k', ['sub1']), {sub2: 'v'});
184
- assert.deepEqual(await db.getSub('k', []), {sub1: {sub2: 'v'}});
185
- });
186
-
187
- it('getSub of missing property returns nullish', async function () {
188
- await db.set('k', {sub1: {}});
189
- assert(await db.getSub('k', ['sub1', 'sub2']) == null);
190
-
191
- await db.set('k', {});
192
- assert(await db.getSub('k', ['sub1', 'sub2']) == null);
193
- assert(await db.getSub('k', ['sub1']) == null);
194
-
195
- await db.remove('k');
196
- assert(await db.getSub('k', ['sub1', 'sub2']) == null);
197
- assert(await db.getSub('k', ['sub1']) == null);
198
- assert(await db.getSub('k', []) == null);
199
- });
200
-
201
- it('setSub can modify an existing property', async function () {
202
- await db.set('k', {sub1: {sub2: 'v'}});
203
- await db.setSub('k', ['sub1', 'sub2'], 'v2');
204
- assert.deepEqual(await db.get('k'), {sub1: {sub2: 'v2'}});
205
-
206
- await db.setSub('k', ['sub1'], 'v2');
207
- assert.deepEqual(await db.get('k'), {sub1: 'v2'});
208
-
209
- await db.setSub('k', [], 'v3');
210
- assert.equal(await db.get('k'), 'v3');
211
- });
212
-
213
- it('setSub can add a new property', async function () {
214
- await db.remove('k');
215
- await db.setSub('k', [], {});
216
- assert.deepEqual(await db.get('k'), {});
217
- await db.setSub('k', ['sub1'], {});
218
- assert.deepEqual(await db.get('k'), {sub1: {}});
219
- await db.setSub('k', ['sub1', 'sub2'], 'v');
220
- assert.deepEqual(await db.get('k'), {sub1: {sub2: 'v'}});
221
-
222
- await db.remove('k');
223
- await db.setSub('k', ['sub1', 'sub2'], 'v');
224
- assert.deepEqual(await db.get('k'), {sub1: {sub2: 'v'}});
225
- });
226
-
227
- it('setSub rejects attempts to set properties on primitives', async function () {
228
- for (const v of ['hello world', 42, true]) {
229
- await db.set('k', v);
230
- assert.rejects(db.setSub('k', ['sub'], 'x'), {
231
- name: 'TypeError',
232
- message: /property "sub" on non-object/,
233
- });
234
- assert.deepEqual(await db.get('k'), v);
235
- }
236
- });
237
-
238
- it('speed is acceptable', async function () {
239
- this.timeout(180000);
240
-
241
- const {speeds: {
242
- count = 1000,
243
- setMax = 3,
244
- getMax = 0.1,
245
- findKeysMax = 3,
246
- removeMax = 1,
247
- } = {}} = dbSettings || {};
248
-
249
- const input = {a: 1, b: new Randexp(/.+/).gen()};
250
- // TODO setting a key with non ascii chars
251
- const key = new Randexp(/([a-z]\w{0,20})foo\1/).gen();
252
- // Pre-allocate an array before starting the timer so that time spent growing the
253
- // array doesn't throw off the benchmarks.
254
- const promises = [...Array(count + 1)].map(() => null);
255
-
256
- const timers = {start: Date.now()};
257
-
258
- for (let i = 0; i < count; ++i) promises[i] = db.set(key + i, input);
259
- promises[count] = db.flush();
260
- await Promise.all(promises);
261
- timers.set = Date.now();
262
-
263
- for (let i = 0; i < count; ++i) promises[i] = db.get(key + i);
264
- await Promise.all(promises);
265
- timers.get = Date.now();
266
-
267
- for (let i = 0; i < count; ++i) promises[i] = db.findKeys(key + i, null);
268
- await Promise.all(promises);
269
- timers.findKeys = Date.now();
270
-
271
- for (let i = 0; i < count; ++i) promises[i] = db.remove(key + i);
272
- promises[count] = db.flush();
273
- await Promise.all(promises);
274
- timers.remove = Date.now();
275
-
276
- const timePerOp = {
277
- set: (timers.set - timers.start) / count,
278
- get: (timers.get - timers.set) / count,
279
- findKeys: (timers.findKeys - timers.get) / count,
280
- remove: (timers.remove - timers.findKeys) / count,
281
- };
282
- speedTable.push([
283
- database,
284
- readCache ? 'yes' : 'no',
285
- writeBuffer ? 'yes' : 'no',
286
- count,
287
- timePerOp.set,
288
- timePerOp.get,
289
- timePerOp.findKeys,
290
- timePerOp.remove,
291
- timers.remove - timers.start,
292
- (timers.remove - timers.start) / count,
293
- ]);
294
-
295
- // Removes the "Acceptable ms/op" column if there is no enforced limit.
296
- const filterColumn = (row) => {
297
- if (readCache && writeBuffer) return row;
298
- row.splice(1, 1);
299
- return row;
300
- };
301
- const acceptableTable = new Clitable({
302
- head: filterColumn(['op', 'Acceptable ms/op', 'Actual ms/op']),
303
- colWidths: filterColumn([10, 18, 18]),
304
- });
305
- acceptableTable.push(...[
306
- ['set', setMax, timePerOp.set],
307
- ['get', getMax, timePerOp.get],
308
- ['findKeys', findKeysMax, timePerOp.findKeys],
309
- ['remove', removeMax, timePerOp.remove],
310
- ].map(filterColumn));
311
- console.log(acceptableTable.toString());
312
-
313
- if (readCache && writeBuffer) {
314
- assert(setMax >= timePerOp.set);
315
- assert(getMax >= timePerOp.get);
316
- assert(findKeysMax >= timePerOp.findKeys);
317
- assert(removeMax >= timePerOp.remove);
318
- }
319
- });
320
- });
321
- }
322
- });
323
- }
324
- });
325
- }
326
- });
327
-
328
- // TODO: Need test which prefills with 1e7 of data then does a get.
package/test/test_bulk.js DELETED
@@ -1,69 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('assert').strict;
4
- const ueberdb = require('../index');
5
- const util = require('util');
6
-
7
- const range = (N) => [...Array(N).keys()];
8
-
9
- describe(__filename, function () {
10
- let db = null;
11
- let mock = null;
12
- const createDb = async (wrapperSettings) => {
13
- const settings = {};
14
- db = new ueberdb.Database('mock', settings, wrapperSettings);
15
- mock = settings.mock;
16
- mock.once('init', (cb) => cb());
17
- await db.init();
18
- };
19
-
20
- afterEach(async function () {
21
- if (mock != null) {
22
- mock.removeAllListeners();
23
- mock.once('close', (cb) => cb());
24
- mock = null;
25
- }
26
- if (db != null) {
27
- await db.close();
28
- db = null;
29
- }
30
- });
31
-
32
- describe('bulkLimit', function () {
33
- const bulkLimits = [0, false, null, undefined, '', 1, 2];
34
- for (const bulkLimit of bulkLimits) {
35
- it(bulkLimit === undefined ? 'undefined' : JSON.stringify(bulkLimit), async function () {
36
- await createDb({bulkLimit});
37
- const gotWrites = [];
38
- mock.on('set', util.callbackify(async (k, v) => gotWrites.push(1)));
39
- mock.on('doBulk', util.callbackify(async (ops) => gotWrites.push(ops.length)));
40
- const N = 10;
41
- await Promise.all(range(N).map((i) => db.set(`key${i}`, `val${i}`)));
42
- const wantLimit = bulkLimit || N;
43
- const wantWrites = range(N / wantLimit).map((i) => wantLimit);
44
- assert.deepEqual(gotWrites, wantWrites);
45
- });
46
- }
47
- });
48
-
49
- it('bulk failures are retried individually', async function () {
50
- await createDb({});
51
- const gotDoBulkCalls = [];
52
- mock.on('doBulk', util.callbackify(async (ops) => {
53
- gotDoBulkCalls.push(ops.length);
54
- throw new Error('test');
55
- }));
56
- const gotWrites = new Map();
57
- const wantWrites = new Map();
58
- mock.on('set', util.callbackify(async (k, v) => gotWrites.set(k, v)));
59
- const N = 10;
60
- await Promise.all(range(N).map(async (i) => {
61
- const k = `key${i}`;
62
- const v = `val${i}`;
63
- wantWrites.set(k, JSON.stringify(v));
64
- await db.set(k, v);
65
- }));
66
- assert.deepEqual(gotDoBulkCalls, [N]);
67
- assert.deepEqual(gotWrites, wantWrites);
68
- });
69
- });
@@ -1,31 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('assert').strict;
4
- const ueberdb = require('../index');
5
-
6
- describe(__filename, function () {
7
- let db;
8
-
9
- beforeEach(async function () {
10
- db = new ueberdb.Database('memory', {}, {});
11
- await db.init();
12
- await db.set('k', {s: 'v'});
13
- });
14
-
15
- afterEach(async function () {
16
- if (db != null) await db.close();
17
- db = null;
18
- });
19
-
20
- it('getSub stops at non-objects', async function () {
21
- assert(await db.getSub('k', ['s', 'length']) == null);
22
- });
23
-
24
- it('getSub ignores non-own properties', async function () {
25
- assert(await db.getSub('k', ['toString']) == null);
26
- });
27
-
28
- it('getSub ignores __proto__', async function () {
29
- assert(await db.getSub('k', ['__proto__']) == null);
30
- });
31
- });
package/test/test_lru.js DELETED
@@ -1,145 +0,0 @@
1
- 'use strict';
2
-
3
- const LRU = require('../lib/CacheAndBufferLayer').exportedForTesting.LRU;
4
- const assert = require('assert').strict;
5
-
6
- describe(__filename, function () {
7
- describe('capacity = 0', function () {
8
- it('constructor does not throw', async function () {
9
- new LRU(0);
10
- });
11
-
12
- describe('behavior when empty', function () {
13
- it('get() returns nullish', async function () {
14
- assert((new LRU(0)).get('k') == null);
15
- });
16
-
17
- it('empty iteration', async function () {
18
- assert.equal([...(new LRU(0))].length, 0);
19
- });
20
-
21
- it('evictOld() does not throw', async function () {
22
- (new LRU(0)).evictOld();
23
- });
24
- });
25
-
26
- describe('single entry with evictable = false', function () {
27
- let evictable, lru, key, val;
28
-
29
- beforeEach(async function () {
30
- evictable = false;
31
- lru = new LRU(0, () => evictable);
32
- key = 'k';
33
- val = 'v';
34
- lru.set(key, val);
35
- });
36
-
37
- it('get() works', async function () {
38
- assert.equal(lru.get(key), val);
39
- });
40
-
41
- it('iterate works', async function () {
42
- assert.deepEqual([...lru], [[key, val]]);
43
- });
44
-
45
- it('re-set() works', async function () {
46
- const val2 = 'v2';
47
- lru.set(key, val2);
48
- assert.equal(lru.get(key), val2);
49
- assert.deepEqual([...lru], [[key, val2]]);
50
- });
51
-
52
- it('evictOld() does not evict', async function () {
53
- lru.evictOld();
54
- assert.deepEqual([...lru], [[key, val]]);
55
- });
56
-
57
- it('evictOld() evicts after setting evictable = true', async function () {
58
- evictable = true;
59
- lru.evictOld();
60
- assert.deepEqual([...lru], []);
61
- });
62
- });
63
-
64
- describe('set immediately evicts if evictable', function () {
65
- it('explicitly evictable', async function () {
66
- const lru = new LRU(0, () => true);
67
- lru.set('k', 'v');
68
- assert(lru.get('k') == null);
69
- assert.deepEqual([...lru], []);
70
- });
71
-
72
- it('is evictable by default', async function () {
73
- const lru = new LRU(0);
74
- lru.set('k', 'v');
75
- assert(lru.get('k') == null);
76
- assert.deepEqual([...lru], []);
77
- });
78
- });
79
- });
80
-
81
- describe('capacity = 2', function () {
82
- let evictable, lru;
83
-
84
- beforeEach(async function () {
85
- evictable = () => false;
86
- lru = new LRU(2, (k, v) => evictable(k, v));
87
- });
88
-
89
- it('iterates oldest first', async function () {
90
- lru.set(0, '0');
91
- lru.set(1, '1');
92
- let i = 0;
93
- for (const [k, v] of lru) {
94
- assert.equal(k, i);
95
- assert.equal(v, `${i}`);
96
- i++;
97
- }
98
- assert.equal(i, 2);
99
- });
100
-
101
- it('get(k) updates recently used', async function () {
102
- lru.set(0, '0');
103
- lru.set(1, '1');
104
- assert.equal(lru.get(0), '0');
105
- assert.deepEqual([...lru], [[1, '1'], [0, '0']]);
106
- });
107
-
108
- it('get(k, false) does not update recently used', async function () {
109
- lru.set(0, '0');
110
- lru.set(1, '1');
111
- assert.equal(lru.get(0, false), '0');
112
- assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
113
- });
114
-
115
- it('re-set() updates recently used', async function () {
116
- lru.set(0, '0');
117
- lru.set(1, '1');
118
- lru.set(0, '00');
119
- assert.deepEqual([...lru], [[1, '1'], [0, '00']]);
120
- });
121
-
122
- it('evictOld() only evicts evictable entries', async function () {
123
- evictable = () => false;
124
- lru.set(0, '0');
125
- lru.set(1, '1');
126
- lru.set(2, '2');
127
- lru.set(3, '3');
128
- assert.deepEqual([...lru], [[0, '0'], [1, '1'], [2, '2'], [3, '3']]);
129
- evictable = (k) => k >= 2;
130
- lru.evictOld();
131
- // The newer entries should be evicted because the older are dirty/writingInProgress.
132
- assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
133
- });
134
-
135
- it('evictOld() does nothing if at or below capacity', async function () {
136
- evictable = () => true;
137
- lru.set(0, '0');
138
- lru.evictOld();
139
- assert.deepEqual([...lru], [[0, '0']]);
140
- lru.set(1, '1');
141
- lru.evictOld();
142
- assert.deepEqual([...lru], [[0, '0'], [1, '1']]);
143
- });
144
- });
145
- });
@@ -1,31 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('assert').strict;
4
- const memory = require('../databases/memory_db');
5
-
6
- describe(__filename, function () {
7
- describe('data option', function () {
8
- it('uses existing records from data option', async function () {
9
- const db = new memory.Database({data: new Map([['foo', 'bar']])});
10
- await db.init();
11
- assert.equal(await db.get('foo'), 'bar');
12
- });
13
-
14
- it('updates existing map', async function () {
15
- const data = new Map();
16
- const db = new memory.Database({data});
17
- await db.init();
18
- await db.set('foo', 'bar');
19
- assert.equal(data.get('foo'), 'bar');
20
- });
21
-
22
- it('does not clear map on close', async function () {
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
- assert.equal(data.get('foo'), 'bar');
29
- });
30
- });
31
- });
@@ -1,16 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('assert').strict;
4
- const {databases} = require('./lib/databases');
5
- const ueberdb = require('../index');
6
-
7
- describe(__filename, function () {
8
- it('connection string instead of settings object', async function () {
9
- const {user, password, host, database} = databases.postgres;
10
- const db =
11
- new ueberdb.Database('postgres', `postgres://${user}:${password}@${host}/${database}`);
12
- await db.init();
13
- await db.set('key', 'val');
14
- assert.equal(await db.get('key'), 'val');
15
- });
16
- });