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 
16 #ifndef DATASHARE_JSUTILS_H
17 #define DATASHARE_JSUTILS_H
18 
19 #include <iostream>
20 #include <map>
21 #include <string>
22 #include <variant>
23 #include <vector>
24 
25 #include "datashare_observer.h"
26 #include "datashare_operation_statement.h"
27 #include "datashare_template.h"
28 #include "datashare_value_object.h"
29 #include "napi/native_api.h"
30 
31 #define NAPI_ASSERT_ERRCODE(env, assertion, error)                                                          \
32 do {                                                                                                        \
33     if (!(assertion)) {                                                                                     \
34         napi_throw_error((env), std::to_string((error)->GetCode()).c_str(), (error)->GetMessage().c_str()); \
35         return;                                                                                             \
36     }                                                                                                       \
37 } while (0)
38 
39 #define NAPI_ASSERT_CALL_ERRCODE(env, assertion, call, retVal) \
40     do {                                                       \
41         if (!(assertion)) {                                    \
42             call;                                              \
43             return retVal;                                     \
44         }                                                      \
45     } while (0)
46 
47 #define NAPI_ASSERT_CALL_ERRCODE_SYNC(env, assertion, call, error, retVal)                                      \
48     do {                                                                                                        \
49         if (!(assertion)) {                                                                                     \
50             call;                                                                                               \
51             napi_throw_error((env), std::to_string((error)->GetCode()).c_str(), (error)->GetMessage().c_str()); \
52             return retVal;                                                                                      \
53         }                                                                                                       \
54     } while (0)
55 
56 namespace OHOS {
57 namespace DataShare {
58 class DataShareJSUtils final {
59 public:
60     static constexpr int32_t DEFAULT_BUF_SIZE = 1024;
61     static constexpr int32_t ASYNC_RST_SIZE = 2;
62     static constexpr int32_t SYNC_RESULT_ELEMNT_NUM = 2;
63 
64     template<typename T>
65     static int32_t Convert2Value(napi_env env, napi_value input, T &output);
66 
67     template<typename T>
68     static int32_t Convert2JSValue(napi_env env, napi_value input, T &output);
69 
70     template<typename T>
71     static napi_value Convert2JSValue(napi_env env, const std::vector<T> &value);
72 
73     template<typename T>
74     static int32_t Convert2Value(napi_env env, napi_value input, std::vector<T> &output);
75 
76     template<typename T>
77     static int32_t Convert2Value(napi_env env, napi_value input, std::map<std::string, T> &output);
78 
79     template<typename T>
80     static int32_t Convert2Value(napi_env env, napi_value input, const char* propertyName, T &output);
81 
82     static int32_t Convert2Value(napi_env env, napi_value input, std::string &str);
83     static int32_t Convert2Value(napi_env env, napi_value input, DataShareObserver::ChangeType &changeType);
84     static int32_t Convert2Value(napi_env env, napi_value input, DataSharePredicates &predicates);
85     static int32_t Convert2Value(napi_env env, napi_value input, DataShareValuesBucket &valueBucket);
86     static int32_t Convert2Value(napi_env env, napi_value input, UpdateOperation &operation);
87     static int32_t Convert2Value(napi_env env, napi_value input, DataShareObserver::ChangeInfo &changeInfo);
88     static std::string Convert2String(napi_env env, napi_value jsStr, size_t max = DEFAULT_BUF_SIZE);
89     static std::vector<std::string> Convert2StrVector(napi_env env, napi_value value, size_t strMax);
90     static std::vector<uint8_t> Convert2U8Vector(napi_env env, napi_value jsValue);
91     static std::string ConvertAny2String(napi_env env, const napi_value jsValue);
92     static std::string UnwrapStringFromJS(napi_env env, napi_value param, const std::string &defaultValue = "");
93     static DataShareValueObject Convert2ValueObject(napi_env env, napi_value value, bool &status);
94     static Template Convert2Template(napi_env env, napi_value value);
95     static TemplateId Convert2TemplateId(napi_env env, napi_value value);
96     static Data Convert2PublishedData(napi_env env, napi_value value);
97 
98     static napi_value Convert2JSValue(napi_env env, const std::monostate &value = {});
99     static napi_value Convert2JSValue(napi_env env, const std::vector<std::string> &value);
100     static napi_value Convert2JSValue(napi_env env, const std::string &value);
101     static napi_value Convert2JSValue(napi_env env, const std::vector<uint8_t> &value, bool isTypedArray = true);
102     static napi_value Convert2JSValue(napi_env env, int32_t value);
103     static napi_value Convert2JSValue(napi_env env, int64_t value);
104     static napi_value Convert2JSValue(napi_env env, uint32_t value);
105     static napi_value Convert2JSValue(napi_env env, double value);
106     static napi_value Convert2JSValue(napi_env env, bool value);
107     static napi_value Convert2JSValue(napi_env env, const std::map<std::string, int> &value);
108     template<class... Types>
109     static napi_value Convert2JSValue(napi_env env, const std::variant<Types...> &value);
110     static napi_value Convert2JSValue(napi_env env, const TemplateId &templateId);
111     static napi_value Convert2JSValue(napi_env env, const RdbChangeNode &changeNode);
112     static napi_value Convert2JSValue(napi_env env, PublishedDataItem &publishedDataItem);
113     static napi_value Convert2JSValue(napi_env env, std::vector<PublishedDataItem> &publishedDataItems);
114     static napi_value Convert2JSValue(napi_env env, PublishedDataChangeNode &changeNode);
115     static napi_value Convert2JSValue(napi_env env, const OperationResult &results);
116     static napi_value Convert2JSValue(napi_env env, const std::vector<OperationResult> &results);
117     static napi_value Convert2JSValue(napi_env env, const DataShareValuesBucket &valueBucket);
118     static std::vector<uint8_t> ConvertU8Vector(napi_env env, napi_value jsValue);
119     static napi_value Convert2JSValue(napi_env env, const DataShareObserver::ChangeInfo &changeInfo);
120     static napi_value Convert2JSValue(napi_env env, const std::vector<BatchUpdateResult> &result);
121 
122     static bool UnwrapDataSharePredicates(napi_env env, napi_value value, DataSharePredicates &dataSharePredicates);
123     static bool Equals(napi_env env, napi_value value, napi_ref copy);
124     static bool UnwrapPublishedDataItem(napi_env env, napi_value value, PublishedDataItem &publishedDataItem);
125     static bool UnwrapPublishedDataItemVector(napi_env env, napi_value value,
126         std::vector<PublishedDataItem> &publishedDataItems);
127     static bool UnwrapTemplatePredicates(napi_env env, napi_value jsPredicates,
128         std::vector<PredicateTemplateNode> &predicates);
129     static bool UnwrapStringByPropertyName(napi_env env, napi_value jsObject, const char *propertyName,
130         std::string &value);
131     static bool IsArrayForNapiValue(napi_env env, napi_value param, uint32_t &arraySize);
132 private:
133     template<typename _VTp>
ReadVariant(napi_env env,uint32_t step,uint32_t index,const _VTp & output)134     static napi_value ReadVariant(napi_env env, uint32_t step, uint32_t index, const _VTp &output)
135     {
136         (void)step;
137         (void)index;
138         (void)output;
139         return Convert2JSValue(env);
140     }
141 
142     template<typename _VTp, typename _First, typename ..._Rest>
ReadVariant(napi_env env,uint32_t step,uint32_t index,const _VTp & value)143     static napi_value ReadVariant(napi_env env, uint32_t step, uint32_t index, const _VTp &value)
144     {
145         if (step == index) {
146             auto *realValue = std::get_if<_First>(&value);
147             if (realValue == nullptr) {
148                 return nullptr;
149             }
150             return Convert2JSValue(env, *realValue);
151         }
152         return ReadVariant<_VTp, _Rest...>(env, step + 1, index, value);
153     }
154 };
155 
156 template<class... Types>
Convert2JSValue(napi_env env,const std::variant<Types...> & value)157 napi_value DataShareJSUtils::Convert2JSValue(napi_env env, const std::variant<Types...> &value)
158 {
159     return ReadVariant<decltype(value), Types...>(env, 0, value.index(), value);
160 }
161 
162 template<typename T>
Convert2Value(napi_env env,napi_value input,const char * propertyName,T & output)163 int32_t DataShareJSUtils::Convert2Value(napi_env env, napi_value input, const char* propertyName, T& output)
164 {
165     napi_value jsObject = nullptr;
166     if (napi_get_named_property(env, input, propertyName, &jsObject) != napi_ok) {
167         return napi_invalid_arg;
168     }
169     if (Convert2Value(env, jsObject, output) != napi_ok) {
170         return napi_invalid_arg;
171     }
172     return napi_ok;
173 }
174 
175 template<typename T>
Convert2JSValue(napi_env env,const std::vector<T> & value)176 napi_value DataShareJSUtils::Convert2JSValue(napi_env env, const std::vector<T> &value)
177 {
178     napi_value jsValue;
179     napi_status status = napi_create_array_with_length(env, value.size(), &jsValue);
180     if (status != napi_ok) {
181         return nullptr;
182     }
183 
184     for (size_t i = 0; i < value.size(); ++i) {
185         napi_set_element(env, jsValue, i, Convert2JSValue(env, value[i]));
186     }
187     return jsValue;
188 }
189 
190 template<typename T>
Convert2Value(napi_env env,napi_value input,std::vector<T> & output)191 int32_t DataShareJSUtils::Convert2Value(napi_env env, napi_value input, std::vector<T> &output)
192 {
193     bool isArray = false;
194     napi_is_array(env, input, &isArray);
195     if (!isArray) {
196         return napi_invalid_arg;
197     }
198 
199     uint32_t arrLen = 0;
200     napi_get_array_length(env, input, &arrLen);
201     if (arrLen == 0) {
202         return napi_invalid_arg;
203     }
204 
205     for (size_t i = 0; i < arrLen; ++i) {
206         napi_value element;
207         napi_get_element(env, input, i, &element);
208         T item;
209         auto status = Convert2Value(env, element, item);
210         if (status != napi_ok) {
211             return napi_invalid_arg;
212         }
213         output.push_back(std::move(item));
214     }
215     return napi_ok;
216 }
217 
218 template<typename T>
Convert2Value(napi_env env,napi_value input,std::map<std::string,T> & output)219 int32_t DataShareJSUtils::Convert2Value(napi_env env, napi_value input, std::map<std::string, T> &output)
220 {
221     napi_value map = nullptr;
222     uint32_t count = 0;
223     napi_status status = napi_get_property_names(env, input, &map);
224     if (status != napi_ok) {
225         return napi_invalid_arg;
226     }
227     status = napi_get_array_length(env, map, &count);
228     if (status != napi_ok || count == 0) {
229         return napi_invalid_arg;
230     }
231     napi_value jsKey = nullptr;
232     napi_value jsVal = nullptr;
233     for (uint32_t index = 0; index < count; index++) {
234         status = napi_get_element(env, map, index, &jsKey);
235         if (status != napi_ok) {
236             return napi_invalid_arg;
237         }
238         std::string key = Convert2String(env, jsKey);
239         status = napi_get_property(env, input, jsKey, &jsVal);
240         if (status != napi_ok || jsVal == nullptr) {
241             return napi_invalid_arg;
242         }
243         T val;
244         int32_t ret = Convert2Value(env, jsVal, val);
245         if (ret != napi_ok) {
246             return napi_invalid_arg;
247         }
248         output.insert(std::pair<std::string, T>(key, val));
249     }
250     return napi_ok;
251 }
252 } // namespace DataShare
253 } // namespace OHOS
254 
255 #endif // DATASHARE_JSUTILS_H