<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
- <component name="JavaScriptLibraryMappings">
- <file url="file://$PROJECT_DIR$/node" libraries="{Node.js v0.8.14 Core Library}" />
- <file url="file://$PROJECT_DIR$/tcejdb" libraries="{Node.js v0.8.14 Core Library}" />
- </component>
-</project>
+<project version="4" />
--- /dev/null
+
+2012-10-27 Anton Adamansky. <adamansky@gmail.com>
+ - Initial release based on Tokyo Cabinet v1.4.48
+ - Release 1.0.0
});
};
+
+const simpleErrCb = function(err) {
+ if (err) {
+ console.error(err);
+ }
+};
+
+/**
+ * DROP indexes of all types for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.dropIndexes = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXDROPALL, cb);
+};
+
+/**
+ * OPTIMIZE indexes of all types for JSON field path.
+ * B+ tree index file optimization.
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.optimizeIndexes = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXOP, cb);
+};
+
+/**
+ * Ensure index presence of String type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.ensureStringIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXSTR, cb);
+};
+
+/**
+ * Rebuild index of String type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.rebuildStringIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXSTR | ejdblib.JBIDXREBLD, cb);
+};
+
+/**
+ * Drop index of String type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.dropStringIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXSTR | ejdblib.JBIDXDROP, cb);
+};
+
+/**
+ * Ensure index presence of Number type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.ensureNumberIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXNUM, cb);
+};
+
+/**
+ * Rebuild index of Number type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.rebuildNumberIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXNUM | ejdblib.JBIDXREBLD, cb);
+};
+
+/**
+ * Drop index of Number type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.dropNumberIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXNUM | ejdblib.JBIDXDROP, cb);
+};
+
+/**
+ * Ensure index presence of Array type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.ensureArrayIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXARR, cb);
+};
+
+/**
+ * Rebuild index of Array type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.rebuildArrayIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXARR | ejdblib.JBIDXREBLD, cb);
+};
+
+/**
+ * Drop index of Array type for JSON field path
+ * @param {String} cname Name of collection
+ * @param {String} path JSON field path
+ * @param {Function} [cb] Optional callback function. Callback args: (error)
+ */
+EJDB.prototype.dropArrayIndex = function(cname, path, cb) {
+ if (typeof cb !== "function") cb = simpleErrCb;
+ return this._impl.setIndex(cname, path, ejdblib.JBIDXARR | ejdblib.JBIDXDROP, cb);
+};
+
module.exports = EJDB;
static Persistent<String> sym_compressed;
static Persistent<String> sym_records;
static Persistent<String> sym_cachedrecords;
+ static Persistent<String> sym_explain;
///////////////////////////////////////////////////////////////////////////
cmdLoad = 2, //Load BSON by oid
cmdRemove = 3, //Remove BSON by oid
cmdQuery = 4, //Query collection
- cmdRemoveColl = 5 //Remove collection
+ cmdRemoveColl = 5, //Remove collection
+ cmdSetIndex = 6 //Set index
};
struct BSONCmdData { //Any bson related cmd data
TCLIST *res;
int qflags;
uint32_t count;
+ TCXSTR *log;
- BSONQCmdData(const char* _cname, int _qflags) :
- BSONCmdData::BSONCmdData(_cname), res(NULL), qflags(_qflags), count(0) {
+ BSONQCmdData(const char *_cname, int _qflags) :
+ BSONCmdData::BSONCmdData(_cname), res(NULL), qflags(_qflags), count(0), log(NULL) {
}
virtual ~BSONQCmdData() {
if (res) {
tclistdel(res);
}
+ if (log) {
+ tcxstrdel(log);
+ }
+
}
};
}
};
+ struct SetIndexCmdData { //set index
+ std::string cname; //Name of collection
+ std::string ipath; //JSON field path for index
+ int flags; //set index op flags
+
+ SetIndexCmdData(const char *_cname, const char *_ipath, int _flags) :
+ cname(_cname), ipath(_ipath), flags(_flags) {
+ }
+ };
+
typedef EIOCmdTask<NodeEJDB> EJBTask;
typedef EIOCmdTask<NodeEJDB, BSONCmdData> BSONCmdTask;
typedef EIOCmdTask<NodeEJDB, BSONQCmdData> BSONQCmdTask;
typedef EIOCmdTask<NodeEJDB, RMCollCmdData> RMCollCmdTask;
+ typedef EIOCmdTask<NodeEJDB, SetIndexCmdData> SetIndexCmdTask;
static Persistent<FunctionTemplate> constructor_template;
}
cmdata->bsons.push_back(bs);
}
+
+ if (len > 1 && qarr->Get(len - 1)->IsObject()) {
+ Local<Object> hints = Local<Object>::Cast(qarr->Get(len - 1));
+ if (hints->Get(sym_explain)->BooleanValue()) {
+ cmdata->log = tcxstrnew();
+ }
+ }
+
NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
BSONQCmdTask *task = new BSONQCmdTask(cb, njb, cmdQuery, cmdata, BSONQCmdTask::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());
}
+ static Handle<Value> s_set_index(const Arguments& args) {
+ HandleScope scope;
+ REQ_ARGS(4);
+ REQ_STR_ARG(0, cname)
+ REQ_STR_ARG(1, ipath)
+ REQ_INT32_ARG(2, flags);
+ REQ_FUN_ARG(3, cb);
+
+ NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
+ SetIndexCmdData *cmdata = new SetIndexCmdData(*cname, *ipath, flags);
+ SetIndexCmdTask *task = new SetIndexCmdTask(cb, njb, cmdSetIndex, cmdata, SetIndexCmdTask::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());
+ }
+
static Handle<Value> s_ecode(const Arguments& args) {
HandleScope scope;
NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
case cmdRemoveColl:
rm_collection((RMCollCmdTask*) task);
break;
+ case cmdSetIndex:
+ set_index((SetIndexCmdTask*) task);
+ break;
}
}
case cmdRemoveColl:
rm_collection_after((RMCollCmdTask*) task);
break;
+ case cmdSetIndex:
+ set_index_after((SetIndexCmdTask*) task);
+ break;
+ }
+ }
+
+ void set_index(SetIndexCmdTask *task) {
+ if (!_check_state((EJBTask*) task)) {
+ return;
+ }
+ SetIndexCmdData *cmdata = task->cmd_data;
+ assert(cmdata);
+ 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();
+ return;
+ }
+ if (!ejdbsetindex(coll, cmdata->ipath.c_str(), cmdata->flags)) {
+ task->cmd_ret = CMD_RET_ERROR;
+ task->cmd_ret_msg = _jb_error_msg();
+ }
+ }
+
+ void set_index_after(SetIndexCmdTask *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);
}
}
task->cmd_ret_msg = _jb_error_msg();
goto finish;
}
- res = ejdbqrysearch(coll, q, &cmdata->count, cmdata->qflags, NULL);
+ res = ejdbqrysearch(coll, q, &cmdata->count, cmdata->qflags, cmdata->log);
if (ejdbecode(m_jb) != TCESUCCESS) {
if (res) {
tclistdel(res);
sym_compressed = NODE_PSYMBOL("compressed");
sym_records = NODE_PSYMBOL("records");
sym_cachedrecords = NODE_PSYMBOL("cachedrecords");
+ sym_explain = NODE_PSYMBOL("$explain");
Local<FunctionTemplate> t = FunctionTemplate::New(s_new_object);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "ensureCollection", s_ensure_collection);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "removeCollection", s_rm_collection);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "isOpen", s_is_open);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "setIndex", s_set_index);
//Symbols
target->Set(String::NewSymbol("NodeEJDB"), constructor_template->GetFunction());
void NodeEJDB::query_after(BSONQCmdTask *task) {
HandleScope scope;
- Local<Value> argv[3];
+ BSONQCmdData *cmdata = task->cmd_data;
+ assert(cmdata);
+
+ Local<Value> argv[4];
if (task->cmd_ret != 0) {
argv[0] = Exception::Error(String::New(task->cmd_ret_msg.c_str()));
TryCatch try_catch;
}
return;
}
- BSONQCmdData *cmdata = task->cmd_data;
- assert(cmdata);
TCLIST *res = cmdata->res;
cmdata->res = NULL; //res will be freed by NodeEJDBCursor instead of ~BSONQCmdData()
argv[0] = Local<Primitive>::New(Null());
Local<Object> cursor(NodeEJDBCursor::constructor_template->GetFunction()->NewInstance(2, cursorArgv));
argv[1] = Local<Object>::New(cursor);
argv[2] = Integer::New(cmdata->count);
+ if (cmdata->log) {
+ argv[3] = String::New((const char*) tcxstrptr(cmdata->log));
+ }
TryCatch try_catch;
- task->cb->Call(Context::GetCurrent()->Global(), 3, argv);
+ task->cb->Call(Context::GetCurrent()->Global(), (cmdata->log) ? 4 : 3, argv);
if (try_catch.HasCaught()) {
FatalException(try_catch);
}
});
};
+module.exports.testUseStringIndex = function(test) {
+ test.ok(jb);
+ test.ok(jb.isOpen());
+ jb.find("birds", {"name" : "Molly"}, {"$explain" : true}, function(err, cursor, count, log) {
+ test.ifError(err);
+ test.ok(cursor);
+ test.ok(count == 1);
+ test.ok(log);
+ test.ok(log.indexOf("RUN FULLSCAN") !== -1);
+ //Now set the name string index
+ jb.ensureStringIndex("birds", "name", function(err) {
+ test.ifError(err);
+ jb.find("birds", {"name" : "Molly"}, {"$explain" : true}, function(err, cursor, count, log) {
+ test.ok(log.indexOf("MAIN IDX: 'sname'") !== -1);
+ test.done();
+ });
+ });
+ });
+};
+
module.exports.testRemove = function(test) {
test.ok(jb);
test.ok(jb.isOpen());
-2012-10-27 Softmotions. <info@softmotions.com>
- - Initial release based on Tokyo Cabinet v1.4.48
- - Release 1.0.0
* - Eg: flag = JBIDXDROP | JBIDXNUM (Drop number index)
* - `JBIDXDROPALL` Drop index for all types.
* - `JBIDXREBLD` Rebuild index of specified type.
- * - `JBIDXOP` Optimize index of specified type.
+ * - `JBIDXOP` Optimize index of specified type. (Optimize the B+ tree index file)
*
* Examples:
* - Set index for JSON path `addressbook.number` for strings and numbers: