• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "JS_DeviceKVStore"
16 #include "js_device_kv_store.h"
17 #include <iomanip>
18 #include "js_kv_store_resultset.h"
19 #include "js_query.h"
20 #include "js_util.h"
21 #include "log_print.h"
22 #include "napi_queue.h"
23 #include "uv_queue.h"
24 #include "distributed_kv_data_manager.h"
25 
26 using namespace OHOS::DistributedKv;
27 using namespace OHOS::DataShare;
28 namespace OHOS::DistributedKVStore {
29 constexpr int DEVICEID_WIDTH = 4;
GetDeviceKey(const std::string & deviceId,const std::string & key)30 static std::string GetDeviceKey(const std::string& deviceId, const std::string& key)
31 {
32     std::ostringstream oss;
33     if (!deviceId.empty()) {
34         oss << std::setfill('0') << std::setw(DEVICEID_WIDTH) << deviceId.length() << deviceId;
35     }
36     oss << key;
37     return oss.str();
38 }
39 
JsDeviceKVStore(const std::string & storeId)40 JsDeviceKVStore::JsDeviceKVStore(const std::string& storeId)
41     : JsSingleKVStore(storeId)
42 {
43 }
44 
Constructor(napi_env env)45 napi_value JsDeviceKVStore::Constructor(napi_env env)
46 {
47     const napi_property_descriptor properties[] = {
48         DECLARE_NAPI_FUNCTION("put", JsSingleKVStore::Put),
49         DECLARE_NAPI_FUNCTION("delete", JsSingleKVStore::Delete),
50         DECLARE_NAPI_FUNCTION("putBatch", JsSingleKVStore::PutBatch),
51         DECLARE_NAPI_FUNCTION("deleteBatch", JsSingleKVStore::DeleteBatch),
52         DECLARE_NAPI_FUNCTION("startTransaction", JsSingleKVStore::StartTransaction),
53         DECLARE_NAPI_FUNCTION("commit", JsSingleKVStore::Commit),
54         DECLARE_NAPI_FUNCTION("rollback", JsSingleKVStore::Rollback),
55         DECLARE_NAPI_FUNCTION("enableSync", JsSingleKVStore::EnableSync),
56         DECLARE_NAPI_FUNCTION("setSyncRange", JsSingleKVStore::SetSyncRange),
57         /* JsDeviceKVStore externs JsSingleKVStore */
58         DECLARE_NAPI_FUNCTION("get", JsDeviceKVStore::Get),
59         DECLARE_NAPI_FUNCTION("getEntries", JsDeviceKVStore::GetEntries),
60         DECLARE_NAPI_FUNCTION("getResultSet", JsDeviceKVStore::GetResultSet),
61         DECLARE_NAPI_FUNCTION("getResultSize", JsDeviceKVStore::GetResultSize),
62         DECLARE_NAPI_FUNCTION("closeResultSet", JsSingleKVStore::CloseResultSet),
63         DECLARE_NAPI_FUNCTION("removeDeviceData", JsSingleKVStore::RemoveDeviceData),
64         DECLARE_NAPI_FUNCTION("sync", JsSingleKVStore::Sync),
65         DECLARE_NAPI_FUNCTION("on", JsSingleKVStore::OnEvent), /* same to JsSingleKVStore */
66         DECLARE_NAPI_FUNCTION("off", JsSingleKVStore::OffEvent) /* same to JsSingleKVStore */
67     };
68     size_t count = sizeof(properties) / sizeof(properties[0]);
69 
70     return JSUtil::DefineClass(env, "DeviceKVStore", properties, count, JsDeviceKVStore::New);
71 }
72 
73 /*
74  * [JS API Prototype]
75  * [AsyncCallback]
76  *      get(deviceId:string, key:string, callback:AsyncCallback<boolean|string|number|Uint8Array>):void;
77  * [Promise]
78  *      get(deviceId:string, key:string):Promise<boolean|string|number|Uint8Array>;
79  */
Get(napi_env env,napi_callback_info info)80 napi_value JsDeviceKVStore::Get(napi_env env, napi_callback_info info)
81 {
82     struct GetContext : public ContextBase {
83         std::string deviceId;
84         std::string key;
85         JSUtil::KvStoreVariant value;
86     };
87     auto ctxt = std::make_shared<GetContext>();
88     auto input = [env, ctxt](size_t argc, napi_value* argv) {
89         // number 2 means: required 2 arguments, <deviceId> + <key>
90         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
91         if (argc > 1) {
92             ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->deviceId);
93             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
94                 "The parameter deviceId is incorrect.");
95         }
96         int32_t pos = (argc == 1) ? 0 : 1;
97         ctxt->status = JSUtil::GetValue(env, argv[pos], ctxt->key);
98         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of key must be string.");
99     };
100     ctxt->GetCbInfo(env, info, input);
101     ASSERT_NULL(!ctxt->isThrowError, "DeviceGet exits");
102 
103     auto execute = [ctxt]() {
104         std::string deviceKey = GetDeviceKey(ctxt->deviceId, ctxt->key);
105         OHOS::DistributedKv::Key key(deviceKey);
106         OHOS::DistributedKv::Value value;
107         auto kvStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->GetKvStorePtr();
108         ASSERT_STATUS(ctxt, "kvStore->result() failed!");
109         bool isSchemaStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->IsSchemaStore();
110         Status status = kvStore->Get(key, value);
111         ZLOGD("kvStore->Get return %{public}d", status);
112         ctxt->value = isSchemaStore ? value.ToString() : JSUtil::Blob2VariantValue(value);
113         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
114             napi_ok : napi_generic_failure;
115     };
116     auto output = [env, ctxt](napi_value& result) {
117         ctxt->status = JSUtil::SetValue(env, ctxt->value, result);
118         ASSERT_STATUS(ctxt, "output failed");
119     };
120     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
121 }
122 
123 struct VariantArgs {
124     /* input arguments' combinations */
125     DataQuery dataQuery;
126     std::string errMsg = "";
127 };
128 
GetVariantArgs(napi_env env,size_t argc,napi_value * argv,VariantArgs & va)129 static napi_status GetVariantArgs(napi_env env, size_t argc, napi_value* argv, VariantArgs& va)
130 {
131     int32_t pos = (argc == 1) ? 0 : 1;
132     napi_valuetype type = napi_undefined;
133     napi_status status = napi_typeof(env, argv[pos], &type);
134     if (status != napi_ok||(type != napi_string && type != napi_object)) {
135         va.errMsg = "The type of parameters keyPrefix/query is incorrect.";
136         return status != napi_ok?status:napi_invalid_arg;
137     }
138     if (type == napi_string) {
139         std::string keyPrefix;
140         status = JSUtil::GetValue(env, argv[pos], keyPrefix);
141         if (keyPrefix.empty()) {
142             va.errMsg = "The type of parameters keyPrefix is incorrect.";
143             return napi_invalid_arg;
144         }
145         va.dataQuery.KeyPrefix(keyPrefix);
146     } else {
147         bool result = false;
148         status = napi_instanceof(env, argv[pos], JsQuery::Constructor(env), &result);
149         if ((status == napi_ok) && (result != false)) {
150             JsQuery *jsQuery = nullptr;
151             status = JSUtil::Unwrap(env, argv[pos], reinterpret_cast<void **>(&jsQuery), JsQuery::Constructor(env));
152             if (jsQuery == nullptr) {
153                 va.errMsg = "The parameters query is incorrect.";
154                 return napi_invalid_arg;
155             }
156             va.dataQuery = jsQuery->GetDataQuery();
157         } else {
158             status = JSUtil::GetValue(env, argv[pos], va.dataQuery);
159             ZLOGD("kvStoreDataShare->GetResultSet return %{public}d", status);
160         }
161     }
162     std::string deviceId;
163     if (argc > 1) {
164         JSUtil::GetValue(env, argv[0], deviceId);
165         va.dataQuery.DeviceId(deviceId);
166     }
167     return status;
168 };
169 
170 /*
171  * [JS API Prototype]
172  *  getEntries(deviceId:string, keyPrefix:string, callback:AsyncCallback<Entry[]>):void
173  *  getEntries(deviceId:string, keyPrefix:string):Promise<Entry[]>
174  *
175  *  getEntries(query:Query, callback:AsyncCallback<Entry[]>):void
176  *  getEntries(query:Query) : Promise<Entry[]>
177  *
178  *  getEntries(deviceId:string, query:Query):callback:AsyncCallback<Entry[]>):void
179  *  getEntries(deviceId:string, query:Query):Promise<Entry[]>
180  */
GetEntries(napi_env env,napi_callback_info info)181 napi_value JsDeviceKVStore::GetEntries(napi_env env, napi_callback_info info)
182 {
183     struct GetEntriesContext : public ContextBase {
184         VariantArgs va;
185         std::vector<Entry> entries;
186     };
187     auto ctxt = std::make_shared<GetEntriesContext>();
188     auto input = [env, ctxt](size_t argc, napi_value* argv) {
189         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
190         ctxt->status = GetVariantArgs(env, argc, argv, ctxt->va);
191         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
192     };
193     ctxt->GetCbInfo(env, info, input);
194     ASSERT_NULL(!ctxt->isThrowError, "GetEntries exit");
195 
196     auto execute = [ctxt]() {
197         auto kvStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->GetKvStorePtr();
198         Status status = kvStore->GetEntries(ctxt->va.dataQuery, ctxt->entries);
199         ZLOGD("kvStore->GetEntries() return %{public}d", status);
200         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
201             napi_ok : napi_generic_failure;
202     };
203     auto output = [env, ctxt](napi_value& result) {
204         auto isSchemaStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->IsSchemaStore();
205         ctxt->status = JSUtil::SetValue(env, ctxt->entries, result, isSchemaStore);
206         ASSERT_STATUS(ctxt, "output failed!");
207     };
208     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
209 }
210 
211 /*
212  * [JS API Prototype]
213  *  getResultSet(deviceId:string, keyPrefix:string, callback:AsyncCallback<KvStoreResultSet>):void
214  *  getResultSet(deviceId:string, keyPrefix:string):Promise<KvStoreResultSet>
215  *
216  *  getResultSet(query:Query, callback:AsyncCallback<KvStoreResultSet>):void
217  *  getResultSet(query:Query):Promise<KvStoreResultSet>
218  *
219  *  getResultSet(deviceId:string, query:Query, callback:AsyncCallback<KvStoreResultSet>):void
220  *  getResultSet(deviceId:string, query:Query):Promise<KvStoreResultSet>
221  */
GetResultSet(napi_env env,napi_callback_info info)222 napi_value JsDeviceKVStore::GetResultSet(napi_env env, napi_callback_info info)
223 {
224     struct GetResultSetContext : public ContextBase {
225         VariantArgs va;
226         JsKVStoreResultSet* resultSet = nullptr;
227         napi_ref ref = nullptr;
228     };
229     auto ctxt = std::make_shared<GetResultSetContext>();
230     auto input = [env, ctxt](size_t argc, napi_value* argv) {
231         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
232         ctxt->status = GetVariantArgs(env, argc, argv, ctxt->va);
233         ASSERT_BUSINESS_ERR(ctxt, ctxt->status != napi_invalid_arg, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
234         ctxt->ref = JSUtil::NewWithRef(env, 0, nullptr, reinterpret_cast<void **>(&ctxt->resultSet),
235             JsKVStoreResultSet::Constructor(env));
236         ASSERT_BUSINESS_ERR(ctxt, ctxt->resultSet != nullptr, Status::INVALID_ARGUMENT,
237             "KVStoreResultSet::New failed!");
238     };
239     ctxt->GetCbInfo(env, info, input);
240     ASSERT_NULL(!ctxt->isThrowError, "GetResultSet exit");
241 
242     auto execute = [ctxt]() {
243         std::shared_ptr<KvStoreResultSet> kvResultSet;
244         auto kvStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->GetKvStorePtr();
245         Status status = kvStore->GetResultSet(ctxt->va.dataQuery, kvResultSet);
246         ZLOGD("kvStore->GetResultSet() return %{public}d", status);
247         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
248             napi_ok : napi_generic_failure;
249         ctxt->resultSet->SetKvStoreResultSetPtr(kvResultSet);
250     };
251     auto output = [env, ctxt](napi_value& result) {
252         ctxt->status = napi_get_reference_value(env, ctxt->ref, &result);
253         napi_delete_reference(env, ctxt->ref);
254         ASSERT_STATUS(ctxt, "output KvResultSet failed");
255     };
256     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
257 }
258 
259 /*
260  * [JS API Prototype]
261  *  getResultSize(query:Query, callback: AsyncCallback<number>):void
262  *  getResultSize(query:Query):Promise<number>
263  *
264  *  getResultSize(deviceId:string, query:Query, callback: AsyncCallback<number>):void
265  *  getResultSize(deviceId:string, query:Query):Promise<number>
266  */
GetResultSize(napi_env env,napi_callback_info info)267 napi_value JsDeviceKVStore::GetResultSize(napi_env env, napi_callback_info info)
268 {
269     struct ResultSizeContext : public ContextBase {
270         VariantArgs va;
271         int resultSize = 0;
272     };
273     auto ctxt = std::make_shared<ResultSizeContext>();
274     auto input = [env, ctxt](size_t argc, napi_value* argv) {
275         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
276         ctxt->status = GetVariantArgs(env, argc, argv, ctxt->va);
277         ASSERT_BUSINESS_ERR(ctxt, ctxt->status != napi_invalid_arg, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
278     };
279 
280     ctxt->GetCbInfo(env, info, input);
281     ASSERT_NULL(!ctxt->isThrowError, "GetResultSize exit");
282 
283     auto execute = [ctxt]() {
284         auto kvStore = reinterpret_cast<JsDeviceKVStore*>(ctxt->native)->GetKvStorePtr();
285         Status status = kvStore->GetCount(ctxt->va.dataQuery, ctxt->resultSize);
286         ZLOGD("kvStore->GetCount() return %{public}d", status);
287         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
288             napi_ok : napi_generic_failure;
289     };
290     auto output = [env, ctxt](napi_value& result) {
291         ctxt->status = JSUtil::SetValue(env, static_cast<int32_t>(ctxt->resultSize), result);
292         ASSERT_STATUS(ctxt, "output resultSize failed!");
293     };
294     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
295 }
296 
New(napi_env env,napi_callback_info info)297 napi_value JsDeviceKVStore::New(napi_env env, napi_callback_info info)
298 {
299     ZLOGD("Constructor single kv store!");
300     std::string storeId;
301     auto ctxt = std::make_shared<ContextBase>();
302     auto input = [env, ctxt, &storeId](size_t argc, napi_value* argv) {
303         // required 2 arguments :: <storeId> <options>
304         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
305         ctxt->status = JSUtil::GetValue(env, argv[0], storeId);
306         ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && !storeId.empty(), Status::INVALID_ARGUMENT,
307             "The type of storeId must be string.");
308     };
309     ctxt->GetCbInfoSync(env, info, input);
310     ASSERT_NULL(!ctxt->isThrowError, "New JsDeviceKVStore exit");
311 
312     JsDeviceKVStore* kvStore = new (std::nothrow) JsDeviceKVStore(storeId);
313     ASSERT_ERR(env, kvStore != nullptr, Status::INVALID_ARGUMENT, "no memory for kvStore");
314 
315     auto finalize = [](napi_env env, void* data, void* hint) {
316         ZLOGI("deviceKvStore finalize.");
317         auto* kvStore = reinterpret_cast<JsDeviceKVStore*>(data);
318         ASSERT_VOID(kvStore != nullptr, "finalize null!");
319         delete kvStore;
320     };
321     ASSERT_CALL(env, napi_wrap(env, ctxt->self, kvStore, finalize, nullptr, nullptr), kvStore);
322     return ctxt->self;
323 }
324 } // namespace OHOS::DistributedKVStore
325