From 10a66dbd68b5f9b01f9d159644f9061738beba57 Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 15 Mar 2013 14:06:21 +0700 Subject: [PATCH] #51 --- luaejdb/ejdb.lua | 2 +- luaejdb/luabson.c | 63 +++++++++++++++++++++++++++++++++++++-------------- luaejdb/luabson.h | 2 ++ luaejdb/luaejdb.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++----- luaejdb/test/t1.lua | 21 +++++++++++++++-- tcejdb/tcutil.h | 2 +- 6 files changed, 128 insertions(+), 27 deletions(-) diff --git a/luaejdb/ejdb.lua b/luaejdb/ejdb.lua index 97ad63d..ca08940 100644 --- a/luaejdb/ejdb.lua +++ b/luaejdb/ejdb.lua @@ -69,7 +69,7 @@ local mtBSON_BOOL = { function luaejdb.toOID(val) - assert(type(val) == "string" and #val == 24) + luaejdb.check_valid_oid_string(val) return setmetatable({ val }, mtBSON_OID); end diff --git a/luaejdb/luabson.c b/luaejdb/luabson.c index f6308ab..d66643c 100644 --- a/luaejdb/luabson.c +++ b/luaejdb/luabson.c @@ -4,10 +4,9 @@ #include #include #include -#include +#include static void lua_push_bson_value(lua_State *L, bson_iterator *it); -static void lua_push_bson_table(lua_State *L, bson_iterator *it); static void lua_push_bson_array(lua_State *L, bson_iterator *it); static void lua_to_bson_impl(lua_State *L, int spos, bson *bs); static void bson_print_xstr(TCXSTR* xstr, const char *data, int depth); @@ -26,6 +25,19 @@ void lua_init_bson(lua_State *L) { lua_pushcfunction(L, print_bson); lua_setfield(L, -2, "print_bson"); + lua_pushcfunction(L, check_valid_oid_string); + lua_setfield(L, -2, "check_valid_oid_string"); +} + +int check_valid_oid_string(lua_State *L) { + bool ret = false; + if (lua_type(L, 1) == LUA_TSTRING) { + ret = ejdbisvalidoidstr(lua_tostring(L, -1)); + } + if (!ret) { + return luaL_error(L, "OID is not valid"); + } + return 0; } int print_bson(lua_State *L) { @@ -121,7 +133,7 @@ static void lua_push_bson_value(lua_State *L, bson_iterator *it) { } } -static void lua_push_bson_table(lua_State *L, bson_iterator *it) { +void lua_push_bson_table(lua_State *L, bson_iterator *it) { bson_type bt; lua_push_bsontype_table(L, BSON_OBJECT); while ((bt = bson_iterator_next(it)) != BSON_EOO) { @@ -298,24 +310,41 @@ static void lua_val_to_bson(lua_State *L, const char *key, int vpos, bson *bs, i lua_pop(L, 1); //-oarr } else { if (key) bson_append_start_object(bs, key); - for (lua_pushnil(L); lua_next(L, vpos); lua_pop(L, 1)) { - int ktype = lua_type(L, -2); - if (ktype == LUA_TNUMBER) { - char vkey[TCNUMBUFSIZ]; - bson_numstrn(vkey, TCNUMBUFSIZ, (int64_t) lua_tointeger(L, -2)); - lua_val_to_bson(L, vkey, lua_gettop(L), bs, tref); - } else if (ktype == LUA_TSTRING) { - size_t klen = 0; - const char *vkey = lua_tolstring(L, -2, &klen); - if (key == NULL && klen == JDBIDKEYNAMEL && !strcmp(JDBIDKEYNAME, vkey)) { //root level OID as string - //pack OID as type table - lua_push_bsontype_table(L, BSON_OID); //+type table - lua_pushvalue(L, -2); //dup oid on stack - lua_rawseti(L, -2, 1); //pop oid val + TCLIST *keys = tclistnew(); + //we need to sort keys due to unordered nature of lua tables + for (lua_pushnil(L); lua_next(L, vpos);) { + lua_pop(L, 1); //-val + size_t ksize = 0; + int ktype = lua_type(L, -1); + if (ktype == LUA_TSTRING) { //accept only string keys + const char* key = lua_tolstring(L, -1, &ksize); + tclistpush(keys, key, ksize); + } + } + tclistsort(keys); + for (int i = 0; i < TCLISTNUM(keys); ++i) { + int vkeysz = TCLISTVALSIZ(keys, i); + const char *vkey = TCLISTVALPTR(keys, i); + lua_pushlstring(L, vkey, vkeysz); + lua_rawget(L, vpos); //+val + if (key == NULL && lua_type(L, -1) == LUA_TSTRING && + vkeysz == JDBIDKEYNAMEL && !strcmp(JDBIDKEYNAME, vkey)) { //root level OID as string + //pack OID as type table + lua_push_bsontype_table(L, BSON_OID); //+type table + lua_pushvalue(L, -2); //dup oid(val) on stack + lua_rawseti(L, -2, 1); //pop oid val + if (ejdbisvalidoidstr(lua_tostring(L, -2))) { + lua_val_to_bson(L, vkey, lua_gettop(L), bs, tref); + } else { + luaL_error(L, "OID _id='%s' is not valid", lua_tostring(L, -2)); } + lua_pop(L, 1); //-type table + } else { lua_val_to_bson(L, vkey, lua_gettop(L), bs, tref); } + lua_pop(L, 1); //-val } + tclistdel(keys); if (key) bson_append_finish_object(bs); } } else { //metafield __bsontype on top diff --git a/luaejdb/luabson.h b/luaejdb/luabson.h index 5c87490..f63e48c 100644 --- a/luaejdb/luabson.h +++ b/luaejdb/luabson.h @@ -19,7 +19,9 @@ extern "C" { int lua_from_bson(lua_State *L); int lua_to_bson(lua_State *L); int print_bson(lua_State *L); + int check_valid_oid_string(lua_State *L); void lua_push_bsontype_table(lua_State* L, int bsontype); + void lua_push_bson_table(lua_State *L, bson_iterator *it); #ifdef __cplusplus } diff --git a/luaejdb/luaejdb.c b/luaejdb/luaejdb.c index c644f81..8ab2a37 100644 --- a/luaejdb/luaejdb.c +++ b/luaejdb/luaejdb.c @@ -131,8 +131,8 @@ static int db_save(lua_State *L) { int argc = lua_gettop(L); luaL_checktype(L, 1, LUA_TTABLE); //self lua_getfield(L, 1, EJDBUDATAKEY); - EJDBDATA *data = luaL_checkudata(L, -1, EJDBUDATAMT); - EJDB *jb = data->db; + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + lua_pop(L, 1); const char *cname = luaL_checkstring(L, 2); //collections name bson bsonval; const char *bsonbuf = luaL_checkstring(L, 3); //Object to save @@ -156,7 +156,57 @@ static int db_save(lua_State *L) { lua_pushstring(L, xoid); bson_destroy(&bsonval); - if (lua_gettop(L) - argc != 2) { //got +lua_getfield(L, 1, EJDBUDATAKEY) + if (lua_gettop(L) - argc != 1) { //got +lua_getfield(L, 1, EJDBUDATAKEY) + return luaL_error(L, "db_save: Invalid stack size: %d should be: %d", (lua_gettop(L) - argc), 1); + } + return 1; +} + +static int db_load(lua_State *L) { + int argc = lua_gettop(L); + luaL_checktype(L, 1, LUA_TTABLE); //self + lua_getfield(L, 1, EJDBUDATAKEY); + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + lua_pop(L, 1); + + const char *cname = luaL_checkstring(L, 2); + bson_oid_t oid; + memset(&oid, 0, sizeof(oid)); + + if (lua_type(L, 3) == LUA_TSTRING) { + const char *soid = lua_tostring(L, 3); + if (ejdbisvalidoidstr(soid)) { + bson_oid_from_string(&oid, soid); + } + } else if (luaL_getmetafield(L, 3, "__bsontype") && lua_tointeger(L, -1) == BSON_OID) { + lua_pop(L, 1); + lua_rawgeti(L, 3, 1); + const char *soid = lua_tostring(L, -1); + if (ejdbisvalidoidstr(soid)) { + bson_oid_from_string(&oid, soid); + } + lua_pop(L, 1); + } + if (!oid.ints[0] && !oid.ints[1] && !oid.ints[2]) { + return luaL_error(L, "Invalid OID arg #2"); + } + EJCOLL *coll = ejdbgetcoll(jb, cname); + if (!coll) { + lua_pushnil(L); + goto finish; + } + bson *bs = ejdbloadbson(coll, &oid); + if (!bs) { + lua_pushnil(L); + goto finish; + } + bson_iterator it; + bson_iterator_init(&it, bs); + lua_push_bson_table(L, &it); + bson_del(bs); + +finish: + if (lua_gettop(L) - argc != 1) { //got return luaL_error(L, "db_save: Invalid stack size: %d should be: %d", (lua_gettop(L) - argc), 1); } return 1; @@ -166,12 +216,13 @@ static int db_find(lua_State *L) { //cname, q.toBSON(), orBsons, q.toHintsBSON(), flags luaL_checktype(L, 1, LUA_TTABLE); //self lua_getfield(L, 1, EJDBUDATAKEY); - EJDBDATA *data = luaL_checkudata(L, -1, EJDBUDATAMT); + EJDB *jb = ((EJDBDATA*) luaL_checkudata(L, -1, EJDBUDATAMT))->db; + lua_pop(L, 1); const char *cname = luaL_checkstring(L, 2); //collections name const char *qbsonbuf = luaL_checkstring(L, 3); //Query bson luaL_checktype(L, 4, LUA_TTABLE); //or joined const char *hbsonbuf = luaL_checkstring(L, 5); //Hints bson - if (!data || !data->db || !qbsonbuf || !hbsonbuf) { + if (!jb || !qbsonbuf || !hbsonbuf) { return luaL_error(L, "Illegal arguments"); } bson oqarrstack[8]; //max 8 $or bsons on stack @@ -179,7 +230,6 @@ static int db_find(lua_State *L) { bson qbson = {NULL}; bson hbson = {NULL}; EJQ *q = NULL; - EJDB *jb = data->db; EJCOLL *coll = NULL; uint32_t count = 0; @@ -245,6 +295,9 @@ static int db_open(lua_State *L) { lua_pushcfunction(L, db_save); lua_setfield(L, -2, "_save"); + lua_pushcfunction(L, db_load); + lua_setfield(L, -2, "load"); + lua_pushcfunction(L, db_find); lua_setfield(L, -2, "_find"); diff --git a/luaejdb/test/t1.lua b/luaejdb/test/t1.lua index f66b7db..f15a0b3 100644 --- a/luaejdb/test/t1.lua +++ b/luaejdb/test/t1.lua @@ -6,6 +6,9 @@ local inspect = require("inspect") local ejdb = require("ejdb") assert(type(ejdb) == "table") +assert(not pcall(function() ejdb.check_valid_oid_string("sss") end)); +assert(pcall(function() ejdb.check_valid_oid_string("510f7fa91ad6270a00000000") end)); + local Q = ejdb.Q local B = ejdb.B @@ -58,15 +61,29 @@ assert(type(obj.bdate) == "table" and getmetatable(obj.bdate).__bsontype == db.B assert(obj.bdate[1] == 1362835380447) assert(type(obj.dst) == "table" and getmetatable(obj.dst).__bsontype == db.BSON_NULL) +assert([[._id(7)=510f7fa91ad6270a00000000 +.a(16)=2 +.c(2)=d +.dd(3)= +..c(16)=1 +..f(2)=v1 +..gt(8)=true + +.ee(2)=t +]] == ejdb.print_bson(ejdb.to_bson({ c = "d", a = 2, _id = "510f7fa91ad6270a00000000", dd = { f = "v1", gt = true, c = 1 }, ee = "t" }))) + -- Test save -- -local oid = db:save("mycoll", {foo="bar"}); +local oid = db:save("mycoll", { foo = "bar" }); assert(oid and #oid == 24) -oid = db:save("mycoll", B("foo2","bar2")); +oid = db:save("mycoll", B("foo2", "bar2"):KV("g", "d"):KV("e", 1):KV("a", "g")); assert(oid and #oid == 24) +obj = db:load("mycoll", oid) +print(inspect(obj)); + db:close() diff --git a/tcejdb/tcutil.h b/tcejdb/tcutil.h index 6c01ab0..b35ac05 100644 --- a/tcejdb/tcutil.h +++ b/tcejdb/tcutil.h @@ -3719,7 +3719,7 @@ typedef unsigned char TCBITMAP; /* type of a bit map object */ #include -#define _TC_VERSION "1.0.65" +#define _TC_VERSION "1.0.66" #define _TC_LIBVER 911 #define _TC_FORMATVER "1.0" -- 2.7.4