#include #include #include #include #include namespace RAT { DBTable::DBTable() : tblname(""), index(""), run_begin(0), run_end(0), pass_number(0), bytes(0) { table.reset(json::TOBJECT); this->tblname = ""; this->index = ""; } DBTable::DBTable(std::string _tblname, std::string _index) : tblname(_tblname), index(_index), run_begin(0), run_end(0), pass_number(0), bytes(0) { table.reset(json::TOBJECT); // -- Assign defaults to the base object SetS("type", _tblname); SetS("index", _index); std::vector tmp_rrange(2,0); SetIArray("run_range",tmp_rrange); SetS("comment", ""); SetS("timestamp", ""); SetI("version",1); SetI("pass",pass_number); } DBTable::DBTable(json::Value &init, const size_t size_bytes) : run_begin(0), run_end(0), pass_number(0), bytes(0), table(init) { // Note table is assigned on instantiation to init! // make a few checks to avoid dirty crashes if (!table.isMember("type")) { Log::Die("DBTable::DBTable : Table does not have field 'type'."); } // Issue a warning if one of these fields isn't present. // Not necessarily a critical issue but it should be there at all times const char *fields_needed[] = {"version","run_range","pass","comment","timestamp"}; std::vector fneeded(fields_needed,fields_needed+5); // Also check for presence of deprecated fields. const char *fields_uneeded[] = {"name","valid_begin","valid_end"}; std::vector fnneeded(fields_uneeded,fields_uneeded+3); for (size_t i = 0; i < fneeded.size(); ++i) { if (!table.isMember(fneeded.at(i))) { // -- Die warn << "DBTable::DBTable : In table " << table["type"].getString() << " : Field " << fneeded.at(i) << " is missing...assuming default." << newline; if (fneeded.at(i) == std::string("version")) { json::Value val(1); table.setMember("version",val); } else if (fneeded.at(i) == std::string("run_range")) { std::vector tmpval(2,0); json::Value val(tmpval); table.setMember("run_range",val); } else if (fneeded.at(i) == std::string("pass")) { json::Value val(-1); table.setMember("pass",val); } else if (fneeded.at(i) == std::string("comment")) { json::Value val(TString("")); table.setMember("comment",val); } else if (fneeded.at(i) == std::string("timestamp")) { json::Value val(TString("")); table.setMember("timestamp",val); } } } // Repeat a similar check for deprecated fields. for (size_t i = 0; i < fnneeded.size(); ++i) { if (table.isMember(fnneeded.at(i))) { warn << "DBTable::DBTable : In table " << table["type"].getString() << " : Found deprecated field " << fnneeded.at(i) << ". Will be ignored." << newline; } } tblname = table["type"].getString(); if (table.isMember("index")) { index = table["index"].getString(); } else { index = ""; } if (init.isMember("run_range")) { json::Value &run_range = table["run_range"]; SetRunRange(run_range[0].cast(), run_range[1].cast()); } else { Log::Die("DBTable::DBTable : Couldn't find 'run_range' in object."); } if (table.isMember("pass")) { pass_number = table["pass"].cast(); } else { Log::Die("DBTable::DBTable : Couldn't find 'pass' in object."); } bytes = size_bytes; #ifdef RTADB_DEBUG warn << "Table " << tblname << "[" << index << "]["<< run_begin << ","<< run_end<< "][pass=" << pass << "] created"<< newline; #endif } DBTable::~DBTable() { // Do nothing } void DBTable::SaveAs(std::string filename) const { json::Value v(this->table); // fill in metadata not actually stored in this->table v["type"] = this->tblname; std::vector run_range; run_range.push_back(this->run_begin); run_range.push_back(this->run_end); v["run_range"] = run_range; if (this->index != "") v["index"] = this->index; v["pass"] = pass_number; std::ofstream outfile; outfile.open(filename.c_str()); json::Writer writer(outfile); writer.putValue(v); outfile.close(); detail << "DBTable::SaveAs: wrote table " << this->tblname << " to " << filename << newline; } void DBTable::SetRunRange(int _run_begin, int _run_end) { run_begin = _run_begin; run_end = _run_end; std::vector tmp_range(2,0); tmp_range[0] = _run_begin; tmp_range[1] = _run_end; SetIArray("run_range",tmp_range); } DBTable::FieldType DBTable::GetFieldType(std::string name) const { if (arrayTypeCache.present(name)) { return arrayTypeCache[name]; } else if (!table.isMember(name)) { return DBTable::NOTFOUND; } else { json::Value &val = table[name]; switch (val.getType()) { case json::TARRAY: if (val.getArraySize() == 0) return DBTable::JSON; // Empty arrays typed as JSON switch (val[0].getType()) { case json::TSTRING: return DBTable::STRING_ARRAY; case json::TUINTEGER: //unsigned (hex) casts to int case json::TINTEGER: return DBTable::INTEGER_ARRAY; case json::TREAL: return DBTable::DOUBLE_ARRAY; case json::TBOOL: return DBTable::BOOLEAN_ARRAY; default: return DBTable::JSON; } case json::TSTRING: return DBTable::STRING; case json::TUINTEGER: //unsigned (hex) casts to int case json::TINTEGER: return DBTable::INTEGER; case json::TREAL: return DBTable::DOUBLE; case json::TBOOL: return DBTable::BOOLEAN; default: return DBTable::JSON; } } } std::vector DBTable::GetFieldList() const { std::vector fields = table.getMembers(); return fields; } int DBTable::GetI(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); try { return table[name].cast(); //must be convertable to int } catch (...) { throw DBWrongTypeError(tblname, index, name, INTEGER, GetFieldType(name)); } } double DBTable::GetD(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); try { return table[name].cast(); //must be convertable to double } catch (...) { throw DBWrongTypeError(tblname, index, name, INTEGER, GetFieldType(name)); } } std::string DBTable::GetS(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); else if (table[name].getType() != json::TSTRING) //we only want true strings, not casts to string throw DBWrongTypeError(tblname, index, name, STRING, GetFieldType(name)); else return table[name].cast(); } bool DBTable::GetZ(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); else if (table[name].getType() != json::TBOOL) //we only want true bools, not casts to bool throw DBWrongTypeError(tblname, index, name, BOOLEAN, GetFieldType(name)); else return table[name].cast(); } json::Value DBTable::GetJSON(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); else return table[name]; } std::vector DBTable::GetIArray(const std::string &name) const { if (!table.isMember(name)) { throw DBNotFoundError(tblname, index, name); } else if (GetFieldType(name) != INTEGER_ARRAY) { throw DBWrongTypeError(tblname, index, name, INTEGER_ARRAY, GetFieldType(name)); } else { const json::Value &json_array = table[name]; return json_array.toVector(); } } std::vector DBTable::GetDArray(const std::string &name) const { if (!table.isMember(name)) { throw DBNotFoundError(tblname, index, name); } else if (GetFieldType(name) == INTEGER_ARRAY) { try { //we will allow this, but it could be deferred, so GetIArray with a bit of overhead const std::vector iv = GetIArray(name); std::vector v(iv.size()); // explicit conversion required for (size_t i = 0; i < iv.size(); i++) { v[i] = iv[i]; } return v; } catch( std::runtime_error ) { // Could be that the first value was an int, but the rest are doubles const json::Value& json_array = table[name]; return json_array.toVector(); } } else if (GetFieldType(name) != DOUBLE_ARRAY) { throw DBWrongTypeError(tblname, index, name, DOUBLE_ARRAY, GetFieldType(name)); } else { const json::Value &json_array = table[name]; return json_array.toVector(); } } std::vector DBTable::GetSArray(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); else if (GetFieldType(name) != STRING_ARRAY) throw DBWrongTypeError(tblname, index, name, STRING_ARRAY, GetFieldType(name)); else return table[name].toVector(); } std::vector DBTable::GetZArray(const std::string &name) const { if (!table.isMember(name)) throw DBNotFoundError(tblname, index, name); else if (GetFieldType(name) != BOOLEAN_ARRAY) throw DBWrongTypeError(tblname, index, name, BOOLEAN_ARRAY, GetFieldType(name)); else return table[name].toVector(); } } // namespace RAT