queryable
Version:
Nosql database that supports subset of mongodb operators
263 lines (222 loc) • 10 kB
JavaScript
//---------------------------------------------------------------
function UnitTest() {
this.num_tests = 0;
this.num_failed = 0;
this.fs = require('fs');
var that = this;
// process.on('exit',function() { this.report(); });
}
UnitTest.prototype = {
stringify: JSON.stringify,
p: function(s) { console.log(s); },
po: function(s) { process.stdout.write(s); },
exe: function(str) { this.p(' '+ str + ' --> ' + eval(str) ); },
ob_eq: function ( A, B ) {
return this.stringify(A) === (B + '').trim();
},
test: function(str,ans) {
++this.num_tests;
this.po( "test: \"" + str + '" => '+ans );
var ret = eval(str);
if ( this.ob_eq( ret, ans ) ) {
this.p( " -- Passed" );
} else {
this.p( " -- Failed \n"+ans+"\n"+this.stringify(ret) );
++this.num_failed;
var debug = function() {
eval(str);
};
debug();
}
},
// dont evaluate, just compare
testEq: function(str,ans) {
++this.num_tests;
this.po( "test: \"" + str + '" => '+ans );
if ( typeof str !== "String" && isNaN(str) )
str = this.stringify(str);
if ( str === ans ) {
this.p( " -- Passed" );
} else {
this.p( " -- Failed \n"+ans+"\n"+str );
++this.num_failed;
}
},
report: function() {
this.p( "\n=======================\n * " + this.num_tests + " tests passed successfully" );
if ( this.num_failed > 0 )
this.p( " ** There were "+this.num_failed+" errors!!!" );
this.p( "=======================\n" );
}
};
//---------------------------------------------------------------
debugger;
var db_name = "QUERYABLE-UNITTEST.db";
var U = new UnitTest();
process.on('exit',function() { U.report(); });
if ( U.fs.existsSync( db_name ) ) {
U.p( '"'+db_name+'" found. Removing...' );
U.fs.unlink( db_name );
}
var i = 0;
var e = U.fs.existsSync( db_name );
while ( e ) {
if ( i++ >= 10 )
break;
e = U.fs.existsSync( db_name );
}
//console.log(e.toString()+' '+i);
if ( U.fs.existsSync( db_name ) === false ) {
U.p( '"'+db_name+'" doesn\'t exist. creating...' );
}
else
U.p( "STILL EXISTS" );
//process.exit(0);
var queryable = require('../queryable');
var db = queryable.open( db_name );
//db.save();
U.p( "\nPATHS: " );
U.p( "\nINSERT TESTS:" );
U.test( "db.insert({a:1})", 1 );
U.test( "db.insert([{a:2,b:2},{a:3,b:3,c:3}])", 2 );
U.test( "db.insert({a:4,b:4,c:4,d:4})", 1 );
U.test( "db.insert([{b:5,c:5,d:5},{c:6,d:6},{c:7}])", 3 );
U.p( "\nFIND TESTS:" );
U.p( "simple find:" );
U.test( "db.find({a:1})", '{"length":1,"rows":[{"_id":1,"a":1}]}' );
U.p( "simple $gt:" );
U.test( "db.find({b:{'$gt':4}})", '{"length":1,"rows":[{"_id":5,"b":5,"c":5,"d":5}]}' );
U.p( "simple $lt:" );
U.test( "db.find({b:{'$lt':4}})", '{"length":2,"rows":[{"_id":2,"a":2,"b":2},{"_id":3,"a":3,"b":3,"c":3}]}' );
U.p( "simple $gte:" );
U.test( "db.find({b:{'$gte':4}})", '{"length":2,"rows":[{"_id":4,"a":4,"b":4,"c":4,"d":4},{"_id":5,"b":5,"c":5,"d":5}]}' );
U.p( "simple $lte:" );
U.test( "db.find({b:{'$lte':4}})", '{"length":3,"rows":[{"_id":2,"a":2,"b":2},{"_id":3,"a":3,"b":3,"c":3},{"_id":4,"a":4,"b":4,"c":4,"d":4}]}' );
U.p( "reverse sort, numeric:" );
U.test( "db.find({b:{'$gte':4}}).sort({'_id':-1})", '{"length":2,"rows":[{"_id":5,"b":5,"c":5,"d":5},{"_id":4,"a":4,"b":4,"c":4,"d":4}]}' );
U.test( "db.insert({name:'Paul'})", 1 );
U.test( "db.insert({name:'Carol'})", 1 );
U.test( "db.insert({name:'Zach'})", 1 );
U.p( "\nALPHABETICAL SORT:" );
U.test( "db.find({name:/(.*)/}).sort({name:1})", '{"length":3,"rows":[{"_id":9,"name":"Carol"},{"_id":8,"name":"Paul"},{"_id":10,"name":"Zach"}]}' );
U.p( "$exists:true:" );
U.test( "db.find({name:{'$exists':true}}).sort({name:-1})", '{"length":3,"rows":[{"_id":10,"name":"Zach"},{"_id":8,"name":"Paul"},{"_id":9,"name":"Carol"}]}' );
U.p( "\n$exists:false && $exists:false:" );
U.test( "db.find({name:{'$exists':false},'a':{'$exists':false},'b':{'$exists':false}}).sort({_id:-1})", '{"length":2,"rows":[{"_id":7,"c":7},{"_id":6,"c":6,"d":6}]}' );
U.p( "\nAND $exists:true:" );
U.test( "db.find({a:{$exists:true},b:{$exists:true},c:{$exists:true},d:{$exists:true}})", '{"length":1,"rows":[{"_id":4,"a":4,"b":4,"c":4,"d":4}]}' );
U.p( "\nOR:" );
U.test( "db.find({$or:[{d:{$exists:true}},{c:{$exists:true}}]}).sort({_id:-1})", '{"length":5,"rows":[{"_id":7,"c":7},{"_id":6,"c":6,"d":6},{"_id":5,"b":5,"c":5,"d":5},{"_id":4,"a":4,"b":4,"c":4,"d":4},{"_id":3,"a":3,"b":3,"c":3}]}' );
U.p( "\nAND CONDITIONAL:" );
U.test( "db.find({b:{$gt:3},c:{$lte:5},d:{$lt:6},b:{$gte:5}})", '{"length":1,"rows":[{"_id":5,"b":5,"c":5,"d":5}]}' );
U.p("\n\n==========================");
U.p( JSON.stringify(db.find()) );
U.p("==========================\n\n");
U.p( "\nNOT-EQUAL::" );
U.test( "db.find({b:{$ne:4}})", '{"length":9,"rows":[{"_id":1,"a":1},{"_id":2,"a":2,"b":2},{"_id":3,"a":3,"b":3,"c":3},{"_id":5,"b":5,"c":5,"d":5},{"_id":6,"c":6,"d":6},{"_id":7,"c":7},{"_id":8,"name":"Paul"},{"_id":9,"name":"Carol"},{"_id":10,"name":"Zach"}]}' );
U.test( "db.find({b:{$ne:5}})", '{"length":9,"rows":[{"_id":1,"a":1},{"_id":2,"a":2,"b":2},{"_id":3,"a":3,"b":3,"c":3},{"_id":4,"a":4,"b":4,"c":4,"d":4},{"_id":6,"c":6,"d":6},{"_id":7,"c":7},{"_id":8,"name":"Paul"},{"_id":9,"name":"Carol"},{"_id":10,"name":"Zach"}]}' );
U.test( "db.find({a:{$ne:3},b:{$ne:2},c:{$ne:6}})", '{"length":7,"rows":[{"_id":1,"a":1},{"_id":4,"a":4,"b":4,"c":4,"d":4},{"_id":5,"b":5,"c":5,"d":5},{"_id":7,"c":7},{"_id":8,"name":"Paul"},{"_id":9,"name":"Carol"},{"_id":10,"name":"Zach"}]}' );
U.p( "\nOR CONDITIONAL:" );
U.test( "db.find( {a:{$exists:true},b:{$lt:3},a:{$gte:1} } )", '{"length":1,"rows":[{"_id":2,"a":2,"b":2}]}' );
U.test( "db.find( {b:{$gt:4},c:{$gte:5},d:{$lte:6}})", '{"length":1,"rows":[{"_id":5,"b":5,"c":5,"d":5}]}' );
U.test( "db.find( {a:3,b:{$gt:2},c:{$lt:7}} )", '{"length":1,"rows":[{"_id":3,"a":3,"b":3,"c":3}]}' );
U.p( "\nAND/OR CONDITIONAL COMBINED:" );
U.test( "db.find( { c:{$lt:6}, $or: [{a:{$gt:5}},{b:{$lte:4}}] } )", '{"length":2,"rows":[{"_id":3,"a":3,"b":3,"c":3},{"_id":4,"a":4,"b":4,"c":4,"d":4}]}' );
U.p( "\nREMOVE: ");
U.test( "db.remove( {name:/[A-Z](.*)/} )", 3 );
U.test( "db.find().count()", 7 );
U.test( "db.remove( {a:{$gt:1},b:{$gt:2},c:{$exists:true},d:{$exists:false}} )", 1 );
U.test( "db.count()", 6 ); // count can be called from db object or result object
U.test( "db.remove( {c:{$exists:true}} )", 4 );
U.p( "\nUPDATE: ");
U.test( "db.update( {b:{$exists:true}}, {$set:{awesome:true}}, {multi:true} )", 1 );
U.test( "db.update( {}, {$set:{everything:1}}, {multi:true} )", 2 );
U.p(db.get_json());
U.test( "db.update( {not:'here'}, {$set:{put:'anyway'}}, {upsert:true} )", 1 );
U.p(db.get_json());
U.p( "\nLIMIT: ");
U.test( "db.remove()", 3 );
var names = ["Dan","Fred","Amy","Ivette","Justin","Phoebe"];
for ( var i = 0; i < 100; i++ ) {
db.insert( {person_id:1000+i,name:names[Math.floor(Math.random()*names.length)]} );
}
var ph = 0;
names.forEach(function(n){
var r = db.find({name:n}).count();
U.p( ' --> adding: '+ n + ' ' + r );
if ( n === "Phoebe" ) ph = r;
});
for ( var lim = 0; lim <= ph+1; lim++ ) {
if ( lim === ph+1 )
U.test( "db.find( {name:'Phoebe'} ).limit("+lim+").count()", lim-1 );
else
U.test( "db.find( {name:'Phoebe'} ).limit("+lim+").count()", lim );
}
/*
SKIP
*/
U.p( "\nSKIP: ");
db.remove();
var A = [];
for ( A = [], i = 0; i < 100; i++ ) {
A.push({'i':i});
}
db.insert(A);
U.test("A=[];db.find().skip(40).limit(20).rows.forEach(function(o){A.push(o['i']);});A;", '[40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59]' );
/*
DISTINCT
*/
U.p( "\nDISTINCT: " );
db.remove();
U.test( "db.find()" , '{"length":0,"rows":[]}' );
db = queryable.open();
db.insert( {tableName:'whatever'} );
A = [];
for ( A = [], i = 0; i < 4; i++ ) {
A.push( {'a': i%2} );
}
db.insert(A);
U.test("db.find();",'{"length":5,"rows":[{"_id":1,"tableName":"whatever"},{"_id":2,"a":0},{"_id":3,"a":1},{"_id":4,"a":0},{"_id":5,"a":1}]}');
U.test("db.distinct('a');",'{"length":2,"rows":[{"_id":2,"a":0},{"_id":3,"a":1}]}');
db.insert([{'a':2},{'a':3}]);
U.test("db.distinct('a',{'a':{$lt:1}});",'{"length":1,"rows":[{"_id":2,"a":0}]}');
U.test("db.distinct('a',{$or:[{'tableName':{$exists:true}},{'a':{$lt:1}}]});",'{"length":1,"rows":[{"_id":2,"a":0}]}');
U.test("db.distinct('a',{$or:[{'tableName':{$exists:true}},{'a':{$gte:2}}]});",'{"length":2,"rows":[{"_id":6,"a":2},{"_id":7,"a":3}]}');
db.insert([{'a':2},{'a':3}]);
U.test("db.distinct('a',{$or:[{'tableName':{$exists:true}},{'a':{$gte:2}}]});",'{"length":2,"rows":[{"_id":6,"a":2},{"_id":7,"a":3}]}');
var db4 = queryable.open( {data:[{n:'jared'},{n:'martha'},{n:'jim'},{n:'nolan'},{n:'jim'},{n:'jared'}]});
U.test("db4.distinct('n',{n:/^j/});", '{"length":2,"rows":[{"_id":1,"n":"jared"},{"_id":3,"n":"jim"}]}' );
/*
CALLBACKS
*/
U.p("\nCALLBACKS:");
// FIND
db.find(null, function(res) {
U.testEq( res, '{"length":9,"rows":[{"_id":1,"tableName":"whatever"},{"_id":2,"a":0},{"_id":3,"a":1},{"_id":4,"a":0},{"_id":5,"a":1},{"_id":6,"a":2},{"_id":7,"a":3},{"_id":8,"a":2},{"_id":9,"a":3}]}' );
});
db.remove();
db.find(null, function(res) {
U.testEq( res, '{"length":0,"rows":[]}' );
});
// INSERT
db = queryable.open();
for ( var i = 0; i < 4; i++ ) {
db.insert( {k:i}, function(res) {
U.testEq(res, 1);
} );
}
// UPDATE
db.update( {k:0}, {$set:{k:4}}, null, function(res) {
U.testEq(res, 1);
});
// DISTINCT
db.distinct( 'k', null, function(res) {
U.testEq(res, '{"length":4,"rows":[{"_id":1,"k":4},{"_id":2,"k":1},{"_id":3,"k":2},{"_id":4,"k":3}]}' );
});
db.distinct( 'k', {k:{$gt:2}}, function(res) {
U.testEq(res, '{"length":2,"rows":[{"_id":1,"k":4},{"_id":4,"k":3}]}' );
});
// REMOVE
db.remove( {k:{$gt:0}}, function(res) {
U.testEq( res, 4 );
});