return this._impl.ensureCollection(cname, copts || {});
};
-EJDB.prototype.rmCollection = function(cname, prune) {
- return this._impl.rmCollection(cname, !!prune);
+
+/**
+ * Call variations:
+ * - rmCollection(cname)
+ * - rmCollection(cname, cb)
+ * - rmCollection(cname, prune, cb)
+ *
+ * @param cname
+ * @param prune
+ * @param cb
+ * @return {*}
+ */
+EJDB.prototype.removeCollection = function(cname, prune, cb) {
+ if (arguments.length == 2) {
+ cb = prune;
+ prune = false;
+ }
+ if (!cb) {
+ cb = function() {
+ };
+ }
+ return this._impl.removeCollection(cname, !!prune, cb);
};
EJDB.prototype.save = function(cname, jsarr, cb) {
/**
*
- * Calling variations:
- * - query(cname, qobj, qobjarr, hints, cb)
- * - query(cname, qobj, hints, cb)
- * - query(cname, qobj, cb)
+ * Call variations:
+ * - find(cname, qobj, cb)
+ * - find(cname, qobj, hints, cb)
+ * - find(cname, qobj, qobjarr, cb)
+ * - find(cname, qobj, qobjarr, hints, cb)
*
* @param cname
* @param qobj
* @param hints
* @param cb
*/
-EJDB.prototype.query = function(cname, qobj, orarr, hints, cb) {
+EJDB.prototype.find = function(cname, qobj, orarr, hints, cb) {
if (arguments.length == 4) {
cb = hints;
- hints = orarr;
- orarr = [];
+ if (orarr && orarr.constructor === Array) {
+ hints = {};
+ } else {
+ hints = orarr;
+ orarr = [];
+ }
} else if (arguments.length == 3) {
cb = orarr;
orarr = [];
if (typeof cname !== "string") {
throw new Error("Collection name 'cname' argument must be specified");
}
- if (typeof hints !== "object") {
+ if (!hints || typeof hints !== "object") {
hints = {};
}
- if (typeof qobj !== "object") {
+ if (!qobj || typeof qobj !== "object") {
qobj = {};
}
return this._impl.query(cname,
cb);
};
+/*
+ * Call variations:
+ * - findOne(cname, qobj, cb)
+ * - findOne(cname, qobj, hints, cb)
+ * - findOne(cname, qobj, qobjarr, cb)
+ * - findOne(cname, qobj, qobjarr, hints, cb)
+ */
+EJDB.prototype.findOne = function(cname, qobj, orarr, hints, cb) {
+ if (arguments.length == 4) {
+ cb = hints;
+ if (orarr && orarr.constructor === Array) {
+ hints = {};
+ } else {
+ hints = orarr;
+ orarr = [];
+ }
+ } else if (arguments.length == 3) {
+ cb = orarr;
+ orarr = [];
+ hints = {};
+ }
+ if (typeof cb !== "function") {
+ throw new Error("Callback 'cb' argument must be specified");
+ }
+ if (typeof cname !== "string") {
+ throw new Error("Collection name 'cname' argument must be specified");
+ }
+ if (!hints || typeof hints !== "object") {
+ hints = {};
+ }
+ if (!qobj || typeof qobj !== "object") {
+ qobj = {};
+ }
+ hints["$max"] = 1;
+ return this._impl.query(cname, [qobj].concat(orarr, hints), 0,
+ function(err, cursor) {
+ if (err) {
+ cb(err);
+ return;
+ }
+ if (cursor.next()) {
+ cb(null, cursor.object());
+ } else {
+ cb(null, null);
+ }
+ });
+};
module.exports = EJDB;
}
break;
case BSON_BINDATA:
- //TODO test it!
if (obt == BSON_ARRAY) {
ret->Set(knum,
Buffer::New(String::New(bson_iterator_bin_data(it),
sf.append("m");
}
bson_append_regex(bs, *spn, *sr, sf.c_str());
+ } else if (Buffer::HasInstance(pv)) {
+ bson_append_binary(bs, *spn, BSON_BIN_BINARY,
+ Buffer::Data(Handle<Object>::Cast(pv)),
+ Buffer::Length(Handle<Object>::Cast(pv)));
} else if (pv->IsObject() || pv->IsArray()) {
if (pv->IsArray()) {
bson_append_start_array(bs, *spn);
} else {
bson_append_finish_object(bs);
}
- } else if (Buffer::HasInstance(pv)) {
- bson_append_binary(bs, *spn, BSON_BIN_BINARY,
- Buffer::Data(Handle<Object>::Cast(pv)),
- Buffer::Length(Handle<Object>::Cast(pv)));
}
}
}
cmdSave = 1, //Save JSON object
cmdLoad = 2, //Load BSON by oid
cmdRemove = 3, //Remove BSON by oid
- cmdQuery = 4 //Query collection
+ cmdQuery = 4, //Query collection
+ cmdRemoveColl = 5 //Remove collection
};
- //Any bson cmd data
-
- struct BSONCmdData {
+ struct BSONCmdData { //Any bson related cmd data
std::string cname; //Name of collection
std::vector<bson*> bsons; //bsons to save|query
std::vector<bson_oid_t> ids; //saved updated oids
bson_oid_t ref; //Bson ref
- BSONCmdData(const char* cname) {
- this->cname = cname;
+ BSONCmdData(const char* _cname) : cname(_cname) {
memset(&ref, 0, sizeof (ref));
}
}
};
- //Query cmd data
-
- struct BSONQCmdData : public BSONCmdData {
+ struct BSONQCmdData : public BSONCmdData { //query cmd data
TCLIST *res;
int qflags;
uint32_t count;
}
};
+ struct RMCollCmdData { //remove collection
+ std::string cname; //Name of collection
+ bool prune;
+
+ RMCollCmdData(const char* _cname, bool _prune) : cname(_cname), prune(_prune) {
+ }
+ };
+
typedef EIOCmdTask<NodeEJDB> EJBTask;
typedef EIOCmdTask<NodeEJDB, BSONCmdData> BSONCmdTask;
typedef EIOCmdTask<NodeEJDB, BSONQCmdData> BSONQCmdTask;
+ typedef EIOCmdTask<NodeEJDB, RMCollCmdData> RMCollCmdTask;
static Persistent<FunctionTemplate> constructor_template;
HandleScope scope;
REQ_STR_ARG(0, cname);
REQ_VAL_ARG(1, prune);
+ REQ_FUN_ARG(2, cb);
NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
if (!ejdbisopen(njb->m_jb)) {
return scope.Close(ThrowException(Exception::Error(String::New("Operation on closed EJDB instance"))));
}
- if (!ejdbrmcoll(njb->m_jb, *cname, prune->BooleanValue())) {
- return scope.Close(ThrowException(Exception::Error(String::New(njb->_jb_error_msg()))));
- }
+ RMCollCmdData *cmdata = new RMCollCmdData(*cname, prune->BooleanValue());
+ RMCollCmdTask *task = new RMCollCmdTask(cb, njb, cmdRemoveColl, cmdata, RMCollCmdTask::delete_val);
+ uv_queue_work(uv_default_loop(), &task->uv_work, s_exec_cmd_eio, s_exec_cmd_eio_after);
return scope.Close(args.This());
}
case cmdRemove:
remove((BSONCmdTask*) task);
break;
+ case cmdRemoveColl:
+ rm_collection((RMCollCmdTask*) task);
+ break;
}
}
case cmdRemove:
remove_after((BSONCmdTask*) task);
break;
+ case cmdRemoveColl:
+ rm_collection_after((RMCollCmdTask*) task);
+ break;
+
+ }
+ }
+
+ void rm_collection(RMCollCmdTask *task) {
+ if (!_check_state((EJBTask*) task)) {
+ return;
+ }
+ RMCollCmdData *cmdata = task->cmd_data;
+ assert(cmdata);
+ if (!ejdbrmcoll(m_jb, cmdata->cname.c_str(), cmdata->prune)) {
+ task->cmd_ret = CMD_RET_ERROR;
+ task->cmd_ret_msg = _jb_error_msg();
+ }
+ }
+
+ void rm_collection_after(RMCollCmdTask *task) {
+ HandleScope scope;
+ Local<Value> argv[1];
+ if (task->cmd_ret != 0) {
+ argv[0] = Exception::Error(String::New(task->cmd_ret_msg.c_str()));
+ } else {
+ argv[0] = Local<Primitive>::New(Null());
+ }
+ TryCatch try_catch;
+ task->cb->Call(Context::GetCurrent()->Global(), 1, argv);
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
}
}
if (!_check_state((EJBTask*) task)) {
return;
}
+ TCLIST *res = NULL;
bson oqarrstack[8]; //max 8 $or bsons on stack
BSONQCmdData *cmdata = task->cmd_data;
- EJCOLL *coll = ejdbcreatecoll(m_jb, cmdata->cname.c_str(), NULL);
- if (!coll) {
- task->cmd_ret = CMD_RET_ERROR;
- task->cmd_ret_msg = _jb_error_msg();
+ EJCOLL *coll = ejdbgetcoll(m_jb, cmdata->cname.c_str());
+ if (!coll) { //No collection -> no results
+ cmdata->res = tclistnew2(1);
+ cmdata->count = 0;
return;
}
std::vector<bson*> &bsons = cmdata->bsons;
for (int i = 1; i < (int) bsons.size() - 1; ++i) {
oqarr[i - 1] = *(bsons.at(i));
}
- TCLIST *res = NULL;
EJQ *q = ejdbcreatequery(
m_jb,
bsons.front(),
NODE_SET_PROTOTYPE_METHOD(constructor_template, "query", s_query);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "lastError", s_ecode);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ensureCollection", s_ensure_collection);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "rmCollection", s_rm_collection);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "removeCollection", s_rm_collection);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "isOpen", s_is_open);
-
//Symbols
target->Set(String::NewSymbol("NodeEJDB"), constructor_template->GetFunction());
}
};
-module.exports.testEnsureCollection = function(test) {
+module.exports.testEnsureAndRemoveCollection = function(test) {
var jb = EJDB.open("var/tdbt12", EJDB.JBOWRITER | EJDB.JBOCREAT | EJDB.JBOTRUNC);
test.equal(jb.isOpen(), true);
var c1opts = {
};
jb.ensureCollection("c1", c1opts);
test.ok(fs.existsSync("var/tdbt12_c1"));
- jb.rmCollection("c1", true);
- test.ok(!fs.existsSync("var/tdbt12_c1"));
- jb.close();
- var err = null;
- try {
- jb.rmCollection("c1", true);
- } catch (e) {
- err = e;
- }
- test.ok(err);
- test.done();
+
+ jb.removeCollection("c1", true, function(err) {
+ test.ifError(err);
+ test.ok(!fs.existsSync("var/tdbt12_c1"));
+
+ //Test operation on closed database instance
+ jb.close();
+ var err = null;
+ try {
+ jb.removeCollection("c1", true);
+ } catch (e) {
+ err = e;
+ }
+ test.ok(err);
+ test.done();
+ });
};
module.exports.testQuery1 = function(test) {
test.ok(jb);
test.ok(jb.isOpen());
- jb.query("parrots", {}, function(err, cursor, count) {
+ jb.find("parrots", {}, function(err, cursor, count) {
test.ifError(err);
test.equal(count, 2);
test.ok(cursor);
module.exports.testQuery2 = function(test) {
test.ok(jb);
test.ok(jb.isOpen());
- jb.query("parrots",
+ jb.find("parrots",
{name : /(grenny|bounty)/ig},
{$orderby : {name : 1}},
function(err, cursor, count) {
};
-//Test with OR
+//Test with OR, cursor.reset
module.exports.testQuery3 = function(test) {
test.ok(jb);
test.ok(jb.isOpen());
- jb.query("parrots",
+ jb.find("parrots",
{}, //main query selector
[
//OR joined conditions
test.equal(rv["likes"].join(","), "green color,night,toys");
test.equal(cursor.field("likes").join(","), "green color,night,toys");
}
+
+ //test cursor reset
+ cursor.reset();
+ for (c = 0; cursor.next(); ++c);
+ test.equal(c, 2);
+
+ //explicit cursor close
+ cursor.close();
+ test.done();
+ });
+};
+
+module.exports.testCircular = function(test) {
+ test.ok(jb);
+ test.ok(jb.isOpen());
+
+ //Circular query object
+ var cirQuery = {};
+ cirQuery.cq = cirQuery;
+ var err = null;
+ try {
+ jb.find("parrots", cirQuery, function(err, cursor, count) {
+ });
+ } catch (e) {
+ err = e;
+ }
+ test.ok(err);
+ test.equal(err.message, "Circular object reference");
+
+ err = null;
+ try {
+ jb.save("parrots", [cirQuery]);
+ } catch (e) {
+ err = e;
+ }
+ test.ok(err);
+ test.equal(err.message, "Circular object reference");
+ test.done();
+};
+
+
+module.exports.testSaveLoadBuffer = function(test) {
+ test.ok(jb);
+ test.ok(jb.isOpen());
+
+ var sally = {
+ "name" : "Sally",
+ "mood" : "Angry",
+ "secret" : new Buffer("Something binary secrect", "utf8")
+ };
+ var molly = {
+ "name" : "Molly",
+ "mood" : "Very angry",
+ "secret" : null
+ };
+
+ jb.save("birds", sally, function(err, oids) {
+ test.ifError(err);
+ test.ok(oids);
+ test.ok(oids.length === 1);
+ test.ok(sally["_id"]);
+ var sallyOid = sally["_id"];
+ jb.load("birds", sallyOid, function(err, obj) {
+ test.ifError(err);
+ test.ok(obj["secret"] instanceof Buffer);
+ test.equal(obj["secret"], "Something binary secrect");
+ jb.save("birds", [sally, molly], function(err, oids) {
+ test.ifError(err);
+ test.ok(oids);
+ test.ok(oids.indexOf(sallyOid) !== -1);
+ test.done();
+ });
+ });
+ });
+};
+
+module.exports.testRemove = function(test) {
+ test.ok(jb);
+ test.ok(jb.isOpen());
+ jb.findOne("birds", {"name" : "Molly"}, function(err, obj) {
+ test.ifError(err);
+ test.ok(obj["_id"]);
+ test.equal(obj["mood"], "Very angry");
+ //Bye bye Molly!
+ jb.remove("birds", obj["_id"], function(err) {
+ test.ifError(err);
+ jb.findOne("birds", {"name" : "Molly"}, function(err, obj) {
+ test.ifError(err);
+ test.ok(obj === null);
test.done();
});
+ });
+ });
+};
+module.exports.testRemoveColls = function(test) {
+ jb.removeCollection("birds", function(err) {
+ test.ifError(err);
+ jb.find("birds", {}, function(err, cursor, count) { //Query on not existing collection
+ test.ifError(err);
+ test.equal(count, 0);
+ test.ok(!cursor.next());
+ test.done();
+ });
+ });
};
module.exports.testClose = function(test) {