Son CV dans un terminal web en Javascript!
https://terminal-cv.gregandev.fr
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
795 lines
27 KiB
795 lines
27 KiB
1 year ago
|
'use strict';
|
||
|
|
||
|
let path = require('path');
|
||
|
let rimraf = require('rimraf');
|
||
|
let chai = require('chai');
|
||
|
let should = chai.should();
|
||
|
let expect = chai.expect;
|
||
|
let spawn = require('child_process').spawn;
|
||
|
|
||
|
let { open, getLastVersion, bufferToKeyValue, keyValueToBuffer, ABORT } = require('..');
|
||
|
const { ArrayLikeIterable } = require('../util/ArrayLikeIterable')
|
||
|
//var inspector = require('inspector'); inspector.open(9330, null, true); debugger
|
||
|
|
||
|
describe('lmdb-store', function() {
|
||
|
let testDirPath = path.resolve(__dirname, './testdata-ls');
|
||
|
|
||
|
// just to make a reasonable sized chunk of data...
|
||
|
function expand(str) {
|
||
|
str = '(' + str + ')';
|
||
|
str = str + str;
|
||
|
str = str + str;
|
||
|
str = str + str;
|
||
|
str = str + str;
|
||
|
str = str + str;
|
||
|
return str;
|
||
|
}
|
||
|
before(function(done) {
|
||
|
// cleanup previous test directory
|
||
|
rimraf(testDirPath, function(err) {
|
||
|
if (err) {
|
||
|
return done(err);
|
||
|
}
|
||
|
done();
|
||
|
});
|
||
|
});
|
||
|
let testIteration = 1
|
||
|
describe('Basic use', basicTests({ compression: false }));
|
||
|
describe('Basic use with encryption', basicTests({ compression: false, encryptionKey: 'Use this key to encrypt the data' }));
|
||
|
//describe('Check encrypted data', basicTests({ compression: false, checkLast: true }));
|
||
|
describe('Basic use with JSON', basicTests({ encoding: 'json' }));
|
||
|
describe('Basic use with ordered-binary', basicTests({ encoding: 'ordered-binary' }));
|
||
|
if (typeof WeakRef != 'undefined')
|
||
|
describe('Basic use with caching', basicTests({ cache: true }));
|
||
|
function basicTests(options) { return function() {
|
||
|
this.timeout(1000000);
|
||
|
let db, db2, db3;
|
||
|
before(function() {
|
||
|
db = open(testDirPath + '/test-' + testIteration + '.mdb', Object.assign({
|
||
|
name: 'mydb3',
|
||
|
create: true,
|
||
|
useVersions: true,
|
||
|
//asyncTransactionOrder: 'strict',
|
||
|
//useWritemap: true,
|
||
|
//noSync: true,
|
||
|
compression: {
|
||
|
threshold: 256,
|
||
|
},
|
||
|
}, options));
|
||
|
testIteration++;
|
||
|
if (!options.checkLast)
|
||
|
db.clear();
|
||
|
db2 = db.openDB(Object.assign({
|
||
|
name: 'mydb4',
|
||
|
create: true,
|
||
|
dupSort: true,
|
||
|
}));
|
||
|
if (!options.checkLast)
|
||
|
db2.clear();
|
||
|
db3 = db.openDB({
|
||
|
name: 'mydb5',
|
||
|
create: true,
|
||
|
dupSort: true,
|
||
|
encoding: 'ordered-binary',
|
||
|
});
|
||
|
if (!options.checkLast)
|
||
|
db3.clear();
|
||
|
});
|
||
|
if (options.checkLast) {
|
||
|
it('encrypted data can not be accessed', function() {
|
||
|
let data = db.get('key1');
|
||
|
console.log({data})
|
||
|
data.should.deep.equal({foo: 1, bar: true})
|
||
|
})
|
||
|
return
|
||
|
}
|
||
|
it('query of keys', async function() {
|
||
|
let keys = [
|
||
|
Symbol.for('test'),
|
||
|
false,
|
||
|
true,
|
||
|
-33,
|
||
|
-1.1,
|
||
|
3.3,
|
||
|
5,
|
||
|
[5,4],
|
||
|
[5,55],
|
||
|
[5, 'words after number'],
|
||
|
[6, 'abc'],
|
||
|
[ 'Test', null, 1 ],
|
||
|
[ 'Test', Symbol.for('test'), 2 ],
|
||
|
[ 'Test', 'not null', 3 ],
|
||
|
'hello',
|
||
|
['hello', 3],
|
||
|
['hello', 'world'],
|
||
|
[ 'uid', 'I-7l9ySkD-wAOULIjOEnb', 'Rwsu6gqOw8cqdCZG5_YNF' ],
|
||
|
'z'
|
||
|
]
|
||
|
for (let key of keys)
|
||
|
await db.put(key, 3);
|
||
|
let returnedKeys = []
|
||
|
for (let { key, value } of db.getRange({
|
||
|
start: Symbol.for('A')
|
||
|
})) {
|
||
|
returnedKeys.push(key)
|
||
|
value.should.equal(db.get(key))
|
||
|
}
|
||
|
keys.should.deep.equal(returnedKeys)
|
||
|
|
||
|
returnedKeys = []
|
||
|
for (let { key, value } of db.getRange({
|
||
|
reverse: true,
|
||
|
})) {
|
||
|
returnedKeys.unshift(key)
|
||
|
value.should.equal(db.get(key))
|
||
|
}
|
||
|
keys.should.deep.equal(returnedKeys)
|
||
|
});
|
||
|
it('reverse query range', async function() {
|
||
|
const keys = [
|
||
|
[ 'Test', 100, 1 ],
|
||
|
[ 'Test', 10010, 2 ],
|
||
|
[ 'Test', 10010, 3 ]
|
||
|
]
|
||
|
for (let key of keys)
|
||
|
await db.put(key, 3);
|
||
|
for (let { key, value } of db.getRange({
|
||
|
start: ['Test', null],
|
||
|
end: ['Test', null],
|
||
|
reverse: true
|
||
|
})) {
|
||
|
throw new Error('Should not return any results')
|
||
|
}
|
||
|
})
|
||
|
it('more reverse query range', async function() {
|
||
|
db.putSync('0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/0Sdtsud6g8YGhPwUK04fRVKhuTywhnx8', 1, 1, null);
|
||
|
db.putSync('0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/0Sdu0mnkm8lS38yIZa4Xte3Q3JUoD84V', 1, 1, null);
|
||
|
const options =
|
||
|
{
|
||
|
start: '0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/0SdvKaMkMNPoydWV6HxZbFtKeQm5sqz3',
|
||
|
end: '0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/00000000dKZzSn03pte5dWbaYfrZl4hG',
|
||
|
reverse: true
|
||
|
};
|
||
|
let returnedKeys = Array.from(db.getKeys(options))
|
||
|
returnedKeys.should.deep.equal(['0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/0Sdu0mnkm8lS38yIZa4Xte3Q3JUoD84V', '0Sdts8FwTqt2Hv5j9KE7ebjsQcFbYDdL/0Sdtsud6g8YGhPwUK04fRVKhuTywhnx8'])
|
||
|
});
|
||
|
it('string', async function() {
|
||
|
await db.put('key1', 'Hello world!');
|
||
|
let data = db.get('key1');
|
||
|
data.should.equal('Hello world!');
|
||
|
await db.remove('key1')
|
||
|
let data2 = db.get('key1');
|
||
|
should.equal(data2, undefined);
|
||
|
});
|
||
|
it('string with version', async function() {
|
||
|
await db.put('key1', 'Hello world!', 53252);
|
||
|
let entry = db.getEntry('key1');
|
||
|
entry.value.should.equal('Hello world!');
|
||
|
entry.version.should.equal(53252);
|
||
|
(await db.remove('key1', 33)).should.equal(false);
|
||
|
entry = db.getEntry('key1');
|
||
|
entry.value.should.equal('Hello world!');
|
||
|
entry.version.should.equal(53252);
|
||
|
(await db.remove('key1', 53252)).should.equal(true);
|
||
|
entry = db.getEntry('key1');
|
||
|
should.equal(entry, undefined);
|
||
|
});
|
||
|
it('string with version branching', async function() {
|
||
|
await db.put('key1', 'Hello world!', 53252);
|
||
|
let entry = db.getEntry('key1');
|
||
|
entry.value.should.equal('Hello world!');
|
||
|
entry.version.should.equal(53252);
|
||
|
(await db.ifVersion('key1', 777, () => {
|
||
|
db.put('newKey', 'test', 6);
|
||
|
db2.put('keyB', 'test', 6);
|
||
|
})).should.equal(false);
|
||
|
should.equal(db.get('newKey'), undefined);
|
||
|
should.equal(db2.get('keyB'), undefined);
|
||
|
let result = (await db.ifVersion('key1', 53252, () => {
|
||
|
db.put('newKey', 'test', 6);
|
||
|
db2.put('keyB', 'test', 6);
|
||
|
}))
|
||
|
should.equal(db.get('newKey'), 'test')
|
||
|
should.equal(db2.get('keyB'), 'test')
|
||
|
should.equal(result, true);
|
||
|
result = await db.ifNoExists('key1', () => {
|
||
|
db.put('newKey', 'changed', 7);
|
||
|
})
|
||
|
should.equal(db.get('newKey'), 'test');
|
||
|
should.equal(result, false);
|
||
|
result = await db.ifNoExists('key-no-exist', () => {
|
||
|
db.put('newKey', 'changed', 7);
|
||
|
})
|
||
|
should.equal(db.get('newKey'), 'changed')
|
||
|
should.equal(result, true);
|
||
|
});
|
||
|
it('string with compression and versions', async function() {
|
||
|
let str = expand('Hello world!')
|
||
|
await db.put('key1', str, 53252);
|
||
|
let entry = db.getEntry('key1');
|
||
|
entry.value.should.equal(str);
|
||
|
entry.version.should.equal(53252);
|
||
|
(await db.remove('key1', 33)).should.equal(false);
|
||
|
let data = db.get('key1');
|
||
|
data.should.equal(str);
|
||
|
(await db.remove('key1', 53252)).should.equal(true);
|
||
|
data = db.get('key1');
|
||
|
should.equal(data, undefined);
|
||
|
});
|
||
|
if (options.encoding == 'ordered-binary')
|
||
|
return // no more tests need to be applied for this
|
||
|
it('store objects', async function() {
|
||
|
let dataIn = {foo: 3, bar: true}
|
||
|
await db.put('key1', dataIn);
|
||
|
let dataOut = db.get('key1');
|
||
|
dataOut.should.deep.equal(dataIn);
|
||
|
db.removeSync('not-there').should.equal(false);
|
||
|
});
|
||
|
it.skip('trigger sync commit', async function() {
|
||
|
let dataIn = {foo: 4, bar: false}
|
||
|
db.immediateBatchThreshold = 1
|
||
|
db.syncBatchThreshold = 1
|
||
|
await db.put('key1', dataIn);
|
||
|
await db.put('key2', dataIn);
|
||
|
db.immediateBatchThreshold = 100000
|
||
|
db.syncBatchThreshold = 1000000
|
||
|
let dataOut = db.get('key1');
|
||
|
dataOut.should.deep.equal(dataIn);
|
||
|
});
|
||
|
function iterateQuery(acrossTransactions) { return async () => {
|
||
|
let data1 = {foo: 1, bar: true}
|
||
|
let data2 = {foo: 2, bar: false}
|
||
|
db.put('key1', data1);
|
||
|
await db.put('key2', data2);
|
||
|
let count = 0
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz', snapshot: !acrossTransactions})) {
|
||
|
if (acrossTransactions)
|
||
|
await delay(10)
|
||
|
count++
|
||
|
switch(key) {
|
||
|
case 'key1': data1.should.deep.equal(value); break;
|
||
|
case 'key2': data2.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
should.equal(count >= 2, true);
|
||
|
should.equal(db.getCount({start:'key', end:'keyz'}) >= 2, true);
|
||
|
}}
|
||
|
it('should iterate over query', iterateQuery(false));
|
||
|
it('should iterate over query, across transactions', iterateQuery(true));
|
||
|
it('should break out of query', async function() {
|
||
|
let data1 = {foo: 1, bar: true}
|
||
|
let data2 = {foo: 2, bar: false}
|
||
|
db.put('key1', data1);
|
||
|
await db.put('key2', data2);
|
||
|
let count = 0;
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz'})) {
|
||
|
if (count > 0)
|
||
|
break;
|
||
|
count++;
|
||
|
data1.should.deep.equal(value);
|
||
|
'key1'.should.equal(key);
|
||
|
}
|
||
|
count.should.equal(1);
|
||
|
});
|
||
|
it('getRange with arrays', async function() {
|
||
|
const keys = [
|
||
|
[ 'foo', 0 ],
|
||
|
[ 'foo', 1 ],
|
||
|
[ 'foo', 2 ],
|
||
|
]
|
||
|
let promise
|
||
|
keys.forEach((key, i) => {
|
||
|
promise = db.put(key, i)
|
||
|
})
|
||
|
await promise
|
||
|
|
||
|
let result = Array.from(db.getRange({
|
||
|
start: [ 'foo'],
|
||
|
end: [ 'foo', 1 ],
|
||
|
}))
|
||
|
result.should.deep.equal([ { key: [ 'foo', 0 ], value: 0 } ])
|
||
|
|
||
|
result = Array.from(db.getRange({
|
||
|
start: [ 'foo', 0 ],
|
||
|
end: [ 'foo', 1 ],
|
||
|
}))
|
||
|
result.should.deep.equal([ { key: [ 'foo', 0 ], value: 0 } ])
|
||
|
|
||
|
result = Array.from(db.getRange({
|
||
|
start: [ 'foo', 2 ],
|
||
|
end: [ 'foo', [2, null] ],
|
||
|
}))
|
||
|
result.should.deep.equal([ { key: [ 'foo', 2 ], value: 2 } ])
|
||
|
})
|
||
|
it('should iterate over query with offset/limit', async function() {
|
||
|
let data1 = {foo: 1, bar: true}
|
||
|
let data2 = {foo: 2, bar: false}
|
||
|
let data3 = {foo: 3, bar: false}
|
||
|
db.put('key1', data1);
|
||
|
db.put('key2', data2);
|
||
|
await db.put('key3', data3);
|
||
|
let count = 0
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz', offset: 1, limit: 1})) {
|
||
|
count++
|
||
|
switch(key) {
|
||
|
case 'key2': data2.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
count.should.equal(1)
|
||
|
count = 0
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz', offset: 3, limit: 3})) {
|
||
|
count++
|
||
|
}
|
||
|
count.should.equal(0)
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz', offset: 10, limit: 3})) {
|
||
|
count++
|
||
|
}
|
||
|
count.should.equal(0)
|
||
|
for (let { key, value } of db.getRange({start:'key', end:'keyz', offset: 2, limit: 3})) {
|
||
|
count++
|
||
|
switch(key) {
|
||
|
case 'key3': data3.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
count.should.equal(1)
|
||
|
});
|
||
|
it('should handle open iterators and cursor renewal', async function() {
|
||
|
let data1 = {foo: 1, bar: true};
|
||
|
let data2 = {foo: 2, bar: false};
|
||
|
let data3 = {foo: 3, bar: false};
|
||
|
db2.put('key1', data1);
|
||
|
db.put('key1', data1);
|
||
|
db.put('key2', data2);
|
||
|
await db.put('key3', data3);
|
||
|
let it1 = db.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
let it2 = db2.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
let it3 = db.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
it1.return();
|
||
|
it2.return();
|
||
|
await new Promise(resolve => setTimeout(resolve, 10));
|
||
|
it1 = db.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
it2 = db2.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
let it4 = db.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
let it5 = db2.getRange({start:'key', end:'keyz'})[Symbol.iterator]();
|
||
|
await new Promise(resolve => setTimeout(resolve, 20));
|
||
|
it4.return()
|
||
|
it5.return()
|
||
|
it1.return()
|
||
|
it2.return()
|
||
|
it3.return()
|
||
|
});
|
||
|
it('should iterate over dupsort query, with removal', async function() {
|
||
|
let data1 = {foo: 1, bar: true}
|
||
|
let data2 = {foo: 2, bar: false}
|
||
|
let data3 = {foo: 3, bar: true}
|
||
|
db2.put('key1', data1);
|
||
|
db2.put('key1', data2);
|
||
|
db2.put('key1', data3);
|
||
|
await db2.put('key2', data3);
|
||
|
let count = 0;
|
||
|
for (let value of db2.getValues('key1')) {
|
||
|
count++
|
||
|
switch(count) {
|
||
|
case 1: data1.should.deep.equal(value); break;
|
||
|
case 2: data2.should.deep.equal(value); break;
|
||
|
case 3: data3.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
count.should.equal(3);
|
||
|
db2.getValuesCount('key1').should.equal(3);
|
||
|
await db2.remove('key1', data2);
|
||
|
count = 0;
|
||
|
for (let value of db2.getValues('key1')) {
|
||
|
count++;
|
||
|
switch(count) {
|
||
|
case 1: data1.should.deep.equal(value); break;
|
||
|
case 2: data3.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
count.should.equal(2)
|
||
|
db2.getValuesCount('key1').should.equal(2);
|
||
|
count = 0;
|
||
|
for (let value of db2.getValues('key1', { reverse: true })) {
|
||
|
count++;
|
||
|
switch(count) {
|
||
|
case 1: data3.should.deep.equal(value); break;
|
||
|
case 2: data1.should.deep.equal(value); break;
|
||
|
}
|
||
|
}
|
||
|
count.should.equal(2);
|
||
|
db2.getValuesCount('key1').should.equal(2);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db2.getValues('key0')) {
|
||
|
count++;
|
||
|
}
|
||
|
count.should.equal(0);
|
||
|
db2.getValuesCount('key0').should.equal(0);
|
||
|
db2.getCount({start: 'key1', end: 'key3'}).should.equal(3);
|
||
|
});
|
||
|
it('should iterate over ordered-binary dupsort query with start/end', async function() {
|
||
|
db3.put('key1', 1);
|
||
|
db3.put('key1', 2);
|
||
|
db3.put('key1', 3);
|
||
|
await db3.put('key2', 3);
|
||
|
let count = 0;
|
||
|
for (let value of db3.getValues('key1', { start: 1 })) {
|
||
|
count++
|
||
|
value.should.equal(count)
|
||
|
}
|
||
|
count.should.equal(3);
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { end: 3 })) {
|
||
|
count++
|
||
|
value.should.equal(count)
|
||
|
}
|
||
|
count.should.equal(2);
|
||
|
});
|
||
|
it('should count ordered-binary dupsort query with start/end', async function() {
|
||
|
db3.put('key1', 1);
|
||
|
db3.put('key1', 2);
|
||
|
db3.put('key1', 3);
|
||
|
await db3.put('key2', 3);
|
||
|
db3.getValuesCount('key1').should.equal(3);
|
||
|
db3.getValuesCount('key1', { start: 1, end: 3 }).should.equal(2);
|
||
|
db3.getValuesCount('key1', { start: 2, end: 3 }).should.equal(1);
|
||
|
db3.getValuesCount('key1', { start: 2 }).should.equal(2);
|
||
|
db3.getValuesCount('key1', { end: 2 }).should.equal(1);
|
||
|
db3.getValuesCount('key1', { start: 1, end: 2 }).should.equal(1);
|
||
|
db3.getValuesCount('key1', { start: 2, end: 2 }).should.equal(0);
|
||
|
db3.getValuesCount('key1').should.equal(3);
|
||
|
});
|
||
|
it('should reverse iterate ordered-binary dupsort query with start/end', async function() {
|
||
|
db3.put('key1', 1);
|
||
|
db3.put('key1', 2);
|
||
|
db3.put('key1', 3);
|
||
|
await db3.put('key2', 3);
|
||
|
let count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, start: 2 })) {
|
||
|
count++;
|
||
|
value.should.equal(3 - count);
|
||
|
}
|
||
|
count.should.equal(2);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, start: 2.5 })) {
|
||
|
count++;
|
||
|
value.should.equal(3 - count);
|
||
|
}
|
||
|
count.should.equal(2);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, start: 50 })) {
|
||
|
count++;
|
||
|
value.should.equal(4 - count);
|
||
|
}
|
||
|
count.should.equal(3);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, start: 2, end: 1 })) {
|
||
|
count++;
|
||
|
value.should.equal(3 - count);
|
||
|
}
|
||
|
count.should.equal(1);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, end: 1 })) {
|
||
|
count++;
|
||
|
value.should.equal(4 - count);
|
||
|
}
|
||
|
count.should.equal(2);
|
||
|
|
||
|
count = 0;
|
||
|
for (let value of db3.getValues('key1', { reverse: true, start: 0.5 })) {
|
||
|
count++;
|
||
|
}
|
||
|
count.should.equal(0);
|
||
|
|
||
|
});
|
||
|
it('doesExist', async function() {
|
||
|
let data1 = {foo: 1, bar: true}
|
||
|
let data2 = {foo: 2, bar: false}
|
||
|
let data3 = {foo: 3, bar: true}
|
||
|
db2.put('key1', data1);
|
||
|
db2.put('key1', data3);
|
||
|
db2.put(false, 3);
|
||
|
await db2.put('key2', data3);
|
||
|
should.equal(db2.doesExist('key1'), true);
|
||
|
should.equal(db2.doesExist('key1', data1), true);
|
||
|
should.equal(db2.doesExist('key1', data2), false);
|
||
|
should.equal(db2.doesExist('key1', data3), true);
|
||
|
should.equal(db2.doesExist(false), true);
|
||
|
should.equal(db2.doesExist(false, 3), true);
|
||
|
should.equal(db2.doesExist(false, 4), false);
|
||
|
})
|
||
|
it('should iterate over keys without duplicates', async function() {
|
||
|
let lastKey
|
||
|
for (let key of db2.getKeys({ start: 'k' })) {
|
||
|
if (key == lastKey)
|
||
|
throw new Error('duplicate key returned')
|
||
|
lastKey = key
|
||
|
}
|
||
|
})
|
||
|
it('big keys', async function() {
|
||
|
let keyBase = ''
|
||
|
for (let i = 0; i < 1900; i++) {
|
||
|
keyBase += 'A'
|
||
|
}
|
||
|
let keys = []
|
||
|
let promise
|
||
|
for (let i = 40; i < 120; i++) {
|
||
|
let key = String.fromCharCode(i) + keyBase
|
||
|
keys.push(key)
|
||
|
promise = db.put(key, i)
|
||
|
}
|
||
|
await promise
|
||
|
let returnedKeys = []
|
||
|
for (let { key, value } of db.getRange({})) {
|
||
|
if (key.length > 1000) {
|
||
|
returnedKeys.push(key)
|
||
|
should.equal(key.charCodeAt(0), value)
|
||
|
should.equal(db.get(key), value)
|
||
|
promise = db.remove(key)
|
||
|
}
|
||
|
}
|
||
|
returnedKeys.should.deep.equal(keys)
|
||
|
await promise
|
||
|
should.equal(db.get(returnedKeys[0]), undefined)
|
||
|
});
|
||
|
|
||
|
it('invalid key', async function() {
|
||
|
expect(() => db.get({ foo: 'bar' })).to.throw();
|
||
|
//expect(() => db.put({ foo: 'bar' }, 'hello')).to.throw();
|
||
|
});
|
||
|
it('put options (sync)', function() {
|
||
|
db.putSync('zkey6', 'test', { append: true, version: 33 });
|
||
|
let entry = db.getEntry('zkey6');
|
||
|
entry.value.should.equal('test');
|
||
|
entry.version.should.equal(33);
|
||
|
db.putSync('zkey7', 'test', { append: true, noOverwrite: true });
|
||
|
db2.putSync('zkey6', 'test1', { appendDup: true });
|
||
|
db2.putSync('zkey6', 'test2', { appendDup: true });
|
||
|
expect(() => db.putSync('zkey5', 'test', { append: true, version: 44 })).to.throw();
|
||
|
expect(() => db.putSync('zkey7', 'test', { noOverwrite: true })).to.throw();
|
||
|
expect(() => db2.putSync('zkey6', 'test1', { noDupData: true })).to.throw();
|
||
|
});
|
||
|
it('async transactions', async function() {
|
||
|
let ranTransaction
|
||
|
db.put('key1', 'async initial value'); // should be queued for async write, but should put before queued transaction
|
||
|
let errorHandled
|
||
|
if (!db.cache) {
|
||
|
db.childTransaction(() => {
|
||
|
db.put('key1', 'should be rolled back');
|
||
|
throw new Error('Make sure this is properly propagated without interfering with next transaction')
|
||
|
}).catch(error => {
|
||
|
if (error)
|
||
|
errorHandled = true
|
||
|
})
|
||
|
await db.childTransaction(() => {
|
||
|
should.equal(db.get('key1'), 'async initial value');
|
||
|
db.put('key-a', 'async test a');
|
||
|
should.equal(db.get('key-a'), 'async test a');
|
||
|
})
|
||
|
should.equal(errorHandled, true);
|
||
|
}
|
||
|
await db.transactionAsync(() => {
|
||
|
ranTransaction = true;
|
||
|
should.equal(db.get('key1'), 'async initial value');
|
||
|
db.put('key1', 'async test 1');
|
||
|
should.equal(db.get('key1'), 'async test 1');
|
||
|
for (let { key, value } of db.getRange({start: 'key1', end: 'key1z' })) {
|
||
|
should.equal(value, 'async test 1');
|
||
|
}
|
||
|
db2.put('key2-async', 'async test 2');
|
||
|
should.equal(db2.get('key2-async'), 'async test 2');
|
||
|
});
|
||
|
should.equal(db.get('key1'), 'async test 1');
|
||
|
should.equal(db2.get('key2-async'), 'async test 2');
|
||
|
should.equal(ranTransaction, true);
|
||
|
});
|
||
|
it('child transaction in sync transaction', async function() {
|
||
|
if (db.cache)
|
||
|
return
|
||
|
await db.transactionSync(async () => {
|
||
|
db.put('key3', 'test-sync-txn');
|
||
|
db.childTransaction(() => {
|
||
|
db.put('key3', 'test-child-txn');
|
||
|
return ABORT;
|
||
|
})
|
||
|
should.equal(db.get('key3'), 'test-sync-txn');
|
||
|
db.childTransaction(() => {
|
||
|
db.put('key3', 'test-child-txn');
|
||
|
})
|
||
|
should.equal(db.get('key3'), 'test-child-txn');
|
||
|
await db.childTransaction(async () => {
|
||
|
await new Promise(resolve => setTimeout(resolve, 1))
|
||
|
db.put('key3', 'test-async-child-txn');
|
||
|
})
|
||
|
should.equal(db.get('key3'), 'test-async-child-txn');
|
||
|
})
|
||
|
});
|
||
|
it('async transaction with interrupting sync transaction default order', async function() {
|
||
|
db.strictAsyncOrder = false
|
||
|
let order = []
|
||
|
let ranSyncTxn
|
||
|
db.transactionAsync(() => {
|
||
|
order.push('a1');
|
||
|
db.put('async1', 'test');
|
||
|
if (!ranSyncTxn) {
|
||
|
ranSyncTxn = true;
|
||
|
setImmediate(() => db.transactionSync(() => {
|
||
|
order.push('s1');
|
||
|
db.put('inside-sync', 'test');
|
||
|
}));
|
||
|
}
|
||
|
});
|
||
|
db.put('outside-txn', 'test');
|
||
|
await db.transactionAsync(() => {
|
||
|
order.push('a2');
|
||
|
db.put('async2', 'test');
|
||
|
});
|
||
|
order.should.deep.equal(['a1', 'a2', 's1']);
|
||
|
should.equal(db.get('async1'), 'test');
|
||
|
should.equal(db.get('outside-txn'), 'test');
|
||
|
should.equal(db.get('inside-sync'), 'test');
|
||
|
should.equal(db.get('async2'), 'test');
|
||
|
});
|
||
|
it('big child transactions', async function() {
|
||
|
let ranTransaction
|
||
|
db.put('key1', 'async initial value'); // should be queued for async write, but should put before queued transaction
|
||
|
let errorHandled
|
||
|
if (!db.cache) {
|
||
|
db.childTransaction(() => {
|
||
|
let value
|
||
|
for (let i = 0; i < 5000; i++) {
|
||
|
db.put('key' + i, 'test')
|
||
|
}
|
||
|
})
|
||
|
await db.put('key1', 'test');
|
||
|
should.equal(db.get('key1'), 'test');
|
||
|
}
|
||
|
});
|
||
|
it('read and write with binary encoding', async function() {
|
||
|
let dbBinary = db.openDB(Object.assign({
|
||
|
name: 'mydb5',
|
||
|
create: true,
|
||
|
encoding: 'binary'
|
||
|
}));
|
||
|
dbBinary.put('buffer', Buffer.from('hello'));
|
||
|
dbBinary.put('empty', Buffer.from([]));
|
||
|
await dbBinary.put('Uint8Array', new Uint8Array([1,2,3]));
|
||
|
dbBinary.get('buffer').toString().should.equal('hello');
|
||
|
dbBinary.get('Uint8Array')[1].should.equal(2);
|
||
|
dbBinary.get('empty').length.should.equal(0);
|
||
|
});
|
||
|
it.skip('read and write with binary methods', async function() {
|
||
|
let dbBinary = db.openDB(Object.assign({
|
||
|
name: 'mydb6',
|
||
|
keyIsUint32: true,
|
||
|
create: true,
|
||
|
}));
|
||
|
dbBinary.put(3, Buffer.from('hello'));
|
||
|
await dbBinary.put(4, new Uint8Array([1,2,3]));
|
||
|
console.log(dbBinary.getBinaryLocation(3))
|
||
|
console.log(dbBinary.getBinaryLocation(4))
|
||
|
});
|
||
|
after(function(done) {
|
||
|
db.get('key1');
|
||
|
let iterator = db.getRange({})[Symbol.iterator]()
|
||
|
setTimeout(() => {
|
||
|
db.get('key1');
|
||
|
// should have open read and cursor transactions
|
||
|
db2.close();
|
||
|
db.close();
|
||
|
done();
|
||
|
},10);
|
||
|
});
|
||
|
}}
|
||
|
describe('direct key', function() {
|
||
|
it('should serialize and deserialize keys', function() {
|
||
|
let keys = [
|
||
|
Symbol.for('test'),
|
||
|
false,
|
||
|
true,
|
||
|
-33,
|
||
|
-1.1,
|
||
|
3.3,
|
||
|
5,
|
||
|
[5,4],
|
||
|
[5,55],
|
||
|
'hello',
|
||
|
['hello', 3],
|
||
|
['hello', 'world'],
|
||
|
[ 'uid', 'I-7l9ySkD-wAOULIjOEnb', 'Rwsu6gqOw8cqdCZG5_YNF' ],
|
||
|
'x'.repeat(1978),
|
||
|
'z'
|
||
|
]
|
||
|
let serializedKeys = []
|
||
|
for (let key of keys) {
|
||
|
let buffer = keyValueToBuffer(key)
|
||
|
serializedKeys.push(bufferToKeyValue(buffer))
|
||
|
}
|
||
|
serializedKeys.should.deep.equal(keys)
|
||
|
})
|
||
|
});
|
||
|
describe('uint32 keys', function() {
|
||
|
this.timeout(10000);
|
||
|
let db, db2;
|
||
|
before(function() {
|
||
|
db = open(testDirPath, {
|
||
|
name: 'uint32',
|
||
|
keyIsUint32: true,
|
||
|
compression: true,
|
||
|
});
|
||
|
});
|
||
|
it('write and read range', async function() {
|
||
|
let lastPromise
|
||
|
for (let i = 0; i < 10; i++) {
|
||
|
lastPromise = db.put(i, 'value' + i);
|
||
|
}
|
||
|
await lastPromise
|
||
|
let i = 0
|
||
|
for (let { key, value } of db.getRange()) {
|
||
|
key.should.equal(i);
|
||
|
value.should.equal('value' + i);
|
||
|
i++;
|
||
|
}
|
||
|
i = 0
|
||
|
for (let { key, value } of db.getRange({ start: 0 })) {
|
||
|
key.should.equal(i);
|
||
|
value.should.equal('value' + i);
|
||
|
i++;
|
||
|
}
|
||
|
});
|
||
|
after(function() {
|
||
|
db.close();
|
||
|
});
|
||
|
});
|
||
|
describe('ArrayLikeIterable', function() {
|
||
|
it('concat and iterate', async function() {
|
||
|
let a = new ArrayLikeIterable([1, 2, 3])
|
||
|
let b = new ArrayLikeIterable([4, 5, 6])
|
||
|
let all = []
|
||
|
for (let v of a.concat(b)) {
|
||
|
all.push(v)
|
||
|
}
|
||
|
all.should.deep.equal([1, 2, 3, 4, 5, 6])
|
||
|
});
|
||
|
});
|
||
|
describe('mixed keys', function() {
|
||
|
this.timeout(10000);
|
||
|
let intKeys, strKeys;
|
||
|
before(function() {
|
||
|
const rootDb = open({
|
||
|
name: `root`,
|
||
|
path: testDirPath + '/test-mixedkeys.mdb',
|
||
|
keyIsUint32: false,
|
||
|
})
|
||
|
|
||
|
intKeys = rootDb.openDB({
|
||
|
name: `intKeys`,
|
||
|
keyIsUint32: true,
|
||
|
})
|
||
|
|
||
|
strKeys = rootDb.openDB({
|
||
|
name: `strKeys`,
|
||
|
keyIsUint32: false,
|
||
|
})
|
||
|
|
||
|
})
|
||
|
it('create with keys', async function() {
|
||
|
let lastPromise
|
||
|
for (let intKey = 0; intKey < 100; intKey++) {
|
||
|
const strKey = `k${intKey}`
|
||
|
intKeys.put(intKey, `${intKey}-value`)
|
||
|
lastPromise = strKeys.put(strKey, `${strKey}-value`)
|
||
|
}
|
||
|
await lastPromise
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
function delay(ms) {
|
||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||
|
}
|