• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "GdbTransactionProxy"
16 #include "napi_gdb_transaction.h"
17 
18 #include <algorithm>
19 #include <cinttypes>
20 #include <cstdint>
21 #include <vector>
22 
23 #include "db_trace.h"
24 #include "js_utils.h"
25 #include "logger.h"
26 #include "napi_gdb_context.h"
27 #include "napi_gdb_error.h"
28 #include "napi_gdb_js_utils.h"
29 
30 namespace OHOS::GraphStoreJsKit {
31 #define ASSERT_RETURN_SET_ERROR(assertion, paramError) \
32     CHECK_RETURN_CORE(assertion, SetError(paramError), ERR)
33 
34 constexpr int32_t MAX_GQL_LEN = 1024 * 1024;
35 
36 constexpr const char *SPACE_NAME = "ohos.data.graphStore";
37 constexpr const char *CLASS_NAME = "Transaction";
38 
39 struct TransactionContext : public ContextBase {
GetInstanceOHOS::GraphStoreJsKit::TransactionContext40     void GetInstance(napi_value self)
41     {
42         auto status = napi_unwrap(env_, self, reinterpret_cast<void **>(&boundObj));
43         if (status != napi_ok || boundObj == nullptr) {
44             LOG_ERROR("GdbTransactionProxy native instance is nullptr! code:%{public}d!", status);
45             return;
46         }
47         transaction_ = reinterpret_cast<GdbTransactionProxy *>(boundObj)->GetInstance();
48     }
StealTransactionOHOS::GraphStoreJsKit::TransactionContext49     std::shared_ptr<Transaction> StealTransaction()
50     {
51         auto trans = std::move(transaction_);
52         transaction_ = nullptr;
53         return trans;
54     }
55     std::shared_ptr<Transaction> transaction_ = nullptr;
56 };
57 
~GdbTransactionProxy()58 GdbTransactionProxy::~GdbTransactionProxy()
59 {
60 }
61 
GdbTransactionProxy(std::shared_ptr<Transaction> gdbTransaction)62 GdbTransactionProxy::GdbTransactionProxy(std::shared_ptr<Transaction> gdbTransaction)
63 {
64     if (GetInstance() == gdbTransaction) {
65         return;
66     }
67     SetInstance(std::move(gdbTransaction));
68 }
69 
Initialize(napi_env env,napi_callback_info info)70 napi_value GdbTransactionProxy::Initialize(napi_env env, napi_callback_info info)
71 {
72     napi_value self = nullptr;
73     NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &self, nullptr));
74     auto *proxy = new (std::nothrow) GdbTransactionProxy();
75     if (proxy == nullptr) {
76         return nullptr;
77     }
78     auto finalize = [](napi_env env, void *data, void *hint) {
79         if (data != hint) {
80             LOG_ERROR("memory corrupted! data:0x%016" PRIXPTR "hint:0x%016" PRIXPTR,
81                 uintptr_t(data), uintptr_t(hint));
82             return;
83         }
84         GdbTransactionProxy *proxy = reinterpret_cast<GdbTransactionProxy *>(data);
85         proxy->SetInstance(nullptr);
86         delete proxy;
87     };
88     napi_status status = napi_wrap(env, self, proxy, finalize, proxy, nullptr);
89     if (status != napi_ok) {
90         LOG_ERROR("napi_wrap failed! code:%{public}d!", status);
91         finalize(env, proxy, proxy);
92         return nullptr;
93     }
94     return self;
95 }
96 
Init(napi_env env,napi_value exports)97 void GdbTransactionProxy::Init(napi_env env, napi_value exports)
98 {
99     auto lambda = []() -> std::vector<napi_property_descriptor> {
100         std::vector<napi_property_descriptor> properties = {
101             DECLARE_NAPI_FUNCTION("read", Read),
102             DECLARE_NAPI_FUNCTION("write", Write),
103             DECLARE_NAPI_FUNCTION("commit", Commit),
104             DECLARE_NAPI_FUNCTION("rollback", Rollback),
105         };
106         return properties;
107     };
108     auto jsCtor = AppDataMgrJsKit::JSUtils::DefineClass(env, SPACE_NAME, CLASS_NAME, lambda, Initialize);
109     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, exports, CLASS_NAME, jsCtor));
110 }
111 
NewInstance(napi_env env,std::shared_ptr<Transaction> value)112 napi_value GdbTransactionProxy::NewInstance(napi_env env, std::shared_ptr<Transaction> value)
113 {
114     if (value == nullptr) {
115         LOG_ERROR("value is nullptr");
116         return nullptr;
117     }
118     napi_value cons = AppDataMgrJsKit::JSUtils::GetClass(env, SPACE_NAME, CLASS_NAME);
119     if (cons == nullptr) {
120         LOG_ERROR("Constructor of Transaction is nullptr!");
121         return nullptr;
122     }
123 
124     napi_value instance = nullptr;
125     auto status = napi_new_instance(env, cons, 0, nullptr, &instance);
126     if (status != napi_ok) {
127         LOG_ERROR("create new instance failed! code:%{public}d!", status);
128         return nullptr;
129     }
130 
131     GdbTransactionProxy *proxy = nullptr;
132     status = napi_unwrap(env, instance, reinterpret_cast<void **>(&proxy));
133     if (status != napi_ok || proxy == nullptr) {
134         LOG_ERROR("native instance is nullptr! code:%{public}d!", status);
135         return instance;
136     }
137     proxy->SetInstance(std::move(value));
138     return instance;
139 }
140 
141 struct ReadWriteContext : public TransactionContext {
ParseOHOS::GraphStoreJsKit::ReadWriteContext142     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
143     {
144         ASSERT_RETURN_SET_ERROR(argc == 1, std::make_shared<ParamNumError>(" 1 "));
145         GetInstance(self);
146         ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared<ParamError>("transaction", "not nullptr."));
147         gql = AppDataMgrJsKit::JSUtils::Convert2String(env, argv[0]);
148         ASSERT_RETURN_SET_ERROR(!gql.empty(), std::make_shared<ParamError>("gql", "not empty"));
149         ASSERT_RETURN_SET_ERROR(gql.size() <= MAX_GQL_LEN,
150             std::make_shared<ParamError>("gql", "too long"));
151         return OK;
152     }
153     std::string gql;
154     std::shared_ptr<Result> result;
155     int32_t errCode;
156 };
157 
Read(napi_env env,napi_callback_info info)158 napi_value GdbTransactionProxy::Read(napi_env env, napi_callback_info info)
159 {
160     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
161     auto context = std::make_shared<ReadWriteContext>();
162     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
163         context->Parse(env, argc, argv, self);
164     };
165     auto exec = [context]() -> int {
166         CHECK_RETURN_ERR(context->transaction_ != nullptr);
167         std::tie(context->errCode, context->result) = context->StealTransaction()->Query(context->gql);
168         return context->errCode;
169     };
170     auto output = [context](napi_env env, napi_value &result) {
171         result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result);
172         CHECK_RETURN_SET_E(context->errCode == OK, std::make_shared<InnerError>(context->errCode));
173     };
174     context->SetAction(env, info, input, exec, output);
175 
176     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
177     return ASYNC_CALL(env, context);
178 }
179 
Write(napi_env env,napi_callback_info info)180 napi_value GdbTransactionProxy::Write(napi_env env, napi_callback_info info)
181 {
182     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
183     auto context = std::make_shared<ReadWriteContext>();
184     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
185         context->Parse(env, argc, argv, self);
186     };
187     auto exec = [context]() -> int {
188         CHECK_RETURN_ERR(context->transaction_ != nullptr);
189         std::tie(context->errCode, context->result) = context->StealTransaction()->Execute(context->gql);
190         return context->errCode;
191     };
192     auto output = [context](napi_env env, napi_value &result) {
193         result = AppDataMgrJsKit::JSUtils::Convert2JSValue(env, context->result);
194         CHECK_RETURN_SET_E(context->errCode == OK, std::make_shared<InnerError>(context->errCode));
195     };
196     context->SetAction(env, info, input, exec, output);
197 
198     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
199     return ASYNC_CALL(env, context);
200 }
201 
202 struct CommitRollbackContext : public TransactionContext {
ParseOHOS::GraphStoreJsKit::CommitRollbackContext203     int32_t Parse(napi_env env, size_t argc, napi_value *argv, napi_value self)
204     {
205         GetInstance(self);
206         ASSERT_RETURN_SET_ERROR(transaction_ != nullptr, std::make_shared<ParamError>("transaction", "a transaction."));
207         return OK;
208     }
209 };
210 
Commit(napi_env env,napi_callback_info info)211 napi_value GdbTransactionProxy::Commit(napi_env env, napi_callback_info info)
212 {
213     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
214     auto context = std::make_shared<CommitRollbackContext>();
215     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
216         context->Parse(env, argc, argv, self);
217     };
218     auto exec = [context]() -> int {
219         CHECK_RETURN_ERR(context->transaction_ != nullptr);
220         return context->StealTransaction()->Commit();
221     };
222     auto output = [context](napi_env env, napi_value &result) {
223         napi_status status = napi_get_undefined(env, &result);
224         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
225     };
226     context->SetAction(env, info, input, exec, output);
227 
228     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
229     return ASYNC_CALL(env, context);
230 }
231 
Rollback(napi_env env,napi_callback_info info)232 napi_value GdbTransactionProxy::Rollback(napi_env env, napi_callback_info info)
233 {
234     DISTRIBUTED_DATA_HITRACE(std::string(__FUNCTION__));
235     auto context = std::make_shared<CommitRollbackContext>();
236     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
237         context->Parse(env, argc, argv, self);
238     };
239     auto exec = [context]() -> int {
240         CHECK_RETURN_ERR(context->transaction_ != nullptr);
241         return context->StealTransaction()->Rollback();
242     };
243     auto output = [context](napi_env env, napi_value &result) {
244         napi_status status = napi_get_undefined(env, &result);
245         CHECK_RETURN_SET_E(status == napi_ok, std::make_shared<InnerError>(E_ERROR));
246     };
247     context->SetAction(env, info, input, exec, output);
248 
249     CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
250     return ASYNC_CALL(env, context);
251 }
252 } // namespace OHOS::GraphStoreJsKit
253