1 /*
2 * Copyright (c) 2025 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 #include "napi_rdb_context.h"
17
18 using namespace OHOS::RelationalStoreJsKit;
19
20 namespace OHOS {
21 namespace RelationalStoreJsKit {
22 constexpr int32_t KEY_INDEX = 0;
23 constexpr int32_t VALUE_INDEX = 1;
StealRdbStore()24 std::shared_ptr<NativeRdb::RdbStore> RdbStoreContextBase::StealRdbStore()
25 {
26 auto rdb = std::move(rdbStore);
27 rdbStore = nullptr;
28 return rdb;
29 }
ParseTransactionOptions(const napi_env & env,size_t argc,napi_value * argv,std::shared_ptr<CreateTransactionContext> context)30 int ParseTransactionOptions(
31 const napi_env &env, size_t argc, napi_value *argv, std::shared_ptr<CreateTransactionContext> context)
32 {
33 context->transactionOptions.transactionType = Transaction::DEFERRED;
34 if (argc > 0 && !JSUtils::IsNull(env, argv[0])) {
35 auto status = JSUtils::Convert2Value(env, argv[0], context->transactionOptions);
36 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("options", "a transactionOptions"));
37 }
38 return OK;
39 }
ParseTableName(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)40 int ParseTableName(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
41 {
42 context->tableName = JSUtils::Convert2String(env, arg);
43 CHECK_RETURN_SET(!context->tableName.empty(), std::make_shared<ParamError>("table", "not empty string."));
44 return OK;
45 }
46
ParseCursor(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)47 int ParseCursor(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
48 {
49 double cursor = 0;
50 auto status = JSUtils::Convert2Value(env, arg, cursor);
51 CHECK_RETURN_SET(status == napi_ok && cursor > 0, std::make_shared<ParamError>("cursor", "valid cursor."));
52 context->cursor = static_cast<uint64_t>(cursor);
53 return OK;
54 }
55
ParseCryptoParam(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)56 int ParseCryptoParam(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
57 {
58 auto status = JSUtils::Convert2Value(env, arg, context->cryptoParam);
59 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("cryptoParam", "valid cryptoParam."));
60 return OK;
61 }
62
ParseColumnName(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)63 int ParseColumnName(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
64 {
65 context->columnName = JSUtils::Convert2String(env, arg);
66 CHECK_RETURN_SET(!context->columnName.empty(), std::make_shared<ParamError>("columnName", "not empty string."));
67 return OK;
68 }
69
ParsePrimaryKey(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)70 int ParsePrimaryKey(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
71 {
72 JSUtils::Convert2Value(env, arg, context->keys);
73 CHECK_RETURN_SET(!context->keys.empty(), std::make_shared<ParamError>("PRIKey", "number or string."));
74 return OK;
75 }
76
ParseDevice(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)77 int ParseDevice(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
78 {
79 context->device = JSUtils::Convert2String(env, arg);
80 CHECK_RETURN_SET(!context->device.empty(), std::make_shared<ParamError>("device", "not empty"));
81 return OK;
82 }
83
ParseSrcType(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)84 int ParseSrcType(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
85 {
86 std::string value = "";
87 int32_t status = JSUtils::Convert2Value(env, arg, value);
88 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("srcName", "not null"));
89 context->srcName = value;
90 return OK;
91 }
92
ParseTablesName(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)93 int ParseTablesName(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
94 {
95 int32_t ret = JSUtils::Convert2Value(env, arg, context->tablesNames);
96 CHECK_RETURN_SET(ret == napi_ok, std::make_shared<ParamError>("tablesNames", "not empty string."));
97 return OK;
98 }
99
ParseSyncModeArg(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)100 int ParseSyncModeArg(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
101 {
102 napi_valuetype type = napi_undefined;
103 napi_typeof(env, arg, &type);
104 CHECK_RETURN_SET(type == napi_number, std::make_shared<ParamError>("mode", "a SyncMode Type."));
105 napi_status status = napi_get_value_int32(env, arg, &context->enumArg);
106 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("mode", "a SyncMode Type."));
107 bool checked = context->enumArg == 0 || context->enumArg == 1;
108 CHECK_RETURN_SET(checked, std::make_shared<ParamError>("mode", "a SyncMode of device."));
109 return OK;
110 }
111
ParseDistributedTypeArg(const napi_env & env,size_t argc,napi_value * argv,std::shared_ptr<RdbStoreContext> context)112 int ParseDistributedTypeArg(
113 const napi_env &env, size_t argc, napi_value *argv, std::shared_ptr<RdbStoreContext> context)
114 {
115 context->distributedType = DistributedRdb::DISTRIBUTED_DEVICE;
116 if (argc > 1) {
117 auto status = JSUtils::Convert2ValueExt(env, argv[1], context->distributedType);
118 bool checked = status == napi_ok && context->distributedType >= DistributedRdb::DISTRIBUTED_DEVICE &&
119 context->distributedType <= DistributedRdb::DISTRIBUTED_CLOUD;
120 CHECK_RETURN_SET(JSUtils::IsNull(env, argv[1]) || checked,
121 std::make_shared<ParamError>("distributedType", "a DistributedType"));
122 }
123 return OK;
124 }
125
ParseDistributedConfigArg(const napi_env & env,size_t argc,napi_value * argv,std::shared_ptr<RdbStoreContext> context)126 int ParseDistributedConfigArg(
127 const napi_env &env, size_t argc, napi_value *argv, std::shared_ptr<RdbStoreContext> context)
128 {
129 context->distributedConfig = { false };
130 // '2' Ensure that the incoming argv contains 3 parameter
131 if (argc > 2) {
132 auto status = JSUtils::Convert2Value(env, argv[2], context->distributedConfig);
133 bool checked = status == napi_ok || JSUtils::IsNull(env, argv[2]);
134 CHECK_RETURN_SET(checked, std::make_shared<ParamError>("distributedConfig", "a DistributedConfig type"));
135 }
136 return OK;
137 }
138
ParseCloudSyncModeArg(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)139 int ParseCloudSyncModeArg(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
140 {
141 auto status = JSUtils::Convert2ValueExt(env, arg, context->syncMode);
142 bool checked = (status == napi_ok && context->syncMode >= DistributedRdb::TIME_FIRST &&
143 context->syncMode <= DistributedRdb::CLOUD_FIRST);
144 CHECK_RETURN_SET(checked, std::make_shared<ParamError>("mode", "a SyncMode of cloud."));
145 return OK;
146 }
147
ParseCallback(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)148 int ParseCallback(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
149 {
150 napi_valuetype valueType = napi_undefined;
151 napi_status status = napi_typeof(env, arg, &valueType);
152 CHECK_RETURN_SET(
153 (status == napi_ok && valueType == napi_function), std::make_shared<ParamError>("callback", "a function."));
154 NAPI_CALL_BASE(env, napi_create_reference(env, arg, 1, &context->callback_), ERR);
155 return OK;
156 }
157
ParseCloudSyncCallback(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)158 int ParseCloudSyncCallback(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
159 {
160 napi_valuetype valueType = napi_undefined;
161 napi_typeof(env, arg, &valueType);
162 CHECK_RETURN_SET(valueType == napi_function, std::make_shared<ParamError>("progress", "a callback type"));
163 NAPI_CALL_BASE(env, napi_create_reference(env, arg, 1, &context->asyncHolder), ERR);
164 return OK;
165 }
166
ParsePredicates(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)167 int ParsePredicates(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
168 {
169 auto status = napi_unwrap(env, arg, reinterpret_cast<void **>(&context->predicatesProxy));
170 CHECK_RETURN_SET(status == napi_ok && context->predicatesProxy != nullptr,
171 std::make_shared<ParamError>("predicates", "an RdbPredicates."));
172 context->tableName = context->predicatesProxy->GetPredicates()->GetTableName();
173 context->rdbPredicates = context->predicatesProxy->GetPredicates();
174 return OK;
175 }
176
ParseSrcName(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)177 int ParseSrcName(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
178 {
179 context->srcName = JSUtils::Convert2String(env, arg);
180 CHECK_RETURN_SET(!context->srcName.empty(), std::make_shared<ParamError>("srcName", "not empty"));
181 return OK;
182 }
183
ParseColumns(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)184 int ParseColumns(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
185 {
186 napi_valuetype type = napi_undefined;
187 napi_typeof(env, arg, &type);
188 if (type == napi_undefined || type == napi_null) {
189 return OK;
190 }
191 int32_t ret = JSUtils::Convert2Value(env, arg, context->columns);
192 CHECK_RETURN_SET(ret == napi_ok, std::make_shared<ParamError>("columns", "a string array"));
193 return OK;
194 }
195
ParseBindArgs(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)196 int ParseBindArgs(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
197 {
198 context->bindArgs.clear();
199 napi_valuetype type = napi_undefined;
200 napi_typeof(env, arg, &type);
201 if (type == napi_undefined || type == napi_null) {
202 return OK;
203 }
204 bool isArray = false;
205 napi_status status = napi_is_array(env, arg, &isArray);
206 CHECK_RETURN_SET(status == napi_ok && isArray, std::make_shared<ParamError>("values", "a BindArgs array."));
207
208 uint32_t arrLen = 0;
209 status = napi_get_array_length(env, arg, &arrLen);
210 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("values", "not empty."));
211 for (size_t i = 0; i < arrLen; ++i) {
212 napi_value element = nullptr;
213 napi_get_element(env, arg, i, &element);
214 ValueObject valueObject;
215 int32_t ret = JSUtils::Convert2Value(env, element, valueObject.value);
216 CHECK_RETURN_SET(ret == OK, std::make_shared<ParamError>(std::to_string(i), "ValueObject"));
217 // The blob is an empty vector.
218 // If the API version is less than 14, and insert null. Otherwise, insert an empty vector.
219 if (valueObject.GetType() == ValueObject::TYPE_BLOB && JSUtils::GetHapVersion() < 14) {
220 std::vector<uint8_t> tmpValue;
221 valueObject.GetBlob(tmpValue);
222 if (tmpValue.empty()) {
223 valueObject = ValueObject();
224 }
225 }
226 context->bindArgs.push_back(std::move(valueObject));
227 }
228 return OK;
229 }
230
ParseSql(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)231 int ParseSql(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
232 {
233 context->sql = JSUtils::Convert2String(env, arg);
234 CHECK_RETURN_SET(!context->sql.empty(), std::make_shared<ParamError>("sql", "not empty"));
235 return OK;
236 }
237
ParseTxId(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)238 int ParseTxId(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
239 {
240 int64_t txId = 0;
241 auto status = JSUtils::Convert2ValueExt(env, arg, txId);
242 CHECK_RETURN_SET(status == napi_ok && txId >= 0, std::make_shared<ParamError>("txId", "not invalid txId"));
243 context->txId = txId;
244 return OK;
245 }
246
ParseSendableValuesBucket(const napi_env env,const napi_value map,std::shared_ptr<RdbStoreContext> context)247 int ParseSendableValuesBucket(const napi_env env, const napi_value map, std::shared_ptr<RdbStoreContext> context)
248 {
249 uint32_t length = 0;
250 napi_status status = napi_map_get_size(env, map, &length);
251 auto error = std::make_shared<ParamError>("ValuesBucket is invalid.");
252 CHECK_RETURN_SET(status == napi_ok && length > 0, error);
253 napi_value entries = nullptr;
254 status = napi_map_get_entries(env, map, &entries);
255 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_map_get_entries failed."));
256 for (uint32_t i = 0; i < length; ++i) {
257 napi_value iter = nullptr;
258 status = napi_map_iterator_get_next(env, entries, &iter);
259 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_map_iterator_get_next failed."));
260 napi_value values = nullptr;
261 status = napi_get_named_property(env, iter, "value", &values);
262 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_get_named_property value failed."));
263 napi_value key = nullptr;
264 status = napi_get_element(env, values, KEY_INDEX, &key);
265 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_get_element key failed."));
266 std::string keyStr = JSUtils::Convert2String(env, key);
267 napi_value value = nullptr;
268 status = napi_get_element(env, values, VALUE_INDEX, &value);
269 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_get_element value failed."));
270 ValueObject valueObject;
271 int32_t ret = JSUtils::Convert2Value(env, value, valueObject.value);
272 if (ret == napi_ok) {
273 context->valuesBucket.Put(keyStr, valueObject);
274 } else if (ret != napi_generic_failure) {
275 CHECK_RETURN_SET(false, std::make_shared<ParamError>("The value type of " + keyStr, "invalid."));
276 }
277 }
278 return OK;
279 }
280
ParseValuesBucket(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)281 int ParseValuesBucket(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
282 {
283 bool isMap = false;
284 napi_status status = napi_is_map(env, arg, &isMap);
285 CHECK_RETURN_SET(
286 status == napi_ok, std::make_shared<InnerError>("call napi_is_map failed" + std::to_string(status)));
287 if (isMap) {
288 return ParseSendableValuesBucket(env, arg, context);
289 }
290 napi_value keys = nullptr;
291 napi_get_all_property_names(env, arg, napi_key_own_only,
292 static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys);
293 uint32_t arrLen = 0;
294 status = napi_get_array_length(env, keys, &arrLen);
295 CHECK_RETURN_SET(status == napi_ok && arrLen > 0, std::make_shared<ParamError>("ValuesBucket is invalid"));
296
297 for (size_t i = 0; i < arrLen; ++i) {
298 napi_value key = nullptr;
299 status = napi_get_element(env, keys, i, &key);
300 CHECK_RETURN_SET(status == napi_ok, std::make_shared<ParamError>("ValuesBucket is invalid."));
301 std::string keyStr = JSUtils::Convert2String(env, key);
302 napi_value value = nullptr;
303 napi_get_property(env, arg, key, &value);
304 ValueObject valueObject;
305 int32_t ret = JSUtils::Convert2Value(env, value, valueObject.value);
306 // The blob is an empty vector.
307 // If the API version is less than 14, and insert null. Otherwise, insert an empty vector.
308 if (ret == napi_ok && valueObject.GetType() == ValueObject::TYPE_BLOB && JSUtils::GetHapVersion() < 14) {
309 std::vector<uint8_t> tmpValue;
310 valueObject.GetBlob(tmpValue);
311 if (tmpValue.empty()) {
312 valueObject = ValueObject();
313 }
314 }
315 if (ret == napi_ok) {
316 context->valuesBucket.Put(keyStr, valueObject);
317 } else if (ret != napi_generic_failure) {
318 CHECK_RETURN_SET(false, std::make_shared<ParamError>("The value type of " + keyStr, "invalid."));
319 }
320 }
321 return OK;
322 }
323
ParseValuesBuckets(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)324 int ParseValuesBuckets(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
325 {
326 bool isArray = false;
327 napi_status status = napi_is_array(env, arg, &isArray);
328 CHECK_RETURN_SET(status == napi_ok && isArray, std::make_shared<ParamError>("ValuesBuckets is invalid."));
329
330 uint32_t arrLen = 0;
331 status = napi_get_array_length(env, arg, &arrLen);
332 CHECK_RETURN_SET(status == napi_ok && arrLen > 0, std::make_shared<ParamError>("ValuesBuckets is invalid."));
333
334 for (uint32_t i = 0; i < arrLen; ++i) {
335 napi_value obj = nullptr;
336 status = napi_get_element(env, arg, i, &obj);
337 CHECK_RETURN_SET(status == napi_ok, std::make_shared<InnerError>("napi_get_element failed."));
338
339 CHECK_RETURN_ERR(ParseValuesBucket(env, obj, context) == OK);
340 context->sharedValuesBuckets.Put(context->valuesBucket);
341 context->valuesBucket.Clear();
342 }
343 return OK;
344 }
345
ParseConflictResolution(const napi_env env,const napi_value arg,std::shared_ptr<RdbStoreContext> context)346 int ParseConflictResolution(const napi_env env, const napi_value arg, std::shared_ptr<RdbStoreContext> context)
347 {
348 int32_t conflictResolution = 0;
349 napi_get_value_int32(env, arg, &conflictResolution);
350 int32_t min = static_cast<int32_t>(NativeRdb::ConflictResolution::ON_CONFLICT_NONE);
351 int32_t max = static_cast<int32_t>(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
352 bool checked = (conflictResolution >= min) && (conflictResolution <= max);
353 CHECK_RETURN_SET(checked, std::make_shared<ParamError>("conflictResolution", "a ConflictResolution."));
354 context->conflictResolution = static_cast<NativeRdb::ConflictResolution>(conflictResolution);
355 return OK;
356 }
357 } // namespace RelationalStoreJsKit
358 } // namespace OHOS