nlohmann::json collection::evaluate_log(std::string const& log) { nlohmann::json json_log; std::istringstream log_stream(log); for(std::string line; std::getline(log_stream, line); ) { auto const delimiter = line.find_first_of(':'); if(delimiter != std::string::npos) { std::string key = line.substr(0, delimiter); std::string val = line.substr(delimiter + 2); std::replace(key.begin(), key.end(), ' ', '_'); std::transform(key.begin(), key.end(), key.begin(), ::tolower); nlohmann::json json_val; try { json_val = boost::lexical_cast<long>(val); } catch(boost::bad_lexical_cast const& e) { if(val == "YES") { json_val = true; } else if(val == "NO") { json_val = false; } else if(val == "'NONE'") { json_val = nullptr; } else { size_t const bson_hex_delimiter = val.find_first_of('/'); if(bson_hex_delimiter != std::string::npos) { std::string const bson_hex_string = val.substr(0, bson_hex_delimiter); std::string bson_decoded_data; boost::algorithm::unhex(bson_hex_string.begin(), bson_hex_string.end(), back_inserter(bson_decoded_data)); json_val = convert_to_json(std::shared_ptr<bson>(bson_create_from_buffer(bson_decoded_data.data(), bson_decoded_data.size()), bson_del)); } else { json_val = val; } } } if(json_log.find(key) != json_log.end()) { if(json_log[key].type() != nlohmann::json::value_t::array) { json_log[key] = nlohmann::json::array_t({ json_log[key] }); } json_log[key].push_back(json_val); } else { json_log[key] = json_val; } } } return json_log; }
static bson *encode_bson(JNIEnv *env, jobject jbson, bson *out) { jclass jBSONClazz = (*env)->FindClass(env, "org/ejdb/bson/BSON"); jmethodID encodeMethodID = (*env)->GetStaticMethodID(env, jBSONClazz, "encode", "(Lorg/ejdb/bson/BSONObject;)[B"); jbyteArray bobjdata = (*env)->CallStaticObjectMethod(env, jBSONClazz, encodeMethodID, jbson); jbyte *bdata = (*env)->GetByteArrayElements(env, bobjdata, NULL); jsize blength = (*env)->GetArrayLength(env, bobjdata); if (NULL == out) { out = bson_create_from_buffer(bdata, blength); } else { bson_create_from_buffer2(out, bdata, blength); } (*env)->ReleaseByteArrayElements(env, bobjdata, bdata, 0); (*env)->DeleteLocalRef(env, bobjdata); return out; };
nlohmann::json collection::query(nlohmann::json::object_t const& selector, nlohmann::json::object_t const& modifier, int flags) throw(ejdb_exception) { nlohmann::json q1 = selector; nlohmann::json q2 = modifier; bool with_modifier = !q2.empty(); if(with_modifier) { std::swap(q1, q2); } auto* ejdb_query = ejdbcreatequery(_db.get(), convert_to_bson(q1).get(), with_modifier ? convert_to_bson(q2).get() : nullptr, (int)with_modifier, nullptr); if(!ejdb_query) { throw_last_ejdb_exception(); } uint32_t count; std::shared_ptr<TCXSTR> log(tcxstrnew(), tcxstrdel); auto cursor = ejdbqryexecute(_coll.get(), ejdb_query, &count, flags, log.get()); ejdbquerydel(ejdb_query); nlohmann::json updates; nlohmann::json upserts; nlohmann::json dropall; nlohmann::json const json_log = evaluate_log(std::string(log->ptr, log->size)); if(json_log.find("updating_mode") != json_log.end() && json_log["updating_mode"]) { if(json_log.find("$update") != json_log.end()) { updates = json_log["$update"]; if(updates.type() != nlohmann::json::value_t::array) { updates = nlohmann::json::array_t({ updates }); } } if(json_log.find("$upsert") != json_log.end()) { upserts = json_log["$upsert"]; if(upserts.type() != nlohmann::json::value_t::array) { upserts = nlohmann::json::array_t({ upserts }); } for(nlohmann::json::object_t doc: upserts) { std::string const id = doc["_id"]; doc.erase("_id"); document_added(id, doc); } } if(json_log.find("$dropall") != json_log.end()) { for(std::string const& id: json_log["$dropall"]) { dropall.push_back(id); } } } nlohmann::json return_val; if(flags & JBQRYCOUNT) { return_val = count; } else { std::vector<nlohmann::json::object_t> results; results.reserve(count); for(int i = 0; i < count; ++i) { int data_size = 0; auto const& result = convert_to_json(std::shared_ptr<bson>(bson_create_from_buffer(static_cast<char const*>(ejdbqresultbsondata(cursor, i, &data_size)), data_size), bson_destroy)); if(i < updates.size()) { auto const& update = updates[i]; if(result != update) { auto const diff = modified_fields(result, update); document_pre_changed(result["_id"], result, update); document_changed(result["_id"], diff["fields"], diff["cleared"]); } } if(i < dropall.size()) { std::string const& id = dropall[i]; if(result["_id"] == id) { document_pre_removed(id, result); document_removed(id); } } results.push_back(result); } ejdbqresultdispose(cursor); return_val = results; } if(flags & JBQRYFINDONE) { return_val = return_val.empty() ? nlohmann::json::object() : return_val[0]; } return return_val; }