Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dirty

Package Overview
Dependencies
Maintainers
6
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dirty - npm Package Compare versions

Comparing version 1.1.2 to 1.1.3

.eslintrc.js

25

benchmark/dirty/for-each.js

@@ -1,12 +0,13 @@

var config = require('../../test/config');
var COUNT = 1e6,
dirty = require(config.LIB_DIRTY)(),
util = require('util');
'use strict';
for (var i = 0; i < COUNT; i++) {
const config = require('../../test/config');
const COUNT = 1e6;
const dirty = require(config.LIB_DIRTY)();
for (let i = 0; i < COUNT; i++) {
dirty.set(i, i);
}
var start = Date.now(), i = 0;
dirty.forEach(function(key, doc) {
const start = Date.now();
dirty.forEach((key, doc) => {
if (!key && key !== 0) {

@@ -17,7 +18,5 @@ throw new Error('implementation fail');

var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,12 +0,13 @@

var config = require('../../test/config');
var COUNT = 1e6,
dirty = require(config.LIB_DIRTY)(),
util = require('util');
'use strict';
for (var i = 0; i < COUNT; i++) {
const config = require('../../test/config');
const COUNT = 1e6;
const dirty = require(config.LIB_DIRTY)();
for (let i = 0; i < COUNT; i++) {
dirty.set(i, i);
}
var start = Date.now();
for (var i = 0; i < COUNT; i++) {
const start = Date.now();
for (let i = 0; i < COUNT; i++) {
if (dirty.get(i) !== i) {

@@ -17,8 +18,5 @@ throw new Error('implementation fail');

var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,24 +0,24 @@

var config = require('../../test/config');
var COUNT = 1e4,
DB_FILE = config.TMP_PATH + '/benchmark-set-drain.dirty',
dirty = require(config.LIB_DIRTY)(DB_FILE),
util = require('util'),
loaded = false;
'use strict';
for (var i = 0; i < COUNT; i++) {
const assert = require('assert').strict;
const config = require('../../test/config');
const Dirty = require(config.LIB_DIRTY);
const COUNT = 1e4;
const DB_FILE = `${config.TMP_PATH}/benchmark-set-drain.dirty`;
const dirty = new Dirty(DB_FILE);
let loaded = false;
for (let i = 0; i < COUNT; i++) {
dirty.set(i, i);
}
dirty.on('drain', function() {
var start = Date.now();
require('dirty')(DB_FILE).on('load', function(length) {
var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Hz ('+million+' million in '+ms+' ms)');
dirty.on('drain', () => {
const start = Date.now();
new Dirty(DB_FILE).on('load', (length) => {
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Hz (${million} million in ${ms} ms)`);
loaded = true;
assert.equal(length, COUNT);

@@ -28,4 +28,4 @@ });

process.on('exit', function() {
process.on('exit', () => {
assert.ok(loaded);
});

@@ -1,25 +0,31 @@

var config = require('../../test/config');
var COUNT = 1e5,
dirty = require(config.LIB_DIRTY)(config.TMP_PATH + '/benchmark-set-drain.dirty'),
util = require('util'),
drained = false;
'use strict';
var start = Date.now();
for (var i = 0; i < COUNT; i++) {
dirty.set(i, 'This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. This string');
}
const assert = require('assert').strict;
const config = require('../../test/config');
const Dirty = require(config.LIB_DIRTY);
dirty.on('drain', function() {
var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2),
million = COUNT / 1e6;
const COUNT = 1e5;
const dirty = new Dirty(`${config.TMP_PATH}/benchmark-set-drain.dirty`);
let drained = false;
const val =
'This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. ' +
'This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. ' +
'This string has 256 bytes. This string has 256 bytes. This string has 256 bytes. ' +
'This string';
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Hz ('+million+' million in '+ms+' ms)');
const start = Date.now();
for (let i = 0; i < COUNT; i++) {
dirty.set(i, val);
}
dirty.on('drain', () => {
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Hz (${million} million in ${ms} ms)`);
drained = true;
});
process.on('exit', function() {
process.on('exit', () => {
assert.ok(drained);
});

@@ -1,25 +0,26 @@

var config = require('../../test/config');
var COUNT = 1e4,
dirty = require(config.LIB_DIRTY)(config.TMP_PATH + '/benchmark-set-drain.dirty'),
util = require('util'),
drained = false;
'use strict';
var start = Date.now();
for (var i = 0; i < COUNT; i++) {
const assert = require('assert').strict;
const config = require('../../test/config');
const Dirty = require(config.LIB_DIRTY);
const COUNT = 1e4;
const dirty = new Dirty(`${config.TMP_PATH}/benchmark-set-drain.dirty`);
let drained = false;
const start = Date.now();
for (let i = 0; i < COUNT; i++) {
dirty.set(i, i);
}
dirty.on('drain', function() {
var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Hz ('+million+' million in '+ms+' ms)');
dirty.on('drain', () => {
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e3).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Hz (${million} million in ${ms} ms)`);
drained = true;
});
process.on('exit', function() {
process.on('exit', () => {
assert.ok(drained);
});

@@ -1,16 +0,17 @@

var config = require('../../test/config');
var COUNT = 1e6,
dirty = require(config.LIB_DIRTY)(config.TMP_PATH + '/benchmark-set.dirty'),
util = require('util');
'use strict';
var start = Date.now();
for (var i = 0; i < COUNT; i++) {
const config = require('../../test/config');
const Dirty = require(config.LIB_DIRTY);
const COUNT = 1e6;
const dirty = new Dirty(`${config.TMP_PATH}/benchmark-set.dirty`);
const start = Date.now();
for (let i = 0; i < COUNT; i++) {
dirty.set(i, i);
}
var ms = Date.now() - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = Date.now() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,11 +0,12 @@

var COUNT = 1e7,
util = require('util'),
a = [];
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e7;
const a = [];
for (let i = 0; i < COUNT; i++) {
a.push(i);
}
var start = +new Date;
a.filter(function(val, i) {
const start = +new Date();
a.filter((val, i) => {
if (val !== i) {

@@ -16,8 +17,5 @@ throw new Error('implementation fail');

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,11 +0,12 @@

var COUNT = 1e7,
util = require('util'),
a = [];
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e7;
const a = [];
for (let i = 0; i < COUNT; i++) {
a.push(i);
}
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
if (a[i] !== i) {

@@ -16,7 +17,5 @@ throw new Error('implementation fail');

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,11 +0,12 @@

var COUNT = 1e7,
util = require('util'),
a = [];
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e7;
const a = [];
for (let i = 0; i < COUNT; i++) {
a.push(i);
}
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
if (a[i] !== i) {

@@ -16,7 +17,5 @@ throw new Error('implementation fail');

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,15 +0,14 @@

var COUNT = 1e6,
util = require('util'),
a = [];
'use strict';
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e6;
const a = [];
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
a.push(i);
}
var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,15 +0,14 @@

var COUNT = 1e6,
util = require('util'),
a = [];
'use strict';
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e6;
const a = [];
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
a[i] = i;
}
var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,11 +0,12 @@

var COUNT = 1e7,
util = require('util'),
o = {};
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e7;
const o = {};
for (let i = 0; i < COUNT; i++) {
o[i] = i;
}
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
if (o[i] !== i) {

@@ -16,7 +17,5 @@ throw new Error('implementation fail');

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,12 +0,14 @@

var COUNT = 1e6,
util = require('util'),
o = {};
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e6;
const o = {};
for (let i = 0; i < COUNT; i++) {
o[i] = i;
}
var start = +new Date, keys = Object.keys(o), length = keys.length;
for (var i = 0; i < keys.length; i++) {
if (o[keys[i]] != i) {
const start = +new Date();
const keys = Object.keys(o);
for (let i = 0; i < keys.length; i++) {
if (o[keys[i]] !== i) {
throw new Error('implementation fail');

@@ -16,7 +18,5 @@ }

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,12 +0,13 @@

var COUNT = 1e6,
util = require('util'),
o = {};
'use strict';
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e6;
const o = {};
for (let i = 0; i < COUNT; i++) {
o[i] = i;
}
var start = +new Date;
for (var i in o) {
if (o[i] != i) {
const start = +new Date();
for (const i in o) {
if (o[i] !== i) {
throw new Error('implementation fail');

@@ -16,7 +17,5 @@ }

var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,15 +0,14 @@

var COUNT = 1e6,
util = require('util'),
o = {};
'use strict';
var start = +new Date;
for (var i = 0; i < COUNT; i++) {
const COUNT = 1e6;
const o = {};
const start = +new Date();
for (let i = 0; i < COUNT; i++) {
o[i] = i;
}
var ms = +new Date - start,
mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2),
million = COUNT / 1e6;
// Can't use console.log() since since I also test this in ancient node versions
util.log(mhz+' Mhz ('+million+' million in '+ms+' ms)');
const ms = +new Date() - start;
const mhz = ((COUNT / (ms / 1000)) / 1e6).toFixed(2);
const million = COUNT / 1e6;
console.log(`${mhz} Mhz (${million} million in ${ms} ms)`);

@@ -1,13 +0,18 @@

require('../test/common');
var db = require('dirty')(TEST_TMP+'/bob.dirty');
'use strict';
db.on('load', function() {
// eslint-disable-next-line node/no-missing-require
const Dirty = require('dirty');
const path = require('path');
const db = new Dirty(path.join(__dirname, 'bob.dirty'));
db.on('load', () => {
db.set('john', {eyes: 'blue'});
console.log('Added john, he has %s eyes.', db.get('john').eyes);
db.set('bob', {eyes: 'brown'}, function() {
console.log('User bob is now saved on disk.')
db.set('bob', {eyes: 'brown'}, () => {
console.log('User bob is now saved on disk.');
});
db.forEach(function(key, val) {
db.forEach((key, val) => {
console.log('Found key: %s, val: %j', key, val);

@@ -17,4 +22,4 @@ });

db.on('drain', function() {
db.on('drain', () => {
console.log('All records are saved on disk now.');
});

@@ -0,1 +1,3 @@

'use strict';
module.exports = require('./lib/dirty');

@@ -1,209 +0,201 @@

if (global.GENTLY) require = GENTLY.hijack(require);
'use strict';
var fs = require('fs'),
util = require('util'),
EventEmitter = require('events').EventEmitter;
const fs = require('fs');
const EventEmitter = require('events').EventEmitter;
class Dirty extends EventEmitter {
constructor(path) {
super();
/**
* Constructor function
*/
var Dirty = exports.Dirty = function(path) {
if (!(this instanceof Dirty)) return new Dirty(path);
this.path = path;
EventEmitter.call(this);
this._data = new Map();
this._queue = new Map(); // Maps key to a list of callbacks.
this._readStream = null;
this._writeStream = null;
this._waitForDrain = false;
this._inFlightWrites = 0;
this.path = path;
this._load();
}
this._data = new Map();
this._queue = new Map(); // Maps key to a list of callbacks.
this._readStream = null;
this._writeStream = null;
this._waitForDrain = false;
this._inFlightWrites = 0;
/**
* set() stores a JSON object in the database at key
* cb is fired when the data is persisted.
* In memory, this is immediate - on disk, it will take some time.
*/
set(key, val, cb) {
if (val === undefined) {
this._data.delete(key);
} else {
this._data.set(key, val);
}
if (this.path) {
const cbs = this._queue.get(key) || [];
if (cb) cbs.push(cb);
this._queue.set(key, cbs);
this._flush();
} else {
setImmediate(() => { if (cb) cb(); this.emit('drain'); });
}
}
this._load();
return this;
};
/**
* Get the value stored at a key in the database
* This is synchronous since a cache is maintained in-memory
*/
get(key) {
return this._data.get(key);
}
util.inherits(Dirty, EventEmitter);
Dirty.Dirty = Dirty;
module.exports = Dirty;
/**
* Get total number of stored keys
*/
size() {
return this._data.size;
}
/**
* Remove a key and the value stored there
*/
rm(key, cb) {
this.set(key, undefined, cb);
}
/**
* set() stores a JSON object in the database at key
* cb is fired when the data is persisted.
* In memory, this is immediate - on disk, it will take some time.
*/
Dirty.prototype.set = function(key, val, cb) {
if (val === undefined) {
this._data.delete(key);
} else {
this._data.set(key, val);
/**
* Iterate over keys, applying match function
*/
forEach(fn) {
for (const [key, val] of this._data) {
if (fn(key, val) === false) break;
}
}
if (this.path) {
let cbs = this._queue.get(key) || [];
if (cb) cbs.push(cb);
this._queue.set(key, cbs);
this._flush();
} else {
setImmediate(() => { if (cb) cb(); this.emit('drain'); });
/**
* Update the value stored at a key in the database.
* This is synchronous since a cache is maintained in-memory
* cb is passed as per Dirty.prototype.set
*/
update(key, updater, cb) {
this.set(key, updater(this.get(key)), cb);
}
};
/**
* Get the value stored at a key in the database
* This is synchronous since a cache is maintained in-memory
*/
Dirty.prototype.get = function(key) {
return this._data.get(key);
};
/**
* Get total number of stored keys
*/
Dirty.prototype.size = function() {
return this._data.size;
};
/**
* Remove a key and the value stored there
*/
Dirty.prototype.rm = function(key, cb) {
this.set(key, undefined, cb);
};
/**
* Iterate over keys, applying match function
*/
Dirty.prototype.forEach = function(fn) {
for (const [key, val] of this._data) {
if (fn(key, val) === false) break;
/**
* Close dirty db file streams
*/
close() {
if (this._queue.size || this._inFlightWrites > 0) {
this.once('drain', () => this.close());
return;
}
if (this._readStream) this._readStream.destroy();
if (this._writeStream) this._writeStream.end(() => this._writeStream.destroy());
}
};
/**
* Update the value stored at a key in the database.
* This is synchronous since a cache is maintained in-memory
* cb is passed as per Dirty.prototype.set
*/
Dirty.prototype.update = function(key, updater, cb) {
this.set(key, updater(this.get(key)), cb);
};
// Called when a dirty connection is instantiated
_load() {
let buffer = '';
/**
* Close dirty db file streams
*/
Dirty.prototype.close = function() {
if (this._queue.size || this._inFlightWrites > 0) {
this.once('drain', () => this.close());
return;
}
if (this._readStream) this._readStream.destroy();
if (this._writeStream) this._writeStream.end(() => this._writeStream.destroy());
};
if (!this.path) {
process.nextTick(() => {
this.emit('load', 0);
});
return;
}
// Called when a dirty connection is instantiated
Dirty.prototype._load = function() {
var buffer = '';
if (!this.path) {
process.nextTick(() => {
this.emit('load', 0);
this._readStream = fs.createReadStream(this.path, {
encoding: 'utf-8',
flags: 'r',
});
return;
}
this._readStream = fs.createReadStream(this.path, {
encoding: 'utf-8',
flags: 'r'
});
this._readStream
.on('error', (err) => {
if (err.code === 'ENOENT') {
this.emit('load', 0);
return;
}
this._readStream
.on('error', (err) => {
if (err.code === 'ENOENT') {
this.emit('load', 0);
return;
}
this.emit('error', err);
})
.on('data', (chunk) => {
buffer += chunk;
if (chunk.lastIndexOf('\n') === -1) return;
const arr = buffer.split('\n');
buffer = arr.pop();
arr.forEach((rowStr) => {
if (!rowStr) {
this.emit('error', new Error('Empty lines never appear in a healthy database'));
return;
}
this.emit('error', err);
})
.on('data', (chunk) => {
buffer += chunk;
if (chunk.lastIndexOf('\n') == -1) return;
var arr = buffer.split('\n');
buffer = arr.pop();
arr.forEach((rowStr) => {
if (!rowStr) {
this.emit('error', new Error('Empty lines never appear in a healthy database'));
return;
}
let row;
try {
row = JSON.parse(rowStr);
if (!('key' in row)) {
throw new Error();
}
} catch (e) {
this.emit('error', new Error(`Could not load corrupted row: ${rowStr}`));
return '';
}
var row;
try {
row = JSON.parse(rowStr);
if (!('key' in row)) {
throw new Error();
if (row.val === undefined) {
this._data.delete(row.key);
} else {
this._data.set(row.key, row.val);
}
return '';
});
})
.on('end', () => {
if (buffer.length) {
this.emit('error', new Error(`Corrupted row at the end of the db: ${buffer}`));
}
} catch (e) {
this.emit('error', new Error('Could not load corrupted row: '+rowStr));
return '';
}
this.emit('load', this._data.size);
})
.on('close', () => {
this._readStream = null;
this.emit('read_close');
});
if (row.val === undefined) {
this._data.delete(row.key);
} else {
this._data.set(row.key, row.val);
}
return '';
});
})
.on('end', () => {
if (buffer.length) {
this.emit('error', new Error('Corrupted row at the end of the db: '+buffer));
this._writeStream = fs.createWriteStream(this.path, {
encoding: 'utf-8',
flags: 'a',
});
this._writeStream.on('drain', () => {
this._waitForDrain = false;
if (!this._queue.size) {
if (this._inFlightWrites <= 0) this.emit('drain');
} else {
this._flush();
}
this.emit('load', this._data.size);
})
.on('close', () => {
this._readStream = null;
this.emit('read_close');
});
this._writeStream = fs.createWriteStream(this.path, {
encoding: 'utf-8',
flags: 'a'
});
this._writeStream.on('close', () => {
this._writeStream = null;
this.emit('write_close');
});
}
this._writeStream.on('drain', () => {
this._waitForDrain = false;
if (!this._queue.size) {
if (this._inFlightWrites <= 0) this.emit('drain');
} else {
this._flush();
_flush() {
if (!this._queue.size || this._waitForDrain) return;
this._writeStream.cork();
for (const [key, cbs] of this._queue) {
this._queue.delete(key);
const data = `${JSON.stringify({key, val: this._data.get(key)})}\n`;
++this._inFlightWrites;
this._waitForDrain = !this._writeStream.write(data, (err) => {
if (!cbs.length && err != null) this.emit('error', err);
if (--this._inFlightWrites <= 0 && !this._waitForDrain) this.emit('drain');
for (const cb of cbs) cb(err);
});
if (this._waitForDrain) break;
}
});
this._writeStream.uncork();
}
}
this._writeStream.on('close', () => {
this._writeStream = null;
this.emit('write_close');
});
};
Dirty.prototype._flush = function() {
if (!this._queue.size || this._waitForDrain) return;
this._writeStream.cork();
for (const [key, cbs] of this._queue) {
this._queue.delete(key);
const data = JSON.stringify({key: key, val: this._data.get(key)})+'\n';
++this._inFlightWrites;
this._waitForDrain = !this._writeStream.write(data, (err) => {
if (!cbs.length && err != null) this.emit('error', err);
if (--this._inFlightWrites <= 0 && !this._waitForDrain) this.emit('drain');
for (const cb of cbs) cb(err);
});
if (this._waitForDrain) break;
}
this._writeStream.uncork();
};
Dirty.Dirty = Dirty;
// Trap `apply` for backwards compatibility with callers that don't use `new`.
module.exports = exports = new Proxy(Dirty, {apply: (target, thisArg, args) => new Dirty(...args)});

@@ -1,1 +0,3 @@

module.exports = require('./dirty');
'use strict';
module.exports = require('./dirty');
{
"name": "dirty",
"description": "A tiny & fast key value store with append-only disk log. Ideal for apps with < 1 million records.",
"version": "1.1.2",
"version": "1.1.3",
"repository": "https://github.com/felixge/node-dirty.git",

@@ -10,8 +10,20 @@ "license": "MIT",

"devDependencies": {
"mocha": "^9.0.0",
"eslint": "^7.32.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-mocha": "^9.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0",
"mocha": "^9.1.1",
"rimraf": "^3.0.2"
},
"engines": {
"node": ">=12.13.0"
},
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "mocha test/test-*.js -R list"
}
}

@@ -27,4 +27,4 @@ # node-dirty

```javascript
var dirty = require('dirty');
var db = dirty('user.db');
var Dirty = require('dirty');
var db = new Dirty('user.db');

@@ -63,10 +63,2 @@ db.on('load', function() {

The constructor can be invoked in multiple ways:
```javascript
require('dirty')('my.db');
require('dirty').Dirty('my.db');
new (require('dirty'))('my.db');
new (require('dirty').Dirty)('my.db');
```
### dirty.path

@@ -109,3 +101,3 @@

Close the dirty db file handle.
Close the dirty db file handle.

@@ -112,0 +104,0 @@ ### dirty event: 'load' (length)

@@ -1,8 +0,10 @@

var path = require('path'),
fs = require('fs'),
rimraf = require('rimraf');
'use strict';
var TMP_PATH = path.join(__dirname, 'tmp'),
LIB_DIRTY = path.join(__dirname, '../lib/dirty');
const path = require('path');
const fs = require('fs');
const rimraf = require('rimraf');
const TMP_PATH = path.join(__dirname, 'tmp');
const LIB_DIRTY = path.join(__dirname, '../lib/dirty');
rimraf.sync(TMP_PATH);

@@ -12,4 +14,4 @@ fs.mkdirSync(TMP_PATH);

module.exports = {
TMP_PATH: TMP_PATH,
LIB_DIRTY: LIB_DIRTY
TMP_PATH,
LIB_DIRTY,
};

@@ -1,50 +0,48 @@

var config = require('./config');
path = require('path'),
fs = require('fs'),
dirty = require(config.LIB_DIRTY),
events = require('events'),
assert = require('assert');
'use strict';
// exists moved from path to fs in node v0.7.1
// https://raw.github.com/joyent/node/v0.7.1/ChangeLog
var exists = (fs.exists) ? fs.exists : path.exists;
const config = require('./config');
const fsp = require('fs').promises;
const Dirty = require(config.LIB_DIRTY);
const events = require('events');
const assert = require('assert');
function dirtyAPITests(file) {
var mode = (file) ? 'persistent' : 'transient';
const dirtyAPITests = (file) => {
const mode = (file) ? 'persistent' : 'transient';
describe('dirty api (' + mode + ' mode)', function() {
function cleanup(done) {
exists(file, function(doesExist) {
if (doesExist) {
fs.unlinkSync(file);
}
describe(`dirty api (${mode} mode)`, function () {
const cleanup = async () => {
try {
await fsp.unlink(file);
} catch (err) { /* intentionally ignored */ }
};
done();
});
}
before(cleanup);
describe('dirty constructor', function() {
var db = dirty(file);
it('constructor without new', async function () {
const db = Dirty(file); // eslint-disable-line new-cap
assert(db instanceof Dirty);
await cleanup();
});
describe('dirty constructor', function () {
let db;
before(async function () { db = new Dirty(file); });
after(cleanup);
it('is an event emitter', function() {
it('is an event emitter', async function () {
assert.ok(db instanceof events.EventEmitter);
});
it('is a dirty', function() {
assert.ok(db instanceof dirty);
it('is a dirty', async function () {
assert.ok(db instanceof Dirty);
});
});
describe('events', function() {
describe('events', function () {
afterEach(cleanup);
it('should fire load', function(done) {
var db = dirty(file);
db.on('load', function(length) {
it('should fire load', function (done) {
const db = new Dirty(file);
db.on('load', (length) => {
assert.strictEqual(length, 0);

@@ -55,12 +53,11 @@ done();

it('should fire drain after write', function(done) {
var db = dirty(file);
db.on('load', function(length) {
it('should fire drain after write', function (done) {
const db = new Dirty(file);
db.on('load', (length) => {
assert.strictEqual(length, 0);
db.set('key', 'value');
db.on('drain', function() {
db.on('drain', () => {
done();
});
});

@@ -70,9 +67,9 @@ });

describe('accessors', function(done) {
describe('accessors', function (done) {
after(cleanup);
var db;
let db;
it('.set should trigger callback', function(done) {
db = dirty(file);
db.set('key', 'value', function(err) {
it('.set should trigger callback', function (done) {
db = new Dirty(file);
db.set('key', 'value', (err) => {
assert.ok(!err);

@@ -83,12 +80,13 @@ done();

it('.get should return value', function() {
it('.get should return value', async function () {
assert.strictEqual(db.get('key'), 'value');
});
it('.path is valid', function() {
it('.path is valid', async function () {
assert.strictEqual(db.path, file);
});
it('.forEach runs for all', function() {
var total = 2, count = 0;
it('.forEach runs for all', async function () {
const total = 2; let
count = 0;
db.set('key1', 'value1');

@@ -99,10 +97,10 @@ db.set('delete', 'me');

var keys = ['key', 'key1'];
var vals = ['value', 'value1'];
const keys = ['key', 'key1'];
const vals = ['value', 'value1'];
db.forEach(function(key, val) {
db.forEach((key, val) => {
assert.strictEqual(key, keys[count]);
assert.strictEqual(val, vals[count]);
count ++;
count++;
});

@@ -113,3 +111,3 @@

it('.rm removes key/value pair', function() {
it('.rm removes key/value pair', async function () {
db.set('test', 'test');

@@ -121,3 +119,3 @@ assert.strictEqual(db.get('test'), 'test');

it('.rm of unknown key is a no-op', async function() {
it('.rm of unknown key is a no-op', async function () {
db.rm('does not exist');

@@ -129,3 +127,3 @@ const got = [];

it('will reload file from disk', function(done) {
it('will reload file from disk', function (done) {
if (!file) {

@@ -136,4 +134,4 @@ console.log('N/A in transient mode');

db = dirty(file);
db.on('load', function(length) {
db = new Dirty(file);
db.on('load', (length) => {
assert.strictEqual(length, 2);

@@ -149,7 +147,7 @@ assert.strictEqual(db.get('key'), 'value');

});
describe('db file close', function(done) {
describe('db file close', function () {
after(cleanup);
it('close', function(done) {
it('close', function (done) {
if (!file) {

@@ -159,6 +157,6 @@ console.log('N/A in transient mode');

}
var db = dirty(file);
db.on('load', function(length) {
const db = new Dirty(file);
db.on('load', (length) => {
db.set('close', 'close');
db.on('drain', function() {
db.on('drain', () => {
db.close();

@@ -168,3 +166,3 @@ });

db.on('write_close',function() {
db.on('write_close', () => {
done();

@@ -174,7 +172,6 @@ });

});
});
}
};
dirtyAPITests('');
dirtyAPITests(config.TMP_PATH + '/apitest.dirty');
dirtyAPITests(`${config.TMP_PATH}/apitest.dirty`);

@@ -1,24 +0,23 @@

var config = require('./config'),
dirty = require(config.LIB_DIRTY),
assert = require('assert'),
fs = require('fs');
'use strict';
describe('test-load-event', function() {
it('should fire load event', function(done) {
var db = dirty();
const config = require('./config');
const Dirty = require(config.LIB_DIRTY);
const assert = require('assert');
db.on('load', function() {
describe('test-load-event', function () {
it('should fire load event', function (done) {
const db = new Dirty();
db.on('load', () => {
done();
});
});
});
describe('test-set-callback', function() {
describe('test-set-callback', function () {
it('should trigger callback on set', function (done) {
const db = new Dirty();
let foo = '';
it ('should trigger callback on set', function(done) {
var db = dirty();
var foo = '';
db.set('foo', 'bar', function() {
db.set('foo', 'bar', () => {
foo = db.get('foo');

@@ -28,5 +27,3 @@ assert.equal(foo, 'bar');

});
});
});

@@ -1,17 +0,20 @@

var config = require('./config'),
fs = require('fs'),
assert = require('assert'),
dirty = require(config.LIB_DIRTY);
'use strict';
describe('test-flush', function() {
var file = config.TMP_PATH + '/flush.dirty';
const config = require('./config');
const fs = require('fs');
const fsp = fs.promises;
const assert = require('assert');
const Dirty = require(config.LIB_DIRTY);
afterEach(function() {
fs.unlinkSync(file);
describe('test-flush', function () {
const file = `${config.TMP_PATH}/flush.dirty`;
afterEach(async function () {
await fsp.unlink(file);
});
it ('should fire drain event on write', function(done) {
var db = dirty(file);
it('should fire drain event on write', function (done) {
const db = new Dirty(file);
db.set('foo', 'bar');
db.on('drain', function() {
db.on('drain', () => {
done();

@@ -21,11 +24,11 @@ });

it ('should write to disk appropriately', function(done) {
var db = dirty(file);
it('should write to disk appropriately', function (done) {
const db = new Dirty(file);
db.set('foo1', 'bar1');
db.on('drain', function() {
var contents = fs.readFileSync(file, 'utf-8');
db.on('drain', () => {
const contents = fs.readFileSync(file, 'utf-8');
assert.strictEqual(
contents,
JSON.stringify({key: 'foo1', val: 'bar1'})+'\n'
contents,
`${JSON.stringify({key: 'foo1', val: 'bar1'})}\n`
);

@@ -36,7 +39,6 @@

});
});
describe('test-for-each', function() {
var db = dirty();
describe('test-for-each', function () {
const db = new Dirty();

@@ -47,5 +49,5 @@ db.set(1, {test: 'foo'});

it('should return each doc key and contents', function() {
var i = 0;
db.forEach(function(key, doc) {
it('should return each doc key and contents', async function () {
let i = 0;
db.forEach((key, doc) => {
i++;

@@ -59,11 +61,11 @@ assert.equal(key, i);

describe('test-load', function() {
var file = config.TMP_PATH +'/load.dirty',
db = dirty(file);
describe('test-load', function () {
const file = `${config.TMP_PATH}/load.dirty`;
const db = new Dirty(file);
afterEach(function() {
fs.unlinkSync(file);
afterEach(async function () {
await fsp.unlink(file);
});
it('should load after write to disk', function(done) {
it('should load after write to disk', function (done) {
db.set(1, 'A');

@@ -74,6 +76,6 @@ db.set(2, 'B');

db.on('drain', function() {
var db2 = dirty(file);
db.on('drain', () => {
const db2 = new Dirty(file);
db2.on('load', function(length) {
db2.on('load', (length) => {
assert.equal(length, 2);

@@ -89,3 +91,2 @@

});
});

@@ -95,4 +96,4 @@ });

describe('test-size', function() {
var db = dirty();
describe('test-size', function () {
const db = new Dirty();

@@ -103,3 +104,3 @@ db.set(1, {test: 'foo'});

it('should be equal to number of keys set', function() {
it('should be equal to number of keys set', async function () {
assert.equal(db.size(), 3);

@@ -109,18 +110,16 @@ });

describe('test-chaining-of-constructor', function() {
var file = config.TMP_PATH + '/chain.dirty';
describe('test-chaining-of-constructor', function () {
const file = `${config.TMP_PATH}/chain.dirty`;
fs.existsSync(file) && fs.unlinkSync(file);
it('should allow .on load to chain to constructor', function() {
var db = dirty(file);
db.on('load', function() {
db.set("x", "y");
db.set("p", "q");
db.close();
it('should allow .on load to chain to constructor', async function () {
let db = new Dirty(file);
await new Promise((resolve) => db.on('load', resolve));
db.set('x', 'y');
db.set('p', 'q');
db.close();
db = dirty(file).on('load', function(size) {
assert.strictEqual(db.size(), 2);
assert.strictEqual(size, 2);
});
});
const size = await new Promise((resolve) => { db = new Dirty(file).on('load', resolve); });
assert.strictEqual(db.size(), 2);
assert.strictEqual(size, 2);
});

@@ -130,11 +129,11 @@ });

describe('test-update', function () {
it('should give the updater the value and then set the value to what updater returns', function() {
var db = dirty();
db.set("foo", "bar");
db.update("foo", function (bar) {
assert.strictEqual(bar, "bar");
return "baz";
it('updater receives old value and sets new value', async function () {
const db = new Dirty();
db.set('foo', 'bar');
db.update('foo', (bar) => {
assert.strictEqual(bar, 'bar');
return 'baz';
});
assert.strictEqual(db.get("foo"), "baz");
assert.strictEqual(db.get('foo'), 'baz');
});
});

@@ -1,19 +0,21 @@

var config = require('./config'),
fs = require('fs'),
dirty = require(config.LIB_DIRTY),
assert = require('assert');
'use strict';
describe.skip('test-types', function() {
var db = dirty(config.TMP_PATH + '/test-types.dirty');
const config = require('./config');
const Dirty = require(config.LIB_DIRTY);
const assert = require('assert');
describe('keys', function() {
it('should prevent storage of an undefined key', function() {
describe.skip('test-types', function () {
let db;
before(async function () { db = new Dirty(`${config.TMP_PATH}/test-types.dirty`); });
describe('keys', function () {
it('should prevent storage of an undefined key', async function () {
db.set(undefined, 'value');
});
it('should not return an undefined key', function() {
it('should not return an undefined key', async function () {
assert(!db.get(undefined));
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc