1 /*
2  * Copyright (c) 2022 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 #define LOG_TAG "JsFieldNode"
16 #include "js_field_node.h"
17 #include "js_util.h"
18 #include "log_print.h"
19 #include "napi_queue.h"
20 #include "uv_queue.h"
21 
22 using namespace OHOS::DistributedKv;
23 
24 namespace OHOS::DistributedData {
25 static std::string FIELD_NAME = "FIELD_NAME";
26 static std::string VALUE_TYPE = "VALUE_TYPE";
27 static std::string DEFAULT_VALUE = "DEFAULT_VALUE";
28 static std::string IS_DEFAULT_VALUE = "IS_DEFAULT_VALUE";
29 static std::string IS_NULLABLE = "IS_NULLABLE";
30 static std::string CHILDREN = "CHILDREN";
31 
32 std::map<uint32_t, std::string> JsFieldNode::valueTypeToString_ = {
33     { JSUtil::STRING, std::string("STRING") },
34     { JSUtil::INTEGER, std::string("INTEGER") },
35     { JSUtil::FLOAT, std::string("DOUBLE") },
36     { JSUtil::BYTE_ARRAY, std::string("BYTE_ARRAY") },
37     { JSUtil::BOOLEAN, std::string("BOOL") },
38     { JSUtil::DOUBLE, std::string("DOUBLE") }
39 };
40 
JsFieldNode(const std::string & fName)41 JsFieldNode::JsFieldNode(const std::string& fName)
42     : fieldName_(fName)
43 {
44 }
45 
GetFieldName()46 std::string JsFieldNode::GetFieldName()
47 {
48     return fieldName_;
49 }
50 
GetValueForJson()51 JsFieldNode::json JsFieldNode::GetValueForJson()
52 {
53     if (fields_.empty()) {
54         if (valueType_ == JSUtil::STRING) {
55             return ToString(valueType_) + ToString(isNullable_ ? "," : ", NOT NULL,") +
56                 " DEFAULT '" + ToString(defaultValue_) + "'";
57         }
58         return ToString(valueType_) + ToString(isNullable_ ? "," : ", NOT NULL,") +
59             " DEFAULT " + ToString(defaultValue_);
60     }
61 
62     json jsFields;
63     for (auto fld : fields_) {
64         jsFields[fld->fieldName_] = fld->GetValueForJson();
65     }
66     return jsFields;
67 }
68 
Constructor(napi_env env)69 napi_value JsFieldNode::Constructor(napi_env env)
70 {
71     const napi_property_descriptor properties[] = {
72         DECLARE_NAPI_FUNCTION("appendChild", JsFieldNode::AppendChild),
73         DECLARE_NAPI_GETTER_SETTER("default", JsFieldNode::GetDefaultValue, JsFieldNode::SetDefaultValue),
74         DECLARE_NAPI_GETTER_SETTER("nullable", JsFieldNode::GetNullable, JsFieldNode::SetNullable),
75         DECLARE_NAPI_GETTER_SETTER("type", JsFieldNode::GetValueType, JsFieldNode::SetValueType)
76     };
77     size_t count = sizeof(properties) / sizeof(properties[0]);
78     return JSUtil::DefineClass(env, "FieldNode", properties, count, JsFieldNode::New);
79 }
80 
New(napi_env env,napi_callback_info info)81 napi_value JsFieldNode::New(napi_env env, napi_callback_info info)
82 {
83     ZLOGD("FieldNode::New");
84     std::string fieldName;
85     auto ctxt = std::make_shared<ContextBase>();
86     auto input = [env, ctxt, &fieldName](size_t argc, napi_value* argv) {
87         // required 1 arguments :: <fieldName>
88         CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
89         ctxt->status = JSUtil::GetValue(env, argv[0], fieldName);
90         CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid fieldName!");
91         CHECK_ARGS_RETURN_VOID(ctxt, !fieldName.empty(), "invalid arg[0], i.e. invalid fieldName!");
92     };
93     ctxt->GetCbInfoSync(env, info, input);
94     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
95 
96     JsFieldNode* fieldNode = new (std::nothrow) JsFieldNode(fieldName);
97     NAPI_ASSERT(env, fieldNode != nullptr, "no memory for fieldNode");
98 
99     auto finalize = [](napi_env env, void* data, void* hint) {
100         ZLOGD("fieldNode finalize.");
101         auto* fieldNode = reinterpret_cast<JsFieldNode*>(data);
102         CHECK_RETURN_VOID(fieldNode != nullptr, "fieldNode is null!");
103         delete fieldNode;
104     };
105     ASSERT_CALL(env, napi_wrap(env, ctxt->self, fieldNode, finalize, nullptr, nullptr), fieldNode);
106     return ctxt->self;
107 }
108 
AppendChild(napi_env env,napi_callback_info info)109 napi_value JsFieldNode::AppendChild(napi_env env, napi_callback_info info)
110 {
111     ZLOGD("FieldNode::AppendChild");
112     JsFieldNode* child = nullptr;
113     auto ctxt = std::make_shared<ContextBase>();
114     auto input = [env, ctxt, &child](size_t argc, napi_value* argv) {
115         // required 1 arguments :: <child>
116         CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
117         ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&child), JsFieldNode::Constructor(env));
118         CHECK_STATUS_RETURN_VOID(ctxt, "napi_unwrap to FieldNode failed");
119         CHECK_ARGS_RETURN_VOID(ctxt, child != nullptr, "invalid arg[0], i.e. invalid FieldNode!");
120     };
121     ctxt->GetCbInfoSync(env, info, input);
122     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
123 
124     auto fieldNode = reinterpret_cast<JsFieldNode*>(ctxt->native);
125     fieldNode->fields_.push_back(child);
126 
127     napi_get_boolean(env, true, &ctxt->output);
128     return ctxt->output;
129 }
130 
GetFieldNode(napi_env env,napi_callback_info info,std::shared_ptr<ContextBase> & ctxt)131 JsFieldNode* JsFieldNode::GetFieldNode(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase>& ctxt)
132 {
133     ctxt->GetCbInfoSync(env, info);
134     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
135     return reinterpret_cast<JsFieldNode*>(ctxt->native);
136 }
137 
138 template <typename T>
GetContextValue(napi_env env,std::shared_ptr<ContextBase> & ctxt,T & value)139 napi_value JsFieldNode::GetContextValue(napi_env env, std::shared_ptr<ContextBase> &ctxt, T &value)
140 {
141     JSUtil::SetValue(env, value, ctxt->output);
142     return ctxt->output;
143 }
144 
GetDefaultValue(napi_env env,napi_callback_info info)145 napi_value JsFieldNode::GetDefaultValue(napi_env env, napi_callback_info info)
146 {
147     ZLOGD("FieldNode::GetDefaultValue");
148     auto ctxt = std::make_shared<ContextBase>();
149     auto fieldNode = GetFieldNode(env, info, ctxt);
150     CHECK_RETURN(fieldNode != nullptr, "getFieldNode nullptr!", nullptr);
151     return GetContextValue(env, ctxt, fieldNode->defaultValue_);
152 }
153 
SetDefaultValue(napi_env env,napi_callback_info info)154 napi_value JsFieldNode::SetDefaultValue(napi_env env, napi_callback_info info)
155 {
156     ZLOGD("FieldNode::SetDefaultValue");
157     auto ctxt = std::make_shared<ContextBase>();
158     JSUtil::KvStoreVariant vv;
159     auto input = [env, ctxt, &vv](size_t argc, napi_value* argv) {
160         // required 1 arguments :: <defaultValue>
161         CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
162         ctxt->status = JSUtil::GetValue(env, argv[0], vv);
163         CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid defaultValue!");
164     };
165     ctxt->GetCbInfoSync(env, info, input);
166     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
167 
168     auto fieldNode = reinterpret_cast<JsFieldNode*>(ctxt->native);
169     fieldNode->defaultValue_ = vv;
170     return nullptr;
171 }
172 
GetNullable(napi_env env,napi_callback_info info)173 napi_value JsFieldNode::GetNullable(napi_env env, napi_callback_info info)
174 {
175     ZLOGD("FieldNode::GetNullable");
176     auto ctxt = std::make_shared<ContextBase>();
177     auto fieldNode = GetFieldNode(env, info, ctxt);
178     CHECK_RETURN(fieldNode != nullptr, "getFieldNode nullptr!", nullptr);
179     return GetContextValue(env, ctxt, fieldNode->isNullable_);
180 }
181 
SetNullable(napi_env env,napi_callback_info info)182 napi_value JsFieldNode::SetNullable(napi_env env, napi_callback_info info)
183 {
184     ZLOGD("FieldNode::SetNullable");
185     auto ctxt = std::make_shared<ContextBase>();
186     bool isNullable = false;
187     auto input = [env, ctxt, &isNullable](size_t argc, napi_value* argv) {
188         // required 1 arguments :: <isNullable>
189         CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
190         ctxt->status = JSUtil::GetValue(env, argv[0], isNullable);
191         CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid isNullable!");
192     };
193     ctxt->GetCbInfoSync(env, info, input);
194     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
195 
196     auto fieldNode = reinterpret_cast<JsFieldNode*>(ctxt->native);
197     fieldNode->isNullable_ = isNullable;
198     return nullptr;
199 }
200 
GetValueType(napi_env env,napi_callback_info info)201 napi_value JsFieldNode::GetValueType(napi_env env, napi_callback_info info)
202 {
203     ZLOGD("FieldNode::GetValueType");
204     auto ctxt = std::make_shared<ContextBase>();
205     auto fieldNode = GetFieldNode(env, info, ctxt);
206     CHECK_RETURN(fieldNode != nullptr, "getFieldNode nullptr!", nullptr);
207     return GetContextValue(env, ctxt, fieldNode->valueType_);
208 }
209 
SetValueType(napi_env env,napi_callback_info info)210 napi_value JsFieldNode::SetValueType(napi_env env, napi_callback_info info)
211 {
212     ZLOGD("FieldNode::SetValueType");
213     auto ctxt = std::make_shared<ContextBase>();
214     uint32_t type = 0;
215     auto input = [env, ctxt, &type](size_t argc, napi_value* argv) {
216         // required 1 arguments :: <valueType>
217         CHECK_ARGS_RETURN_VOID(ctxt, argc == 1, "invalid arguments!");
218         ctxt->status = JSUtil::GetValue(env, argv[0], type);
219         CHECK_STATUS_RETURN_VOID(ctxt, "invalid arg[0], i.e. invalid valueType!");
220         CHECK_ARGS_RETURN_VOID(ctxt, (JSUtil::STRING <= type) && (type <= JSUtil::DOUBLE),
221             "invalid arg[0], i.e. invalid valueType!");
222     };
223     ctxt->GetCbInfoSync(env, info, input);
224     NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
225 
226     auto fieldNode = reinterpret_cast<JsFieldNode*>(ctxt->native);
227     fieldNode->valueType_ = type;
228     return nullptr;
229 }
230 
ToString(const JSUtil::KvStoreVariant & value)231 std::string JsFieldNode::ToString(const JSUtil::KvStoreVariant &value)
232 {
233     auto strValue = std::get_if<std::string>(&value);
234     if (strValue != nullptr) {
235         return (*strValue);
236     }
237     auto intValue = std::get_if<int32_t>(&value);
238     if (intValue != nullptr) {
239         return std::to_string(*intValue);
240     }
241     auto fltValue = std::get_if<float>(&value);
242     if (fltValue != nullptr) {
243         return std::to_string(*fltValue);
244     }
245     auto boolValue = std::get_if<bool>(&value);
246     if (boolValue != nullptr) {
247         return std::to_string(*boolValue);
248     }
249     auto dblValue = std::get_if<double>(&value);
250     if (dblValue != nullptr) {
251         return std::to_string(*dblValue);
252     }
253     ZLOGE("ValueType is INVALID");
254     return std::string();
255 }
256 
ToString(uint32_t type)257 std::string JsFieldNode::ToString(uint32_t type)
258 {
259     // DistributedDB::FieldType
260     auto it = valueTypeToString_.find(type);
261     if (valueTypeToString_.find(type) != valueTypeToString_.end()) {
262         return it->second;
263     } else {
264         return std::string();
265     }
266 }
267 
Dump()268 std::string JsFieldNode::Dump()
269 {
270     json jsFields;
271     for (auto fld : fields_) {
272         jsFields.push_back(fld->Dump());
273     }
274 
275     json jsNode = {
276         { FIELD_NAME, fieldName_ },
277         { VALUE_TYPE, ToString(valueType_) },
278         { DEFAULT_VALUE, ToString(defaultValue_) },
279         { IS_DEFAULT_VALUE, isWithDefaultValue_ },
280         { IS_NULLABLE, isNullable_ },
281         { CHILDREN, jsFields.dump() }
282     };
283     return jsNode.dump();
284 }
285 } // namespace OHOS::DistributedData
286