background
I want to complete json as the data medium to operate the database and network transmission. Looking up the data, we found that rapid json is a popular json library, and it is fast. But in my way of use, it's very cumbersome to use, and my purpose is data exchange. Rapid json is very common. It seems that it should be a value transfer operation. In fact, it is a memory move. Although this can achieve the goal of high efficiency, it will make mistakes if you are not careful, and it looks ugly when you write it, so I wrote a proxy class to meet my needs.
design idea
Just add some convenient operation methods, provide a variety of constructors to easily create objects, provide a copy constructor, provide a convenient interface to add elements, provide object traversal methods and so on. In fact, it's a rapidjson object. All the actual operations are based on rapidjson. Rjson is just a proxy. It changes the way of use and provides value transmission, which will cause some performance degradation, but it's a necessary change to meet my needs.
Specific implementation
Class structure
Document * json is the actual json object. I encapsulate it to provide a new access interface without exposing other details, such as the value object. Therefore, the traversal design of Rjson objects is rather cumbersome. Finally, I chose a way similar to ES6, providing a GetAllKeys method first, and then accessing each value one by one for traversal.
class Rjson { private: Document* json; public: Rjson(); Rjson(const char* jstr); Rjson ExtendObject(Rjson& obj); void AddValueInt(string k, int v); void AddValueString(string k, string v) ; ... }
Default constructor
Rjson() { json = new Document(); //After a Document object is created by rapidjosn, you must add Value or call SetObject() to form an empty json, otherwise an error will be reported json->SetObject(); //I merge two operations to create an empty json }
Constructor, accepts char * parameter
Rjson(const char* jstr) { //Note that this is const char *, otherwise from string.c_str() will be forced to transfer when it is passed, otherwise it will be matched with the overloaded constructor of string parameter. json = new Document(); //The combination of two-step operation, simple processing, can facilitate a lot of code creation json->Parse(jstr); }
Constructor, accepts string parameter
Rjson(string jstr) { //Notice the way to call the overloaded constructor in the constructor. new (this)Rjson(jstr.c_str()); }
copy constructor
Rjson(const Rjson& origin) { json = new Document(); //Copy from json->CopyFrom(*(origin.json), json->GetAllocator()); }
Assignment operation
Rjson& operator = (const Rjson& origin) { new (this)Rjson(origin); //Using copy constructor to implement return(*this); }
Overload [] operator
string operator[](string key) { //Values are returned as strings string rs = ""; if (json->HasMember(key.c_str())) { int vType; GetValueAndTypeByKey(key.c_str(), &rs, &vType); } return rs; }
Add value type
void AddValueInt(string k, int v) { string* newK = new string(k); //New must be created Value aInt(kNumberType); aInt.SetInt(v); json->AddMember(StringRef(newK->c_str()), aInt, json->GetAllocator()); //The addMember method is address passing }
Add string type
void AddValueString(string k, string v) { string* newK = new string(k); Value aStr(kStringType); //New must be created aStr.SetString(v.c_str(), json->GetAllocator()); json->AddMember(StringRef(newK->c_str()), aStr, json->GetAllocator()); }
Add object array
void AddValueArray(string k, vector<string>& arr) { string* newK = new string(k); int len = arr.size(); Value rows(kArrayType); for (int i = 0; i < len; i++) { Value al(kStringType); //New must be created al.SetString(arr.at(i).c_str(),json->GetAllocator()); rows.PushBack(al, json->GetAllocator()); } json->AddMember(StringRef(newK->c_str()), rows, json->GetAllocator()); }
Get all keys
vector<string> GetAllKeys() { //Do not want to expose the Value object, use this interface plus the [] operator to complete the traversal. If you need a Value type, use the GetValueAndTypeByKey method. vector<string> keys; for (auto iter = json->MemberBegin(); iter != json->MemberEnd(); ++iter) { keys.push_back((iter->name).GetString()); } return keys; }
Gets the specified value and its type
There are seven value types defined by rapidjson, which need to be handled one by one
enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number };
Only numeric value, string and array type are processed temporarily
void GetValueAndTypeByKey(string key, string* v, int* vType) { Value::ConstMemberIterator iter = json->FindMember(key.c_str()); if (iter != json->MemberEnd()) { *vType = (int)(iter->value.GetType()); if (iter->value.IsInt()) { std::stringstream s; s << iter->value.GetInt(); *v = s.str(); } else if (iter->value.IsString()) { *v = iter->value.GetString(); } else if (iter->value.IsArray()) { *v = GetJsonString((Value&)iter->value); } else { *v = ""; } } else { *vType = kStringType; *v = ""; } }
Get json string
string GetJsonString() { StringBuffer strBuffer; Writer<StringBuffer> writer(strBuffer); json->Accept(writer); return strBuffer.GetString(); }
Extending json objects
Rjson ExtendObject(Rjson& obj) { Document* src = obj.GetOriginRapidJson(); for (auto iter = src->MemberBegin(); iter != src->MemberEnd(); ++iter) { if (json->HasMember(iter->name)) { //Key exists, update Value& v = (*json)[iter->name]; v.CopyFrom(iter->value, json->GetAllocator()); //v = (Value&)std::move(vTmp); } else { //Key does not exist, new string* newK = new string(iter->name.GetString()); Value vTmp; vTmp.CopyFrom(iter->value, json->GetAllocator()); json->AddMember(StringRef(newK->c_str()), vTmp, json->GetAllocator()); } } return *(this); }
Use example
Rjson obj; obj.AddValueString("username", "Insert test"); obj.AddValueInt("password", 3245); cout << obj.GetJsonString() << endl; Rjson obj2(obj); Rjson obj3("{\"user\":\"bill\",\"age\":12}");
Project address
https://github.com/zhoutk/Jorm
Series article planning
- Design of general interface for c + + operational relational database (JSON ORM version c + +)
- Design and implementation of rjson -- rapid JSON agent
- Implementation and analysis of SQL it 3 database operation
- Implementation and analysis of mysql database operation
- Implementation and analysis of postgres database operation
- Implementation and analysis of oracle database operation
- Implementation and analysis of mssql database operation
- Summary (if required)
feel
This is the first step to encapsulate the database universal access interface, providing convenient json object operation, or writing a json object will be depressing. I miss the feeling of operating json in javascript, silky lubrication