Esempio n. 1
0
    std::string collection::insert(nlohmann::json::object_t const& document) throw(std::runtime_error)
    {
        bson_oid_t oid;

        std::shared_ptr<bson> bson_doc = convert_to_bson(document);
        if(document.find("_id") != document.end()) {
            std::string const &id = document.find("_id")->second;
            if(!ejdbisvalidoidstr(id.c_str())) {
                throw ejdb_exception(JBEINVALIDBSONPK);
            }
            bson_oid_from_string(&oid, id.c_str());
            std::shared_ptr<bson> bson_oid(bson_create(), bson_del);
            bson_init(bson_oid.get());
            bson_append_oid(bson_oid.get(), "_id", &oid);
            bson_finish(bson_oid.get());
            std::shared_ptr<bson> bson_doc_with_oid(bson_create(), bson_del);
            bson_init(bson_doc_with_oid.get());
            bson_merge(bson_oid.get(), bson_doc.get(), true, bson_doc_with_oid.get());
            bson_finish(bson_doc_with_oid.get());
            bson_doc.swap(bson_doc_with_oid);
        }

        if(!ejdbsavebson(_coll.get(), bson_doc.get(), &oid)) {
            throw_last_ejdb_exception();
        }

        std::string id(24, '\0');
        bson_oid_to_string(&oid, &id[0]);

        document_added(id, document);
        return id;
    }
