mirror of https://github.com/seald/nedb
re-make the build process with webpack, swicth to Karma for the browser tests, bumps all dependencies except , remove bower.json, remove browser build from repo (will be published on npm though)
parent
1b16d2f541
commit
a4cd69f5c6
@ -0,0 +1,92 @@ |
|||||||
|
const util = require('util') |
||||||
|
|
||||||
|
function formatTime (time, precision) { |
||||||
|
// If we're dealing with ms, round up to seconds when time is at least 1 second
|
||||||
|
if (time > 1000 && precision === 'ms') { |
||||||
|
return (Math.floor(time / 100) / 10) + ' s' |
||||||
|
} else { |
||||||
|
return time.toFixed(3) + ' ' + precision |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// get time in ns
|
||||||
|
function getTime () { |
||||||
|
const t = process.hrtime() |
||||||
|
return (t[0] * 1e9 + t[1]) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a profiler with name testName to monitor the execution time of a route |
||||||
|
* The profiler has two arguments: a step msg and an optional reset for the internal timer |
||||||
|
* It will display the execution time per step and total from latest rest |
||||||
|
* |
||||||
|
* Optional logToConsole flag, which defaults to true, causes steps to be printed to console. |
||||||
|
* otherwise, they can be accessed from Profiler.steps array. |
||||||
|
*/ |
||||||
|
function Profiler (name, logToConsole, precision) { |
||||||
|
this.name = name |
||||||
|
this.steps = [] |
||||||
|
this.sinceBeginning = null |
||||||
|
this.lastStep = null |
||||||
|
this.logToConsole = typeof (logToConsole) === 'undefined' ? true : logToConsole |
||||||
|
this.precision = typeof (precision) === 'undefined' ? 'ms' : precision |
||||||
|
this.divisor = 1 |
||||||
|
|
||||||
|
if (this.precision === 'ms') this.divisor = 1e6 |
||||||
|
} |
||||||
|
|
||||||
|
Profiler.prototype.beginProfiling = function () { |
||||||
|
if (this.logToConsole) { console.log(this.name + ' - Begin profiling') } |
||||||
|
this.resetTimers() |
||||||
|
} |
||||||
|
|
||||||
|
Profiler.prototype.resetTimers = function () { |
||||||
|
this.sinceBeginning = getTime() |
||||||
|
this.lastStep = getTime() |
||||||
|
this.steps.push(['BEGIN_TIMER', this.lastStep]) |
||||||
|
} |
||||||
|
|
||||||
|
Profiler.prototype.elapsedSinceBeginning = function () { |
||||||
|
return (getTime() - this.sinceBeginning) / this.divisor |
||||||
|
} |
||||||
|
|
||||||
|
Profiler.prototype.elapsedSinceLastStep = function () { |
||||||
|
return (getTime() - this.lastStep) / this.divisor |
||||||
|
} |
||||||
|
|
||||||
|
// Return the deltas between steps, in nanoseconds
|
||||||
|
|
||||||
|
Profiler.prototype.getSteps = function () { |
||||||
|
const divisor = this.divisor |
||||||
|
|
||||||
|
return this.steps.map(function (curr, index, arr) { |
||||||
|
if (index === 0) return undefined |
||||||
|
const delta = (curr[1] - arr[index - 1][1]) |
||||||
|
return [curr[0], (delta / divisor)] |
||||||
|
}).slice(1) |
||||||
|
} |
||||||
|
|
||||||
|
Profiler.prototype.step = function (msg) { |
||||||
|
if (!this.sinceBeginning || !this.lastStep) { |
||||||
|
console.log(util.format( |
||||||
|
'%s - %s - You must call beginProfiling before registering steps', |
||||||
|
this.name, |
||||||
|
msg |
||||||
|
)) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if (this.logToConsole) { |
||||||
|
console.log(util.format('%s - %s - %s (total: %s)', |
||||||
|
this.name, |
||||||
|
msg, |
||||||
|
formatTime(this.elapsedSinceLastStep(), this.precision), |
||||||
|
formatTime(this.elapsedSinceBeginning(), this.precision) |
||||||
|
)) |
||||||
|
} |
||||||
|
|
||||||
|
this.lastStep = getTime() |
||||||
|
this.steps.push([msg, this.lastStep]) |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = Profiler |
@ -1,6 +0,0 @@ |
|||||||
{ |
|
||||||
"name": "nedb", |
|
||||||
"description": "The Javascript Database for Node, nwjs, Electron and the browser", |
|
||||||
"ignore": ["benchmarks", "lib", "test", "test_lac"], |
|
||||||
"main": ["browser-version/nedb.js", "browser-version/nedb.min.js"] |
|
||||||
} |
|
@ -1,95 +0,0 @@ |
|||||||
/** |
|
||||||
* Way data is stored for this database |
|
||||||
* For a Node.js/Node Webkit database it's the file system |
|
||||||
* For a browser-side database it's localforage, which uses the best backend available (IndexedDB then WebSQL then localStorage) |
|
||||||
* |
|
||||||
* This version is the browser version |
|
||||||
*/ |
|
||||||
|
|
||||||
var localforage = require('localforage') |
|
||||||
|
|
||||||
// Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name
|
|
||||||
localforage.config({ |
|
||||||
name: 'NeDB' |
|
||||||
, storeName: 'nedbdata' |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
function exists (filename, callback) { |
|
||||||
localforage.getItem(filename, function (err, value) { |
|
||||||
if (value !== null) { // Even if value is undefined, localforage returns null
|
|
||||||
return callback(true); |
|
||||||
} else { |
|
||||||
return callback(false); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function rename (filename, newFilename, callback) { |
|
||||||
localforage.getItem(filename, function (err, value) { |
|
||||||
if (value === null) { |
|
||||||
localforage.removeItem(newFilename, function () { return callback(); }); |
|
||||||
} else { |
|
||||||
localforage.setItem(newFilename, value, function () { |
|
||||||
localforage.removeItem(filename, function () { return callback(); }); |
|
||||||
}); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function writeFile (filename, contents, options, callback) { |
|
||||||
// Options do not matter in browser setup
|
|
||||||
if (typeof options === 'function') { callback = options; } |
|
||||||
localforage.setItem(filename, contents, function () { return callback(); }); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function appendFile (filename, toAppend, options, callback) { |
|
||||||
// Options do not matter in browser setup
|
|
||||||
if (typeof options === 'function') { callback = options; } |
|
||||||
|
|
||||||
localforage.getItem(filename, function (err, contents) { |
|
||||||
contents = contents || ''; |
|
||||||
contents += toAppend; |
|
||||||
localforage.setItem(filename, contents, function () { return callback(); }); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function readFile (filename, options, callback) { |
|
||||||
// Options do not matter in browser setup
|
|
||||||
if (typeof options === 'function') { callback = options; } |
|
||||||
localforage.getItem(filename, function (err, contents) { return callback(null, contents || ''); }); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
function unlink (filename, callback) { |
|
||||||
localforage.removeItem(filename, function () { return callback(); }); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Nothing to do, no directories will be used on the browser
|
|
||||||
function mkdirp (dir, callback) { |
|
||||||
return callback(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Nothing to do, no data corruption possible in the brower
|
|
||||||
function ensureDatafileIntegrity (filename, callback) { |
|
||||||
return callback(null); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// Interface
|
|
||||||
module.exports.exists = exists; |
|
||||||
module.exports.rename = rename; |
|
||||||
module.exports.writeFile = writeFile; |
|
||||||
module.exports.crashSafeWriteFile = writeFile; // No need for a crash safe function in the browser
|
|
||||||
module.exports.appendFile = appendFile; |
|
||||||
module.exports.readFile = readFile; |
|
||||||
module.exports.unlink = unlink; |
|
||||||
module.exports.mkdirp = mkdirp; |
|
||||||
module.exports.ensureDatafileIntegrity = ensureDatafileIntegrity; |
|
||||||
|
|
@ -1,101 +0,0 @@ |
|||||||
/** |
|
||||||
* Build the browser version of nedb |
|
||||||
*/ |
|
||||||
|
|
||||||
var fs = require('fs') |
|
||||||
, path = require('path') |
|
||||||
, child_process = require('child_process') |
|
||||||
, toCopy = ['lib', 'node_modules'] |
|
||||||
, async, browserify, uglify |
|
||||||
; |
|
||||||
|
|
||||||
// Ensuring both node_modules (the source one and build one), src and out directories exist
|
|
||||||
function ensureDirExists (name) { |
|
||||||
try { |
|
||||||
fs.mkdirSync(path.join(__dirname, name)); |
|
||||||
} catch (e) { |
|
||||||
if (e.code !== 'EEXIST') { |
|
||||||
console.log("Error ensuring that node_modules exists"); |
|
||||||
process.exit(1); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
ensureDirExists('../node_modules'); |
|
||||||
ensureDirExists('node_modules'); |
|
||||||
ensureDirExists('out'); |
|
||||||
ensureDirExists('src'); |
|
||||||
|
|
||||||
|
|
||||||
// Installing build dependencies and require them
|
|
||||||
console.log("Installing build dependencies"); |
|
||||||
child_process.exec('npm install', { cwd: __dirname }, function (err, stdout, stderr) { |
|
||||||
if (err) { console.log("Error reinstalling dependencies"); process.exit(1); } |
|
||||||
|
|
||||||
fs = require('fs-extra'); |
|
||||||
async = require('async'); |
|
||||||
browserify = require('browserify'); |
|
||||||
uglify = require('uglify-js'); |
|
||||||
|
|
||||||
async.waterfall([ |
|
||||||
function (cb) { |
|
||||||
console.log("Installing source dependencies if needed"); |
|
||||||
|
|
||||||
child_process.exec('npm install', { cwd: path.join(__dirname, '..') }, function (err) { return cb(err); }); |
|
||||||
} |
|
||||||
, function (cb) { |
|
||||||
console.log("Removing contents of the src directory"); |
|
||||||
|
|
||||||
async.eachSeries(fs.readdirSync(path.join(__dirname, 'src')), function (item, _cb) { |
|
||||||
fs.remove(path.join(__dirname, 'src', item), _cb); |
|
||||||
}, cb); |
|
||||||
} |
|
||||||
, function (cb) { |
|
||||||
console.log("Copying source files"); |
|
||||||
|
|
||||||
async.eachSeries(toCopy, function (item, _cb) { |
|
||||||
fs.copy(path.join(__dirname, '..', item), path.join(__dirname, 'src', item), _cb); |
|
||||||
}, cb); |
|
||||||
} |
|
||||||
, function (cb) { |
|
||||||
console.log("Copying browser specific files to replace their server-specific counterparts"); |
|
||||||
|
|
||||||
async.eachSeries(fs.readdirSync(path.join(__dirname, 'browser-specific')), function (item, _cb) { |
|
||||||
fs.copy(path.join(__dirname, 'browser-specific', item), path.join(__dirname, 'src', item), _cb); |
|
||||||
}, cb); |
|
||||||
} |
|
||||||
, function (cb) { |
|
||||||
console.log("Browserifying the code"); |
|
||||||
|
|
||||||
var b = browserify() |
|
||||||
, srcPath = path.join(__dirname, 'src/lib/datastore.js'); |
|
||||||
|
|
||||||
b.add(srcPath); |
|
||||||
b.bundle({ standalone: 'Nedb' }, function (err, out) { |
|
||||||
if (err) { return cb(err); } |
|
||||||
fs.writeFile(path.join(__dirname, 'out/nedb.js'), out, 'utf8', function (err) { |
|
||||||
if (err) { |
|
||||||
return cb(err); |
|
||||||
} else { |
|
||||||
return cb(null, out); |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
} |
|
||||||
, function (out, cb) { |
|
||||||
console.log("Creating the minified version"); |
|
||||||
|
|
||||||
var compressedCode = uglify.minify(out, { fromString: true }); |
|
||||||
fs.writeFile(path.join(__dirname, 'out/nedb.min.js'), compressedCode.code, 'utf8', cb); |
|
||||||
} |
|
||||||
], function (err) { |
|
||||||
if (err) { |
|
||||||
console.log("Error during build"); |
|
||||||
console.log(err); |
|
||||||
} else { |
|
||||||
console.log("Build finished with success"); |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@ |
|||||||
|
/** |
||||||
|
* Way data is stored for this database |
||||||
|
* For a Node.js/Node Webkit database it's the file system |
||||||
|
* For a browser-side database it's localforage, which uses the best backend available (IndexedDB then WebSQL then localStorage) |
||||||
|
* |
||||||
|
* This version is the browser version |
||||||
|
*/ |
||||||
|
const localforage = require('localforage') |
||||||
|
|
||||||
|
// Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name
|
||||||
|
const store = localforage.createInstance({ |
||||||
|
name: 'NeDB', |
||||||
|
storeName: 'nedbdata' |
||||||
|
}) |
||||||
|
|
||||||
|
function exists (filename, cback) { |
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
store.getItem(filename, (err, value) => { |
||||||
|
if (value !== null) return cback(true) // Even if value is undefined, localforage returns null
|
||||||
|
else return cback(false) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function rename (filename, newFilename, callback) { |
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
store.getItem(filename, (err, value) => { |
||||||
|
if (value === null) store.removeItem(newFilename, () => callback()) |
||||||
|
else { |
||||||
|
store.setItem(newFilename, value, () => { |
||||||
|
store.removeItem(filename, () => callback()) |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function writeFile (filename, contents, options, callback) { |
||||||
|
// Options do not matter in browser setup
|
||||||
|
if (typeof options === 'function') { callback = options } |
||||||
|
store.setItem(filename, contents, () => callback()) |
||||||
|
} |
||||||
|
|
||||||
|
function appendFile (filename, toAppend, options, callback) { |
||||||
|
// Options do not matter in browser setup
|
||||||
|
if (typeof options === 'function') { callback = options } |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
store.getItem(filename, (err, contents) => { |
||||||
|
contents = contents || '' |
||||||
|
contents += toAppend |
||||||
|
store.setItem(filename, contents, () => callback()) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
function readFile (filename, options, callback) { |
||||||
|
// Options do not matter in browser setup
|
||||||
|
if (typeof options === 'function') { callback = options } |
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
store.getItem(filename, (err, contents) => callback(null, contents || '')) |
||||||
|
} |
||||||
|
|
||||||
|
function unlink (filename, callback) { |
||||||
|
store.removeItem(filename, () => callback()) |
||||||
|
} |
||||||
|
|
||||||
|
// Nothing to do, no directories will be used on the browser
|
||||||
|
function mkdir (dir, options, callback) { |
||||||
|
return callback() |
||||||
|
} |
||||||
|
|
||||||
|
// Nothing to do, no data corruption possible in the brower
|
||||||
|
function ensureDatafileIntegrity (filename, callback) { |
||||||
|
return callback(null) |
||||||
|
} |
||||||
|
|
||||||
|
// Interface
|
||||||
|
module.exports.exists = exists |
||||||
|
module.exports.rename = rename |
||||||
|
module.exports.writeFile = writeFile |
||||||
|
module.exports.crashSafeWriteFile = writeFile // No need for a crash safe function in the browser
|
||||||
|
module.exports.appendFile = appendFile |
||||||
|
module.exports.readFile = readFile |
||||||
|
module.exports.unlink = unlink |
||||||
|
module.exports.mkdir = mkdir |
||||||
|
module.exports.ensureDatafileIntegrity = ensureDatafileIntegrity |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,8 +0,0 @@ |
|||||||
{ |
|
||||||
"dependencies": { |
|
||||||
"async": "~0.2.9", |
|
||||||
"fs-extra": "~0.6.3", |
|
||||||
"uglify-js": "~2.3.6", |
|
||||||
"browserify": "~2.25.0" |
|
||||||
} |
|
||||||
} |
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,24 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Mocha tests for NeDB</title> |
|
||||||
<link rel="stylesheet" href="mocha.css"> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div id="mocha"></div> |
|
||||||
<script src="jquery.min.js"></script> |
|
||||||
<script src="chai.js"></script> |
|
||||||
<script src="underscore.min.js"></script> |
|
||||||
<script src="mocha.js"></script> |
|
||||||
<script>mocha.setup('bdd')</script> |
|
||||||
<script src="../out/nedb.min.js"></script> |
|
||||||
<script src="localforage.js"></script> |
|
||||||
<script src="nedb-browser.js"></script> |
|
||||||
<script> |
|
||||||
mocha.checkLeaks(); |
|
||||||
mocha.globals(['jQuery']); |
|
||||||
mocha.run(); |
|
||||||
</script> |
|
||||||
</body> |
|
||||||
</html> |
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -1,199 +0,0 @@ |
|||||||
@charset "UTF-8"; |
|
||||||
body { |
|
||||||
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
||||||
padding: 60px 50px; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha ul, #mocha li { |
|
||||||
margin: 0; |
|
||||||
padding: 0; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha ul { |
|
||||||
list-style: none; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha h1, #mocha h2 { |
|
||||||
margin: 0; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha h1 { |
|
||||||
margin-top: 15px; |
|
||||||
font-size: 1em; |
|
||||||
font-weight: 200; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha h1 a { |
|
||||||
text-decoration: none; |
|
||||||
color: inherit; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha h1 a:hover { |
|
||||||
text-decoration: underline; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .suite .suite h1 { |
|
||||||
margin-top: 0; |
|
||||||
font-size: .8em; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha h2 { |
|
||||||
font-size: 12px; |
|
||||||
font-weight: normal; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .suite { |
|
||||||
margin-left: 15px; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test { |
|
||||||
margin-left: 15px; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test:hover h2::after { |
|
||||||
position: relative; |
|
||||||
top: 0; |
|
||||||
right: -10px; |
|
||||||
content: '(view source)'; |
|
||||||
font-size: 12px; |
|
||||||
font-family: arial; |
|
||||||
color: #888; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pending:hover h2::after { |
|
||||||
content: '(pending)'; |
|
||||||
font-family: arial; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pass.medium .duration { |
|
||||||
background: #C09853; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pass.slow .duration { |
|
||||||
background: #B94A48; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pass::before { |
|
||||||
content: '✓'; |
|
||||||
font-size: 12px; |
|
||||||
display: block; |
|
||||||
float: left; |
|
||||||
margin-right: 5px; |
|
||||||
color: #00d6b2; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pass .duration { |
|
||||||
font-size: 9px; |
|
||||||
margin-left: 5px; |
|
||||||
padding: 2px 5px; |
|
||||||
color: white; |
|
||||||
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|
||||||
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|
||||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.2); |
|
||||||
-webkit-border-radius: 5px; |
|
||||||
-moz-border-radius: 5px; |
|
||||||
-ms-border-radius: 5px; |
|
||||||
-o-border-radius: 5px; |
|
||||||
border-radius: 5px; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pass.fast .duration { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pending { |
|
||||||
color: #0b97c4; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.pending::before { |
|
||||||
content: '◦'; |
|
||||||
color: #0b97c4; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.fail { |
|
||||||
color: #c00; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.fail pre { |
|
||||||
color: black; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test.fail::before { |
|
||||||
content: '✖'; |
|
||||||
font-size: 12px; |
|
||||||
display: block; |
|
||||||
float: left; |
|
||||||
margin-right: 5px; |
|
||||||
color: #c00; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test pre.error { |
|
||||||
color: #c00; |
|
||||||
} |
|
||||||
|
|
||||||
#mocha .test pre { |
|
||||||
display: inline-block; |
|
||||||
font: 12px/1.5 monaco, monospace; |
|
||||||
margin: 5px; |
|
||||||
padding: 15px; |
|
||||||
border: 1px solid #eee; |
|
||||||
border-bottom-color: #ddd; |
|
||||||
-webkit-border-radius: 3px; |
|
||||||
-webkit-box-shadow: 0 1px 3px #eee; |
|
||||||
} |
|
||||||
|
|
||||||
#report.pass .test.fail { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
|
|
||||||
#report.fail .test.pass { |
|
||||||
display: none; |
|
||||||
} |
|
||||||
|
|
||||||
#error { |
|
||||||
color: #c00; |
|
||||||
font-size: 1.5 em; |
|
||||||
font-weight: 100; |
|
||||||
letter-spacing: 1px; |
|
||||||
} |
|
||||||
|
|
||||||
#stats { |
|
||||||
position: fixed; |
|
||||||
top: 15px; |
|
||||||
right: 10px; |
|
||||||
font-size: 12px; |
|
||||||
margin: 0; |
|
||||||
color: #888; |
|
||||||
} |
|
||||||
|
|
||||||
#stats .progress { |
|
||||||
float: right; |
|
||||||
padding-top: 0; |
|
||||||
} |
|
||||||
|
|
||||||
#stats em { |
|
||||||
color: black; |
|
||||||
} |
|
||||||
|
|
||||||
#stats a { |
|
||||||
text-decoration: none; |
|
||||||
color: inherit; |
|
||||||
} |
|
||||||
|
|
||||||
#stats a:hover { |
|
||||||
border-bottom: 1px solid #eee; |
|
||||||
} |
|
||||||
|
|
||||||
#stats li { |
|
||||||
display: inline-block; |
|
||||||
margin: 0 5px; |
|
||||||
list-style: none; |
|
||||||
padding-top: 11px; |
|
||||||
} |
|
||||||
|
|
||||||
code .comment { color: #ddd } |
|
||||||
code .init { color: #2F6FAD } |
|
||||||
code .string { color: #5890AD } |
|
||||||
code .keyword { color: #8A6343 } |
|
||||||
code .number { color: #2F6FAD } |
|
File diff suppressed because it is too large
Load Diff
@ -1,309 +0,0 @@ |
|||||||
/** |
|
||||||
* Testing the browser version of NeDB |
|
||||||
* The goal of these tests is not to be exhaustive, we have the server-side NeDB tests for that |
|
||||||
* This is more of a sanity check which executes most of the code at least once and checks |
|
||||||
* it behaves as the server version does |
|
||||||
*/ |
|
||||||
|
|
||||||
var assert = chai.assert; |
|
||||||
|
|
||||||
/** |
|
||||||
* Given a docs array and an id, return the document whose id matches, or null if none is found |
|
||||||
*/ |
|
||||||
function findById (docs, id) { |
|
||||||
return _.find(docs, function (doc) { return doc._id === id; }) || null; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
describe('Basic CRUD functionality', function () { |
|
||||||
|
|
||||||
it('Able to create a database object in the browser', function () { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
assert.equal(db.inMemoryOnly, true); |
|
||||||
assert.equal(db.persistence.inMemoryOnly, true); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Insertion and querying', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ a: 4 }, function (err, newDoc1) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ a: 40 }, function (err, newDoc2) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ a: 400 }, function (err, newDoc3) { |
|
||||||
assert.isNull(err); |
|
||||||
|
|
||||||
db.find({ a: { $gt: 36 } }, function (err, docs) { |
|
||||||
var doc2 = _.find(docs, function (doc) { return doc._id === newDoc2._id; }) |
|
||||||
, doc3 = _.find(docs, function (doc) { return doc._id === newDoc3._id; }) |
|
||||||
; |
|
||||||
|
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(doc2.a, 40); |
|
||||||
assert.equal(doc3.a, 400); |
|
||||||
|
|
||||||
db.find({ a: { $lt: 36 } }, function (err, docs) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(docs.length, 1); |
|
||||||
assert.equal(docs[0].a, 4); |
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Querying with regular expressions', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ planet: 'Earth' }, function (err, newDoc1) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ planet: 'Mars' }, function (err, newDoc2) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ planet: 'Jupiter' }, function (err, newDoc3) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ planet: 'Eaaaaaarth' }, function (err, newDoc4) { |
|
||||||
assert.isNull(err); |
|
||||||
db.insert({ planet: 'Maaaars' }, function (err, newDoc5) { |
|
||||||
assert.isNull(err); |
|
||||||
|
|
||||||
db.find({ planet: /ar/ }, function (err, docs) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(docs.length, 4); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc1._id; }).planet, 'Earth'); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc2._id; }).planet, 'Mars'); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id; }).planet, 'Eaaaaaarth'); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id; }).planet, 'Maaaars'); |
|
||||||
|
|
||||||
db.find({ planet: /aa+r/ }, function (err, docs) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id; }).planet, 'Eaaaaaarth'); |
|
||||||
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id; }).planet, 'Maaaars'); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Updating documents', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ planet: 'Eaaaaarth' }, function (err, newDoc1) { |
|
||||||
db.insert({ planet: 'Maaaaars' }, function (err, newDoc2) { |
|
||||||
// Simple update
|
|
||||||
db.update({ _id: newDoc2._id }, { $set: { planet: 'Saturn' } }, {}, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth'); |
|
||||||
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn'); |
|
||||||
|
|
||||||
// Failing update
|
|
||||||
db.update({ _id: 'unknown' }, { $inc: { count: 1 } }, {}, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 0); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth'); |
|
||||||
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn'); |
|
||||||
|
|
||||||
// Document replacement
|
|
||||||
db.update({ planet: 'Eaaaaarth' }, { planet: 'Uranus' }, { multi: false }, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(findById(docs, newDoc1._id).planet, 'Uranus'); |
|
||||||
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn'); |
|
||||||
|
|
||||||
// Multi update
|
|
||||||
db.update({}, { $inc: { count: 3 } }, { multi: true }, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 2); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 2); |
|
||||||
assert.equal(findById(docs, newDoc1._id).planet, 'Uranus'); |
|
||||||
assert.equal(findById(docs, newDoc1._id).count, 3); |
|
||||||
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn'); |
|
||||||
assert.equal(findById(docs, newDoc2._id).count, 3); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Updating documents: special modifiers', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ planet: 'Earth' }, function (err, newDoc1) { |
|
||||||
// Pushing to an array
|
|
||||||
db.update({}, { $push: { satellites: 'Phobos' } }, {}, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.findOne({}, function (err, doc) { |
|
||||||
assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos'] }); |
|
||||||
|
|
||||||
db.update({}, { $push: { satellites: 'Deimos' } }, {}, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.findOne({}, function (err, doc) { |
|
||||||
assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos', 'Deimos'] }); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Upserts', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.update({ a: 4 }, { $inc: { b: 1 } }, { upsert: true }, function (err, nr, upsert) { |
|
||||||
assert.isNull(err); |
|
||||||
// Return upserted document
|
|
||||||
assert.equal(upsert.a, 4); |
|
||||||
assert.equal(upsert.b, 1); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 1); |
|
||||||
assert.equal(docs[0].a, 4); |
|
||||||
assert.equal(docs[0].b, 1); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Removing documents', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ a: 2 }); |
|
||||||
db.insert({ a: 5 }); |
|
||||||
db.insert({ a: 7 }); |
|
||||||
|
|
||||||
// Multi remove
|
|
||||||
db.remove({ a: { $in: [ 5, 7 ] } }, { multi: true }, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 2); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 1); |
|
||||||
assert.equal(docs[0].a, 2); |
|
||||||
|
|
||||||
// Remove with no match
|
|
||||||
db.remove({ b: { $exists: true } }, { multi: true }, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 0); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 1); |
|
||||||
assert.equal(docs[0].a, 2); |
|
||||||
|
|
||||||
// Simple remove
|
|
||||||
db.remove({ a: { $exists: true } }, { multi: true }, function (err, nr) { |
|
||||||
assert.isNull(err); |
|
||||||
assert.equal(nr, 1); |
|
||||||
|
|
||||||
db.find({}, function (err, docs) { |
|
||||||
assert.equal(docs.length, 0); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
}); // ==== End of 'Basic CRUD functionality' ==== //
|
|
||||||
|
|
||||||
|
|
||||||
describe('Indexing', function () { |
|
||||||
|
|
||||||
it('getCandidates works as expected', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.insert({ a: 4 }, function () { |
|
||||||
db.insert({ a: 6 }, function () { |
|
||||||
db.insert({ a: 7 }, function () { |
|
||||||
db.getCandidates({ a: 6 }, function (err, candidates) { |
|
||||||
console.log(candidates); |
|
||||||
assert.equal(candidates.length, 3); |
|
||||||
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 4; })); |
|
||||||
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6; })); |
|
||||||
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 7; })); |
|
||||||
|
|
||||||
db.ensureIndex({ fieldName: 'a' }); |
|
||||||
|
|
||||||
db.getCandidates({ a: 6 }, function (err, candidates) { |
|
||||||
assert.equal(candidates.length, 1); |
|
||||||
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6; })); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
it('Can use indexes to enforce a unique constraint', function (done) { |
|
||||||
var db = new Nedb(); |
|
||||||
|
|
||||||
db.ensureIndex({ fieldName: 'u', unique: true }); |
|
||||||
|
|
||||||
db.insert({ u : 5 }, function (err) { |
|
||||||
assert.isNull(err); |
|
||||||
|
|
||||||
db.insert({ u : 98 }, function (err) { |
|
||||||
assert.isNull(err); |
|
||||||
|
|
||||||
db.insert({ u : 5 }, function (err) { |
|
||||||
assert.equal(err.errorType, 'uniqueViolated'); |
|
||||||
|
|
||||||
done(); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
}); // ==== End of 'Indexing' ==== //
|
|
||||||
|
|
||||||
|
|
||||||
describe("Don't forget to launch persistence tests!", function () { |
|
||||||
|
|
||||||
it("See file testPersistence.html", function (done) { |
|
||||||
done(); |
|
||||||
}); |
|
||||||
|
|
||||||
}); // ===== End of 'persistent in-browser database' =====
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Playground for NeDB</title> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<script src="../out/nedb.min.js"></script> |
|
||||||
</body> |
|
||||||
</html> |
|
||||||
|
|
@ -1,16 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Test NeDB persistence load in the browser</title> |
|
||||||
<link rel="stylesheet" href="mocha.css"> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div id="results"></div> |
|
||||||
<script src="./localforage.js"></script> |
|
||||||
<script src="./async.js"></script> |
|
||||||
<script src="../out/nedb.js"></script> |
|
||||||
<script src="./testLoad.js"></script> |
|
||||||
</body> |
|
||||||
</html> |
|
||||||
|
|
@ -1,111 +0,0 @@ |
|||||||
console.log('BEGINNING'); |
|
||||||
|
|
||||||
var N = 50000 |
|
||||||
, db = new Nedb({ filename: 'loadTest', autoload: true }) |
|
||||||
, t, i |
|
||||||
, sample = JSON.stringify({ data: Math.random(), _id: Math.random() }); |
|
||||||
; |
|
||||||
|
|
||||||
// Some inserts in sequence, using the default storage mechanism (IndexedDB in my case)
|
|
||||||
function someInserts (sn, N, callback) { |
|
||||||
var i = 0, beg = Date.now(); |
|
||||||
async.whilst( function () { return i < N; } |
|
||||||
, function (_cb) { |
|
||||||
db.insert({ data: Math.random() }, function (err) { i += 1; return _cb(err); }); |
|
||||||
} |
|
||||||
, function (err) { |
|
||||||
console.log("Inserts, series " + sn + " " + (Date.now() - beg)); |
|
||||||
return callback(err); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
// Manually updating the localStorage on the same variable
|
|
||||||
function someLS (sn, N, callback) { |
|
||||||
var i = 0, beg = Date.now(); |
|
||||||
for (i = 0; i < N; i += 1) { |
|
||||||
localStorage.setItem('loadTestLS', getItem('loadTestLS') + sample); |
|
||||||
} |
|
||||||
console.log("localStorage, series " + sn + " " + (Date.now() - beg)); |
|
||||||
return callback(); |
|
||||||
} |
|
||||||
|
|
||||||
// Manually updating the localStorage on different variables
|
|
||||||
function someLSDiff (sn, N, callback) { |
|
||||||
var i = 0, beg = Date.now(); |
|
||||||
for (i = 0; i < N; i += 1) { |
|
||||||
localStorage.setItem('loadTestLS-' + i, sample); |
|
||||||
} |
|
||||||
console.log("localStorage, series " + sn + " " + (Date.now() - beg)); |
|
||||||
return callback(); |
|
||||||
} |
|
||||||
|
|
||||||
// Manually updating the localforage default on the same variable (IndexedDB on my machine)
|
|
||||||
function someLF (sn, N, callback) { |
|
||||||
var i = 0, beg = Date.now(); |
|
||||||
async.whilst( function () { return i < N; } |
|
||||||
, function (_cb) { |
|
||||||
localforage.getItem('loadTestLF', function (err, value) { |
|
||||||
if (err) { return _cb(err); } |
|
||||||
localforage.setItem('loadTestLF', value + sample, function (err) { i += 1; return _cb(err); }); |
|
||||||
}); |
|
||||||
} |
|
||||||
, function (err) { |
|
||||||
console.log("localForage/IDB, series " + sn + " " + (Date.now() - beg)); |
|
||||||
return callback(err); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
// Manually updating the localforage default on the different variables (IndexedDB on my machine)
|
|
||||||
function someLFDiff (sn, N, callback) { |
|
||||||
var i = 0, beg = Date.now(); |
|
||||||
async.whilst( function () { return i < N; } |
|
||||||
, function (_cb) { |
|
||||||
localforage.setItem('loadTestLF-' + i, sample, function (err) { i += 1; return _cb(err); }); |
|
||||||
} |
|
||||||
, function (err) { |
|
||||||
console.log("localForage/IDB, series " + sn + " " + (Date.now() - beg)); |
|
||||||
return callback(err); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
localStorage.setItem('loadTestLS', ''); |
|
||||||
async.waterfall([ |
|
||||||
function (cb) { db.remove({}, { multi: true }, function (err) { return cb(err); }); } |
|
||||||
|
|
||||||
// Slow and gets slower with database size
|
|
||||||
//, async.apply(someInserts, "#1", N) // N=5000, 141s
|
|
||||||
//, async.apply(someInserts, "#2", N) // N=5000, 208s
|
|
||||||
//, async.apply(someInserts, "#3", N) // N=5000, 281s
|
|
||||||
//, async.apply(someInserts, "#4", N) // N=5000, 350s
|
|
||||||
|
|
||||||
// Slow and gets slower really fast with database size, then outright crashes
|
|
||||||
//, async.apply(someLS, "#1", N) // N=4000, 2.5s
|
|
||||||
//, async.apply(someLS, "#2", N) // N=4000, 8.0s
|
|
||||||
//, async.apply(someLS, "#3", N) // N=4000, 26.5s
|
|
||||||
//, async.apply(someLS, "#4", N) // N=4000, 47.8s then crash, can't get string (with N=5000 crash happens on second pass)
|
|
||||||
|
|
||||||
// Much faster and more consistent
|
|
||||||
//, async.apply(someLSDiff, "#1", N) // N=50000, 0.7s
|
|
||||||
//, async.apply(someLSDiff, "#2", N) // N=50000, 0.5s
|
|
||||||
//, async.apply(someLSDiff, "#3", N) // N=50000, 0.5s
|
|
||||||
//, async.apply(someLSDiff, "#4", N) // N=50000, 0.5s
|
|
||||||
|
|
||||||
// Slow and gets slower with database size
|
|
||||||
//, function (cb) { localforage.setItem('loadTestLF', '', function (err) { return cb(err) }) }
|
|
||||||
//, async.apply(someLF, "#1", N) // N=5000, 69s
|
|
||||||
//, async.apply(someLF, "#2", N) // N=5000, 108s
|
|
||||||
//, async.apply(someLF, "#3", N) // N=5000, 137s
|
|
||||||
//, async.apply(someLF, "#4", N) // N=5000, 169s
|
|
||||||
|
|
||||||
// Quite fast and speed doesn't change with database size (tested with N=10000 and N=50000, still no slow-down)
|
|
||||||
//, async.apply(someLFDiff, "#1", N) // N=5000, 18s
|
|
||||||
//, async.apply(someLFDiff, "#2", N) // N=5000, 18s
|
|
||||||
//, async.apply(someLFDiff, "#3", N) // N=5000, 18s
|
|
||||||
//, async.apply(someLFDiff, "#4", N) // N=5000, 18s
|
|
||||||
]); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,13 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Test NeDB persistence in the browser</title> |
|
||||||
<link rel="stylesheet" href="mocha.css"> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div id="results"></div> |
|
||||||
<script src="../out/nedb.js"></script> |
|
||||||
<script src="./testPersistence.js"></script> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,20 +0,0 @@ |
|||||||
console.log("Beginning tests"); |
|
||||||
console.log("Please note these tests work on Chrome latest, might not work on other browsers due to discrepancies in how local storage works for the file:// protocol"); |
|
||||||
|
|
||||||
function testsFailed () { |
|
||||||
document.getElementById("results").innerHTML = "TESTS FAILED"; |
|
||||||
} |
|
||||||
|
|
||||||
var filename = 'test'; |
|
||||||
|
|
||||||
var db = new Nedb({ filename: filename, autoload: true }); |
|
||||||
db.remove({}, { multi: true }, function () { |
|
||||||
db.insert({ hello: 'world' }, function (err) { |
|
||||||
if (err) { |
|
||||||
testsFailed(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
window.location = './testPersistence2.html'; |
|
||||||
}); |
|
||||||
}); |
|
@ -1,14 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Test NeDB persistence in the browser - Results</title> |
|
||||||
<link rel="stylesheet" href="mocha.css"> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<div id="results"></div> |
|
||||||
<script src="jquery.min.js"></script> |
|
||||||
<script src="../out/nedb.js"></script> |
|
||||||
<script src="./testPersistence2.js"></script> |
|
||||||
</body> |
|
||||||
</html> |
|
@ -1,39 +0,0 @@ |
|||||||
// Capture F5 to reload the base page testPersistence.html not this one
|
|
||||||
$(document).on('keydown', function (e) { |
|
||||||
if (e.keyCode === 116) { |
|
||||||
e.preventDefault(); |
|
||||||
window.location = 'testPersistence.html'; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
console.log("Checking tests results"); |
|
||||||
console.log("Please note these tests work on Chrome latest, might not work on other browsers due to discrepancies in how local storage works for the file:// protocol"); |
|
||||||
|
|
||||||
function testsFailed () { |
|
||||||
document.getElementById("results").innerHTML = "TESTS FAILED"; |
|
||||||
} |
|
||||||
|
|
||||||
var filename = 'test'; |
|
||||||
|
|
||||||
var db = new Nedb({ filename: filename, autoload: true }); |
|
||||||
db.find({}, function (err, docs) { |
|
||||||
if (docs.length !== 1) { |
|
||||||
console.log(docs); |
|
||||||
console.log("Unexpected length of document database"); |
|
||||||
return testsFailed(); |
|
||||||
} |
|
||||||
|
|
||||||
if (Object.keys(docs[0]).length !== 2) { |
|
||||||
console.log("Unexpected length insert document in database"); |
|
||||||
return testsFailed(); |
|
||||||
} |
|
||||||
|
|
||||||
if (docs[0].hello !== 'world') { |
|
||||||
console.log("Unexpected document"); |
|
||||||
return testsFailed(); |
|
||||||
} |
|
||||||
|
|
||||||
document.getElementById("results").innerHTML = "BROWSER PERSISTENCE TEST PASSED"; |
|
||||||
}); |
|
||||||
|
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@ |
|||||||
|
'use strict' |
||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */ |
||||||
|
|
||||||
|
const template = require('./karma.conf.template.js') |
||||||
|
|
||||||
|
module.exports = function (config) { |
||||||
|
const localBrowser = { |
||||||
|
ChromeHeadlessNoSandbox: { |
||||||
|
base: 'ChromeHeadless', |
||||||
|
flags: ['--no-sandbox'] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
config.set(Object.assign({}, template(config), { |
||||||
|
customLaunchers: localBrowser, |
||||||
|
browsers: ['ChromeHeadlessNoSandbox'] |
||||||
|
// browsers: ['FirefoxHeadless'],
|
||||||
|
// browsers: ['Safari'],
|
||||||
|
// browsers: ['ChromeHeadlessNoSandbox', 'FirefoxHeadless', 'Safari'],
|
||||||
|
|
||||||
|
// concurrency: 3
|
||||||
|
})) |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
'use strict' |
||||||
|
|
||||||
|
const path = require('path') |
||||||
|
|
||||||
|
module.exports = (config) => ({ |
||||||
|
// Increase timeout in case connection in CI is slow
|
||||||
|
captureTimeout: 120000, |
||||||
|
browserNoActivityTimeout: 300000, |
||||||
|
browserDisconnectTimeout: 300000, |
||||||
|
browserDisconnectTolerance: 3, |
||||||
|
|
||||||
|
// frameworks to use
|
||||||
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
|
frameworks: ['mocha', 'chai', 'source-map-support'], |
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files: [ |
||||||
|
'node_modules/underscore/underscore-min.js', |
||||||
|
'node_modules/localforage/dist/localforage.min.js', |
||||||
|
'node_modules/async/lib/async.js', |
||||||
|
'browser-version/out/nedb.min.js', |
||||||
|
'test/browser/nedb-browser.spec.js', |
||||||
|
'test/browser/load.spec.js' |
||||||
|
], |
||||||
|
|
||||||
|
// test results reporter to use
|
||||||
|
// possible values: 'dots', 'progress'
|
||||||
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
reporters: ['progress', 'junit'], |
||||||
|
|
||||||
|
junitReporter: { |
||||||
|
outputDir: 'test-results', // results will be saved as $outputDir/$browserName.xml
|
||||||
|
useBrowserName: true // add browser name to report and classes names
|
||||||
|
}, |
||||||
|
|
||||||
|
// Continuous Integration mode
|
||||||
|
// if true, Karma captures browsers, runs the tests and exits
|
||||||
|
singleRun: true, |
||||||
|
|
||||||
|
// web server port
|
||||||
|
port: 9876, |
||||||
|
|
||||||
|
// enable / disable colors in the output (reporters and logs)
|
||||||
|
colors: true, |
||||||
|
|
||||||
|
// level of logging
|
||||||
|
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||||
|
logLevel: config.LOG_INFO, |
||||||
|
|
||||||
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
autoWatch: false, |
||||||
|
|
||||||
|
// Concurrency level
|
||||||
|
// how many browser should be started simultaneous
|
||||||
|
concurrency: 1, |
||||||
|
|
||||||
|
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||||
|
basePath: '', |
||||||
|
|
||||||
|
// list of files to exclude
|
||||||
|
exclude: [] |
||||||
|
}) |
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"reporterEnabled": "mocha-junit-reporter, spec", |
||||||
|
"mochaJunitReporterReporterOptions": { |
||||||
|
"mochaFile": "test-results/report.xml" |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,125 @@ |
|||||||
|
/* eslint-env mocha, browser */ |
||||||
|
/* global async, Nedb, localforage */ |
||||||
|
|
||||||
|
const N = 5000 |
||||||
|
const db = new Nedb({ filename: 'loadTest', autoload: true }) |
||||||
|
const sample = JSON.stringify({ data: Math.random(), _id: Math.random() }) |
||||||
|
|
||||||
|
// Some inserts in sequence, using the default storage mechanism (IndexedDB in my case)
|
||||||
|
const someInserts = (sn, N, callback) => { |
||||||
|
const beg = Date.now() |
||||||
|
let i = 0 |
||||||
|
async.whilst(() => i < N, _cb => { |
||||||
|
db.insert({ data: Math.random() }, err => { i += 1; return _cb(err) }) |
||||||
|
}, err => { |
||||||
|
console.log('Inserts, series ' + sn + ' ' + (Date.now() - beg)) |
||||||
|
return callback(err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Manually updating the localStorage on the same variable
|
||||||
|
const someLS = (sn, N, callback) => { |
||||||
|
const beg = Date.now() |
||||||
|
for (let i = 0; i < N; i += 1) { |
||||||
|
localStorage.setItem('loadTestLS', localStorage.getItem('loadTestLS') + sample) |
||||||
|
} |
||||||
|
console.log('localStorage, series ' + sn + ' ' + (Date.now() - beg)) |
||||||
|
return callback() |
||||||
|
} |
||||||
|
|
||||||
|
// Manually updating the localStorage on different variables
|
||||||
|
const someLSDiff = (sn, N, callback) => { |
||||||
|
const beg = Date.now() |
||||||
|
for (let i = 0; i < N; i += 1) { |
||||||
|
localStorage.setItem('loadTestLS-' + i, sample) |
||||||
|
} |
||||||
|
console.log('localStorage, series ' + sn + ' ' + (Date.now() - beg)) |
||||||
|
return callback() |
||||||
|
} |
||||||
|
|
||||||
|
// Manually updating the localforage default on the same variable (IndexedDB on my machine)
|
||||||
|
function someLF (sn, N, callback) { |
||||||
|
const beg = Date.now() |
||||||
|
let i = 0 |
||||||
|
async.whilst(() => i < N, _cb => { |
||||||
|
localforage.getItem('loadTestLF', (err, value) => { |
||||||
|
if (err) return _cb(err) |
||||||
|
localforage.setItem('loadTestLF', value + sample, err => { i += 1; return _cb(err) }) |
||||||
|
}) |
||||||
|
}, err => { |
||||||
|
console.log('localForage/IDB, series ' + sn + ' ' + (Date.now() - beg)) |
||||||
|
return callback(err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Manually updating the localforage default on the different variables (IndexedDB on my machine)
|
||||||
|
const someLFDiff = (sn, N, callback) => { |
||||||
|
const beg = Date.now() |
||||||
|
let i = 0 |
||||||
|
async.whilst(() => i < N, _cb => { |
||||||
|
localforage.setItem('loadTestLF-' + i, sample, err => { i += 1; return _cb(err) }) |
||||||
|
}, err => { |
||||||
|
console.log('localForage/IDB, series ' + sn + ' ' + (Date.now() - beg)) |
||||||
|
return callback(err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// These tests benchmark various key/value storage methods, we skip them by default
|
||||||
|
describe.skip('Load tests', function () { |
||||||
|
this.timeout(60000) |
||||||
|
before('Cleanup', function (done) { |
||||||
|
localStorage.setItem('loadTestLS', '') |
||||||
|
db.remove({}, { multi: true }, err => done(err)) |
||||||
|
}) |
||||||
|
|
||||||
|
it.skip('Inserts', function (done) { |
||||||
|
async.waterfall([ |
||||||
|
// Slow and gets slower with database size
|
||||||
|
async.apply(someInserts, '#1', N), // N=5000, 141s
|
||||||
|
async.apply(someInserts, '#2', N), // N=5000, 208s
|
||||||
|
async.apply(someInserts, '#3', N), // N=5000, 281s
|
||||||
|
async.apply(someInserts, '#4', N) // N=5000, 350s
|
||||||
|
], done) |
||||||
|
}) |
||||||
|
|
||||||
|
it.skip('Localstorage', function (done) { |
||||||
|
async.waterfall([ |
||||||
|
// Slow and gets slower really fast with database size, then outright crashes
|
||||||
|
async.apply(someLS, '#1', N), // N=4000, 2.5s
|
||||||
|
async.apply(someLS, '#2', N), // N=4000, 8.0s
|
||||||
|
async.apply(someLS, '#3', N), // N=4000, 26.5s
|
||||||
|
async.apply(someLS, '#4', N) // N=4000, 47.8s then crash, can't get string (with N=5000 crash happens on second pass)
|
||||||
|
], done) |
||||||
|
}) |
||||||
|
|
||||||
|
it.skip('Localstorage Diff', function (done) { |
||||||
|
async.waterfall([ |
||||||
|
// Much faster and more consistent
|
||||||
|
async.apply(someLSDiff, '#1', N), // N=50000, 0.7s
|
||||||
|
async.apply(someLSDiff, '#2', N), // N=50000, 0.5s
|
||||||
|
async.apply(someLSDiff, '#3', N), // N=50000, 0.5s
|
||||||
|
async.apply(someLSDiff, '#4', N) // N=50000, 0.5s
|
||||||
|
], done) |
||||||
|
}) |
||||||
|
|
||||||
|
it.skip('LocalForage', function (done) { |
||||||
|
async.waterfall([ |
||||||
|
// Slow and gets slower with database size
|
||||||
|
cb => { localforage.setItem('loadTestLF', '', err => cb(err)) }, |
||||||
|
async.apply(someLF, '#1', N), // N=5000, 69s
|
||||||
|
async.apply(someLF, '#2', N), // N=5000, 108s
|
||||||
|
async.apply(someLF, '#3', N), // N=5000, 137s
|
||||||
|
async.apply(someLF, '#4', N) // N=5000, 169s
|
||||||
|
], done) |
||||||
|
}) |
||||||
|
|
||||||
|
it.skip('LocalForage diff', function (done) { |
||||||
|
async.waterfall([ |
||||||
|
// Quite fast and speed doesn't change with database size (tested with N=10000 and N=50000, still no slow-down)
|
||||||
|
async.apply(someLFDiff, '#1', N), // N=5000, 18s
|
||||||
|
async.apply(someLFDiff, '#2', N), // N=5000, 18s
|
||||||
|
async.apply(someLFDiff, '#3', N), // N=5000, 18s
|
||||||
|
async.apply(someLFDiff, '#4', N) // N=5000, 18s
|
||||||
|
], done) |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,342 @@ |
|||||||
|
/* eslint-env mocha */ |
||||||
|
/* global chai, _, Nedb */ |
||||||
|
|
||||||
|
/** |
||||||
|
* Testing the browser version of NeDB |
||||||
|
* The goal of these tests is not to be exhaustive, we have the server-side NeDB tests for that |
||||||
|
* This is more of a sanity check which executes most of the code at least once and checks |
||||||
|
* it behaves as the server version does |
||||||
|
*/ |
||||||
|
|
||||||
|
const assert = chai.assert |
||||||
|
|
||||||
|
/** |
||||||
|
* Given a docs array and an id, return the document whose id matches, or null if none is found |
||||||
|
*/ |
||||||
|
function findById (docs, id) { |
||||||
|
return _.find(docs, function (doc) { return doc._id === id }) || null |
||||||
|
} |
||||||
|
|
||||||
|
describe('Basic CRUD functionality', function () { |
||||||
|
it('Able to create a database object in the browser', function () { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
assert.equal(db.inMemoryOnly, true) |
||||||
|
assert.equal(db.persistence.inMemoryOnly, true) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Insertion and querying', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.insert({ a: 4 }, function (err, newDoc1) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ a: 40 }, function (err, newDoc2) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ a: 400 }, function (err, newDoc3) { |
||||||
|
assert.isNull(err) |
||||||
|
|
||||||
|
db.find({ a: { $gt: 36 } }, function (err, docs) { |
||||||
|
const doc2 = _.find(docs, function (doc) { return doc._id === newDoc2._id }) |
||||||
|
const doc3 = _.find(docs, function (doc) { return doc._id === newDoc3._id }) |
||||||
|
|
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(doc2.a, 40) |
||||||
|
assert.equal(doc3.a, 400) |
||||||
|
|
||||||
|
db.find({ a: { $lt: 36 } }, function (err, docs) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(docs.length, 1) |
||||||
|
assert.equal(docs[0].a, 4) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Querying with regular expressions', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.insert({ planet: 'Earth' }, function (err, newDoc1) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ planet: 'Mars' }, function (err, newDoc2) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ planet: 'Jupiter' }, function (err, newDoc3) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ planet: 'Eaaaaaarth' }, function (err, newDoc4) { |
||||||
|
assert.isNull(err) |
||||||
|
db.insert({ planet: 'Maaaars' }, function (err, newDoc5) { |
||||||
|
assert.isNull(err) |
||||||
|
|
||||||
|
db.find({ planet: /ar/ }, function (err, docs) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(docs.length, 4) |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc1._id }).planet, 'Earth') |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc2._id }).planet, 'Mars') |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id }).planet, 'Eaaaaaarth') |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id }).planet, 'Maaaars') |
||||||
|
|
||||||
|
db.find({ planet: /aa+r/ }, function (err, docs) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc4._id }).planet, 'Eaaaaaarth') |
||||||
|
assert.equal(_.find(docs, function (doc) { return doc._id === newDoc5._id }).planet, 'Maaaars') |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Updating documents', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.insert({ planet: 'Eaaaaarth' }, function (err, newDoc1) { |
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.insert({ planet: 'Maaaaars' }, function (err, newDoc2) { |
||||||
|
// Simple update
|
||||||
|
db.update({ _id: newDoc2._id }, { $set: { planet: 'Saturn' } }, {}, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth') |
||||||
|
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn') |
||||||
|
|
||||||
|
// Failing update
|
||||||
|
db.update({ _id: 'unknown' }, { $inc: { count: 1 } }, {}, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 0) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(findById(docs, newDoc1._id).planet, 'Eaaaaarth') |
||||||
|
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn') |
||||||
|
|
||||||
|
// Document replacement
|
||||||
|
db.update({ planet: 'Eaaaaarth' }, { planet: 'Uranus' }, { multi: false }, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(findById(docs, newDoc1._id).planet, 'Uranus') |
||||||
|
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn') |
||||||
|
|
||||||
|
// Multi update
|
||||||
|
db.update({}, { $inc: { count: 3 } }, { multi: true }, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 2) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 2) |
||||||
|
assert.equal(findById(docs, newDoc1._id).planet, 'Uranus') |
||||||
|
assert.equal(findById(docs, newDoc1._id).count, 3) |
||||||
|
assert.equal(findById(docs, newDoc2._id).planet, 'Saturn') |
||||||
|
assert.equal(findById(docs, newDoc2._id).count, 3) |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Updating documents: special modifiers', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.insert({ planet: 'Earth' }, function (err, newDoc1) { |
||||||
|
// Pushing to an array
|
||||||
|
db.update({}, { $push: { satellites: 'Phobos' } }, {}, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.findOne({}, function (err, doc) { |
||||||
|
assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos'] }) |
||||||
|
|
||||||
|
db.update({}, { $push: { satellites: 'Deimos' } }, {}, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.findOne({}, function (err, doc) { |
||||||
|
assert.deepEqual(doc, { planet: 'Earth', _id: newDoc1._id, satellites: ['Phobos', 'Deimos'] }) |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Upserts', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.update({ a: 4 }, { $inc: { b: 1 } }, { upsert: true }, function (err, nr, upsert) { |
||||||
|
assert.isNull(err) |
||||||
|
// Return upserted document
|
||||||
|
assert.equal(upsert.a, 4) |
||||||
|
assert.equal(upsert.b, 1) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 1) |
||||||
|
assert.equal(docs[0].a, 4) |
||||||
|
assert.equal(docs[0].b, 1) |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Removing documents', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.insert({ a: 2 }) |
||||||
|
db.insert({ a: 5 }) |
||||||
|
db.insert({ a: 7 }) |
||||||
|
|
||||||
|
// Multi remove
|
||||||
|
db.remove({ a: { $in: [5, 7] } }, { multi: true }, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 2) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 1) |
||||||
|
assert.equal(docs[0].a, 2) |
||||||
|
|
||||||
|
// Remove with no match
|
||||||
|
db.remove({ b: { $exists: true } }, { multi: true }, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 0) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 1) |
||||||
|
assert.equal(docs[0].a, 2) |
||||||
|
|
||||||
|
// Simple remove
|
||||||
|
db.remove({ a: { $exists: true } }, { multi: true }, function (err, nr) { |
||||||
|
assert.isNull(err) |
||||||
|
assert.equal(nr, 1) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.find({}, function (err, docs) { |
||||||
|
assert.equal(docs.length, 0) |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) // ==== End of 'Basic CRUD functionality' ==== //
|
||||||
|
|
||||||
|
describe('Indexing', function () { |
||||||
|
it('getCandidates works as expected', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.insert({ a: 4 }, function () { |
||||||
|
db.insert({ a: 6 }, function () { |
||||||
|
db.insert({ a: 7 }, function () { |
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.getCandidates({ a: 6 }, function (err, candidates) { |
||||||
|
assert.equal(candidates.length, 3) |
||||||
|
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 4 })) |
||||||
|
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6 })) |
||||||
|
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 7 })) |
||||||
|
|
||||||
|
db.ensureIndex({ fieldName: 'a' }) |
||||||
|
|
||||||
|
// eslint-disable-next-line node/handle-callback-err
|
||||||
|
db.getCandidates({ a: 6 }, function (err, candidates) { |
||||||
|
assert.equal(candidates.length, 1) |
||||||
|
assert.isDefined(_.find(candidates, function (doc) { return doc.a === 6 })) |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Can use indexes to enforce a unique constraint', function (done) { |
||||||
|
const db = new Nedb() |
||||||
|
|
||||||
|
db.ensureIndex({ fieldName: 'u', unique: true }) |
||||||
|
|
||||||
|
db.insert({ u: 5 }, function (err) { |
||||||
|
assert.isNull(err) |
||||||
|
|
||||||
|
db.insert({ u: 98 }, function (err) { |
||||||
|
assert.isNull(err) |
||||||
|
|
||||||
|
db.insert({ u: 5 }, function (err) { |
||||||
|
assert.equal(err.errorType, 'uniqueViolated') |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) // ==== End of 'Indexing' ==== //
|
||||||
|
|
||||||
|
describe("Don't forget to launch persistence tests!", function () { |
||||||
|
const filename = 'test' |
||||||
|
|
||||||
|
before('Clean & write', function (done) { |
||||||
|
const db = new Nedb({ filename: filename, autoload: true }) |
||||||
|
db.remove({}, { multi: true }, function () { |
||||||
|
db.insert({ hello: 'world' }, function (err) { |
||||||
|
assert.isNull(err) |
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
it('Read & check', function (done) { |
||||||
|
const db = new Nedb({ filename: filename, autoload: true }) |
||||||
|
db.find({}, (err, docs) => { |
||||||
|
assert.isNull(err) |
||||||
|
if (docs.length !== 1) { |
||||||
|
return done(new Error('Unexpected length of document database')) |
||||||
|
} |
||||||
|
|
||||||
|
if (Object.keys(docs[0]).length !== 2) { |
||||||
|
return done(new Error('Unexpected length insert document in database')) |
||||||
|
} |
||||||
|
|
||||||
|
if (docs[0].hello !== 'world') { |
||||||
|
return done(new Error('Unexpected document')) |
||||||
|
} |
||||||
|
|
||||||
|
done() |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) // ===== End of 'persistent in-browser database' =====
|
@ -0,0 +1,48 @@ |
|||||||
|
'use strict' |
||||||
|
|
||||||
|
const path = require('path') |
||||||
|
const webpack = require('webpack') |
||||||
|
|
||||||
|
module.exports = (env, argv) => { |
||||||
|
const minimize = argv.optimizationMinimize || false |
||||||
|
return { |
||||||
|
mode: 'production', |
||||||
|
cache: false, |
||||||
|
watch: false, |
||||||
|
target: 'web', |
||||||
|
node: { |
||||||
|
global: true |
||||||
|
}, |
||||||
|
optimization: { |
||||||
|
minimize: minimize |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
fallback: { |
||||||
|
fs: false, |
||||||
|
path: require.resolve('path-browserify'), |
||||||
|
util: require.resolve('util/'), |
||||||
|
events: require.resolve('events/'), |
||||||
|
crypto: false |
||||||
|
} |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new webpack.NormalModuleReplacementPlugin(new RegExp(path.resolve(__dirname, 'lib/storage.js')), path.resolve(__dirname, 'browser-version/lib/storage.js')), |
||||||
|
new webpack.NormalModuleReplacementPlugin(new RegExp(path.resolve(__dirname, 'lib/customUtils.js')), path.resolve(__dirname, 'browser-version/lib/customUtils.js')), |
||||||
|
new webpack.ProvidePlugin({ |
||||||
|
process: 'process/browser', |
||||||
|
Buffer: ['buffer', 'Buffer'], |
||||||
|
setImmediate: ['timers-browserify', 'setImmediate'], |
||||||
|
clearImmediate: ['timers-browserify', 'clearImmediate'] |
||||||
|
}) |
||||||
|
], |
||||||
|
entry: { |
||||||
|
Nedb: path.join(__dirname, 'lib', 'datastore.js') |
||||||
|
}, |
||||||
|
output: { |
||||||
|
path: path.join(__dirname, 'browser-version/out'), |
||||||
|
filename: minimize ? 'nedb.min.js' : 'nedb.js', |
||||||
|
libraryTarget: 'window', |
||||||
|
library: '[name]' |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue