From c39b980928cde615a2719af759f5e1fd7a543d30 Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 13 Sep 2013 22:33:40 +0700 Subject: [PATCH] rbejdb moved into ejdb-ruby repo --- .idea/vcs.xml | 1 - .npmignore | 1 - rbejdb/Makefile | 28 - rbejdb/README.md | 64 -- rbejdb/ext/rbejdb/extconf.rb | 9 - rbejdb/ext/rbejdb/src/rbbson.c | 444 ------------- rbejdb/ext/rbejdb/src/rbbson.h | 38 -- rbejdb/ext/rbejdb/src/rbejdb.c | 1435 ---------------------------------------- rbejdb/rbejdb.gemspec | 20 - rbejdb/rbejdb.iml | 10 - rbejdb/test/Makefile | 9 - rbejdb/test/t1.rb | 53 -- rbejdb/test/t2.rb | 658 ------------------ rbejdb/test/t3.rb | 90 --- 14 files changed, 2860 deletions(-) delete mode 100644 rbejdb/Makefile delete mode 100644 rbejdb/README.md delete mode 100644 rbejdb/ext/rbejdb/extconf.rb delete mode 100644 rbejdb/ext/rbejdb/src/rbbson.c delete mode 100644 rbejdb/ext/rbejdb/src/rbbson.h delete mode 100644 rbejdb/ext/rbejdb/src/rbejdb.c delete mode 100644 rbejdb/rbejdb.gemspec delete mode 100644 rbejdb/rbejdb.iml delete mode 100644 rbejdb/test/Makefile delete mode 100644 rbejdb/test/t1.rb delete mode 100644 rbejdb/test/t2.rb delete mode 100644 rbejdb/test/t3.rb diff --git a/.idea/vcs.xml b/.idea/vcs.xml index f372c8c..275077f 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,7 +2,6 @@ - diff --git a/.npmignore b/.npmignore index 35040ca..63dea6c 100644 --- a/.npmignore +++ b/.npmignore @@ -89,7 +89,6 @@ addressbook* /var /node/samples/sample1/zoo* /tcejdb/debian -/rbejdb /misc /node/nodejs /node/tests/bench diff --git a/rbejdb/Makefile b/rbejdb/Makefile deleted file mode 100644 index 4597ac2..0000000 --- a/rbejdb/Makefile +++ /dev/null @@ -1,28 +0,0 @@ - -all: build doc - -build: - mkdir -p build - cd ./build; ruby ../ext/rbejdb/extconf.rb ../ext/rbejdb/src - make -C ./build - -install: - make install -C ./build - -check: - make -C ./test - -doc: - rdoc ext/rbejdb/src - -build-gem: - gem build rbejdb.gemspec - -clean: - rm -rf build - rm -rf doc - rm -rf test/testdb - rm -f mkmf.log - rm -f rbejdb*.gem - -.PHONY: all build install check doc build-gem clean diff --git a/rbejdb/README.md b/rbejdb/README.md deleted file mode 100644 index 0d0e162..0000000 --- a/rbejdb/README.md +++ /dev/null @@ -1,64 +0,0 @@ -Embedded JSON database library Ruby binding -============================================================ - -Installation ------------------------------------------------------ - -**Required tools/system libraries:** - -* gcc -* **ruby >= 1.9.1 and ruby-dev** -* EJDB C library **libtcejdb-dev** ([from sources](https://github.com/Softmotions/ejdb#manual-installation) or as [debian packages](https://github.com/Softmotions/ejdb/wiki/Debian-Ubuntu-installation)) - -**(A) Installing directly from sources** - -``` -git clone https://github.com/Softmotions/ejdb.git -cd ./rbejdb -make && sudo make install && make check -``` - -One snippet intro ---------------------------------- - -```Ruby -require "rbejdb" - -#Open zoo DB -jb = EJDB.open("zoo", EJDB::DEFAULT_OPEN_MODE | EJDB::JBOTRUNC) - -parrot1 = { - "name" => "Grenny", - "type" => "African Grey", - "male" => true, - "age" => 1, - "birthdate" => Time.now, - "likes" => ["green color", "night", "toys"], - "extra1" => nil -} -parrot2 = { - "name" => "Bounty", - "type" => "Cockatoo", - "male" => false, - "age" => 15, - "birthdate" => Time.now, - "likes" => ["sugar cane"], - "extra1" => nil -} - -jb.save("parrots", parrot1, parrot2) -puts "Grenny OID: #{parrot1["_id"]}" -puts "Bounty OID: #{parrot2["_id"]}" - -results = jb.find("parrots", {"likes" => "toys"}, {"$orderby" => {"name" => 1}}) - -puts "Found #{results.count} parrots" - -results.each { |res| - puts "#{res['name']} likes toys!" -} - -results.close #It's not mandatory to close cursor explicitly -jb.close #Close the database - -``` diff --git a/rbejdb/ext/rbejdb/extconf.rb b/rbejdb/ext/rbejdb/extconf.rb deleted file mode 100644 index 4fe9048..0000000 --- a/rbejdb/ext/rbejdb/extconf.rb +++ /dev/null @@ -1,9 +0,0 @@ -require "mkmf" - -unless have_library('tcejdb') - raise "EJDB C library is not installed!" -end - -$CFLAGS << ' -Wall' -CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '') -create_makefile("rbejdb", ARGV[0] || 'src') \ No newline at end of file diff --git a/rbejdb/ext/rbejdb/src/rbbson.c b/rbejdb/ext/rbejdb/src/rbbson.c deleted file mode 100644 index 4d8ef18..0000000 --- a/rbejdb/ext/rbejdb/src/rbbson.c +++ /dev/null @@ -1,444 +0,0 @@ -/************************************************************************************************** - * Ruby BSON API for EJDB database library http://ejdb.org - * Copyright (C) 2012-2013 Softmotions Ltd - * - * This file is part of EJDB. - * EJDB is free software; you can redistribute it and/or modify it under the terms of - * the GNU Lesser General Public License as published by the Free Software Foundation; either - * version 2.1 of the License or any later version. EJDB is distributed in the hope - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * You should have received a copy of the GNU Lesser General Public License along with EJDB; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA. - *************************************************************************************************/ -#include "rbbson.h" - -#include -#include - -#define BSON_CONTEXT_RUBY_CLASS "EJDB_BSON_CONTEXT" -#define BSON_RUBY_CLASS "EJDB_BSON" - -typedef struct { - bson* bsonval; - bool owns_bsonval; - - VALUE obj; - int arrayIndex; - int flags; - - VALUE traverse_hash; -} RBBSON_CONTEXT; - -typedef struct { - bson* bsonval; -} RBBSON; - - -VALUE iterate_array_callback(VALUE val, VALUE bsonContextWrap); - -VALUE bson_array_to_ruby(bson_iterator* it); - -bson_date_t ruby_time_to_bson_internal(VALUE time); - -void ruby_to_bson_internal(VALUE rbobj, bson** bsonresp, VALUE traverse, int flags); - -VALUE bson_date_to_ruby(bson_date_t date); - -VALUE bson_regex_to_ruby(const char* regex, const char* opts); - - -VALUE bsonContextClass = Qnil; -VALUE bsonWrapClass = Qnil; - - -void rbbson_private_new_method_stub(VALUE clazz) { - VALUE className = rb_inspect(clazz); - rb_raise(rb_eRuntimeError, "%s is internal EJDB class and cannot be instantiated!", StringValuePtr(className)); -} - -void init_ruby_to_bson() { - bsonContextClass = rb_define_class(BSON_CONTEXT_RUBY_CLASS, rb_cObject); - bsonWrapClass = rb_define_class(BSON_RUBY_CLASS, rb_cObject); - rb_define_singleton_method(bsonContextClass, "new", RUBY_METHOD_FUNC(rbbson_private_new_method_stub), 0); - rb_define_singleton_method(bsonWrapClass, "new", RUBY_METHOD_FUNC(rbbson_private_new_method_stub), 0); -} - -void rbbson_context_mark(RBBSON_CONTEXT* rbbsctx) { - rb_gc_mark(rbbsctx->obj); - rb_gc_mark(rbbsctx->traverse_hash); -} - -void rbbson_context_free(RBBSON_CONTEXT* rbbsctx) { - if (rbbsctx->bsonval && rbbsctx->owns_bsonval) { - bson_del(rbbsctx->bsonval); - } - ruby_xfree(rbbsctx); -} - -void rbbson_free(RBBSON* rbbson) { - ruby_xfree(rbbson); -} - - -VALUE createBsonContextWrap(bson* bsonval, bool owns_bsonval, VALUE rbobj, VALUE traverse, int flags) { - if (NIL_P(bsonContextClass)) { - if (owns_bsonval) { - bson_del(bsonval); - } - rb_raise(rb_eRuntimeError, "Ruby to BSON library must be initialized"); - } - VALUE bsonContextWrap = Data_Wrap_Struct(bsonContextClass, rbbson_context_mark, rbbson_context_free, ruby_xmalloc(sizeof(RBBSON_CONTEXT))); - - RBBSON_CONTEXT* rbbsctx; - Data_Get_Struct(bsonContextWrap, RBBSON_CONTEXT, rbbsctx); - rbbsctx->bsonval = bsonval; - rbbsctx->owns_bsonval = owns_bsonval; - rbbsctx->obj = rbobj; - rbbsctx->arrayIndex = 0; - rbbsctx->flags= flags; - rbbsctx->traverse_hash = !NIL_P(traverse) ? traverse : rb_hash_new(); - - return bsonContextWrap; -} - -VALUE createBsonWrap(bson* bsonval) { - if (NIL_P(bsonWrapClass)) { - rb_raise(rb_eRuntimeError, "Ruby to BSON library must be initialized"); - } - VALUE bsonWrap = Data_Wrap_Struct(bsonWrapClass, NULL, rbbson_free, ruby_xmalloc(sizeof(RBBSON))); - RBBSON* rbbson; - Data_Get_Struct(bsonWrap, RBBSON, rbbson); - - rbbson->bsonval = bsonval; - return bsonWrap; -} - -void add_ruby_to_traverse(VALUE rbobj, VALUE traverse) { - Check_Type(traverse, T_HASH); - - if (!NIL_P(rb_hash_aref(traverse, rbobj))) { - rb_raise(rb_eRuntimeError, "Converting circular structure to BSON"); - } - rb_hash_aset(traverse, rbobj, Qtrue); -} - - -int iterate_key_values_callback(VALUE key, VALUE val, VALUE bsonContextWrap) { - key = rb_funcall(key, rb_intern("to_s"), 0); - char* attrName = StringValuePtr(key); - - if (attrName[0] == '@') attrName++; // hack, removing @ - - RBBSON_CONTEXT* rbbsctx; - Data_Get_Struct(bsonContextWrap, RBBSON_CONTEXT, rbbsctx); - bson* b = rbbsctx->bsonval; - - switch (TYPE(val)) { - case T_OBJECT: - if (0 == strcmp(rb_obj_classname(val), "EJDBBinary")) { - VALUE bdata = rb_iv_get(val, "@data"); - Check_Type(bdata, T_ARRAY); - - int length = NUM2INT(rb_funcall(bdata, rb_intern("length"), 0)); - char* buf = (char*) malloc(sizeof(char) * length); - int i; - - for (i = 0; i < length; i++) { - VALUE byte = rb_ary_entry(bdata, i); - buf[i] = (char) NUM2INT(byte); - } - - bson_append_binary(b, attrName, BSON_BIN_BINARY, buf, length); - - free(buf); - break; - } - //else same as hash :) - case T_HASH: { - bson* subbson; - ruby_to_bson_internal(val, &subbson, rbbsctx->traverse_hash, rbbsctx->flags); - bson_append_bson(b, attrName, subbson); - bson_del(subbson); - } - break; - case T_ARRAY: - add_ruby_to_traverse(val, rbbsctx->traverse_hash); - bson_append_start_array(b, attrName); - rb_iterate(rb_each, val, iterate_array_callback, createBsonContextWrap(b, false, rbbsctx->obj, rbbsctx->traverse_hash, rbbsctx->flags)); - bson_append_finish_array(b); - break; - case T_STRING: - if (0 != strcmp("_id", attrName)) { - bson_append_string(b, attrName, StringValuePtr(val)); - } else { - bson_oid_t oid = ruby_to_bson_oid(val); - bson_append_oid(b, attrName, &oid); - } - break; - case T_SYMBOL: { - if (rbbsctx->flags & RUBY_TO_BSON_AS_QUERY) { - rb_raise(rb_eRuntimeError, "Symbol values in queries are not supported"); - } - VALUE sname = rb_funcall(val, rb_intern("to_s"), 0); - bson_append_symbol(b, attrName, StringValuePtr(sname)); - } - break; - case T_FIXNUM: - bson_append_long(b, attrName, NUM2LONG(val)); - break; - case T_BIGNUM: - bson_append_long(b, attrName, rb_big2ll(val)); - break; - case T_FLOAT: - bson_append_double(b, attrName, NUM2DBL(val)); - break; - case T_DATA: - if (0 == strcmp(rb_obj_classname(val), "Time")) { - bson_append_date(b, attrName, ruby_time_to_bson_internal(val)); - } else { - rb_raise(rb_eRuntimeError, "Cannot convert ruby data object to bson: %s", rb_obj_classname(val)); - } - break; - case T_REGEXP: { - VALUE regexp = rb_inspect(val); - VALUE source = rb_funcall(val, rb_intern("source"), 0); - bson_append_regex(b, attrName, StringValuePtr(source), StringValuePtr(regexp) + 2 + strlen(StringValuePtr(source))); // "2" for skipping "//" :) - } - break; - case T_TRUE: - bson_append_bool(b, attrName, 1); - break; - case T_FALSE: - bson_append_bool(b, attrName, 0); - break; - case T_NIL: - bson_append_null(b, attrName); - break; - default: { - VALUE objStr = rb_inspect(val); - rb_raise(rb_eRuntimeError, "Cannot convert ruby value to bson: %s: %s", rb_obj_classname(val), StringValuePtr(objStr)); - } - } - return 0; -} - -VALUE iterate_array_callback(VALUE val, VALUE bsonContextWrap) { - RBBSON_CONTEXT* rbbsctx; - Data_Get_Struct(bsonContextWrap, RBBSON_CONTEXT, rbbsctx); - - iterate_key_values_callback(INT2NUM(rbbsctx->arrayIndex++), val, bsonContextWrap); - return val; -} - -VALUE iterate_object_attrs_callback(VALUE key, VALUE bsonContextWrap) { - RBBSON_CONTEXT* rbbsctx; - Data_Get_Struct(bsonContextWrap, RBBSON_CONTEXT, rbbsctx); - VALUE val = rb_funcall(rbbsctx->obj, rb_intern("instance_variable_get"), 1, key); - - iterate_key_values_callback(key, val, bsonContextWrap); - return val; -} - -bson_date_t ruby_time_to_bson_internal(VALUE time) { - VALUE microsecs = rb_funcall(time, rb_intern("to_f"), 0); - Check_Type(microsecs, T_FLOAT); - return (bson_date_t) NUM2DBL(microsecs) * 1000; -} - - -void ruby_object_to_bson_internal(VALUE rbobj, VALUE bsonContextWrap) { - Check_Type(rbobj, T_OBJECT); - - VALUE attrs = rb_funcall(rbobj, rb_intern("instance_variables"), 0); - Check_Type(attrs, T_ARRAY); - - rb_iterate(rb_each, attrs, iterate_object_attrs_callback, bsonContextWrap); -} - -void ruby_hash_to_bson_internal(VALUE rbhash, VALUE bsonContextWrap) { - Check_Type(rbhash, T_HASH); - rb_hash_foreach(rbhash, iterate_key_values_callback, bsonContextWrap); -} - - -void ruby_to_bson_internal(VALUE rbobj, bson** bsonresp, VALUE traverse, int flags) { - - bson* bsonval = bson_create(); - - if (flags & RUBY_TO_BSON_AS_QUERY) { - bson_init_as_query(bsonval); - } else { - bson_init(bsonval); - } - - VALUE bsonContextWrap = createBsonContextWrap(bsonval, true, rbobj, traverse, flags); - RBBSON_CONTEXT* rbbsctx; - Data_Get_Struct(bsonContextWrap, RBBSON_CONTEXT, rbbsctx); - - add_ruby_to_traverse(rbobj, rbbsctx->traverse_hash); - - switch (TYPE(rbobj)) { - case T_OBJECT: - case T_DATA: - ruby_object_to_bson_internal(rbobj, bsonContextWrap); - break; - case T_HASH: - ruby_hash_to_bson_internal(rbobj, bsonContextWrap); - break; - default: { - VALUE objStr = rb_inspect(rbobj); - rb_raise(rb_eRuntimeError, "Cannot convert object to bson: %s: %s", rb_obj_classname(rbobj), StringValuePtr(objStr)); - } - } - - bson_finish(rbbsctx->bsonval); - - *bsonresp = bson_create(); - bson_copy(*bsonresp, rbbsctx->bsonval); -} - -void ruby_to_bson(VALUE rbobj, bson** bsonresp, int flags) { - ruby_to_bson_internal(rbobj, bsonresp, Qnil, flags); -} - - - -VALUE bson_iterator_to_ruby(bson_iterator* it, bson_type t) { - VALUE val; - switch (t) { - case BSON_OID: - val = bson_oid_to_ruby(bson_iterator_oid(it)); - break; - case BSON_STRING: - val = rb_str_new2(bson_iterator_string(it)); - break; - case BSON_SYMBOL: - val = ID2SYM(rb_intern(bson_iterator_string(it))); - break; - case BSON_BOOL: - val = bson_iterator_bool(it) ? Qtrue : Qfalse; - break; - case BSON_INT: - val = INT2NUM(bson_iterator_int(it)); - break; - case BSON_LONG: - val = LONG2NUM(bson_iterator_long(it)); - break; - case BSON_DOUBLE: - val = rb_float_new(bson_iterator_double(it)); - break; - case BSON_DATE: - val = bson_date_to_ruby(bson_iterator_date(it)); - break; - case BSON_REGEX: - val = bson_regex_to_ruby(bson_iterator_regex(it), bson_iterator_regex_opts(it)); - break; - case BSON_OBJECT: { - bson subbson; - bson_iterator_subobject(it, &subbson); - val = bson_to_ruby(&subbson); - } - break; - case BSON_ARRAY: - val = bson_array_to_ruby(it); - break; - case BSON_BINDATA: { - const char* buf = bson_iterator_bin_data(it); - int length = bson_iterator_bin_len(it); - - VALUE bdata = rb_ary_new(); - int i; - for (i = 0; i < length; i++) { - rb_ary_push(bdata, INT2NUM((unsigned char) buf[i])); - } - - val = rb_funcall(rb_path2class("EJDBBinary"), rb_intern("new"), 1, bdata); - } - break; - case BSON_NULL: - val = Qnil; - break; - default: - rb_raise(rb_eRuntimeError, "Cannot convert object from bson: %d", t); - } - - return val; -} - -VALUE bson_array_to_ruby(bson_iterator* it) { - VALUE res = rb_ary_new(); - - bson_iterator nit; - bson_iterator_subiterator(it, &nit); - - while (bson_iterator_next(&nit) != BSON_EOO) { - rb_ary_push(res, bson_iterator_to_ruby(&nit, bson_iterator_type(&nit))); - } - - return res; -} - -VALUE bson_date_to_ruby(bson_date_t date) { - return rb_funcall(rb_path2class("Time"), rb_intern("at"), 2, - INT2NUM(date / 1000), // seconds - INT2NUM((date % 1000) * 1000)); // microseconds -} - -VALUE bson_regex_to_ruby(const char* regex, const char* opts) { - char* regexbuf = malloc(sizeof(char) * (strlen(regex) + strlen(opts) + 3)); // 3 for // and 0 - sprintf(regexbuf, "/%s/%s", regex, opts); - VALUE res = rb_eval_string(regexbuf); - - free(regexbuf); - return res; -} - - -VALUE bson_to_ruby(const bson* bsonval) { - VALUE res = rb_hash_new(); - - bson_iterator it; - bson_iterator_init(&it, bsonval); - - while (bson_iterator_next(&it) != BSON_EOO) { - rb_hash_aset(res, rb_str_new2(bson_iterator_key(&it)), - bson_iterator_to_ruby(&it, bson_iterator_type(&it))); - } - return res; -} - -VALUE bson_to_ruby_wrapper(VALUE bsonWrap) { - RBBSON* rbbson; - Data_Get_Struct(bsonWrap, RBBSON, rbbson); - return bson_to_ruby(rbbson->bsonval); -} - -VALUE bson_to_ruby_ensure_del_wrapper(VALUE bsonWrap, VALUE exception) { - RBBSON* rbbson; - Data_Get_Struct(bsonWrap, RBBSON, rbbson); - if (rbbson->bsonval) { - bson_del(rbbson->bsonval); - } - rbbson->bsonval = NULL; - return Qnil; -} - -VALUE bson_to_ruby_ensure_del(bson* bsonval) { - VALUE bsonWrap = createBsonWrap(bsonval); - return rb_ensure(bson_to_ruby_wrapper, bsonWrap, bson_to_ruby_ensure_del_wrapper, bsonWrap); -} - -VALUE bson_oid_to_ruby(const bson_oid_t* oid) { - char oidhex[25]; - bson_oid_to_string(oid, oidhex); - return rb_str_new2(oidhex); -} - -bson_oid_t ruby_to_bson_oid(VALUE rboid) { - bson_oid_t oid; - bson_oid_from_string(&oid, StringValuePtr(rboid)); - return oid; -} diff --git a/rbejdb/ext/rbejdb/src/rbbson.h b/rbejdb/ext/rbejdb/src/rbbson.h deleted file mode 100644 index 5820ef5..0000000 --- a/rbejdb/ext/rbejdb/src/rbbson.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * File: rbbson.h - * Author: yudanov - * - * Created on March 25, 2013, 2:31 PM - */ - -#ifndef RBBSON_H -#define RBBSON_H - -#include -#include - -#define RUBY_TO_BSON_AS_QUERY 1 - -#ifdef __cplusplus -extern "C" { -#endif - - void init_ruby_to_bson(); - - void ruby_to_bson(VALUE rbobj, bson** bsonbuf, int flags); - - VALUE bson_to_ruby(const bson* bsonval); - - VALUE bson_to_ruby_ensure_del(bson* bsonval); - - - VALUE bson_oid_to_ruby(const bson_oid_t* oid); - - bson_oid_t ruby_to_bson_oid(VALUE rboid); - -#ifdef __cplusplus -} -#endif - -#endif /* RBBSON_H */ - diff --git a/rbejdb/ext/rbejdb/src/rbejdb.c b/rbejdb/ext/rbejdb/src/rbejdb.c deleted file mode 100644 index 983760f..0000000 --- a/rbejdb/ext/rbejdb/src/rbejdb.c +++ /dev/null @@ -1,1435 +0,0 @@ -/************************************************************************************************** - * Ruby API for EJDB database library http://ejdb.org - * Copyright (C) 2012-2013 Softmotions Ltd - * - * This file is part of EJDB. - * EJDB is free software; you can redistribute it and/or modify it under the terms of - * the GNU Lesser General Public License as published by the Free Software Foundation; either - * version 2.1 of the License or any later version. EJDB is distributed in the hope - * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * You should have received a copy of the GNU Lesser General Public License along with EJDB; - * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307 USA. - *************************************************************************************************/ - -/* - * Document-class: EJDB - * Main EJDB class that contains all database control methods. Instance should be created by EJDB::open - */ - -/* - * Document-class: EJDBQuery - * :nodoc: - * Internal EJDB class - */ - -/* - * Document-class: EJDBResults - * Class for accessing EJDB query resuts. Access to results is provided by methods of {Enumerble}[http://ruby-doc.org/core-1.9.1/Enumerable.html] mixin. - * Instance of this class can be created only by calling EJDB.find method. - */ - -/* - * Document-class: EJDBBinary - * Class for wrapping ruby binary data array to save as BSON binary. Access to data array is provided by methods of {Enumerble}[http://ruby-doc.org/core-1.9.1/Enumerable.html] mixin. - * - * Example: - * secret = EJDBBinary.new("Some binary secrect".encode("utf-8").bytes.to_a) - * our_string_back = secret.to_a.pack("U*") - */ - -#include -#include - -#include "rbbson.h" - -#define DEFAULT_OPEN_MODE (JBOWRITER | JBOCREAT) - -typedef struct { - EJDB* ejdb; -} RBEJDB; - -typedef struct { - TCLIST* results; - TCLIST* results_raw; - uint32_t count; - TCXSTR* log; -} RBEJDB_RESULTS; - -typedef struct { - bson* qbson; - bson* hintsbson; - int orarrlng; - bson* orarrbson; -} RBEJDB_QUERY; - - -VALUE create_EJDB_query_results(TCLIST* qres, uint32_t count, TCXSTR *log); - - -VALUE ejdbClass; -VALUE ejdbResultsClass; -VALUE ejdbBinaryClass; -VALUE ejdbQueryClass; - - -void private_new_method_stub(VALUE clazz) { - VALUE className = rb_inspect(clazz); - rb_raise(rb_eRuntimeError, "%s is internal EJDB class and cannot be instantiated!", StringValuePtr(className)); -} - - -VALUE get_hash_option(VALUE hash, const char* opt) { - Check_Type(hash, T_HASH); - - VALUE res = Qnil; - - ID symId = rb_intern(opt); - - if (symId) { - VALUE symbol = ID2SYM(symId); - if (TYPE(symbol) == T_SYMBOL) { - res = rb_hash_aref(hash, symbol); - } - } - - return !NIL_P(res) ? res : rb_hash_aref(hash, rb_str_new2(opt)); -} - -int raise_ejdb_error(EJDB *ejdb) { - int ecode = ejdbecode(ejdb); - const char *emsg = ejdberrmsg(ecode); - rb_raise(rb_eRuntimeError, "%s", emsg); -} - -VALUE nil_or_raise_ejdb_error(EJDB *ejdb) { - int ecode = ejdbecode(ejdb); - if (ecode != TCESUCCESS && ecode != TCENOREC) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - - -EJDB* getEJDB(VALUE self) { - RBEJDB* rejdb; - Data_Get_Struct(self, RBEJDB, rejdb); - return rejdb->ejdb; -} - - -VALUE EJDB_new(VALUE self) { - rb_raise(rb_eRuntimeError, "EJDB.open() method should be used!"); - return self; -} - -void EJDB_free(RBEJDB* rejdb) { - if (rejdb->ejdb) { - ejdbclose(rejdb->ejdb); - ejdbdel(rejdb->ejdb); - } - ruby_xfree(rejdb); -} - - -/* - * call-seq: - * EJDB::open(path, mode) -> EJDB - * - * Open database. Return database instance handle object. - * Default open mode: JBOWRITER | JBOCREAT . - * - * - +path+ (String) - database main file name - * - +mode+ (Number) - bitmask of open modes: - * - * [JBOREADER] Open as a reader. - * [JBOWRITER] Open as a writer. - * [JBOCREAT] Create if db file not exists - * [JBOTRUNC] Truncate db. - * - */ -VALUE EJDB_open(VALUE clazz, VALUE path, VALUE mode) { - SafeStringValue(path); - Check_Type(mode, T_FIXNUM); - - VALUE ejdbWrap = Data_Wrap_Struct(clazz, NULL, EJDB_free, ruby_xmalloc(sizeof(RBEJDB))); - - RBEJDB* rejdb; - Data_Get_Struct(ejdbWrap, RBEJDB, rejdb); - - rejdb->ejdb = ejdbnew(); - - if (!rejdb->ejdb) { - rb_raise(rb_eRuntimeError, "Failed to init ejdb!"); - } - - if (!ejdbopen(rejdb->ejdb, StringValuePtr(path), NUM2INT(mode))) { - raise_ejdb_error(rejdb->ejdb); - } - return ejdbWrap; -} - -/* - * call-seq: - * ejdb.open? -> true|false - * - * Check if database in opened state. - */ -VALUE EJDB_is_open(VALUE self) { - EJDB* ejdb = getEJDB(self); - return ejdb && ejdbisopen(ejdb) ? Qtrue : Qfalse; -} - - -/* - * call-seq: - * ejdb.close -> nil - * - * Close database. - * If database was not opened it does nothing. - */ -VALUE EJDB_close(VALUE self) { - ejdbclose(getEJDB(self)); - return Qnil; -} - -/* - * call-seq: - * ejdb.ensure_collection(collName, [copts]) -> nil - * - * Automatically creates new collection if it does't exists. Collection options +copts+ applied only for newly created collection. - * For existing collections +copts+ takes no effect. - * - * Collection options (copts): - * [:cachedrecords] Max number of cached records in shared memory segment. Default: 0 - * [:records] Estimated number of records in this collection. Default: 65535. - * [:large] Specifies that the size of the database can be larger than 2GB. Default: false - * [:compressed] If true collection records will be compressed with DEFLATE compression. Default: false. - */ -VALUE EJDB_ensure_collection(int argc, VALUE* argv, VALUE self) { - VALUE collName; - VALUE copts; - - rb_scan_args(argc, argv, "11", &collName, &copts); - - SafeStringValue(collName); - - EJCOLLOPTS jcopts = {NULL}; - if (!NIL_P(copts)) { - Check_Type(copts, T_HASH); - - VALUE cachedrecords = get_hash_option(copts, "cachedrecords"); - VALUE compressed = get_hash_option(copts, "compressed"); - VALUE large = get_hash_option(copts, "large"); - VALUE records = get_hash_option(copts, "records"); - - jcopts.cachedrecords = !NIL_P(cachedrecords) ? NUM2INT(cachedrecords) : 0; - jcopts.compressed = RTEST(compressed); - jcopts.large = RTEST(large); - jcopts.records = !NIL_P(records) ? NUM2INT(records) : 0; - } - - EJDB* ejdb = getEJDB(self); - - if (!ejdbcreatecoll(ejdb, StringValuePtr(collName), &jcopts)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.drop_collection(collName, [prune=false]) -> nil - * - * Drop collection. - * - +collName+ (String) - name of collection - * - +prune+ (true|false) - if true the collection data will be erased from disk. - */ -VALUE EJDB_drop_collection(int argc, VALUE* argv, VALUE self) { - VALUE collName; - VALUE prune; - - rb_scan_args(argc, argv, "11", &collName, &prune); - SafeStringValue(collName); - - EJDB* ejdb = getEJDB(self); - if (!ejdbrmcoll(ejdb, StringValuePtr(collName), RTEST(prune))) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.save(collName, [obj1, …, objN, merge = false]) -> Array or Number or nil - * - * Save/update specified hashes or Ruby objects in the collection. If collection with +collName+ does not exists it will be created. - * Each persistent object has unique identifier (OID) placed in the _id property. If a saved object does not have _id it will be autogenerated. - * To identify and update object it should contains _id property. - * - * NOTE: Field names of passed objects may not contain $ and . characters, error condition will be fired in this case. - * - +collName+ (String) - name of collection - * - +obj+ (Hash or Object) - one or more objects to save - * - +merge+ (Hash or Object) - if true a saved objects will be merged with who's - * - * - * Returns: - * - oid of saved object, as string, if single object provided in arguments - * - array of oids, in other case - */ -VALUE EJDB_save(int argc, VALUE *argv, VALUE self) { - if (argc < 1) { - rb_raise(rb_eArgError, "Error calling EJDB.save(): need to specify collection name"); - } - - VALUE collName = argv[0]; - Check_Type(collName, T_STRING); - - bool merge = TYPE(argv[argc - 1]) == T_TRUE; - - EJDB* ejdb = getEJDB(self); - - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - VALUE oids = rb_ary_new(); - int i; - for (i = 1; i < argc; i++) { - VALUE rbobj = argv[i]; - - if (i == argc - 1 && (TYPE(rbobj) == T_TRUE || TYPE(rbobj) == T_FALSE)) break; - - if (NIL_P(rbobj)) { - rb_ary_push(oids, Qnil); - continue; - } - - if (TYPE(rbobj) != T_HASH && TYPE(rbobj) != T_OBJECT && TYPE(rbobj) != T_DATA) { - rb_raise(rb_eArgError, "Cannot save passed ruby value: %s", rb_obj_classname(rbobj)); - } - - bson* bsonval; - ruby_to_bson(rbobj, &bsonval, 0); - - bson_oid_t oid; - bool saved = ejdbsavebson2(coll, bsonval, &oid, merge); - bson_del(bsonval); - - if (!saved) { - raise_ejdb_error(ejdb); - } - - VALUE roid = bson_oid_to_ruby(&oid); - rb_ary_push(oids, roid); - - switch(TYPE(rbobj)) { - case T_HASH: - rb_hash_aset(rbobj, rb_str_new2("_id"), roid); - break; - default: - rb_iv_set(rbobj, "@id", roid); - } - } - - switch (RARRAY_LEN(oids)) { - case 0 : return Qnil; - case 1: return rb_ary_pop(oids); - default: return oids; - } -} - -/* - * call-seq: - * ejdb.load(collName, oid) -> Hash or nil - * - * Loads JSON object identified by OID from the collection. - * - * - +collName+ (String) - name of collection - * - +oid+ (String) - object identifier (OID) - * - * - * Returns: - * - BSON object as hash - * - nil, if it is not found - */ -VALUE EJDB_load(VALUE self, VALUE collName, VALUE rboid) { - SafeStringValue(collName); - SafeStringValue(rboid); - - EJDB* ejdb = getEJDB(self); - - EJCOLL *coll = ejdbgetcoll(ejdb, StringValuePtr(collName)); - if (!coll) { - return nil_or_raise_ejdb_error(ejdb); - } - - bson_oid_t oid = ruby_to_bson_oid(rboid); - bson *bs = ejdbloadbson(coll, &oid); - - return bs ? bson_to_ruby_ensure_del(bs) : nil_or_raise_ejdb_error(ejdb); -} - -/* - * call-seq: - * ejdb.remove(collName, oid) -> nil - * - * Removes JSON object from the collection. - * - * - +collName+ (String) - name of collection - * - +oid+ (String) - object identifier (OID) - */ -VALUE EJDB_remove(VALUE self, VALUE collName, VALUE rboid) { - SafeStringValue(collName); - SafeStringValue(rboid); - - EJDB* ejdb = getEJDB(self); - - EJCOLL *coll = ejdbgetcoll(ejdb, StringValuePtr(collName)); - if (!coll) { - raise_ejdb_error(ejdb); - } - - bson_oid_t oid = ruby_to_bson_oid(rboid); - if (!ejdbrmbson(coll, &oid)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - - -void prepare_query_hint(VALUE res, VALUE hints, const char* hint) { - VALUE val = get_hash_option(hints, hint); - if (!NIL_P(val)) { - rb_hash_aset(res, rb_str_concat(rb_str_new2("$"), rb_str_new2(hint)), val); - } -} - -VALUE prepare_query_hints(VALUE hints) { - VALUE res = rb_hash_new(); - prepare_query_hint(res, hints, "orderby"); - prepare_query_hint(res, hints, "max"); - prepare_query_hint(res, hints, "skip"); - prepare_query_hint(res, hints, "fields"); - return res; -} - -void EJDB_remove_query_internal(RBEJDB_QUERY* rbquery) { - if (rbquery->qbson) { - bson_del(rbquery->qbson); - rbquery->qbson = NULL; - } - if (rbquery->hintsbson) { - bson_del(rbquery->hintsbson); - rbquery->hintsbson = NULL; - } - if (rbquery->orarrbson) { - int i; - for (i = 0; i < rbquery->orarrlng; i++) { - bson_destroy(rbquery->orarrbson + i); - } - free(rbquery->orarrbson); - rbquery->orarrbson = NULL; - } -} - -VALUE EJDB_query_free(RBEJDB_QUERY* rbquery) { - ruby_xfree(rbquery); - return Qnil; -} - -VALUE EJDB_find_internal(VALUE self, VALUE collName, VALUE queryWrap, VALUE q, VALUE orarr, VALUE hints) { - RBEJDB_QUERY* rbquery; - Data_Get_Struct(queryWrap, RBEJDB_QUERY, rbquery); - - VALUE orarrlng = rb_funcall(orarr, rb_intern("length"), 0); - rbquery->qbson = NULL; - rbquery->hintsbson = NULL; - rbquery->orarrbson = NUM2INT(orarrlng) ? (bson*) malloc(NUM2INT(orarrlng) * sizeof(bson)) : NULL; - rbquery->orarrlng = 0; - - ruby_to_bson(q, &(rbquery->qbson), RUBY_TO_BSON_AS_QUERY); - - int i = 0; - while(!NIL_P(rb_ary_entry(orarr, 0))) { - VALUE orq = rb_ary_shift(orarr); - bson* orqbson; - ruby_to_bson(orq, &orqbson, RUBY_TO_BSON_AS_QUERY); - bson_copy(rbquery->orarrbson + (i++), orqbson); - bson_del(orqbson); - rbquery->orarrlng++; - } - - ruby_to_bson(prepare_query_hints(hints), &(rbquery->hintsbson), RUBY_TO_BSON_AS_QUERY); - - bool onlycount = RTEST(get_hash_option(hints, "onlycount")); - bool explain = RTEST(get_hash_option(hints, "explain")); - bool createResults = !onlycount || explain; - - EJDB* ejdb = getEJDB(self); - - EJCOLL *coll = ejdbgetcoll(ejdb, StringValuePtr(collName)); - if (!coll) { - bson_iterator it; - if (bson_find(&it, rbquery->qbson, "$upsert") == BSON_OBJECT) { - coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - } - if (!coll) { - return createResults ? create_EJDB_query_results(tclistnew2(1), 0, NULL) : INT2NUM(0); - } - } - - EJQ *ejq = ejdbcreatequery(ejdb, rbquery->qbson, rbquery->orarrbson, NUM2INT(orarrlng), rbquery->hintsbson); - if (!ejq) { - raise_ejdb_error(ejdb); - } - - uint32_t count; - int qflags = onlycount ? EJQONLYCOUNT : 0; - TCXSTR *log = explain ? tcxstrnew() : NULL; - - TCLIST* qres = ejdbqryexecute(coll, ejq, &count, qflags, log); - ejdbquerydel(ejq); - - if (!createResults) { - tclistdel(qres); - } - - return createResults ? create_EJDB_query_results(qres, count, log) : UINT2NUM(count); -} - -VALUE EJDB_find_internal_wrapper(VALUE args) { - return EJDB_find_internal(rb_ary_pop(args), rb_ary_pop(args), rb_ary_pop(args), - rb_ary_pop(args), rb_ary_pop(args), rb_ary_pop(args)); -} - -VALUE EJDB_find_ensure(VALUE queryWrap, VALUE exception) { - RBEJDB_QUERY* rbquery; - Data_Get_Struct(queryWrap, RBEJDB_QUERY, rbquery); - EJDB_remove_query_internal(rbquery); - return Qnil; -} - - -/* - * call-seq: - * ejdb.find(collName, [q = {}, orarr = [], hints = {}]) -> EJDBResults or Number - * - * Execute query on collection. EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy. - * Both in query and in +hints+ strings or symbols may be used as keys (f. e. "fpath" and :fpath are equal). - * Supported queries: - * - Simple matching of String OR Number OR Array value: - * - {"fpath" => "val", ...} - * - $not Negate operation. - * - {"fpath" => {"$not" => val}} #Field not equal to val - * - {"fpath" => {"$not" => {"$begin" => prefix}}} #Field not begins with val - * - $begin String starts with prefix - * - {"fpath" => {"$begin" => prefix}} - * - $gt, $gte (>, >=) and $lt, $lte for number types: - * - {"fpath" => {"$gt" => number}, ...} - * - $bt Between for number types: - * - {"fpath" => {"$bt" => [num1, num2]}} - * - $in String OR Number OR Array val matches to value in specified array: - * - {"fpath" => {"$in" => [val1, val2, val3]}} - * - $nin - Not IN - * - $strand String tokens OR String array val matches all tokens in specified array: - * - {"fpath" => {"$strand" => [val1, val2, val3]}} - * - $stror String tokens OR String array val matches any token in specified array: - * - {"fpath" => {"$stror" => [val1, val2, val3]}} - * - $exists Field existence matching: - * - {"fpath" => {"$exists" => true|false}} - * - $icase Case insensitive string matching: - * - {"fpath" => {"$icase" => "val1"}} #icase matching - * Ignore case matching with "$in" operation: - * - {"name" => {"$icase" => {"$in" => ["tHéâtre - театр", "heLLo WorlD"]}}} - * For case insensitive matching you can create special type of string index. - * - $elemMatch The $elemMatch operator matches more than one component within an array element. - * - { array=> { $elemMatch=> { value1 => 1, value2 => { $gt=> 1 } } } } - * Restriction: only one $elemMatch allowed in context of one array field. - * - * Queries can be used to update records: - * - * - $set Field set operation. - * - {.., "$set" => {"field1" => val1, "fieldN" => valN}} - * - $upsert Atomic upsert. If matching records are found it will be "$set" operation, otherwise new record will be - * inserted with fields specified by argment object. - * - {.., "$upsert" => {"field1" => val1, "fieldN" => valN}} - * - $inc Increment operation. Only number types are supported. - * - {.., "$inc" => {"field1" => number, ..., "field1" => number} - * - $dropall In-place record removal operation. - * - {.., "$dropall" => true} - * - $addToSet Atomically adds value to the array only if its not in the array already. If containing array is missing it will be created. - * - {.., "$addToSet" => {"fpath" => val1, "fpathN" => valN, ...}} - * - $addToSetAll Batch version if $addToSet - * - {.., "$addToSetAll" => {"fpath" => [array of values to add], ...}} - * - $pull Atomically removes all occurrences of value from field, if field is an array. - * - {.., "$pull" => {"fpath" => val1, "fpathN" => valN, ...}} - * - $pullAll Batch version of $pull - * - {.., "$pullAll" => {"fpath" => [array of values to remove], ...}} - * - * - * NOTE: It is better to execute update queries with `$onlycount=true` hint flag - * or use the special +update+ method to avoid unnecessarily rows fetching. - * - * NOTE: Negate operations: $not and $nin not using indexes - * so they can be slow in comparison to other matching operations. - * - * NOTE: Only one index can be used in search query operation. - * - * QUERY HINTS (specified by +hints+ argument): - * [:max] Maximum number in the result set - * [:skip] Number of skipped results in the result set - * [:orderby] Sorting order of query fields. - * [:onlycount] If `true` only count of matching records will be returned without placing records in result set. - * [:fields] Set subset of fetched fields - * If a field presented in +:orderby+ clause it will be forced to include in resulting records. - * Example: - * hints = { - * :orderby => { #ORDER BY field1 ASC, field2 DESC - * "field1" => 1, - * "field2" => -1 - * }, - * :fields => { #SELECT ONLY {_id, field1, field2} - * "field1" => 1, - * "field2" => 1 - * } - * } - * - * Many C API query examples can be found in `tcejdb/testejdb/t2.c` test case. - * - * - +collName+ (String) - name of collection - * - +q+ (Hash or Object) - query object. In most cases it will be easier to use hash to specify EJDB queries - * - +orarr+ (Array) - array of additional OR query objects (joined with OR predicate). If 3rd argument is not array it - * will be recognized as +hints+ argument - * - +hints+ (Hash or Object) - object with query hints - * - * - * Returns: - * - EJDBResults object, if no +:onlycount+ hint specified or :explain hint specified - * - results count as Number, otherwise - * - */ -VALUE EJDB_find(int argc, VALUE* argv, VALUE self) { - VALUE collName; - VALUE q; - VALUE orarr; - VALUE hints; - - VALUE p3; - VALUE p4; - - rb_scan_args(argc, argv, "13", &collName, &q, &p3, &p4); - - SafeStringValue(collName); - q = !NIL_P(q) ? q :rb_hash_new(); - orarr = TYPE(p3) == T_ARRAY ? rb_ary_dup(p3) : rb_ary_new(); - hints = TYPE(p3) != T_ARRAY ? p3 : p4; - hints = !NIL_P(hints) ? hints :rb_hash_new(); - - Check_Type(q, T_HASH); - Check_Type(hints, T_HASH); - - VALUE queryWrap = Data_Wrap_Struct(ejdbQueryClass, NULL, EJDB_query_free, ruby_xmalloc(sizeof(RBEJDB_QUERY))); - RBEJDB_QUERY* rbquery; - Data_Get_Struct(queryWrap, RBEJDB_QUERY, rbquery); - rbquery->qbson = NULL; - rbquery->hintsbson = NULL; - rbquery->orarrbson = NULL; - rbquery->orarrlng = 0; - - VALUE params = rb_ary_new3(6, self, collName, queryWrap, q, orarr, hints); - - // Even if exception raised during find() we will free memory, taken for query - return rb_ensure(EJDB_find_internal_wrapper, params, EJDB_find_ensure, queryWrap); -} - -VALUE EJDB_block_true(VALUE yielded_object, VALUE context, int argc, VALUE argv[]){ - return Qtrue; -} - - -/* - * call-seq: - * ejdb.find_one(collName, oid) -> Hash or Number or nil - * - * Same as +find+ but retrieves only one matching object. - * - * - +collName+ (String) - name of collection - * - +q+ (Hash or Object) - query object. In most cases it will be easier to use hash to specify EJDB queries - * - +orarr+ (Array) - array of additional OR query objects (joined with OR predicate). If 3rd argument is not array it - * will be recognized as +hints+ argument - * - +hints+ (Hash or Object) - object with query hints - * - * - * Returns: - * - found object as hash, if no +:onlycount+ hint specified - * - nil, if no +:onlycount+ hint specified and nothing found - * - results count as Number, otherwise - */ -VALUE EJDB_find_one(int argc, VALUE* argv, VALUE self) { - VALUE results = EJDB_find(argc, argv, self); - if (TYPE(results) == T_DATA) { - return rb_block_call(results, rb_intern("find"), 0, NULL, RUBY_METHOD_FUNC(EJDB_block_true), Qnil); // "find" with "always true" block gets first element - } - return results; -} - - -/* - * call-seq: - * ejdb.update(collName, [q = {}, orarr = [], hints = {}]) -> EJDBResults or Number - * - * Convenient method to execute update queries. - * - * - $set Field set operation: - * - {some fields for selection, "$set" => {"field1" => obj, ..., "fieldN" => obj}} - * - $upsert Atomic upsert. If matching records are found it will be "$set" operation, otherwise new record will be inserted with fields specified by argment object. - * - {.., "$upsert" => {"field1" => val1, "fieldN" => valN}} - * - $inc Increment operation. Only number types are supported. - * - {some fields for selection, "$inc" => {"field1" => number, ..., "fieldN" => number} - * - $dropall In-place record removal operation. - * - {some fields for selection, "$dropall" => true} - * - $addToSet | $addToSetAll Atomically adds value to the array only if its not in the array already. If containing array is missing it will be created. - * - {.., "$addToSet" => {"fpath" => val1, "fpathN" => valN, ...}} - * - $pull | pullAll Atomically removes all occurrences of value from field, if field is an array. - * - {.., "$pull" => {"fpath" => val1, "fpathN" => valN, ...}} - * - * - * - +collName+ (String) - name of collection - * - +q+ (Hash or Object) - query object. In most cases it will be easier to use hash to specify EJDB queries - * - +orarr+ (Array) - array of additional OR query objects (joined with OR predicate). If 3rd argument is not array it - * will be recognized as +hints+ argument - * - +hints+ (Hash or Object) - object with query hints - * - * - * Returns: - * - EJDBResults object, with only +count+ and +log+ methods available if :explain hint specified - * - updated objects count as Number, otherwise - */ -VALUE EJDB_update(int argc, VALUE* argv, VALUE self) { - VALUE collName; - VALUE q; - VALUE orarr; - VALUE hints; - - VALUE p3; - VALUE p4; - - rb_scan_args(argc, argv, "13", &collName, &q, &p3, &p4); - - orarr = TYPE(p3) == T_ARRAY ? p3 : rb_ary_new(); - hints = TYPE(p3) != T_ARRAY ? p3 : p4; - hints = !NIL_P(hints) ? hints : rb_hash_new(); - - Check_Type(hints, T_HASH); - rb_hash_aset(hints, rb_str_new2("onlycount"), Qtrue); - - VALUE findargs[4] = {collName, q, orarr, hints}; - return EJDB_find(4, findargs, self); -} - -/** - * call-seq: - * ejdb.command(cmd) -> Hash - * - * Execute the ejdb database command. - * - * Supported commands: - * - * 1) Exports database collections data. See ejdbexport() method. - * - * :export => { - * :path => string, //Exports database collections data - * :cnames => [string array]|nil, //List of collection names to export - * :mode => int|nil //Values: null|`JBJSONEXPORT` See ejdbexport() method - * } - * - * Command response: - * { - * "log" => string, //Diagnostic log about executing this command - * "error" => string|nil, //ejdb error message - * "errorCode" => int|0, //ejdb error code - * } - * - * 2) Imports previously exported collections data into ejdb. - * - * :import => { - * :path => string //The directory path in which data resides - * :cnames => [string array]|nil, //List of collection names to import - * :mode => int|nil //Values: null|`JBIMPORTUPDATE`|`JBIMPORTREPLACE` See ejdbimport() method - * } - * - * Command response: - * { - * "log" => string, //Diagnostic log about executing this command - * "error" => string|nil, //ejdb error message - * "errorCode" => int|0, //ejdb error code - * } - * - * - +cmd+ (Hash or Object) - command spec. - * - * Returns allocated command response object as hash. - */ -VALUE EJDB_command(VALUE self, VALUE command) { - EJDB* ejdb = getEJDB(self); - - bson* bsoncmd; - ruby_to_bson(command, &bsoncmd, 0); - - bson* res = ejdbcommand(ejdb, bsoncmd); - bson_del(bsoncmd); - - if (!res) { - raise_ejdb_error(ejdb); - } - - return bson_to_ruby_ensure_del(res); -} - - -VALUE EJDB_set_index_internal(VALUE self, VALUE collName, VALUE fpath, int flags) { - SafeStringValue(collName); - SafeStringValue(fpath); - - EJDB* ejdb = getEJDB(self); - - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - if (!ejdbsetindex(coll, StringValuePtr(fpath), flags)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.drop_indexes(collName, fpath) -> nil - * - * Drop indexes of all types for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_drop_indexes(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXDROPALL); -}; - -/* - * call-seq: - * ejdb.optimize_indexes(collName, fpath) -> nil - * - * Optimize indexes of all types for BSON field path. Performs B+ tree index file optimization. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_optimize_indexes(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXOP); -}; - -/* - * call-seq: - * ejdb.ensure_string_index(collName, fpath) -> nil - * - * Ensure index presence of String type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_ensure_string_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXSTR); -} - -/* - * call-seq: - * ejdb.rebuild_string_index(collName, fpath) -> nil - * - * Rebuild index of String type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_rebuild_string_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXSTR | JBIDXREBLD); -} - -/* - * call-seq: - * ejdb.drop_string_index(collName, fpath) -> nil - * - * Drop index of String type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_drop_string_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXSTR | JBIDXDROP); -} - -/* - * call-seq: - * ejdb.ensure_istring_index(collName, fpath) -> nil - * - * Ensure index presence of IString type for BSON field path. - * IString is the special type of String index for case insensitive matching. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_ensure_istring_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXISTR); -} - -/* - * call-seq: - * ejdb.rebuild_istring_index(collName, fpath) -> nil - * - * Rebuild index of IString type for BSON field path. - * IString is the special type of String index for case insensitive matching. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_rebuild_istring_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXISTR | JBIDXREBLD); -} - -/* - * call-seq: - * ejdb.drop_istring_index(collName, fpath) -> nil - * - * Drop index of IString type for BSON field path. - * IString is the special type of String index for case insensitive matching. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_drop_istring_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXISTR | JBIDXDROP); -} - -/* - * call-seq: - * ejdb.ensure_number_index(collName, fpath) -> nil - * - * Ensure index of Number type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_ensure_number_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXNUM); -} - -/* - * call-seq: - * ejdb.rebuild_number_index(collName, fpath) -> nil - * - * Rebuild index of Number type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_rebuild_number_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXNUM | JBIDXREBLD); -} - -/* - * call-seq: - * ejdb.drop_number_index(collName, fpath) -> nil - * - * Drop index of Number type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_drop_number_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXNUM | JBIDXDROP); -} - -/* - * call-seq: - * ejdb.ensure_array_index(collName, fpath) -> nil - * - * Ensure index presence of Array type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_ensure_array_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXARR); -} - -/* - * call-seq: - * ejdb.rebuild_array_index(collName, fpath) -> nil - * - * Rebuild index of Array type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_rebuild_array_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXARR | JBIDXREBLD); -} - -/* - * call-seq: - * ejdb.drop_array_index(collName, fpath) -> nil - * - * Drop index of Array type for BSON field path. - * - * - +collName+ (String) - name of collection - * - +fpath+ (String) - BSON field path - */ -VALUE EJDB_drop_array_index(VALUE self, VALUE collName, VALUE fpath) { - return EJDB_set_index_internal(self, collName, fpath, JBIDXARR | JBIDXDROP); -} - -/* - * call-seq: - * ejdb.get_db_meta -> Hash - * - * Get hash that describes a database structure and collections. - * Sample meta: - * { - * "collections" => [ - * { - * "file" => "testdb_ecoll", - * "indexes" => [], - * "name" => "ecoll", - * "options" => { - * "buckets" => 425977, - * "cachedrecords" => 0, - * "compressed" => false, - * "large" => true - * }, - * "records" => 1 - * }, - * { - * "file" => "testdb_mycoll", - * "indexes" => [ { - * "field" => "foo", - * "file" => "testdb_mycoll.idx.sfoo.lex", - * "iname" => "sfoo", - * "records" => 3, - * "type" => "lexical" - * }], - * "name" => "mycoll", - * "options" => { - * "buckets" => 131071, - * "cachedrecords" => 0, - * "compressed" => false, - * "large" => false - * }, - * "records" => 4 - * } - * ], - * "file" => "testdb" - * } - */ -VALUE EJDB_get_db_meta(VALUE self) { - EJDB* ejdb = getEJDB(self); - - TCLIST *cols = ejdbgetcolls(ejdb); - if (!cols) { - raise_ejdb_error(ejdb); - } - - VALUE res = rb_hash_new(); - VALUE collections = rb_ary_new(); - rb_hash_aset(res, rb_str_new2("collections"), collections); - int i, j; - for (i = 0; i < TCLISTNUM(cols); ++i) { - EJCOLL *coll = (EJCOLL*) TCLISTVALPTR(cols, i); - - VALUE collhash = rb_hash_new(); - rb_ary_push(collections, collhash); - rb_hash_aset(collhash, rb_str_new2("name"), rb_str_new2(coll->cname)); - rb_hash_aset(collhash, rb_str_new2("file"), rb_str_new2(coll->tdb->hdb->path)); - rb_hash_aset(collhash, rb_str_new2("records"), INT2NUM(coll->tdb->hdb->rnum)); - - VALUE options = rb_hash_new(); - rb_hash_aset(collhash, rb_str_new2("options"), options); - rb_hash_aset(options, rb_str_new2("buckets"), INT2NUM(coll->tdb->hdb->bnum)); - rb_hash_aset(options, rb_str_new2("cachedrecords"), INT2NUM(coll->tdb->hdb->rcnum)); - rb_hash_aset(options, rb_str_new2("large"), coll->tdb->opts & TDBTLARGE ? Qtrue : Qfalse); - rb_hash_aset(options, rb_str_new2("compressed"), coll->tdb->opts & TDBTDEFLATE ? Qtrue : Qfalse); - - VALUE indexes = rb_ary_new(); - rb_hash_aset(collhash, rb_str_new2("indexes"), indexes); - for (j = 0; j < coll->tdb->inum; ++j) { - TDBIDX *idx = (coll->tdb->idxs + j); - if (idx->type != TDBITLEXICAL && idx->type != TDBITDECIMAL && idx->type != TDBITTOKEN) { - continue; - } - VALUE imeta = rb_hash_new(); - rb_ary_push(indexes, imeta); - rb_hash_aset(imeta, rb_str_new2("filed"), rb_str_new2(idx->name + 1)); - rb_hash_aset(imeta, rb_str_new2("iname"), rb_str_new2(idx->name)); - rb_hash_aset(imeta, rb_str_new2("type"), rb_str_new2( - idx->type == TDBITLEXICAL ? "lexical" : - idx->type == TDBITDECIMAL ? "decimal" : - idx->type == TDBITTOKEN ? "token" : "" - )); - - TCBDB *idb = (TCBDB*) idx->db; - if (idb) { - rb_hash_aset(imeta, rb_str_new2("records"), INT2NUM(idb->rnum)); - rb_hash_aset(imeta, rb_str_new2("file"), rb_str_new2(idb->hdb->path)); - } - } - } - rb_hash_aset(res, rb_str_new2("file"), rb_str_new2(ejdb->metadb->hdb->path)); - - tclistdel(cols); - - return res; -} - -/* - * call-seq: - * ejdb.sync -> nil - * - * Synchronize entire EJDB database with disk. - */ -VALUE EJDB_sync(VALUE self) { - EJDB* ejdb = getEJDB(self); - if (!ejdbsyncdb(ejdb)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.get_transaction_status(collName) -> true|false - * - * Get collection transaction status. Returns true if transaction is active. - * - * - +collName+ (String) - name of collection - */ -VALUE EJDB_get_transaction_status(VALUE self, VALUE collName) { - SafeStringValue(collName); - - EJDB* ejdb = getEJDB(self); - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - bool status; - if (!ejdbtranstatus(coll, &status)) { - raise_ejdb_error(ejdb); - } - - return status ? Qtrue : Qfalse; -} - -/* - * call-seq: - * ejdb.begin_transaction(collName) -> nil - * - * Begin collection transaction. - * - * - +collName+ (String) - name of collection - */ -VALUE EJDB_begin_transaction(VALUE self, VALUE collName) { - SafeStringValue(collName); - - EJDB* ejdb = getEJDB(self); - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - if (!ejdbtranbegin(coll)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.commit_transaction(collName) -> nil - * - * Commit collection transaction. - * - * - +collName+ (String) - name of collection - */ -VALUE EJDB_commit_transaction(VALUE self, VALUE collName) { - SafeStringValue(collName); - - EJDB* ejdb = getEJDB(self); - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - if (!ejdbtrancommit(coll)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * ejdb.rollback_transaction(collName) -> nil - * - * Rollback collection transaction. - * - * - +collName+ (String) - name of collection - */ -VALUE EJDB_rollback_transaction(VALUE self, VALUE collName) { - SafeStringValue(collName); - - EJDB* ejdb = getEJDB(self); - EJCOLL *coll = ejdbcreatecoll(ejdb, StringValuePtr(collName), NULL); - if (!coll) { - raise_ejdb_error(ejdb); - } - - if (!ejdbtranabort(coll)) { - raise_ejdb_error(ejdb); - } - return Qnil; -} - -/* - * call-seq: - * EJDB::valid_oid_string?(oid) -> true|false - * - * Returns true if argument string contains valid oid. - * - * - +oid+ (String) - oid as string - */ -VALUE EJDB_is_valid_oid_string(VALUE clazz, VALUE oid) { - return TYPE(oid) == T_STRING && ejdbisvalidoidstr(StringValuePtr(oid)) ? Qtrue : Qfalse; -} - - -void close_ejdb_results_internal(RBEJDB_RESULTS* rbres) { - if (rbres->results) { - int i; - for (i = 0; i < TCLISTNUM(rbres->results); i++) { - bson* bsonval = *(bson**) TCLISTVALPTR(rbres->results, i); - bson_dispose(bsonval); - } - - tclistdel(rbres->results); - rbres->results = NULL; - } - if (rbres->results_raw) { - tclistdel(rbres->results_raw); - rbres->results_raw = NULL; - } - if (rbres->log) { - tcxstrdel(rbres->log); - rbres->log = NULL; - } -} - -void EJDB_results_free(RBEJDB_RESULTS* rbres) { - close_ejdb_results_internal(rbres); - ruby_xfree(rbres); -} - -VALUE create_EJDB_query_results(TCLIST* qres, uint32_t count, TCXSTR *log) { - VALUE resultsWrap = Data_Wrap_Struct(ejdbResultsClass, NULL, EJDB_results_free, ruby_xmalloc(sizeof(RBEJDB_RESULTS))); - RBEJDB_RESULTS* rbresults; - Data_Get_Struct(resultsWrap, RBEJDB_RESULTS, rbresults); - - TCLIST* results = tclistnew2(TCLISTNUM(qres)); - int i; - for (i = 0; i < TCLISTNUM(qres); i++) { - char* bsrawdata = TCLISTVALPTR(qres, i); - bson* bsonval = bson_create(); - bson_init_finished_data(bsonval, bsrawdata); - tclistpush(results, &bsonval, sizeof(bson*)); - } - - rbresults->results = results; - rbresults->results_raw = qres; - rbresults->count = count; - rbresults->log = log; - - return resultsWrap; -} - -void EJDB_results_each(VALUE self) { - RBEJDB_RESULTS* rbresults; - Data_Get_Struct(self, RBEJDB_RESULTS, rbresults); - - if (!rbresults || !rbresults->results) { - rb_raise(rb_eRuntimeError, "each() method called on invalid ejdb query results"); - } - - TCLIST* results = rbresults->results; - int i; - for (i = 0; i < TCLISTNUM(results); i++) { - bson* bsonval = *(bson**) TCLISTVALPTR(results, i); - rb_yield(bson_to_ruby(bsonval)); - } -} - -/* - * call-seq: - * results.count -> Number - * - * Returns total number of query result objects. - */ -VALUE EJDB_results_count(VALUE self) { - RBEJDB_RESULTS* rbresults; - Data_Get_Struct(self, RBEJDB_RESULTS, rbresults); - - if (!rbresults) { - rb_raise(rb_eRuntimeError, "count() method called on invalid ejdb query results"); - } - - return UINT2NUM(rbresults->count); -} - -/* - * call-seq: - * results.log -> String or nil - * - * Returns query log. - * To get this log +:explain+ option must be passed to +hints+ argument of query. - * Otherwise method returns +nil+. - */ -VALUE EJDB_results_log(VALUE self) { - RBEJDB_RESULTS* rbresults; - Data_Get_Struct(self, RBEJDB_RESULTS, rbresults); - - return rbresults->log ? rb_str_new2(TCXSTRPTR(rbresults->log)) : Qnil; -} - -/* - * call-seq: - * results.close -> nil - * - * Closes query results and immediately frees memory taken for results. - * Calling this method invalidates results container and any further access attempts will cause +RuntimeError+. - */ -VALUE EJDB_results_close(VALUE self) { - RBEJDB_RESULTS* rbresults; - Data_Get_Struct(self, RBEJDB_RESULTS, rbresults); - - close_ejdb_results_internal(rbresults); - return Qnil; -} - -/* - * call-seq: - * EJDBBinary.new(bdata) -> EJDBBinary - * - * - +bdata+ (Array) - array of binary data. All elements of array must be numbers in range [0..255] - * - */ -VALUE EJDB_binary_init(VALUE self, VALUE bdata) { - Check_Type(bdata, T_ARRAY); - - int length = NUM2INT(rb_funcall(bdata, rb_intern("length"), 0)); - int i; - for (i = 0; i < length; i++) { - VALUE byte = rb_ary_entry(bdata, i); - if (NUM2INT(byte) > 255 || NUM2INT(byte) < 0) { - rb_raise(rb_eRuntimeError, "Invalid value in binary array for EJDBBinary: %d", NUM2INT(byte)); - } - } - - rb_iv_set(self, "@data", rb_ary_dup(bdata)); - return self; -} - - -static VALUE EJDB_block_proxy_context(VALUE yielded_object, VALUE context, int argc, VALUE argv[]){ - VALUE block = context; - return rb_funcall(block, rb_intern("call"), 1, yielded_object); -} - -void EJDB_binary_each(VALUE self) { - VALUE bdata = rb_iv_get(self, "@data"); - Check_Type(bdata, T_ARRAY); - - VALUE block = rb_block_proc(); - rb_block_call(bdata, rb_intern("each"), 0, NULL, RUBY_METHOD_FUNC(EJDB_block_proxy_context), block); -} - - -void Init_rbejdb() { - init_ruby_to_bson(); - - ejdbClass = rb_define_class("EJDB", rb_cObject); - rb_define_singleton_method(ejdbClass, "new", RUBY_METHOD_FUNC(EJDB_new), 0); - - rb_define_const(ejdbClass, "DEFAULT_OPEN_MODE", INT2FIX(DEFAULT_OPEN_MODE)); - rb_define_const(ejdbClass, "JBOREADER", INT2FIX(JBOREADER)); - rb_define_const(ejdbClass, "JBOWRITER", INT2FIX(JBOWRITER)); - rb_define_const(ejdbClass, "JBOCREAT", INT2FIX(JBOCREAT)); - rb_define_const(ejdbClass, "JBOTSYNC", INT2FIX(JBOTSYNC)); - rb_define_const(ejdbClass, "JBOTRUNC", INT2FIX(JBOTRUNC)); - - rb_define_singleton_method(ejdbClass, "open", RUBY_METHOD_FUNC(EJDB_open), 2); - rb_define_method(ejdbClass, "open?", RUBY_METHOD_FUNC(EJDB_is_open), 0); - rb_define_method(ejdbClass, "close", RUBY_METHOD_FUNC(EJDB_close), 0); - rb_define_method(ejdbClass, "save", RUBY_METHOD_FUNC(EJDB_save), -1); - rb_define_method(ejdbClass, "load", RUBY_METHOD_FUNC(EJDB_load), 2); - rb_define_method(ejdbClass, "find", RUBY_METHOD_FUNC(EJDB_find), -1); - rb_define_method(ejdbClass, "find_one", RUBY_METHOD_FUNC(EJDB_find_one), -1); - rb_define_method(ejdbClass, "update", RUBY_METHOD_FUNC(EJDB_update), -1); - rb_define_method(ejdbClass, "remove", RUBY_METHOD_FUNC(EJDB_remove), 2); - - rb_define_method(ejdbClass, "command", RUBY_METHOD_FUNC(EJDB_command), 1); - - rb_define_method(ejdbClass, "drop_collection", RUBY_METHOD_FUNC(EJDB_drop_collection), -1); - rb_define_method(ejdbClass, "ensure_collection", RUBY_METHOD_FUNC(EJDB_ensure_collection), -1); - - rb_define_method(ejdbClass, "drop_indexes", RUBY_METHOD_FUNC(EJDB_drop_indexes), 2); - rb_define_method(ejdbClass, "optimize_indexes", RUBY_METHOD_FUNC(EJDB_optimize_indexes), 2); - rb_define_method(ejdbClass, "ensure_string_index", RUBY_METHOD_FUNC(EJDB_ensure_string_index), 2); - rb_define_method(ejdbClass, "rebuild_string_index", RUBY_METHOD_FUNC(EJDB_rebuild_string_index), 2); - rb_define_method(ejdbClass, "drop_string_index", RUBY_METHOD_FUNC(EJDB_drop_string_index), 2); - rb_define_method(ejdbClass, "ensure_istring_index", RUBY_METHOD_FUNC(EJDB_ensure_istring_index), 2); - rb_define_method(ejdbClass, "rebuild_istring_index", RUBY_METHOD_FUNC(EJDB_rebuild_istring_index), 2); - rb_define_method(ejdbClass, "drop_istring_index", RUBY_METHOD_FUNC(EJDB_drop_istring_index), 2); - rb_define_method(ejdbClass, "ensure_number_index", RUBY_METHOD_FUNC(EJDB_ensure_number_index), 2); - rb_define_method(ejdbClass, "rebuild_number_index", RUBY_METHOD_FUNC(EJDB_rebuild_number_index), 2); - rb_define_method(ejdbClass, "drop_number_index", RUBY_METHOD_FUNC(EJDB_drop_number_index), 2); - rb_define_method(ejdbClass, "ensure_array_index", RUBY_METHOD_FUNC(EJDB_ensure_array_index), 2); - rb_define_method(ejdbClass, "rebuild_array_index", RUBY_METHOD_FUNC(EJDB_rebuild_array_index), 2); - rb_define_method(ejdbClass, "drop_array_index", RUBY_METHOD_FUNC(EJDB_drop_array_index), 2); - - rb_define_method(ejdbClass, "get_db_meta", RUBY_METHOD_FUNC(EJDB_get_db_meta), 0); - rb_define_method(ejdbClass, "sync", RUBY_METHOD_FUNC(EJDB_sync), 0); - - rb_define_method(ejdbClass, "get_transaction_status", RUBY_METHOD_FUNC(EJDB_get_transaction_status), 1); - rb_define_method(ejdbClass, "begin_transaction", RUBY_METHOD_FUNC(EJDB_begin_transaction), 1); - rb_define_method(ejdbClass, "commit_transaction", RUBY_METHOD_FUNC(EJDB_commit_transaction), 1); - rb_define_method(ejdbClass, "rollback_transaction", RUBY_METHOD_FUNC(EJDB_rollback_transaction), 1); - - rb_define_singleton_method(ejdbClass, "valid_oid_string?", RUBY_METHOD_FUNC(EJDB_is_valid_oid_string), 1); - - - ejdbResultsClass = rb_define_class("EJDBResults", rb_cObject); - rb_define_singleton_method(ejdbResultsClass, "new", RUBY_METHOD_FUNC(private_new_method_stub), 0); - rb_include_module(ejdbResultsClass, rb_mEnumerable); - rb_define_method(ejdbResultsClass, "each", RUBY_METHOD_FUNC(EJDB_results_each), 0); - rb_define_method(ejdbResultsClass, "count", RUBY_METHOD_FUNC(EJDB_results_count), 0); - rb_define_method(ejdbResultsClass, "log", RUBY_METHOD_FUNC(EJDB_results_log), 0); - rb_define_method(ejdbResultsClass, "close", RUBY_METHOD_FUNC(EJDB_results_close), 0); - - - ejdbBinaryClass = rb_define_class("EJDBBinary", rb_cObject); - rb_include_module(ejdbBinaryClass, rb_mEnumerable); - rb_define_private_method(ejdbBinaryClass, "initialize", RUBY_METHOD_FUNC(EJDB_binary_init), 1); - rb_define_method(ejdbBinaryClass, "each", RUBY_METHOD_FUNC(EJDB_binary_each), 0); - - ejdbQueryClass = rb_define_class("EJDBQuery", rb_cObject); -} \ No newline at end of file diff --git a/rbejdb/rbejdb.gemspec b/rbejdb/rbejdb.gemspec deleted file mode 100644 index 15dace9..0000000 --- a/rbejdb/rbejdb.gemspec +++ /dev/null @@ -1,20 +0,0 @@ -Gem::Specification.new do |spec| - spec.name = 'rbejdb' - spec.version = '0.9' - spec.summary = 'Ruby binding for EJDB database engine.' - spec.author = 'Softmotions' - spec.homepage = 'http://ejdb.org' - spec.license = 'LGPL' - - spec.required_ruby_version = '>= 1.9.1' - spec.files = Dir['ext/**/*'] - spec.platform = Gem::Platform::RUBY - spec.require_paths = ['ext'] - spec.extensions = Dir['ext/rbejdb/extconf.rb'] - - spec.has_rdoc = true - spec.rdoc_options = %w[ - --exclude .*\.o - --exclude .*\.so - ] -end \ No newline at end of file diff --git a/rbejdb/rbejdb.iml b/rbejdb/rbejdb.iml deleted file mode 100644 index a11e999..0000000 --- a/rbejdb/rbejdb.iml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/rbejdb/test/Makefile b/rbejdb/test/Makefile deleted file mode 100644 index d60c436..0000000 --- a/rbejdb/test/Makefile +++ /dev/null @@ -1,9 +0,0 @@ - -all: check - -check: - ruby t1.rb - ruby t2.rb - ruby t3.rb - -.PHONY: all check diff --git a/rbejdb/test/t1.rb b/rbejdb/test/t1.rb deleted file mode 100644 index 670b51a..0000000 --- a/rbejdb/test/t1.rb +++ /dev/null @@ -1,53 +0,0 @@ -require "rbejdb" - -TESTDB_DIR = 'testdb' - -unless File.exists?(TESTDB_DIR) - Dir.mkdir TESTDB_DIR -end - -Dir.chdir TESTDB_DIR - -ejdb = EJDB.open("zoo", EJDB::DEFAULT_OPEN_MODE) - -raise "Failed to open ejdb" unless ejdb.open? - -ejdb.drop_collection("parrots", true) -ejdb.drop_collection("cows", true) - -ejdb.ensure_collection("parrots") -ejdb.ensure_collection("parrots", {"large" => true, "records" => 200000}) - -class Parrot - def initialize(name, size) - @name = name - @size = size - end -end - -parrot1 = Parrot.new("Cacadoo", 12) -ejdb.save("parrots", parrot1) - -parrot2 = {:name => "Mamadoo", :size => 666, "likes" => ["green color", "night", ["toys", "joys"], parrot1]} -ejdb.save("parrots", parrot2) - -ejdb.save("cows", :name => "moo") - - -ejdb.find("parrots", {:name => "Cacadoo"}).each { |res| - puts res.inspect -} - -ejdb.find("parrots", {:name => {"$in" => %w(Mamadoo Sauron)}}).each { |res| - puts res.inspect -} - -puts ejdb.find("cows", {}).to_a.inspect - -raise "Error querying cows" unless ejdb.find("cows", :name => "moo").any? {|res| res["name"] == 'moo'} - -ejdb.close - -raise "Failed to close ejdb" unless !ejdb.open? - -puts "CONGRATULATIONS!!! Test batch 1 has passed completely!" diff --git a/rbejdb/test/t2.rb b/rbejdb/test/t2.rb deleted file mode 100644 index 71e3f50..0000000 --- a/rbejdb/test/t2.rb +++ /dev/null @@ -1,658 +0,0 @@ -require "rbejdb" -require 'test/unit' - -TESTDB_DIR = 'testdb' - -unless File.exists?(TESTDB_DIR) - Dir.mkdir TESTDB_DIR -end - -Dir.chdir TESTDB_DIR - -$now = Time.now -$jb = EJDB.open("tdbt2", EJDB::JBOWRITER | EJDB::JBOCREAT | EJDB::JBOTRUNC) - - -class EJDBTestUnit < Test::Unit::TestCase - - def test_ejdb1_save_load - assert $jb.open? - - parrot1 = { - "name" => "Grenny", - "type" => "African Grey", - "male" => true, - "age" => 1, - "birthdate" => $now, - "likes" => ["green color", "night", "toys"], - "extra1" => nil - } - parrot2 = { - "name" => "Bounty", - "type" => "Cockatoo", - "male" => false, - "age" => 15, - "birthdate" => $now, - "likes" => ["sugar cane"], - "extra1" => nil - } - - oids = $jb.save("parrots", parrot1, nil, parrot2) - assert_not_nil oids - assert_equal(3, oids.length) - assert_equal(parrot1["_id"], oids[0]) - assert_nil oids[1] - assert_equal(parrot2["_id"], oids[2]) - - obj = $jb.load("parrots", parrot2["_id"]) - assert_not_nil obj - assert_equal(parrot2["_id"], obj["_id"]) - assert_equal("Bounty", obj["name"]) - - assert EJDB.valid_oid_string?(parrot2["_id"]) - assert !EJDB.valid_oid_string?("ololo") - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb2_query1 - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("parrots", {}) - - assert_not_nil results - - assert_equal(2, results.to_a.length) - assert_equal(2, results.to_a.length) #checking second call gets same result - - results.each { |rv| - assert rv - assert rv["_id"].is_a? String - assert rv["name"].is_a? String - assert rv["age"].is_a? Numeric - assert rv["birthdate"] != nil && rv["birthdate"].is_a?(Object) - assert rv["male"] == true || rv["male"] == false - assert_nil rv["extra1"] - assert rv["likes"] != nil && rv["likes"].is_a?(Array) - assert rv["likes"].length > 0 - } - - results = $jb.find("parrots", {}) - assert_not_nil results - assert_equal(2, results.to_a.length) - - - #count mode - count = $jb.find("parrots", {}, :onlycount => true) - assert count.is_a? Numeric - assert_equal(2, count) - - #findOne - obj = $jb.find_one("parrots") - assert_not_nil obj - assert obj["name"].is_a? String - assert obj["age"].is_a? Numeric - - #empty query - results = $jb.find("parrots") - assert_not_nil results - assert_equal(2, results.to_a.length) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb3_query2 - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("parrots", {:name => /(grenny|bounty)/i}, {:orderby => {:name => 1}}) - - assert_not_nil results - assert_equal(2, results.to_a.length) - - results.each_with_index { |rv, index| - if index == 0 - assert_equal("Bounty", rv["name"]) - assert_equal("Cockatoo", rv["type"]) - assert_equal(false, rv["male"]) - assert_equal(15, rv["age"]) - assert_equal($now.inspect, rv["birthdate"].inspect) - assert_equal("sugar cane", rv["likes"].join(",")) - end - } - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb4_query3 - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("parrots", {}, [{:name => "Grenny"}, {:name => "Bounty"}], {:orderby => {:name => 1}}) - - assert_not_nil results - assert_equal(2, results.to_a.length) - - results.each_with_index { |rv, index| - if index == 1 - assert_equal("Grenny", rv["name"]) - assert_equal("African Grey", rv["type"]) - assert_equal(true, rv["male"]) - assert_equal(1, rv["age"]) - assert_equal($now.inspect, rv["birthdate"].inspect) - assert_equal("green color,night,toys", rv["likes"].join(",")) - end - } - - assert_equal(2, results.to_a.length) - - # testing force close - results.close - - assert_raise(RuntimeError) { - results.to_a.length - } - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb5_circular - assert_not_nil $jb - assert $jb.open? - - #Circular query object - cir_query = {} - cir_query["cq"] = cir_query - - err = nil - begin - $jb.find("parrots", cir_query) - rescue Exception => e - err = e - end - - assert_not_nil err - assert_equal(err.message, "Converting circular structure to BSON") - - err = nil - begin - $jb.find("parrots", {:q => [cir_query]}) - rescue Exception => e - err = e - end - - assert_not_nil err - assert_equal(err.message, "Converting circular structure to BSON") - - - cir_array = [] - cir_array[0] = cir_array - - err = nil - begin - $jb.find("parrots", {:q => cir_array}) - rescue Exception => e - err = e - end - - assert_not_nil err - assert_equal(err.message, "Converting circular structure to BSON") - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb6_save_load_buffer - assert_not_nil $jb - assert $jb.open? - - sally = { - "name" => "Sally", - "mood" => "Angry", - "secret" => EJDBBinary.new("Some binary secrect".encode("utf-8").bytes.to_a) - } - - molly = { - "name" => "Molly", - "mood" => "Very angry", - "secret" => nil - } - - sally_oid = $jb.save("birds", sally) - - assert_not_nil sally_oid - assert_not_nil sally["_id"] - - obj = $jb.load("birds", sally_oid) - - assert(obj["secret"].is_a? EJDBBinary) - assert_equal("Some binary secrect", obj["secret"].to_a.pack("U*")) - - oids = $jb.save("birds", sally, molly) - - assert_not_nil oids - assert_not_nil oids.find { |oid| - oid == sally_oid - } - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb7_use_string_index - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("birds", {"name" => "Molly"}, {:explain => true}) - assert_not_nil results - assert_equal(1, results.to_a.length) - - log = results.log - - assert_not_nil log - assert log.include? "RUN FULLSCAN" - - #Now set the name string index - $jb.ensure_string_index("birds", "name") - - results = $jb.find("birds", {"name" => "Molly"}, {:explain => true}) - assert results.log.include? "MAIN IDX: 'sname" - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdb8_cmeta - assert_not_nil $jb - assert $jb.open? - - dm = $jb.get_db_meta - assert dm - assert_equal("tdbt2", dm["file"]) - assert_not_nil dm["collections"] - assert dm["collections"].is_a? Array - - parrots = dm["collections"][0] - assert_not_nil parrots - assert_equal("parrots", parrots["name"]) - - puts __method__.inspect + " has passed successfull" - end - - def test_ejdb9_test_update1 - assert_not_nil $jb - assert $jb.open? - - result = $jb.update("parrots", {"name" => {"$icase" => "GRENNY"}, "$inc" => {"age" => 10}}, {:explain => true}) - assert_equal(1, result.count) - - log = result.log - assert_not_nil log - assert log.include?("UPDATING MODE: YES") - - obj = $jb.find_one("parrots", {"age" => 11}) - assert_not_nil obj - assert_equal("Grenny", obj["name"]) - - id = $jb.save("parrots", {"_id" => obj["_id"], "extra1" => 1}, true) - assert_not_nil id - - obj = $jb.load("parrots", id) - assert_not_nil obj - assert_equal("Grenny", obj["name"]) - assert_equal(1, obj["extra1"]) - - q = {"_id" => {"$in" => [id]}, "$set" => {"stime" => Time.now}} - assert_equal(1, $jb.update("parrots", q)) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdba_id_nin - assert_not_nil $jb - assert $jb.open? - - obj = $jb.find_one("parrots", {}) - assert_not_nil obj - - results = $jb.find("parrots", {"_id" => {"$in" => [obj["_id"]]}}) - - assert_equal(1, results.count) - assert_equal(obj["_id"], results.find { true }["_id"]) - - results = $jb.find("parrots", {"_id" => {"$nin" => [obj["_id"]]}}, {:explain => true}) - assert results.count > 0 - - results.each { |other| - assert other["_id"] - assert other["_id"] != obj["_id"] - } - assert results.log.include? "RUN FULLSCAN" - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbb_test_remove - assert_not_nil $jb - assert $jb.open? - - obj = $jb.find_one("birds", {"name" => "Molly"}) - assert_not_nil obj - assert_not_nil obj["_id"] - assert_equal("Very angry", obj["mood"]) - - #Bye bye Molly! - $jb.remove("birds", obj["_id"]) - - obj = $jb.find_one("birds", {"name" => "Molly"}) - assert_nil obj - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbc_sync - assert_not_nil $jb - assert $jb.open? - $jb.sync - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbd_remove_colls - assert_not_nil $jb - assert $jb.open? - - $jb.drop_collection("birds") - - results = $jb.find("birds", {}) - assert_equal(0, results.count) - assert_nil results.find { true } - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbe_tx1 - assert_not_nil $jb - assert $jb.open? - - obj = {:foo => "bar"} - - assert_equal(false, $jb.get_transaction_status("bars")) - - $jb.begin_transaction("bars") - - $jb.save("bars", obj) - id = obj["_id"] - assert_not_nil id - - obj = $jb.load("bars", obj["_id"]) - assert_not_nil obj - assert $jb.get_transaction_status("bars") - - $jb.rollback_transaction("bars") - assert_equal(false, $jb.get_transaction_status("bars")) - - obj = $jb.load("bars", obj["_id"]) - assert_nil obj - - $jb.begin_transaction("bars") - - assert $jb.get_transaction_status("bars") - assert_nil $jb.load("bars", id) - obj = {:foo => "bar"} - - $jb.save("bars", obj) - id = obj["_id"] - assert_not_nil id - - assert_not_nil $jb.load("bars", id) - - $jb.commit_transaction("bars") - - assert_equal(false, $jb.get_transaction_status("bars")) - - assert_not_nil $jb.load("bars", id) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbf_create_collection_on_upsert - assert_not_nil $jb - assert $jb.open? - - assert_equal(1, $jb.update("upsertcoll", {:foo => "bar", "$upsert" => {:foo => "bar"}})) - - obj = $jb.find_one("upsertcoll", {:foo => "bar"}) - assert_equal("bar", obj["foo"]) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbg_max_and_skip_hints - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("parrots", {}) - assert_not_equal(1, results.count) - - results = $jb.find("parrots", {}, {:max => 1}) - assert_equal(1, results.count) - - results = $jb.find("parrots", {}, {:skip => 1}) - assert_equal(1, results.count) - - results = $jb.find("parrots", {}, {:skip => 2}) - assert_equal(0, results.count) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbh_command - assert_not_nil $jb - assert $jb.open? - - cmdret = $jb.command(:ping => {}) - - assert_not_nil cmdret - assert_equal("pong", cmdret["log"]) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbi_different_hacks - assert_nil $jb.load("monsters", "111") - assert_nil $jb.load("parrots", "111") - assert_nil $jb.load("parrots", "") - - #testing load - assert_raise(ArgumentError) { - $jb.load - } - assert_raise(ArgumentError) { - $jb.load("parrots") - } - assert_raise(TypeError) { - $jb.load("parrots", :what_is_this?) - } - assert_raise(ArgumentError) { - $jb.load("parrots", "", "sldslk") - } - - - #testing save - assert_raise(ArgumentError) { - $jb.save - } - assert_raise(TypeError) { - $jb.save({}) - } - $jb.save("monsters") - assert_raise(ArgumentError) { - $jb.save("monsters", :monster) #Cannot convert object to bson - } - - $jb.save("monsters", {}) - assert_raise(RuntimeError) { - $jb.save("@&^3872638126//d\n", {}) - } - - oid = $jb.save("monsters", {:name => :abracadabra}) - $jb.load("monsters", oid) - - $jb.save("monsters", {:name => :abracadabra}, true) - - assert_raise(ArgumentError) { - $jb.save("monsters", [{:name => :abracadabra}]) - } - - $jb.save("monsters", nil) - $jb.save("monsters", {:name => :abracadabra}, {:name => :chupacabra}) - $jb.save("monsters", self) - $jb.save("monsters", nil, false) - - # what we can save - maxfixnum = 2 ** (0.size * 8 -2) - 1 - minfixnum = -(2**(0.size * 8 -2)) - oid = $jb.save("monsters", { - :nil => nil, - :object => EJDBTestUnit.new("test"), - :float => 0.2323232, - :string => "string", - :regexp => /regexp.*\\\n/imx, - :array => [1, 2, 3, 4, 5], - :maxfixnum => maxfixnum, - :minfixnum => minfixnum, - :hash => {:key => "value"}, - :bignum => maxfixnum + 1, #but not too big ) - :true => true, - :false => false, - :symbol => :symbol, - :binary => EJDBBinary.new([1, 0, 255]), - :time => Time.now - }) - - obj = $jb.load("monsters", oid) - assert_nil obj["nil"] - assert obj["object"].is_a? Hash - assert_equal(0.2323232, obj["float"]) - assert_equal("string", obj["string"]) - assert_equal(/regexp.*\\\n/imx, obj["regexp"]) - assert_equal([1, 2, 3, 4, 5], obj["array"]) - assert obj["maxfixnum"].is_a? Fixnum - assert obj["minfixnum"].is_a? Fixnum - assert obj["hash"].is_a? Hash - assert_equal("value", obj["hash"]["key"]) - assert_equal(maxfixnum + 1, obj["bignum"]) - assert obj["bignum"].is_a? Bignum - assert obj["true"] - assert !obj["false"] - assert obj["symbol"].is_a? Symbol - assert_equal(:symbol, obj["symbol"]) - assert_equal([1, 0, 255], obj["binary"].to_a) - assert obj["time"].is_a? Time - - #what we can't save (yet? :) - assert_raise(RangeError) { - $jb.save("monsters", :toobigint => 3791237293719837192837292) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :class => Array) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :data => $jb) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :module => Math) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :range => 0..100500) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :complex => Complex::polar(1, 1)) - } - assert_raise(RuntimeError) { - $jb.save("monsters", :file => File::open("/tmp")) - } - - #puts $jb.find("monsters").to_a.to_s - assert_equal(7, $jb.find("monsters").count) - - - #testing find - assert_raise(ArgumentError) { - $jb.find - } - - assert_equal(0, $jb.find("dsldajsdlkjasl").count) - - assert_equal(0, $jb.find("monsters", {:name => "abracadabra"}).count) - assert_equal(0, $jb.find("monsters", {:name => ":abracadabra"}).count) - assert_raise(RuntimeError) { - $jb.find("monsters", {:name => :abracadabra}) #todo: symbol search seems to be not supported yet - } - - assert_equal(0, $jb.find("monsters", {:name => {"$in" => ["what_is_this?"]}}).count) - - assert_equal(1, $jb.find("monsters", {:maxfixnum => {"$exists" => true}}, {:onlycount => true})) - assert_equal(6, $jb.find("monsters", {:maxfixnum => {"$exists" => false}}, {:onlycount => true})) - - assert_equal(0, $jb.find("monsters", {:maxfixnum => {"$in" => [maxfixnum - 1, maxfixnum + 1]}}, {:onlycount => true})) - assert_equal(1, $jb.find("monsters", {:maxfixnum => {"$gt" => maxfixnum - 1, "$lt" => maxfixnum + 1}}, {:onlycount => true})) - - results = $jb.find("monsters", {}, {:orderby => {:name => -1, :maxfixnum => -1}}) - assert_not_nil results.to_a[0] - assert_equal(:chupacabra, results.to_a[0]["name"]) - - #wow, we have oredered hash! - results = $jb.find("monsters", {}, {:orderby => {:maxfixnum => -1, :name => -1}}) - assert_not_nil results.to_a[0] - assert_not_equal(:chupacabra, results.to_a[0]["name"]) - - assert_nil $jb.find_one("monsters", {:name => "Sauron"}) - - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbj_internal_rbejdb_classes - assert_raise(RuntimeError) { - EJDB.new - } - assert_raise(RuntimeError) { - EJDBResults.new - } - puts __method__.inspect + " has passed successfull" - end - - - def test_ejdbk_close - assert_not_nil $jb - assert $jb.open? - - results = $jb.find("parrots", {}) - assert_not_nil results - results.close - - assert_raise(RuntimeError) { - results.to_a - } - - assert_nil $jb.close - - assert !$jb.open? - puts __method__.inspect + " has passed successfull" - end - -end diff --git a/rbejdb/test/t3.rb b/rbejdb/test/t3.rb deleted file mode 100644 index 9db0beb..0000000 --- a/rbejdb/test/t3.rb +++ /dev/null @@ -1,90 +0,0 @@ -require "rbejdb" -require 'test/unit' - -TESTDB_DIR = 'testdb' - -unless File.exists?(TESTDB_DIR) - Dir.mkdir TESTDB_DIR -end - -Dir.chdir TESTDB_DIR - -$jb = EJDB.open("tdbt3", EJDB::JBOWRITER | EJDB::JBOCREAT | EJDB::JBOTRUNC) - -class EJDBAdvancedTestUnit < Test::Unit::TestCase - RS = 100000 - QRS = 100 - - def test_ejdbadv1_performance - assert_not_nil $jb - assert $jb.open? - - puts "Generating test batch" - - recs = [] - letters = ('a'..'z').to_a - (1..RS).each { |i| - recs.push({ - :ts => Time.now, - :rstring => (0...rand(128)).map { letters.sample }.join - } - ) - if i % 10000 == 0 - puts "#{i} records generated" - end - - } - - puts "Saving..." - st = Time.now - recs.each { |rec| $jb.save("pcoll1", rec) } - puts "Saved #{RS} objects, time: #{Time.now - st} s" - - puts "Checking saved..." - assert_equal(RS, $jb.find("pcoll1", {}, :onlycount => true)) - recs.each { |rec| - assert_equal(1, $jb.find("pcoll1", rec, :onlycount => true)) - } - - $jb.drop_string_index("pcoll1", "rstring") - - puts "Quering..." - - st = Time.now - (1..QRS).each { - $jb.find("pcoll1", recs.sample, :onlycount => true) - } - secs = Time.now - st - puts "#{QRS} queries, time: #{secs} s, #{'%.7f' % (secs / QRS)} s per query" - - - puts "Setting index..." - - st = Time.now - $jb.ensure_string_index("pcoll1", "rstring") - puts "Index built in #{Time.now - st} s" - - puts "Quering again..." - - st = Time.now - (1..QRS).each { - $jb.find("pcoll1", recs.sample, :onlycount => true) - } - secs = Time.now - st - puts "#{QRS} queries with rstring index, time: #{secs} s, #{'%.7f' % (secs / QRS)} s per query" - - - puts "Quering with $set..." - st = Time.now - assert_equal(RS, $jb.update("pcoll1", {"$set" => {"intv" => 1}})) - puts "Update query ($set) time: #{Time.now - st}" - - puts "Quering with $inc..." - st = Time.now - assert_equal(RS, $jb.update("pcoll1", {"$inc" => {"intv" => 1}})) - puts "Update query ($inc) time: #{Time.now - st}" - - assert_equal(RS, $jb.find("pcoll1", {"intv" => 2}, :onlycount => true)) - - end -end -- 2.7.4