Esempio n. 2
0
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;
}
Esempio n. 3
0
static void lua_val_to_bson(lua_State *L, const char *key, int vpos, bson *bs, int tref) {
    int vtype = lua_type(L, vpos);
    char nbuf[TCNUMBUFSIZ];
    if (key == NULL && vtype != LUA_TTABLE) {
        luaL_error(L, "lua_val_to_bson: Table must be on top of lua stack");
        return;
    }
    switch (vtype) {
        case LUA_TTABLE:
        {
            if (vpos < 0) {
                vpos = lua_gettop(L) + vpos + 1;
            }
            lua_checkstack(L, 3);
            int bsontype_found = luaL_getmetafield(L, vpos, "__bsontype");
            if (!bsontype_found) {
                lua_rawgeti(L, LUA_REGISTRYINDEX, tref); //+ reg table
                lua_pushvalue(L, vpos); //+ val
                lua_rawget(L, -2); //-val +reg table val
                if (lua_toboolean(L, -1)) { //already traversed
                    lua_pop(L, 2);
                    break;
                }
                lua_pop(L, 1); //-reg table val
                lua_pushvalue(L, vpos);
                lua_pushboolean(L, 1);
                lua_rawset(L, -3);
                lua_pop(L, 1); //-reg table

                int len = 0;
                bool query = false;
                bool array = true;

                if (luaL_getmetafield(L, vpos, "__query")) {
                    lua_pop(L, 1);
                    query = true;
                    array = false;
                }
                if (array) {
                    for (lua_pushnil(L); lua_next(L, vpos); lua_pop(L, 1)) {
                        ++len;
                        if ((lua_type(L, -2) != LUA_TNUMBER) || (lua_tointeger(L, -2) != len)) {
                            lua_pop(L, 2);
                            array = false;
                            break;
                        }
                    }
                }
                if (array) {
                    if (key) bson_append_start_array(bs, key);
                    int i;
                    for (i = 1; i <= len; ++i, lua_pop(L, 1)) {
                        lua_rawgeti(L, vpos, i);
                        bson_numstrn(nbuf, TCNUMBUFSIZ, (int64_t) i);
                        lua_val_to_bson(L, nbuf, -1, bs, tref);
                    }
                    if (key) bson_append_finish_array(bs);
                } else if (query) { //special query builder case
                    //oarr format:
                    //{ {fname1, v1, v2...}, {fname2, v21, v22,..}, ... }
                    //where: vN: {op, val} OR {val} with '__bval' metafield
                    //Eg: {fname : {$inc : {...}, $dec : {...}}} -> {fname, {$inc, {}}, {$dec, {}}}

                    lua_getfield(L, vpos, "_oarr"); //+oarr
                    if (!lua_istable(L, -1)) { //it is not array
                        lua_pop(L, 1);
                        break;
                    }
                    if (key) bson_append_start_object(bs, key);
                    //iterate over _oarr
                    int ipos = lua_gettop(L);
                    size_t ilen = lua_objlen(L, ipos);
                    lua_checkstack(L, 2);
                    size_t i;
                    for (i = 1; i <= ilen; ++i, lua_pop(L, 1)) {
                        lua_rawgeti(L, ipos, i);
                        //gettop == 3
                        if (!lua_istable(L, -1)) continue;
                        char *fname = NULL;
                        int jpos = lua_gettop(L);
                        size_t jlen = lua_objlen(L, jpos);
                        lua_checkstack(L, 3);
                        bool wrapped = false;
                        size_t j;
                        for (j = 1; j <= jlen; ++j, lua_pop(L, 1)) {
                            lua_rawgeti(L, jpos, j);
                            if (j == 1) {
                                fname = strdup(lua_tostring(L, -1));
                                continue;
                            }
                            if (!fname || !lua_istable(L, -1)) { //invalid state
                                lua_pop(L, 1); //pop val
                                break;
                            }
                            int vblkpos = lua_gettop(L);
                            if (j == 2 && luaL_getmetafield(L, -1, "__bval")) { //{val} single value +metafield
                                lua_pop(L, 1); //-metafield
                                lua_rawgeti(L, vblkpos, 1); //+val
                                lua_val_to_bson(L, fname, lua_gettop(L), bs, tref);
                                lua_pop(L, 2); //-val -lua_rawgeti
                                break; //Terminate due single val
                            } else { //{op, val} value
                                if (!wrapped) {
                                    bson_append_start_object(bs, fname);
                                    wrapped = true;
                                }
                                lua_rawgeti(L, vblkpos, 1); //+op
                                const char *op = lua_tostring(L, -1);
                                if (op) {
                                    lua_rawgeti(L, vblkpos, 2); //+val
                                    lua_val_to_bson(L, op, lua_gettop(L), bs, tref);
                                    lua_pop(L, 1); //-val
                                }
                                lua_pop(L, 1); //-op
                            }
                        }
                        if (wrapped) {
                            bson_append_finish_object(bs);
                        }
                        if (fname) {
                            free(fname);
                            fname = NULL;
                        }
                    }
                    if (key) bson_append_finish_object(bs);
                    lua_pop(L, 1); //-oarr
                } else {
                    if (key) bson_append_start_object(bs, key);
                    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);
                    int i;
                    for (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
                int bson_type = lua_tointeger(L, -1);
                if (!key && bson_type != BSON_OBJECT && bson_type != BSON_ARRAY) {
                    lua_pop(L, 1);
                    luaL_error(L, "Invalid object structure");
                }
                lua_pop(L, 1); //-metafield __bsontype
                lua_rawgeti(L, -1, 1); //get first value
                switch (bson_type) {
                    case BSON_OID:
                    {
                        const char* boid = lua_tostring(L, -1);
                        if (boid && strlen(boid) == 24) {
                            bson_oid_t oid;
                            bson_oid_from_string(&oid, boid);
                            bson_append_oid(bs, key, &oid);
                        }
                        break;
                    }
                    case BSON_DATE:
                        bson_append_date(bs, key, (bson_date_t) lua_tonumber(L, -1));
                        break;
                    case BSON_REGEX:
                    {
                        const char* regex = lua_tostring(L, -1);
                        lua_rawgeti(L, -2, 2); // re opts
                        const char* options = lua_tostring(L, -1);
                        if (regex && options) {
                            bson_append_regex(bs, key, regex, options);
                        }
                        lua_pop(L, 1);
                        break;
                    }
                    case BSON_BINDATA:
                    {
                        size_t len;
                        const char* cbuf = lua_tolstring(L, -1, &len);
                        bson_append_binary(bs, key, BSON_BIN_BINARY, cbuf, len);
                        break;
                    }
                    case BSON_NULL:
                        bson_append_null(bs, key);
                        break;
                    case BSON_UNDEFINED:
                        bson_append_undefined(bs, key);
                        break;
                    case BSON_OBJECT:
                        if (key) bson_append_start_object(bs, key);
                        lua_val_to_bson(L, NULL, vpos, bs, tref);
                        if (key) bson_append_finish_object(bs);
                        break;
                    case BSON_ARRAY:
                        if (key) bson_append_start_array(bs, key);
                        lua_val_to_bson(L, NULL, vpos, bs, tref);
                        if (key) bson_append_finish_array(bs);
                        break;
                    case BSON_DOUBLE:
                        bson_append_double(bs, key, (double) lua_tonumber(L, -1));
                        break;
                    case BSON_INT:
                        bson_append_int(bs, key, (int32_t) lua_tonumber(L, -1));
                        break;
                    case BSON_LONG:
                        bson_append_long(bs, key, (int64_t) lua_tonumber(L, -1));
                        break;
                    case BSON_BOOL:
                        bson_append_bool(bs, key, lua_toboolean(L, -1));
                        break;
                    default:
                        break;
                }
                lua_pop(L, 1); //-1 first value
            }
            break;
        }
        case LUA_TNIL:
            bson_append_null(bs, key);
            break;
        case LUA_TNUMBER:
        {
            lua_Number numval = lua_tonumber(L, vpos);
            if (numval == floor(numval)) {
                int64_t iv = (int64_t) numval;
                if (-(1LL << 31) <= iv && iv <= (1LL << 31)) {
                    bson_append_int(bs, key, iv);
                } else {
                    bson_append_long(bs, key, iv);
                }
            } else {
                bson_append_double(bs, key, numval);
            }
            break;
        }
        case LUA_TBOOLEAN:
            bson_append_bool(bs, key, lua_toboolean(L, vpos));
            break;

        case LUA_TSTRING:
            bson_append_string(bs, key, lua_tostring(L, vpos));
            break;
    }
}