• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #define LOG_TAG "TransactionProxy"
17 #include "napi_transaction.h"
18 
19 #include "js_utils.h"
20 #include "napi_async_call.h"
21 #include "napi_rdb_error.h"
22 #include "napi_rdb_js_utils.h"
23 #include "napi_rdb_predicates.h"
24 #include "napi_result_set.h"
25 #include "rdb_common.h"
26 #include "rdb_errno.h"
27 using namespace OHOS::Rdb;
28 using namespace OHOS::NativeRdb;
29 using namespace OHOS::AppDataMgrJsKit;
30 namespace OHOS::RelationalStoreJsKit {
31 #define ASSERT_RETURN_SET_ERROR(assertion, paramError) \
32     CHECK_RETURN_CORE(assertion, SetError(paramError), ERR)
33 
34 struct TransactionContext : public ContextBase {
GetInstanceOHOS::RelationalStoreJsKit::TransactionContext35     void GetInstance(napi_value self)
36     {
37         auto status = napi_unwrap(env_, self, reinterpret_cast<void **>(&boundObj));
38         if (status != napi_ok || boundObj == nullptr) {
39             LOG_ERROR("TransactionProxy native instance is nullptr! code:%{public}d!", status);
40             return;
41         }
42         transaction_ = reinterpret_cast<TransactionProxy *>(boundObj)->GetInstance();
43     }
StealTransactionOHOS::RelationalStoreJsKit::TransactionContext44     std::shared_ptr<NativeRdb::Transaction> StealTransaction()
45     {
46         auto trans = std::move(transaction_);
47         transaction_ = nullptr;
48         return trans;
49     }
50     int32_t ParseRdbPredicatesProxy(napi_env env, napi_value arg, std::shared_ptr<RdbPredicates> &predicates);
51     int32_t ParseSendableValuesBucket(napi_env env, napi_value arg, ValuesBucket &valuesBucket);
52     int32_t ParseValuesBucket(napi_env env, napi_value arg, ValuesBucket &valuesBucket);
53     int32_t ParseValuesBuckets(napi_env env, napi_value arg, std::vector<ValuesBucket> &valuesBuckets);
54     int32_t ParseConflictResolution(napi_env env, napi_value arg, NativeRdb::ConflictResolution &conflictResolution);
55     std::shared_ptr<NativeRdb::Transaction> transaction_ = nullptr;
56     static constexpr int32_t KEY_INDEX = 0;
57     static constexpr int32_t VALUE_INDEX = 1;
58 };
59 
ParseRdbPredicatesProxy(napi_env env,napi_value arg,std::shared_ptr<RdbPredicates> & predicates)60 int32_t TransactionContext::ParseRdbPredicatesProxy(
61     napi_env env, napi_value arg, std::shared_ptr<RdbPredicates> &predicates)
62 {
63     RdbPredicatesProxy *predicatesProxy = nullptr;
64     auto status = napi_unwrap(env, arg, reinterpret_cast<void **>(&predicatesProxy));
65     ASSERT_RETURN_SET_ERROR(status == napi_ok && predicatesProxy != nullptr,
66         std::make_shared<ParamError>("predicates", "an RdbPredicates."));
67     predicates = predicatesProxy->GetInstance();
68     ASSERT_RETURN_SET_ERROR(predicates != nullptr, std::make_shared<ParamError>("predicates", "an RdbPredicates."));
69     return OK;
70 }
71 
ParseSendableValuesBucket(const napi_env env,const napi_value map,ValuesBucket & valuesBucket)72 int32_t TransactionContext::ParseSendableValuesBucket(
73     const napi_env env, const napi_value map, ValuesBucket &valuesBucket)
74 {
75     uint32_t length = 0;
76     napi_status status = napi_map_get_size(env, map, &length);
77     auto error = std::make_shared<ParamError>("ValuesBucket is invalid.");
78     ASSERT_RETURN_SET_ERROR(status == napi_ok && length > 0, error);
79     napi_value entries = nullptr;
80     status = napi_map_get_entries(env, map, &entries);
81     ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<InnerError>("napi_map_get_entries failed."));
82     for (uint32_t i = 0; i < length; ++i) {
83         napi_value iter = nullptr;
84         status = napi_map_iterator_get_next(env, entries, &iter);
85         ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<InnerError>("napi_map_iterator_get_next failed."));
86         napi_value values = nullptr;
87         status = napi_get_named_property(env, iter, "value", &values);
88         ASSERT_RETURN_SET_ERROR(
89             status == napi_ok, std::make_shared<InnerError>("napi_get_named_property value failed."));
90         napi_value key = nullptr;
91         status = napi_get_element(env, values, KEY_INDEX, &key);
92         ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<InnerError>("napi_get_element key failed."));
93         std::string keyStr = JSUtils::Convert2String(env, key);
94         napi_value value = nullptr;
95         status = napi_get_element(env, values, VALUE_INDEX, &value);
96         ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<InnerError>("napi_get_element value failed."));
97         ValueObject valueObject;
98         int32_t ret = JSUtils::Convert2Value(env, value, valueObject.value);
99         if (ret == napi_ok) {
100             valuesBucket.values_.insert_or_assign(std::move(keyStr), std::move(valueObject));
101         } else if (ret != napi_generic_failure) {
102             ASSERT_RETURN_SET_ERROR(false, std::make_shared<ParamError>("The value type of " + keyStr, "invalid."));
103         }
104     }
105     return OK;
106 }
107 
ParseValuesBucket(napi_env env,napi_value arg,ValuesBucket & valuesBucket)108 int32_t TransactionContext::ParseValuesBucket(napi_env env, napi_value arg, ValuesBucket &valuesBucket)
109 {
110     bool isMap = false;
111     napi_status status = napi_is_map(env, arg, &isMap);
112     ASSERT_RETURN_SET_ERROR(
113         status == napi_ok, std::make_shared<InnerError>("call napi_is_map failed" + std::to_string(status)));
114     if (isMap) {
115         return ParseSendableValuesBucket(env, arg, valuesBucket);
116     }
117     napi_value keys = nullptr;
118     napi_get_all_property_names(env, arg, napi_key_own_only,
119         static_cast<napi_key_filter>(napi_key_enumerable | napi_key_skip_symbols), napi_key_numbers_to_strings, &keys);
120     uint32_t arrLen = 0;
121     status = napi_get_array_length(env, keys, &arrLen);
122     ASSERT_RETURN_SET_ERROR(status == napi_ok && arrLen > 0, std::make_shared<ParamError>("ValuesBucket is invalid"));
123 
124     for (size_t i = 0; i < arrLen; ++i) {
125         napi_value key = nullptr;
126         status = napi_get_element(env, keys, i, &key);
127         ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<ParamError>("ValuesBucket is invalid."));
128         std::string keyStr = JSUtils::Convert2String(env, key);
129         napi_value value = nullptr;
130         napi_get_property(env, arg, key, &value);
131         ValueObject valueObject;
132         int32_t ret = JSUtils::Convert2Value(env, value, valueObject.value);
133         if (ret == napi_ok) {
134             valuesBucket.values_.insert_or_assign(std::move(keyStr), std::move(valueObject));
135         } else if (ret != napi_generic_failure) {
136             ASSERT_RETURN_SET_ERROR(false, std::make_shared<ParamError>("The value type of " + keyStr, "invalid."));
137         }
138     }
139     return OK;
140 }
141 
ParseValuesBuckets(napi_env env,napi_value arg,std::vector<ValuesBucket> & valuesBuckets)142 int32_t TransactionContext::ParseValuesBuckets(napi_env env, napi_value arg, std::vector<ValuesBucket> &valuesBuckets)
143 {
144     bool isArray = false;
145     auto status = napi_is_array(env, arg, &isArray);
146     ASSERT_RETURN_SET_ERROR(status == napi_ok && isArray, std::make_shared<ParamError>("ValuesBucket is invalid."));
147 
148     uint32_t arrLen = 0;
149     status = napi_get_array_length(env, arg, &arrLen);
150     ASSERT_RETURN_SET_ERROR(status == napi_ok && arrLen > 0, std::make_shared<ParamError>("ValuesBucket is invalid."));
151 
152     for (uint32_t i = 0; i < arrLen; ++i) {
153         napi_value obj = nullptr;
154         status = napi_get_element(env, arg, i, &obj);
155         ASSERT_RETURN_SET_ERROR(status == napi_ok, std::make_shared<InnerError>("napi_get_element failed."));
156         ValuesBucket valuesBucket;
157         ASSERT_RETURN_SET_ERROR(
158             ParseValuesBucket(env, obj, valuesBucket) == OK, std::make_shared<ParamError>("ValuesBucket is invalid."));
159         valuesBuckets.push_back(std::move(valuesBucket));
160     }
161     return OK;
162 }
163 
ParseConflictResolution(const napi_env env,const napi_value arg,NativeRdb::ConflictResolution & conflictResolution)164 int32_t TransactionContext::ParseConflictResolution(
165     const napi_env env, const napi_value arg, NativeRdb::ConflictResolution &conflictResolution)
166 {
167     int32_t input = 0;
168     auto status = napi_get_value_int32(env, arg, &input);
169     int min = static_cast<int32_t>(NativeRdb::ConflictResolution::ON_CONFLICT_NONE);
170     int max = static_cast<int32_t>(NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
171     bool checked = status == napi_ok && (input >= min) && (input <= max);
172     ASSERT_RETURN_SET_ERROR(checked, std::make_shared<ParamError>("conflictResolution", "a ConflictResolution."));
173     conflictResolution = static_cast<NativeRdb::ConflictResolution>(input);
174     return OK;
175 }
176 
NewInstance(napi_env env,std::shared_ptr<NativeRdb::Transaction> transaction)177 napi_value TransactionProxy::NewInstance(napi_env env, std::shared_ptr<NativeRdb::Transaction> transaction)
178 {
179     napi_value cons = JSUtils::GetClass(env, "ohos.data.relationalStore", "Transaction");
180     if (cons == nullptr) {
181         LOG_ERROR("Constructor of Transaction is nullptr!");
182         return nullptr;
183     }
184     napi_value instance = nullptr;
185     auto status = napi_new_instance(env, cons, 0, nullptr, &instance);
186     if (status != napi_ok) {
187         LOG_ERROR("NewInstance napi_new_instance failed! code:%{public}d!", status);
188         return nullptr;
189     }
190 
191     TransactionProxy *proxy = nullptr;
192     status = napi_unwrap(env, instance, reinterpret_cast<void **>(&proxy));
193     if (proxy == nullptr) {
194         LOG_ERROR("NewInstance native instance is nullptr! code:%{public}d!", status);
195         return instance;
196     }
197     proxy->SetInstance(std::move(transaction));
198     return instance;
199 }
200 
Init(napi_env env,napi_value exports)201 void TransactionProxy::Init(napi_env env, napi_value exports)
202 {
203     auto lambda = []() -> std::vector<napi_property_descriptor> {
204         std::vector<napi_property_descriptor> properties = {
205             DECLARE_NAPI_FUNCTION("rollback", Rollback),
206             DECLARE_NAPI_FUNCTION("commit", Commit),
207             DECLARE_NAPI_FUNCTION_WITH_DATA("delete", Delete, ASYNC),
208             DECLARE_NAPI_FUNCTION_WITH_DATA("update", Update, ASYNC),
209             DECLARE_NAPI_FUNCTION_WITH_DATA("insert", Insert, ASYNC),
210             DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsert", BatchInsert, ASYNC),
211             DECLARE_NAPI_FUNCTION_WITH_DATA("query", Query, ASYNC),
212             DECLARE_NAPI_FUNCTION_WITH_DATA("querySql", QuerySql, ASYNC),
213             DECLARE_NAPI_FUNCTION_WITH_DATA("execute", Execute, ASYNC),
214         };
215         AddSyncFunctions(properties);
216         return properties;
217     };
218     auto jsCtor = JSUtils::DefineClass(env, "ohos.data.relationalStore", "Transaction", lambda, Initialize);
219     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, "Transaction", jsCtor));
220 
221     LOG_DEBUG("TransactionProxy::Init end.");
222 }
223 
AddSyncFunctions(std::vector<napi_property_descriptor> & properties)224 void TransactionProxy::AddSyncFunctions(std::vector<napi_property_descriptor> &properties)
225 {
226     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("deleteSync", Delete, SYNC));
227     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("updateSync", Update, SYNC));
228     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("insertSync", Insert, SYNC));
229     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("batchInsertSync", BatchInsert, SYNC));
230     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySync", Query, SYNC));
231     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("querySqlSync", QuerySql, SYNC));
232     properties.push_back(DECLARE_NAPI_FUNCTION_WITH_DATA("executeSync", Execute, SYNC));
233 }
234 
~TransactionProxy()235 TransactionProxy::~TransactionProxy()
236 {
237 }
238 
TransactionProxy(std::shared_ptr<NativeRdb::Transaction> transaction)239 TransactionProxy::TransactionProxy(std::shared_ptr<NativeRdb::Transaction> transaction)
240 {
241     if (GetInstance() == transaction) {
242         return;
243     }
244     SetInstance(std::move(transaction));
245 }
246 
Initialize(napi_env env,napi_callback_info info)247 napi_value TransactionProxy::Initialize(napi_env env, napi_callback_info info)
248 {
249     napi_value self = nullptr;
250     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr));
251     auto *proxy = new (std::nothrow) TransactionProxy();
252     if (proxy == nullptr) {
253         LOG_ERROR("no memory, new TransactionProxy failed!");
254         return nullptr;
255     }
256     auto finalize = [](napi_env env, void *data, void *hint) {
257         if (data != hint) {
258             LOG_ERROR("memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR, uintptr_t(data),
259                 uintptr_t(hint));
260             return;
261         }
262         TransactionProxy *proxy = reinterpret_cast<TransactionProxy *>(data);
263         proxy->SetInstance(nullptr);
264         delete proxy;
265     };
266     napi_status status = napi_wrap(env, self, proxy, finalize, proxy, nullptr);
267     if (status != napi_ok) {
268         LOG_ERROR("napi_wrap failed! code:%{public}d!", status);
269         finalize(env, proxy, proxy);
270         return nullptr;
271     }
272     return self;
273 }
274 
275 struct CommitContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::CommitContext276     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
277     {
278         GetInstance(self);
279         ASSERT_RETURN_SET_ERROR(
280             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
281         return OK;
282     }
283 };
284 /*
285  * [JS API Prototype]
286  * [Promise]
287  *      commit(): Promise<void>;
288  */
Commit(napi_env env,napi_callback_info info)289 napi_value TransactionProxy::Commit(napi_env env, napi_callback_info info)
290 {
291     auto context = std::make_shared<CommitContext>();
292     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
293         context->Parse(env, argc, argv, self);
294     };
295     auto exec = [context]() -> int {
296         CHECK_RETURN_ERR(context->transaction_ != nullptr);
297         return context->StealTransaction()->Commit();
298     };
299     auto output = [context](napi_env env, napi_value &result) {
300         napi_status status = napi_get_undefined(env, &result);
301         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
302     };
303     context->SetAction(env, info, input, exec, output);
304 
305     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
306     return ASYNC_CALL(env, context);
307 }
308 
309 struct RollbackContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::RollbackContext310     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
311     {
312         GetInstance(self);
313         ASSERT_RETURN_SET_ERROR(
314             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
315         return OK;
316     }
317 };
318 
319 /*
320  * [JS API Prototype]
321  * [Promise]
322  *      rollback(): Promise<void>;
323  */
Rollback(napi_env env,napi_callback_info info)324 napi_value TransactionProxy::Rollback(napi_env env, napi_callback_info info)
325 {
326     auto context = std::make_shared<RollbackContext>();
327     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
328         context->Parse(env, argc, argv, self);
329     };
330     auto exec = [context]() -> int {
331         CHECK_RETURN_ERR(context->transaction_ != nullptr);
332         return context->StealTransaction()->Rollback();
333     };
334     auto output = [context](napi_env env, napi_value &result) {
335         napi_status status = napi_get_undefined(env, &result);
336         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
337     };
338     context->SetAction(env, info, input, exec, output);
339 
340     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
341     return ASYNC_CALL(env, context);
342 }
343 
344 struct DeleteContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::DeleteContext345     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
346     {
347         ASSERT_RETURN_SET_ERROR(argc == 1, std::make_shared<ParamNumError>("1"));
348         GetInstance(self);
349         ASSERT_RETURN_SET_ERROR(
350             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
351         CHECK_RETURN_ERR(ParseRdbPredicatesProxy(env, argv[0], rdbPredicates) == OK);
352         return OK;
353     }
354     std::shared_ptr<RdbPredicates> rdbPredicates = nullptr;
355 
356     int64_t deleteRows = -1;
357 };
358 
359 /*
360  * [JS API Prototype]
361  * [Promise]
362  *      delete(predicates: RdbPredicates): Promise<number>;
363  */
Delete(napi_env env,napi_callback_info info)364 napi_value TransactionProxy::Delete(napi_env env, napi_callback_info info)
365 {
366     auto context = std::make_shared<DeleteContext>();
367     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
368         context->Parse(env, argc, argv, self);
369     };
370     auto exec = [context]() -> int {
371         CHECK_RETURN_ERR(context->transaction_ != nullptr && context->rdbPredicates != nullptr);
372         auto [code, deleteRows] = context->StealTransaction()->Delete(*(context->rdbPredicates));
373         context->deleteRows = deleteRows;
374         return code;
375     };
376     auto output = [context](napi_env env, napi_value &result) {
377         napi_status status = napi_create_int64(env, context->deleteRows, &result);
378         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
379     };
380     context->SetAction(env, info, input, exec, output);
381 
382     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
383     return ASYNC_CALL(env, context);
384 }
385 
386 struct UpdateContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::UpdateContext387     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
388     {
389         ASSERT_RETURN_SET_ERROR(argc == 2 || argc == 3, std::make_shared<ParamNumError>("2 to 3"));
390         GetInstance(self);
391         ASSERT_RETURN_SET_ERROR(
392             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
393         CHECK_RETURN_ERR(ParseValuesBucket(env, argv[0], valuesBucket) == OK);
394         CHECK_RETURN_ERR(ParseRdbPredicatesProxy(env, argv[1], rdbPredicates) == OK);
395         // 'argv[2]' is an optional parameter
396         if (argc > 2 && !JSUtils::IsNull(env, argv[2])) {
397             // 'argv[2]' represents a ConflictResolution parameter
398             CHECK_RETURN_ERR(ParseConflictResolution(env, argv[2], conflictResolution));
399         }
400         return OK;
401     }
402     ValuesBucket valuesBucket;
403     std::shared_ptr<RdbPredicates> rdbPredicates = nullptr;
404     NativeRdb::ConflictResolution conflictResolution = ConflictResolution::ON_CONFLICT_NONE;
405 
406     int64_t updateRows = -1;
407 };
408 
409 /*
410  * [JS API Prototype]
411  * [Promise]
412  *      update(values: ValuesBucket, predicates: RdbPredicates, conflict?: ConflictResolution): Promise<number>;
413  */
Update(napi_env env,napi_callback_info info)414 napi_value TransactionProxy::Update(napi_env env, napi_callback_info info)
415 {
416     auto context = std::make_shared<UpdateContext>();
417     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
418         context->Parse(env, argc, argv, self);
419     };
420     auto exec = [context]() -> int {
421         CHECK_RETURN_ERR(context->transaction_ != nullptr && context->rdbPredicates != nullptr);
422         auto [code, updateRows] = context->StealTransaction()->Update(
423             context->valuesBucket, *context->rdbPredicates, context->conflictResolution);
424         context->updateRows = updateRows;
425         return code;
426     };
427     auto output = [context](napi_env env, napi_value &result) {
428         napi_status status = napi_create_int64(env, context->updateRows, &result);
429         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
430     };
431     context->SetAction(env, info, input, exec, output);
432 
433     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
434     return ASYNC_CALL(env, context);
435 }
436 
437 struct InsertContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::InsertContext438     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
439     {
440         ASSERT_RETURN_SET_ERROR(argc == 2 || argc == 3, std::make_shared<ParamNumError>("2 to 3"));
441         GetInstance(self);
442         ASSERT_RETURN_SET_ERROR(
443             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
444         CHECK_RETURN_ERR(JSUtils::Convert2Value(env, argv[0], tableName) == OK);
445         CHECK_RETURN_ERR(ParseValuesBucket(env, argv[1], valuesBucket) == OK);
446         // 'argv[2]' is an optional parameter
447         if (argc > 2 && !JSUtils::IsNull(env, argv[2])) {
448             // 'argv[2]' represents a ConflictResolution parameter
449             CHECK_RETURN_ERR(ParseConflictResolution(env, argv[2], conflictResolution));
450         }
451         return OK;
452     }
453     std::string tableName;
454     ValuesBucket valuesBucket;
455     NativeRdb::ConflictResolution conflictResolution = ConflictResolution::ON_CONFLICT_NONE;
456 
457     int64_t insertRows = -1;
458 };
459 
460 /*
461  * [JS API Prototype]
462  * [Promise]
463  *      insert(table: string, values: ValuesBucket, conflict?: ConflictResolution): Promise<number>;
464  */
Insert(napi_env env,napi_callback_info info)465 napi_value TransactionProxy::Insert(napi_env env, napi_callback_info info)
466 {
467     auto context = std::make_shared<InsertContext>();
468     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
469         context->Parse(env, argc, argv, self);
470     };
471     auto exec = [context]() -> int {
472         CHECK_RETURN_ERR(context->transaction_ != nullptr);
473         auto [code, insertRows] = context->StealTransaction()->Insert(
474             context->tableName, context->valuesBucket, context->conflictResolution);
475         context->insertRows = insertRows;
476         return code;
477     };
478     auto output = [context](napi_env env, napi_value &result) {
479         napi_status status = napi_create_int64(env, context->insertRows, &result);
480         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
481     };
482     context->SetAction(env, info, input, exec, output);
483 
484     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
485     return ASYNC_CALL(env, context);
486 }
487 
488 struct BatchInsertContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::BatchInsertContext489     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
490     {
491         ASSERT_RETURN_SET_ERROR(argc == 2, std::make_shared<ParamNumError>("2"));
492         GetInstance(self);
493         ASSERT_RETURN_SET_ERROR(
494             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
495         ASSERT_RETURN_SET_ERROR(
496             JSUtils::Convert2Value(env, argv[0], tableName) == OK, std::make_shared<ParamError>("table", "a string."));
497         CHECK_RETURN_ERR(ParseValuesBuckets(env, argv[1], valuesBuckets) == OK);
498         return OK;
499     }
500     std::string tableName;
501     std::vector<ValuesBucket> valuesBuckets;
502 
503     int64_t insertRows = -1;
504 };
505 
506 /*
507  * [JS API Prototype]
508  * [Promise]
509  *      batchInsert(table: string, values: Array<ValuesBucket>): Promise<number>;
510  */
BatchInsert(napi_env env,napi_callback_info info)511 napi_value TransactionProxy::BatchInsert(napi_env env, napi_callback_info info)
512 {
513     auto context = std::make_shared<BatchInsertContext>();
514     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
515         context->Parse(env, argc, argv, self);
516     };
517     auto exec = [context]() -> int {
518         CHECK_RETURN_ERR(context->transaction_ != nullptr);
519         auto [code, insertRows] = context->StealTransaction()->BatchInsert(context->tableName, context->valuesBuckets);
520         context->insertRows = insertRows;
521         return code;
522     };
523     auto output = [context](napi_env env, napi_value &result) {
524         napi_status status = napi_create_int64(env, context->insertRows, &result);
525         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
526     };
527     context->SetAction(env, info, input, exec, output);
528 
529     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
530     return ASYNC_CALL(env, context);
531 }
532 
533 struct QueryContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::QueryContext534     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
535     {
536         ASSERT_RETURN_SET_ERROR(argc == 1 || argc == 2, std::make_shared<ParamNumError>("1 to 2"));
537         GetInstance(self);
538         ASSERT_RETURN_SET_ERROR(
539             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
540         CHECK_RETURN_ERR(ParseRdbPredicatesProxy(env, argv[0], rdbPredicates) == OK);
541         if (argc > 1 && !JSUtils::IsNull(env, argv[1])) {
542             ASSERT_RETURN_SET_ERROR(JSUtils::Convert2Value(env, argv[1], columns) == OK,
543                 std::make_shared<ParamError>("columns", "a Array<string>."));
544         }
545         return OK;
546     }
547     std::shared_ptr<RdbPredicates> rdbPredicates = nullptr;
548     std::vector<std::string> columns;
549 
550     std::shared_ptr<ResultSet> resultSet;
551 };
552 
553 /*
554  * [JS API Prototype]
555  * [Promise]
556  *      query(predicates: RdbPredicates, columns?: Array<string>): Promise<ResultSet>;
557  */
Query(napi_env env,napi_callback_info info)558 napi_value TransactionProxy::Query(napi_env env, napi_callback_info info)
559 {
560     auto context = std::make_shared<QueryContext>();
561     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
562         context->Parse(env, argc, argv, self);
563     };
564     auto exec = [context]() -> int {
565         CHECK_RETURN_ERR(context->transaction_ != nullptr && context->rdbPredicates != nullptr);
566         context->resultSet = context->StealTransaction()->QueryByStep(*(context->rdbPredicates), context->columns);
567         return (context->resultSet != nullptr) ? E_OK : E_ALREADY_CLOSED;
568     };
569     auto output = [context](napi_env env, napi_value &result) {
570         result = ResultSetProxy::NewInstance(env, context->resultSet);
571         CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
572     };
573     context->SetAction(env, info, input, exec, output);
574 
575     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
576     return ASYNC_CALL(env, context);
577 }
578 
579 struct QuerySqlContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::QuerySqlContext580     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
581     {
582         ASSERT_RETURN_SET_ERROR(argc == 1 || argc == 2, std::make_shared<ParamNumError>("1 to 2"));
583         GetInstance(self);
584         ASSERT_RETURN_SET_ERROR(
585             transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
586         ASSERT_RETURN_SET_ERROR(
587             JSUtils::Convert2Value(env, argv[0], sql) == OK, std::make_shared<ParamError>("sql", "a string."));
588         if (argc > 1 && !JSUtils::IsNull(env, argv[1])) {
589             ASSERT_RETURN_SET_ERROR(JSUtils::Convert2Value(env, argv[1], bindArgs) == OK,
590                 std::make_shared<ParamError>("bindArgs", "a Array<ValueType>."));
591         }
592         return OK;
593     }
594     std::string sql;
595     std::vector<ValueObject> bindArgs;
596 
597     std::shared_ptr<ResultSet> resultSet;
598 };
599 
600 /*
601  * [JS API Prototype]
602  * [Promise]
603  *      querySql(sql: string, bindArgs?: Array<ValueType>): Promise<ResultSet>;
604  */
QuerySql(napi_env env,napi_callback_info info)605 napi_value TransactionProxy::QuerySql(napi_env env, napi_callback_info info)
606 {
607     auto context = std::make_shared<QuerySqlContext>();
608     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
609         context->Parse(env, argc, argv, self);
610     };
611     auto exec = [context]() -> int {
612         CHECK_RETURN_ERR(context->transaction_ != nullptr);
613         context->resultSet = context->StealTransaction()->QueryByStep(context->sql, context->bindArgs);
614         return (context->resultSet != nullptr) ? E_OK : E_ALREADY_CLOSED;
615     };
616     auto output = [context](napi_env env, napi_value &result) {
617         result = ResultSetProxy::NewInstance(env, context->resultSet);
618         CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
619     };
620     context->SetAction(env, info, input, exec, output);
621 
622     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
623     return ASYNC_CALL(env, context);
624 }
625 
626 struct ExecuteContext : public TransactionContext {
ParseOHOS::RelationalStoreJsKit::ExecuteContext627     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
628     {
629         ASSERT_RETURN_SET_ERROR(argc == 1 || argc == 2, std::make_shared<ParamNumError>("1 to 2"));
630         GetInstance(self);
631         ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
632         CHECK_RETURN_ERR(JSUtils::Convert2Value(env, argv[0], sql) == OK);
633         if (argc > 1 && !JSUtils::IsNull(env, argv[1])) {
634             CHECK_RETURN_ERR(JSUtils::Convert2Value(env, argv[1], bindArgs) == OK);
635         }
636         return OK;
637     }
638     std::string sql;
639     std::vector<ValueObject> bindArgs;
640 
641     ValueObject output;
642 };
643 
644 /*
645  * [JS API Prototype]
646  * [Promise]
647  *      execute(sql: string, args?: Array<ValueType>): Promise<ValueType>;
648  */
Execute(napi_env env,napi_callback_info info)649 napi_value TransactionProxy::Execute(napi_env env, napi_callback_info info)
650 {
651     auto context = std::make_shared<ExecuteContext>();
652     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
653         context->Parse(env, argc, argv, self);
654     };
655     auto exec = [context]() -> int {
656         CHECK_RETURN_ERR(context->transaction_ != nullptr);
657         auto status = E_ERROR;
658         std::tie(status, context->output) = context->StealTransaction()->Execute(context->sql, context->bindArgs);
659         return status;
660     };
661     auto output = [context](napi_env env, napi_value &result) {
662         result = JSUtils::Convert2JSValue(env, context->output);
663         CHECK_RETURN_SET_E(result != nullptr, std::make_shared<InnerError>(E_ERROR));
664     };
665     context->SetAction(env, info, input, exec, output);
666 
667     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
668     return ASYNC_CALL(env, context);
669 }
670 } // namespace OHOS::RelationalStoreJsKit
671