1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef JSON_OBJECT_H
17 #define JSON_OBJECT_H
18 
19 #include <map>
20 #include <set>
21 #include <string>
22 #include <vector>
23 #ifndef OMIT_JSON
24 #include <json/json.h>
25 #endif
26 #include "db_types.h"
27 
28 namespace DistributedDB {
29 // JsonObject is the abstraction of JsonString, it hides the JsonLib that we use and other messy details.
30 // JsonObject do not support concurrence inherently, use it locally or under mutex protection.
31 class JsonObject final {
32 public:
33     // Set max allowed nest depth and return the value before set.
34     static uint32_t SetMaxNestDepth(uint32_t nestDepth);
35 
36     // Calculate nest depth when json string is legal or estimate depth by legal part from illegal json.
37     static uint32_t CalculateNestDepth(const std::string &inString, int &errCode);
38     static uint32_t CalculateNestDepth(const uint8_t *dataBegin, const uint8_t *dataEnd, int &errCode);
39 
40     // Support default constructor, copy constructor and copy assignment
41     JsonObject() = default;
42     ~JsonObject() = default;
43     JsonObject(const JsonObject &);
44     JsonObject& operator=(const JsonObject &);
45 
46     explicit JsonObject(const Json::Value &value);
47 
48     // Should be called on an invalid JsonObject, create new JsonObject if need to reparse
49     // Require the type of the root to be JsonObject, otherwise parse fail
50     int Parse(const std::string &inString);
51     int Parse(const std::vector<uint8_t> &inData); // Whether ends with '\0' in vector is OK
52 
53     // The end refer to the byte after the last valid byte
54     int Parse(const uint8_t *dataBegin, const uint8_t *dataEnd);
55 
56     bool IsValid() const;
57 
58     // Unnecessary spacing will be removed and fieldName resorted by lexicographical order
59     std::string ToString() const;
60 
61     bool IsFieldPathExist(const FieldPath &inPath) const;
62     int GetFieldTypeByFieldPath(const FieldPath &inPath, FieldType &outType) const;
63     int GetFieldValueByFieldPath(const FieldPath &inPath, FieldValue &outValue) const;
64 
65     int GetObjectArrayByFieldPath(const FieldPath &inPath, std::vector<JsonObject> &outArray) const;
66     int GetStringArrayByFieldPath(const FieldPath &inPath, std::vector<std::string> &outArray) const;
67 
68     int GetObjectByFieldPath(const FieldPath &inPath, JsonObject &outObj) const;
69 
70     // An empty fieldPath indicate the root, the outSubPath should be empty before call, we will not empty it at first.
71     // If inPath is of multiple path, then outSubPath is combination of result of each inPath.
72     int GetSubFieldPath(const FieldPath &inPath, std::set<FieldPath> &outSubPath) const;
73     int GetSubFieldPath(const std::set<FieldPath> &inPath, std::set<FieldPath> &outSubPath) const;
74     int GetSubFieldPathAndType(const FieldPath &inPath, std::map<FieldPath, FieldType> &outSubPathType) const;
75     int GetSubFieldPathAndType(const std::set<FieldPath> &inPath, std::map<FieldPath, FieldType> &outSubPathType) const;
76 
77     // If inPath not refer to an array, return error.
78     int GetArraySize(const FieldPath &inPath, uint32_t &outSize) const;
79 
80     // If inPath not refer to an array, return error. If not all members are string or array type, return error.
81     // If array-type member is empty, ignore. If not all members of the array-type member are string, return error.
82     int GetArrayContentOfStringOrStringArray(const FieldPath &inPath,
83         std::vector<std::vector<std::string>> &outContent) const;
84 
85     // Can be called no matter JsonObject valid or not. Invalid turn into valid after call(insert on invalid never fail
86     // if parameter is valid). An empty inPath is not allowed. LEAF_FIELD_ARRAY and INTERNAL_FIELD_OBJECT is not
87     // supported. infinite double is not support. inValue is ignored for LEAF_FIELD_NULL.
88     // When inPath already exist, append value if it's an arrayObject, otherwise returns -E_JSON_INSERT_PATH_EXIST
89     // if nearest path ends with type not object, rets -E_JSON_INSERT_PATH_CONFLICT.
90     // Otherwise, insert field as well as filling up intermediate field, then returns E_OK;
91     // isAppend: when it's true, append inValue as path is an arrayObject if path not exist.
92     int InsertField(const FieldPath &inPath, FieldType inType, const FieldValue &inValue, bool isAppend = false);
93 
94     // Add json object to an array field. should be called on an valid JsonObject. Never turn into invalid after call.
95     // If inPath not refer to an array, return error.
96     int InsertField(const FieldPath &inPath, const JsonObject &inValue, bool isAppend = false);
97 
98     // Should be called on an valid JsonObject. Never turn into invalid after call. An empty inPath is not allowed.
99     // If inPath not exist, returns -E_JSON_DELETE_PATH_NOT_FOUND. Otherwise, delete field from its parent returns E_OK;
100     int DeleteField(const FieldPath &inPath);
101 private:
102 #ifndef OMIT_JSON
103     // Auxiliary Method: If inPath not refer to an array, return error. If not all members are string, return error.
104     int GetStringArrayContentByJsonValue(const Json::Value &value, std::vector<std::string> &outStringArray) const;
105 
106     // Common Type Judgement Logic
107     int GetFieldTypeByJsonValue(const Json::Value &value, FieldType &outType) const;
108 
109     // Return E_OK if JsonValueNode found at exact the path, otherwise not E_OK
110     const Json::Value &GetJsonValueByFieldPath(const FieldPath &inPath, int &errCode) const;
111 
112     // REQUIRE: JsonObject is valid(Root value is object type).
113     // If inPath empty(means root), set exact and nearest to root value and nearDepth to 0, then ret E_OK;
114     // If JsonValue exist at exact path, set exact to this JsonValue, set nearest to its parent JsonValue, set nearDepth
115     // to the depth of this parent JsonValue, then ret E_OK;
116     // If exact path no exist, set exact to nullptr, set nearest to nearest JsonValue that can be found, set nearDepth
117     // to the depth of this nearest JsonValue, then ret -E_NOT_FOUND;
118     int LocateJsonValueByFieldPath(const FieldPath &inPath, Json::Value *&exact,
119         Json::Value *&nearest, uint32_t &nearDepth);
120 
121     // create if path not exist
122     int MoveToPath(const FieldPath &inPath, Json::Value *&exact, Json::Value *&nearest);
123 
124     static uint32_t maxNestDepth_;
125 
126     bool isValid_ = false;
127     Json::Value value_;
128 #endif
129 };
130 } // namespace DistributedDB
131 #endif // JSON_OBJECT_H