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

penseur

Package Overview
Dependencies
Maintainers
1
Versions
103
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

penseur - npm Package Compare versions

Comparing version 2.2.0 to 2.3.0

277

lib/db.js

@@ -18,98 +18,150 @@ 'use strict';

exports = module.exports = internals.Db = function (name, options) {
exports = module.exports = class {
options = options || {};
Hoek.assert(!options.db, 'Cannot set db option');
constructor(name, options) {
this._settings = Hoek.clone(options);
this._name = name;
this._connection = null;
options = options || {};
Hoek.assert(!options.db, 'Cannot set db option');
if (this._settings.test) {
this.disable = internals.disable;
this.enable = internals.enable;
this._settings = Hoek.clone(options);
this._name = name;
this._connection = null;
if (this._settings.test) {
this.disable = internals.disable;
this.enable = internals.enable;
}
delete this._settings.test; // Always delete in case value is falsy
this.tables = {};
}
delete this._settings.test; // Always delete in case value is falsy
connect(callback) {
this.tables = {};
};
RethinkDB.connect(this._settings, (err, connection) => {
if (err) {
return callback(err);
}
internals.Db.prototype.connect = function (callback) {
this._connection = connection;
return callback(null);
});
}
RethinkDB.connect(this._settings, (err, connection) => {
close(next) {
if (err) {
return callback(err);
next = next || Hoek.ignore;
if (!this._connection) {
return next();
}
this._connection = connection;
return callback(null);
});
};
// Close change stream cursors
const tables = Object.keys(this.tables);
for (let i = 0; i < tables.length; ++i) {
const table = this.tables[tables[i]];
for (let j = 0; j < table._cursors.length; ++j) {
table._cursors[j].close();
}
internals.Db.prototype.close = function (next) {
table._cursors = [];
}
next = next || Hoek.ignore;
// Close connection
if (!this._connection) {
return next();
this._connection.close((err) => { // Explicit callback to avoid generating a promise
return next(err);
});
}
// Close change stream cursors
table(tables, options) {
const tables = Object.keys(this.tables);
for (let i = 0; i < tables.length; ++i) {
const table = this.tables[tables[i]];
for (let j = 0; j < table._cursors.length; ++j) {
table._cursors[j].close();
}
options = options || {};
table._cursors = [];
}
const Proto = options.extended || this._settings.extended || Table;
// Close connection
tables = [].concat(tables);
this._connection.close((err) => { // Explicit callback to avoid generating a promise
for (let i = 0; i < tables.length; ++i) {
const table = tables[i];
if (this.tables[table]) {
return;
}
return next(err);
});
};
const record = new Proto(table, this);
// Decorate object with tables
internals.Db.prototype.table = function (tables) {
this.tables[table] = record;
if (!this[table] &&
table[0] !== '_') { // Do not override prototype or private members
const Proto = this._settings.extended || Table;
this[table] = record;
}
}
}
tables = [].concat(tables);
establish(tables, callback) {
for (let i = 0; i < tables.length; ++i) {
const table = tables[i];
if (this.tables[table]) {
// Connect if not connected already
if (!this._connection) {
this.connect((err) => {
if (err) {
return callback(err);
}
return this.establish(tables, callback);
});
return;
}
const record = new Proto(table, this);
RethinkDB.dbList().run(this._connection, (err, names) => {
// Decorate object with tables
if (err) {
return callback(err);
}
this.tables[table] = record;
if (!this[table] &&
table[0] !== '_') { // Do not override prototype or private members
if (names.indexOf(this._name) === -1) {
this[table] = record;
}
// Create new database
RethinkDB.dbCreate(this._name).run(this._connection, (err, created) => {
if (err) {
return callback(err);
}
return this._createTable(tables, callback);
});
}
else {
// Reuse existing
return this._createTable(tables, callback);
}
});
}
};
_createTable(tables, callback) {
internals.Db.prototype.establish = function (tables, callback) {
let names = tables;
const tablesOptions = {};
if (!Array.isArray(tables)) {
names = Object.keys(tables);
for (let i = 0; i < names.length; ++i) {
const name = names[i];
tablesOptions[name] = (!tables[name] ? false : (tables[name] === true ? {} : tables[name]));
}
}
// Connect if not connected already
RethinkDB.db(this._name).tableList().run(this._connection, (err, existing) => {
if (!this._connection) {
this.connect((err) => {
if (err) {

@@ -119,71 +171,92 @@ return callback(err);

return this.establish(tables, callback);
});
const each = (name, next) => {
return;
}
if (tablesOptions[name] === false) {
return next();
}
RethinkDB.dbList().run(this._connection, (err, names) => {
const options = tablesOptions[name] || {};
this.table(name, options);
if (err) {
return callback(err);
}
const finalize = (err, indexes) => {
if (names.indexOf(this._name) === -1) {
if (err) {
return next(err);
}
// Create new database
if (indexes) {
return this.tables[name].index(indexes, next);
}
RethinkDB.dbCreate(this._name).run(this._connection, (err, created) => {
return next();
};
if (err) {
return callback(err);
// Create new table
if (existing.indexOf(name) === -1) {
return RethinkDB.db(this._name).tableCreate(name).run(this._connection, (err) => finalize(err, options.index));
}
return this._createTable(tables, callback);
});
}
else {
// Reuse existing table
// Reuse existing
const recreate = () => {
return this._createTable(tables, callback);
}
});
};
RethinkDB.db(this._name).table(name).indexList().run(this._connection, (err, currentIndexes) => {
if (err) {
return next(err);
}
internals.Db.prototype._createTable = function (tables, callback) {
const requestedIndexes = [].concat(options.index || []);
const intersection = Hoek.intersect(currentIndexes, requestedIndexes);
const creatIndexes = internals.difference(requestedIndexes, intersection);
const removeIndesex = internals.difference(currentIndexes, intersection);
RethinkDB.db(this._name).tableList().run(this._connection, (err, names) => {
const eachIndex = (index, nextIndex) => {
if (err) {
return callback(err);
}
RethinkDB.db(this._name).table(name).indexDrop(index).run(this._connection, nextIndex);
};
const each = (table, next) => {
Items.serial(removeIndesex, eachIndex, (err) => finalize(err, creatIndexes));
});
};
if (names.indexOf(table) === -1) {
if (options.purge === false) { // Defaults to true
return recreate();
}
// Create new table
this.tables[name].empty((err) => {
RethinkDB.db(this._name).tableCreate(table).run(this._connection, (err, result) => {
if (err) {
return next(err);
}
this.table(table);
return next(err);
return recreate();
});
}
else {
};
// Empty existing table
Items.serial(names, each, callback);
});
}
this.table(table);
return this.tables[table].empty(next);
}
};
fields(criteria) {
Items.serial(tables, each, callback);
});
return new Criteria(criteria, 'fields');
}
};
internals.difference = function (superset, subset) {
const result = [];
for (let i = 0; i < superset.length; ++i) {
if (subset.indexOf(superset[i]) === -1) {
result.push(superset[i]);
}
}
return result;
};
internals.disable = function (table, method) {

@@ -212,7 +285,1 @@

};
internals.Db.prototype.fields = function (criteria) {
return new Criteria(criteria, 'fields');
};

@@ -6,2 +6,3 @@ 'use strict';

const Boom = require('boom');
const Items = require('items');
const RethinkDB = require('rethinkdb');

@@ -57,3 +58,3 @@ const Cursor = require('./cursor');

});
};
}

@@ -63,3 +64,3 @@ count(criteria, callback) {

this._run(Criteria.wrap(criteria).select(this._table).count(), 'count', { criteria: criteria }, callback);
};
}

@@ -98,3 +99,3 @@ insert(items, callback) {

});
};
}

@@ -113,3 +114,3 @@ update(id, changes, callback) {

});
};
}

