296 lines
7.1 KiB
JavaScript
296 lines
7.1 KiB
JavaScript
|
'use strict'
|
||
|
|
||
|
let db
|
||
|
|
||
|
exports.setUp = function (test, testCommon) {
|
||
|
test('setUp db', function (t) {
|
||
|
db = testCommon.factory()
|
||
|
db.open(t.end.bind(t))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
exports.args = function (test, testCommon) {
|
||
|
test('test batch has db reference', function (t) {
|
||
|
t.ok(db.batch().db === db)
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
test('test batch#put() with missing, null or undefined `value`', function (t) {
|
||
|
t.plan(3 * 2)
|
||
|
|
||
|
for (const args of [[null], [undefined], []]) {
|
||
|
const batch = db.batch()
|
||
|
|
||
|
try {
|
||
|
batch.put('key', ...args)
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_INVALID_VALUE', 'correct error code')
|
||
|
t.is(batch.length, 0, 'length is not incremented on error')
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
test('test batch#put() with missing, null or undefined `key`', function (t) {
|
||
|
t.plan(3 * 2)
|
||
|
|
||
|
for (const args of [[], [null, 'foo'], [undefined, 'foo']]) {
|
||
|
const batch = db.batch()
|
||
|
|
||
|
try {
|
||
|
batch.put(...args)
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_INVALID_KEY', 'correct error code')
|
||
|
t.is(batch.length, 0, 'length is not incremented on error')
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
test('test batch#del() with missing, null or undefined `key`', function (t) {
|
||
|
t.plan(3 * 2)
|
||
|
|
||
|
for (const args of [[null], [undefined], []]) {
|
||
|
const batch = db.batch()
|
||
|
|
||
|
try {
|
||
|
batch.del(...args)
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_INVALID_KEY', 'correct error code')
|
||
|
t.is(batch.length, 0, 'length is not incremented on error')
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
|
||
|
test('test batch#clear() doesn\'t throw', function (t) {
|
||
|
db.batch().clear()
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
test('test batch#put() after write()', function (t) {
|
||
|
const batch = db.batch().put('foo', 'bar')
|
||
|
batch.write(function () {})
|
||
|
try {
|
||
|
batch.put('boom', 'bang')
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||
|
return t.end()
|
||
|
}
|
||
|
t.fail('should have thrown')
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
test('test batch#del() after write()', function (t) {
|
||
|
const batch = db.batch().put('foo', 'bar')
|
||
|
batch.write(function () {})
|
||
|
try {
|
||
|
batch.del('foo')
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||
|
return t.end()
|
||
|
}
|
||
|
t.fail('should have thrown')
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
test('test batch#clear() after write()', function (t) {
|
||
|
const batch = db.batch().put('foo', 'bar')
|
||
|
batch.write(function () {})
|
||
|
try {
|
||
|
batch.clear()
|
||
|
} catch (err) {
|
||
|
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||
|
return t.end()
|
||
|
}
|
||
|
t.fail('should have thrown')
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
test('test batch#write() after write()', function (t) {
|
||
|
t.plan(1)
|
||
|
const batch = db.batch().put('foo', 'bar')
|
||
|
batch.write(function () {})
|
||
|
batch.write(function (err) {
|
||
|
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('test batch#write() with no operations', function (t) {
|
||
|
let async = false
|
||
|
|
||
|
db.batch().write(function (err) {
|
||
|
t.ifError(err, 'no error from write()')
|
||
|
t.ok(async, 'callback is asynchronous')
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
async = true
|
||
|
})
|
||
|
|
||
|
test('test batch#write() with promise and no operations', function (t) {
|
||
|
db.batch().write()
|
||
|
.then(t.end.bind(t))
|
||
|
.catch(t.end.bind(t))
|
||
|
})
|
||
|
|
||
|
test('test twice batch#close() is idempotent', function (t) {
|
||
|
const batch = db.batch()
|
||
|
batch.close(function () {
|
||
|
let async = false
|
||
|
|
||
|
batch.close(function () {
|
||
|
t.ok(async, 'callback is asynchronous')
|
||
|
t.end()
|
||
|
})
|
||
|
|
||
|
async = true
|
||
|
})
|
||
|
})
|
||
|
}
|
||
|
|
||
|
exports.batch = function (test, testCommon) {
|
||
|
test('test basic batch', function (t) {
|
||
|
db.batch([
|
||
|
{ type: 'put', key: 'one', value: '1' },
|
||
|
{ type: 'put', key: 'two', value: '2' },
|
||
|
{ type: 'put', key: 'three', value: '3' }
|
||
|
], function (err) {
|
||
|
t.error(err)
|
||
|
|
||
|
const batch = db.batch()
|
||
|
.put('1', 'one')
|
||
|
.del('2', 'two')
|
||
|
.put('3', 'three')
|
||
|
|
||
|
t.is(batch.length, 3, 'length was incremented')
|
||
|
|
||
|
batch.clear()
|
||
|
t.is(batch.length, 0, 'length is reset')
|
||
|
|
||
|
batch.put('one', 'I')
|
||
|
.put('two', 'II')
|
||
|
.del('three')
|
||
|
.put('foo', 'bar')
|
||
|
|
||
|
t.is(batch.length, 4, 'length was incremented')
|
||
|
|
||
|
batch.write(function (err) {
|
||
|
t.error(err, 'no write() error')
|
||
|
|
||
|
db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' }).all(function (err, entries) {
|
||
|
t.error(err)
|
||
|
t.same(entries, [
|
||
|
['foo', 'bar'],
|
||
|
['one', 'I'],
|
||
|
['two', 'II']
|
||
|
])
|
||
|
t.end()
|
||
|
})
|
||
|
})
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('test basic batch with promise', function (t) {
|
||
|
const db = testCommon.factory()
|
||
|
|
||
|
db.open(function (err) {
|
||
|
t.error(err)
|
||
|
|
||
|
db.batch()
|
||
|
.put('1', 'one')
|
||
|
.put('2', 'two')
|
||
|
.put('3', 'three')
|
||
|
.write().then(function () {
|
||
|
db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' }).all(function (err, entries) {
|
||
|
t.error(err)
|
||
|
t.same(entries, [
|
||
|
['1', 'one'],
|
||
|
['2', 'two'],
|
||
|
['3', 'three']
|
||
|
])
|
||
|
db.close(t.end.bind(t))
|
||
|
})
|
||
|
}).catch(t.fail.bind(t))
|
||
|
})
|
||
|
})
|
||
|
|
||
|
// NOTE: adapted from levelup
|
||
|
test('chained batch with per-operation encoding options', async function (t) {
|
||
|
t.plan(2)
|
||
|
|
||
|
const db = testCommon.factory()
|
||
|
await db.open()
|
||
|
|
||
|
db.once('batch', function (operations) {
|
||
|
t.same(operations, [
|
||
|
{ type: 'put', key: 'a', value: 'a', valueEncoding: 'json' },
|
||
|
{ type: 'put', key: 'b', value: 'b' },
|
||
|
{ type: 'put', key: '"c"', value: 'c' },
|
||
|
{ type: 'del', key: 'c', keyEncoding: 'json', arbitraryOption: true }
|
||
|
])
|
||
|
})
|
||
|
|
||
|
await db.batch()
|
||
|
.put('a', 'a', { valueEncoding: 'json' })
|
||
|
.put('b', 'b')
|
||
|
.put('"c"', 'c')
|
||
|
.del('c', { keyEncoding: 'json', arbitraryOption: true })
|
||
|
.write()
|
||
|
|
||
|
t.same(await db.iterator().all(), [
|
||
|
['a', '"a"'],
|
||
|
['b', 'b']
|
||
|
])
|
||
|
|
||
|
return db.close()
|
||
|
})
|
||
|
}
|
||
|
|
||
|
exports.events = function (test, testCommon) {
|
||
|
test('test chained batch() emits batch event', async function (t) {
|
||
|
t.plan(2)
|
||
|
|
||
|
const db = testCommon.factory()
|
||
|
await db.open()
|
||
|
|
||
|
t.ok(db.supports.events.batch)
|
||
|
|
||
|
db.on('batch', function (ops) {
|
||
|
t.same(ops, [
|
||
|
{ type: 'put', key: 987, value: 'b', custom: 123 },
|
||
|
{ type: 'del', key: 216, custom: 999 }
|
||
|
])
|
||
|
})
|
||
|
|
||
|
await db.batch().put(987, 'b', { custom: 123 }).del(216, { custom: 999 }).write()
|
||
|
await db.close()
|
||
|
})
|
||
|
|
||
|
test('test close() on chained batch event', async function () {
|
||
|
const db = testCommon.factory()
|
||
|
await db.open()
|
||
|
|
||
|
let promise
|
||
|
|
||
|
db.on('batch', function () {
|
||
|
// Should not interfere with the current write() operation
|
||
|
promise = db.close()
|
||
|
})
|
||
|
|
||
|
await db.batch().put('a', 'b').write()
|
||
|
await promise
|
||
|
})
|
||
|
}
|
||
|
|
||
|
exports.tearDown = function (test, testCommon) {
|
||
|
test('tearDown', function (t) {
|
||
|
db.close(t.end.bind(t))
|
||
|
})
|
||
|
}
|
||
|
|
||
|
exports.all = function (test, testCommon) {
|
||
|
exports.setUp(test, testCommon)
|
||
|
exports.args(test, testCommon)
|
||
|
exports.batch(test, testCommon)
|
||
|
exports.events(test, testCommon)
|
||
|
exports.tearDown(test, testCommon)
|
||
|
}
|