@@ -129,3 +130,3 @@ increment(id, field, value, callback) {

});
};
}

@@ -144,3 +145,3 @@ append(id, field, value, callback) {

});
};
}

@@ -161,3 +162,3 @@ unset(id, fields, callback) {

});
};
}

@@ -181,9 +182,12 @@ remove(criteria, callback) {

});
};
}
empty(callback) {
this._run(this._table.delete(), 'empty', null, callback);
};
this._run(this._table.delete(), 'empty', null, (err, result) => {
return callback(err, result ? result.deleted : 0);
});
}
sync(callback) {

@@ -199,4 +203,18 @@

});
};
}
index(names, callback) {
names = [].concat(names);
const each = (name, next) => {
this._run(this._table.indexCreate(name), 'index', null, (err, result) => {
return next(err);
});
};
Items.serial(names, each, callback);
}
changes(criteria, each, callback) {

@@ -246,3 +264,3 @@

});
};
}

@@ -280,3 +298,3 @@ _run(request, action, inputs, callback, next) {

});
};
}

@@ -286,3 +304,3 @@ _error(action, err, inputs, callback) {

return callback(Boom.internal('Database error', { error: err, table: this._name, action: action, inputs: inputs }));
};
}
};
{
"name": "penseur",
"description": "Lightweight RethinkDB wrapper",
"version": "2.2.0",
"version": "2.3.0",
"author": "Eran Hammer <eran@hammer.io> (http://hueniverse.com)",

@@ -6,0 +6,0 @@ "repository": "git://github.com/hueniverse/penseur",

@@ -162,5 +162,46 @@ 'use strict';

db.establish(['test'], (err) => {
db.establish({ test: { index: 'other' } }, (err) => {
expect(err).to.not.exist();
RethinkDB.db(db._name).table('test').indexList().run(db._connection, (err, result) => {
expect(result).to.deep.equal(['other']);
db.close(done);
});
});
});
});
});
it('customize table options', (done) => {
const Override = class extends Penseur.Table {
insert(items, callback) {
items = [].concat(items);
for (let i = 0; i < items.length; ++i) {
items[i].flag = true;
}
return super.insert(items, callback);
}
};
const db = new Penseur.Db('penseurtest', { host: 'localhost', port: 28015 });
db.establish({ test: { extended: Override }, user: false, other: true }, (err) => {
expect(err).to.not.exist();
expect(db.user).to.not.exist();
expect(db.other).to.exist();
db.test.insert({ id: 1, value: 'x' }, (err, result) => {
expect(err).to.not.exist();
db.test.get(1, (err, item) => {
expect(err).to.not.exist();
expect(item.value).to.equal('x');
expect(item.flag).to.equal(true);
db.close(done);

@@ -172,2 +213,111 @@ });

it('creates database with different table indexes', (done) => {
const db1 = new Penseur.Db('penseurtest');
db1.connect((err) => {
expect(err).to.not.exist();
db1.establish({ test: { index: 'other' } }, (err) => {
expect(err).to.not.exist();
RethinkDB.db(db1._name).table('test').indexList().run(db1._connection, (err, result1) => {
expect(result1).to.deep.equal(['other']);
db1.close(() => {
const db2 = new Penseur.Db('penseurtest');
db2.connect((err) => {
expect(err).to.not.exist();
db2.establish(['test'], (err) => {
expect(err).to.not.exist();
RethinkDB.db(db2._name).table('test').indexList().run(db2._connection, (err, result2) => {
expect(result2).to.deep.equal([]);
db2.close(done);
});
});
});
});
});
});
});
});
it('creates database with different table indexes (partial overlap)', (done) => {
const db1 = new Penseur.Db('penseurtest');
db1.connect((err) => {
expect(err).to.not.exist();
db1.establish({ test: { index: ['a', 'b'] } }, (err) => {
expect(err).to.not.exist();
RethinkDB.db(db1._name).table('test').indexList().run(db1._connection, (err, result1) => {
expect(result1).to.deep.equal(['a', 'b']);
db1.close(() => {
const db2 = new Penseur.Db('penseurtest');
db2.connect((err) => {
expect(err).to.not.exist();
db2.establish({ test: { index: ['b', 'c'] } }, (err) => {
expect(err).to.not.exist();
RethinkDB.db(db2._name).table('test').indexList().run(db2._connection, (err, result2) => {
expect(result2).to.deep.equal(['b', 'c']);
db2.close(done);
});
});
});
});
});
});
});
});
it('retains records in existing table', (done) => {
const db1 = new Penseur.Db('penseurtest');
db1.connect((err) => {
expect(err).to.not.exist();
db1.establish(['test'], (err) => {
expect(err).to.not.exist();
db1.test.insert({ id: 1 }, (err, id) => {
expect(err).to.not.exist();
db1.close(() => {
const db2 = new Penseur.Db('penseurtest');
db2.connect((err) => {
expect(err).to.not.exist();
db2.establish({ test: { purge: false } }, (err) => {
expect(err).to.not.exist();
db2.test.get(1, (err, item) => {
expect(err).to.not.exist();
expect(item.id).to.equal(1);
db2.close(done);
});
});
});
});
});
});
});
});
it('fails creating a database', (done) => {

@@ -195,2 +345,25 @@

it('errors on database indexList() error', { parallel: false }, (done) => {
const db = new Penseur.Db('penseurtest');
const orig = RethinkDB.dbList;
RethinkDB.dbList = function () {
RethinkDB.dbList = orig;
return {
run: function (connection, next) {
return next(new Error('Bad database'));
}
};
};
db.establish(['test'], (err) => {
expect(err).to.exist();
db.close(done);
});
});
it('errors on database dbList() error', { parallel: false }, (done) => {

@@ -249,2 +422,77 @@

});
it('errors on database indexList() error', { parallel: false }, (done) => {
const db = new Penseur.Db('penseurtest');
const orig = RethinkDB.db;
let count = 0;
RethinkDB.db = function () {
return {
tableList: function () {
return {
run: function (connection, next) {
return next(null, ['test']);
}
};
},
table: function () {
if (++count === 1) {
return orig('penseurtest').table('test');
}
RethinkDB.db = orig;
return {
indexList: function () {
return {
run: function (connection, next) {
return next(new Error('Bad database'));
}
};
}
};
}
};
};
db.establish(['test'], (err) => {
expect(err).to.exist();
db.close(done);
});
});
it('errors creating new table', (done) => {
const db = new Penseur.Db('penseurtest');
db.establish(['bad name'], (err) => {
expect(err).to.exist();
db.close(done);
});
});
it('errors emptying existing table', (done) => {
const Override = class extends Penseur.Table {
empty(callback) {
return callback(new Error('failed'));
}
};
const db = new Penseur.Db('penseurtest', { host: 'localhost', port: 28015 });
db.establish({ test: { extended: Override } }, (err) => {
expect(err).to.exist();
db.close(done);
});
});
});

@@ -251,0 +499,0 @@

@@ -630,2 +630,46 @@ 'use strict';

describe('empty()', () => {
it('removes all records', (done) => {
const db = new Penseur.Db('penseurtest');
db.establish(['test'], (err) => {
expect(err).to.not.exist();
db.test.insert([{ id: 1, a: 1 }, { id: 2, a: 1 }], (err, keys) => {
expect(err).to.not.exist();
db.test.empty((err, count1) => {
expect(err).to.not.exist();
expect(count1).to.equal(2);
db.test.count({ a: 1 }, (err, count2) => {
expect(err).to.not.exist();
expect(count2).to.equal(0);
done();
});
});
});
});
});
it('errors on unknown table', (done) => {
const db = new Penseur.Db('penseurtest');
db.connect((err) => {
db.table('no_such_table_test');
db.no_such_table_test.empty((err, count) => {
expect(err).to.exist();
expect(count).to.equal(0);
done();
});
});
});
});
describe('_run()', () => {

@@ -632,0 +676,0 @@

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