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 "JsSingleKVStore"
16 #include "js_single_kv_store.h"
17 #include "js_util.h"
18 #include "js_kv_store_resultset.h"
19 #include "datashare_predicates.h"
20 #include "js_query.h"
21 #include "log_print.h"
22 #include "napi_queue.h"
23 #include "uv_queue.h"
24 #include "kv_utils.h"
25 
26 using namespace OHOS::DistributedKv;
27 using namespace OHOS::DataShare;
28 namespace OHOS::DistributedKVStore {
29 inline static uint8_t UNVALID_SUBSCRIBE_TYPE = 255;
30 std::map<std::string, JsSingleKVStore::Exec> JsSingleKVStore::onEventHandlers_ = {
31     { "dataChange", JsSingleKVStore::OnDataChange },
32     { "syncComplete", JsSingleKVStore::OnSyncComplete }
33 };
34 
35 std::map<std::string, JsSingleKVStore::Exec> JsSingleKVStore::offEventHandlers_ = {
36     { "dataChange", JsSingleKVStore::OffDataChange },
37     { "syncComplete", JsSingleKVStore::OffSyncComplete }
38 };
39 
40 std::map<napi_valuetype, std::string> JsSingleKVStore::valueTypeToString_ = {
41     { napi_string, std::string("string") },
42     { napi_number, std::string("integer") },
43     { napi_object, std::string("bytearray") },
44     { napi_boolean, std::string("bollean") },
45 };
46 
ValidSubscribeType(uint8_t type)47 static bool ValidSubscribeType(uint8_t type)
48 {
49     return (SUBSCRIBE_LOCAL <= type) && (type <= SUBSCRIBE_LOCAL_REMOTE);
50 }
51 
ToSubscribeType(uint8_t type)52 static SubscribeType ToSubscribeType(uint8_t type)
53 {
54     switch (type) {
55         case 0:  // 0 means SUBSCRIBE_TYPE_LOCAL
56             return SubscribeType::SUBSCRIBE_TYPE_LOCAL;
57         case 1:  // 1 means SUBSCRIBE_TYPE_REMOTE
58             return SubscribeType::SUBSCRIBE_TYPE_REMOTE;
59         case 2:  // 2 means SUBSCRIBE_TYPE_ALL
60             return SubscribeType::SUBSCRIBE_TYPE_ALL;
61         default:
62             return static_cast<SubscribeType>(UNVALID_SUBSCRIBE_TYPE);
63     }
64 }
65 
JsSingleKVStore(const std::string & storeId)66 JsSingleKVStore::JsSingleKVStore(const std::string& storeId)
67     : storeId_(storeId)
68 {
69 }
70 
SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)71 void JsSingleKVStore::SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)
72 {
73     kvStore_ = kvStore;
74 }
75 
GetKvStorePtr()76 std::shared_ptr<SingleKvStore> JsSingleKVStore::GetKvStorePtr()
77 {
78     return kvStore_;
79 }
80 
SetContextParam(std::shared_ptr<ContextParam> param)81 void JsSingleKVStore::SetContextParam(std::shared_ptr<ContextParam> param)
82 {
83     param_ = param;
84 }
85 
SetUvQueue(std::shared_ptr<UvQueue> uvQueue)86 void JsSingleKVStore::SetUvQueue(std::shared_ptr<UvQueue> uvQueue)
87 {
88     uvQueue_ = uvQueue;
89 }
90 
IsSchemaStore() const91 bool JsSingleKVStore::IsSchemaStore() const
92 {
93     return isSchemaStore_;
94 }
95 
SetSchemaInfo(bool isSchemaStore)96 void JsSingleKVStore::SetSchemaInfo(bool isSchemaStore)
97 {
98     isSchemaStore_ = isSchemaStore;
99 }
100 
IsSystemApp() const101 bool JsSingleKVStore::IsSystemApp() const
102 {
103     return param_->isSystemApp;
104 }
105 
~JsSingleKVStore()106 JsSingleKVStore::~JsSingleKVStore()
107 {
108     ZLOGD("no memory leak for JsSingleKVStore");
109     if (kvStore_ == nullptr) {
110         return;
111     }
112 
113     std::lock_guard<std::mutex> lck(listMutex_);
114     for (uint8_t type = SUBSCRIBE_LOCAL; type < SUBSCRIBE_COUNT; type++) {
115         for (auto& observer : dataObserver_[type]) {
116             auto subscribeType = ToSubscribeType(type);
117             kvStore_->UnSubscribeKvStore(subscribeType, observer);
118             observer->Clear();
119         }
120         dataObserver_[type].clear();
121     }
122 
123     kvStore_->UnRegisterSyncCallback();
124     for (auto &syncObserver : syncObservers_) {
125         syncObserver->Clear();
126     }
127     syncObservers_.clear();
128 }
129 
Constructor(napi_env env)130 napi_value JsSingleKVStore::Constructor(napi_env env)
131 {
132     auto lambda = []() -> std::vector<napi_property_descriptor> {
133         std::vector<napi_property_descriptor> properties = {
134             DECLARE_NAPI_FUNCTION("put", JsSingleKVStore::Put),
135             DECLARE_NAPI_FUNCTION("delete", JsSingleKVStore::Delete),
136             DECLARE_NAPI_FUNCTION("putBatch", JsSingleKVStore::PutBatch),
137             DECLARE_NAPI_FUNCTION("deleteBatch", JsSingleKVStore::DeleteBatch),
138             DECLARE_NAPI_FUNCTION("startTransaction", JsSingleKVStore::StartTransaction),
139             DECLARE_NAPI_FUNCTION("commit", JsSingleKVStore::Commit),
140             DECLARE_NAPI_FUNCTION("rollback", JsSingleKVStore::Rollback),
141             DECLARE_NAPI_FUNCTION("enableSync", JsSingleKVStore::EnableSync),
142             DECLARE_NAPI_FUNCTION("setSyncRange", JsSingleKVStore::SetSyncRange),
143             DECLARE_NAPI_FUNCTION("backup", JsSingleKVStore::Backup),
144             DECLARE_NAPI_FUNCTION("restore", JsSingleKVStore::Restore),
145             DECLARE_NAPI_FUNCTION("deleteBackup", JsSingleKVStore::DeleteBackup),
146 
147             DECLARE_NAPI_FUNCTION("get", JsSingleKVStore::Get),
148             DECLARE_NAPI_FUNCTION("getEntries", JsSingleKVStore::GetEntries),
149             DECLARE_NAPI_FUNCTION("getResultSet", JsSingleKVStore::GetResultSet),
150             DECLARE_NAPI_FUNCTION("closeResultSet", JsSingleKVStore::CloseResultSet),
151             DECLARE_NAPI_FUNCTION("getResultSize", JsSingleKVStore::GetResultSize),
152             DECLARE_NAPI_FUNCTION("removeDeviceData", JsSingleKVStore::RemoveDeviceData),
153             DECLARE_NAPI_FUNCTION("sync", JsSingleKVStore::Sync),
154             DECLARE_NAPI_FUNCTION("setSyncParam", JsSingleKVStore::SetSyncParam),
155             DECLARE_NAPI_FUNCTION("getSecurityLevel", JsSingleKVStore::GetSecurityLevel),
156             DECLARE_NAPI_FUNCTION("on", JsSingleKVStore::OnEvent), /* same to JsDeviceKVStore */
157             DECLARE_NAPI_FUNCTION("off", JsSingleKVStore::OffEvent) /* same to JsDeviceKVStore */
158         };
159         return properties;
160     };
161     return JSUtil::DefineClass(env, "ohos.data.distributedKVStore", "SingleKVStore", lambda, JsSingleKVStore::New);
162 }
163 
164 /*
165  * [JS API Prototype]
166  * [AsyncCallback]
167  *      put(key:string, value:Uint8Array | string | boolean | number, callback: AsyncCallback<void>):void;
168  * [Promise]
169  *      put(key:string, value:Uint8Array | string | boolean | number):Promise<void>;
170  */
Put(napi_env env,napi_callback_info info)171 napi_value JsSingleKVStore::Put(napi_env env, napi_callback_info info)
172 {
173     struct PutContext : public ContextBase {
174         std::string key;
175         JSUtil::KvStoreVariant value;
176     };
177     auto ctxt = std::make_shared<PutContext>();
178     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value* argv) {
179         // required 2 arguments :: <key> <value>
180         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT,
181             "Parameter error:Mandatory parameters are left unspecified");
182         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
183         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
184             "Parameter error:parameters key must be string");
185         ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->value);
186         if (ctxt->status != napi_ok) {
187             ctxt->isThrowError = true;
188             napi_valuetype ntype = napi_undefined;
189             napi_typeof(env, argv[0], &ntype);
190             auto type = valueTypeToString_.find(ntype);
191             ThrowNapiError(env, Status::INVALID_ARGUMENT, "Parameter error:the type of value must be:" + type->second);
192             return;
193         }
194     });
195     ASSERT_NULL(!ctxt->isThrowError, "Put exit");
196 
197     auto execute = [ctxt]() {
198         DistributedKv::Key key(ctxt->key);
199         bool isSchemaStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSchemaStore();
200         auto &kvStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->kvStore_;
201         DistributedKv::Value value = isSchemaStore ? DistributedKv::Blob(std::get<std::string>(ctxt->value))
202                                                    : JSUtil::VariantValue2Blob(ctxt->value);
203         Status status = kvStore->Put(key, value);
204         ZLOGD("kvStore->Put return %{public}d", status);
205         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
206             napi_ok : napi_generic_failure;
207     };
208     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
209 }
210 
211 /*
212  * [JS API Prototype]
213  * [AsyncCallback]
214  *      delete(key: string, callback: AsyncCallback<void>): void;
215  * [Promise]
216  *      delete(key: string): Promise<void>;
217  */
Delete(napi_env env,napi_callback_info info)218 napi_value JsSingleKVStore::Delete(napi_env env, napi_callback_info info)
219 {
220     struct DeleteContext : public ContextBase {
221         std::string key;
222         std::vector<DistributedKv::Blob> keys;
223         napi_valuetype type;
224     };
225     auto ctxt = std::make_shared<DeleteContext>();
226     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value* argv) {
227         // required 1 arguments :: <key> || <predicates>
228         ASSERT_BUSINESS_ERR(ctxt, argc == 1, Status::INVALID_ARGUMENT,
229             "Parameter error:Mandatory parameters are left unspecified");
230         ctxt->type = napi_undefined;
231         ctxt->status = napi_typeof(env, argv[0], &(ctxt->type));
232         if (ctxt->type == napi_string) {
233             ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
234             ZLOGD("kvStore->Delete %{public}.6s  status:%{public}d", ctxt->key.c_str(), ctxt->status);
235             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
236                 "Parameter error:parameters key must be string");
237         } else if (ctxt->type == napi_object) {
238             JSUtil::StatusMsg statusMsg = JSUtil::GetValue(env, argv[0], ctxt->keys);
239             ctxt->status = statusMsg.status;
240             ZLOGD("kvStore->Delete status:%{public}d", ctxt->status);
241             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
242                 "Parameter error:please check predicates type");
243             ASSERT_PERMISSION_ERR(ctxt,
244                 !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
245                 reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
246         }
247     });
248     ASSERT_NULL(!ctxt->isThrowError, "Delete exit");
249 
250     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), [ctxt]() {
251         Status status = Status::INVALID_ARGUMENT;
252         if (ctxt->type == napi_string) {
253             OHOS::DistributedKv::Key key(ctxt->key);
254             auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
255             status = kvStore->Delete(key);
256             ZLOGD("kvStore->Delete %{public}.6s status:%{public}d", ctxt->key.c_str(), status);
257         } else if (ctxt->type == napi_object) {
258             auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
259             status = kvStore->DeleteBatch(ctxt->keys);
260             ZLOGD("kvStore->DeleteBatch status:%{public}d", status);
261         }
262         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
263             napi_ok : napi_generic_failure;
264     });
265 }
266 
267 /*
268  * [JS API Prototype]
269  * [Callback]
270  *      on(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
271  *      on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
272  */
OnEvent(napi_env env,napi_callback_info info)273 napi_value JsSingleKVStore::OnEvent(napi_env env, napi_callback_info info)
274 {
275     auto ctxt = std::make_shared<ContextBase>();
276     auto input = [env, ctxt](size_t argc, napi_value* argv) {
277         // required 2 arguments :: <event> [...] <callback>
278         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT,
279             "Parameter error:Mandatory parameters are left unspecified");
280         std::string event;
281         ctxt->status = JSUtil::GetValue(env, argv[0], event);
282         ZLOGI("subscribe to event:%{public}s", event.c_str());
283         auto handle = onEventHandlers_.find(event);
284         ASSERT_BUSINESS_ERR(ctxt, handle != onEventHandlers_.end(), Status::INVALID_ARGUMENT,
285             "Parameter error:onevent type must belong dataChange or syncComplete");
286         // shift 1 argument, for JsSingleKVStore::Exec.
287         handle->second(env, argc - 1, &argv[1], ctxt);
288     };
289     ctxt->GetCbInfoSync(env, info, input);
290     ASSERT_NULL(!ctxt->isThrowError, "OnEvent exit");
291     if (ctxt->status != napi_ok) {
292         ThrowNapiError(env, Status::INVALID_ARGUMENT, "");
293     }
294     return nullptr;
295 }
296 
297 /*
298  * [JS API Prototype]
299  * [Callback]
300  *      off(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
301  *      off(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
302  */
OffEvent(napi_env env,napi_callback_info info)303 napi_value JsSingleKVStore::OffEvent(napi_env env, napi_callback_info info)
304 {
305     auto ctxt = std::make_shared<ContextBase>();
306     auto input = [env, ctxt](size_t argc, napi_value* argv) {
307         // required 1 arguments :: <event> [callback]
308         ASSERT_BUSINESS_ERR(ctxt, argc != 0, Status::INVALID_ARGUMENT,
309             "Parameter error:Mandatory parameters are left unspecified");
310         std::string event;
311         ctxt->status = JSUtil::GetValue(env, argv[0], event);
312         ZLOGI("unsubscribe to event:%{public}s", event.c_str());
313         auto handle = offEventHandlers_.find(event);
314         ASSERT_BUSINESS_ERR(ctxt, handle != offEventHandlers_.end(), Status::INVALID_ARGUMENT,
315             "Parameter error:offevent type must belong dataChange or syncComplete");
316         // shift 1 argument, for JsSingleKVStore::Exec.
317         handle->second(env, argc - 1, &argv[1], ctxt);
318     };
319     ctxt->GetCbInfoSync(env, info, input);
320     ASSERT_NULL(!ctxt->isThrowError, "OffEvent exit");
321     if (ctxt->status != napi_ok) {
322         ThrowNapiError(env, Status::INVALID_ARGUMENT, "");
323     }
324     return nullptr;
325 }
326 
327 /*
328  * [JS API Prototype]
329  * [AsyncCallback]
330  *      putBatch(entries: Entry[], callback: AsyncCallback<void>):void;
331  *      putBatch(valuesBucket: ValuesBucket[], callback: AsyncCallback<void>): void;
332  * [Promise]
333  *      putBatch(entries: Entry[]):Promise<void>;
334  *      putBatch(valuesBuckets: ValuesBucket[]): Promise<void>;
335  */
PutBatch(napi_env env,napi_callback_info info)336 napi_value JsSingleKVStore::PutBatch(napi_env env, napi_callback_info info)
337 {
338     struct PutBatchContext : public ContextBase {
339         std::vector<Entry> entries;
340     };
341     auto ctxt = std::make_shared<PutBatchContext>();
342     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
343         // required 1 arguments :: <entries>
344         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
345             "Parameter error:Mandatory parameters are left unspecified");
346         auto isSchemaStore = reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSchemaStore();
347         JSUtil::StatusMsg statusMsg = JSUtil::GetValue(env, argv[0], ctxt->entries, isSchemaStore);
348         ctxt->status = statusMsg.status;
349         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
350             "Parameter error:params entries type must be one of string,number,boolean,array");
351         ASSERT_PERMISSION_ERR(ctxt,
352             !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
353             reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
354     });
355     ASSERT_NULL(!ctxt->isThrowError, "PutBatch exit");
356 
357     auto execute = [ctxt]() {
358         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
359         Status status = kvStore->PutBatch(ctxt->entries);
360         ZLOGD("kvStore->DeleteBatch return %{public}d", status);
361         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
362             napi_ok : napi_generic_failure;
363     };
364     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
365 }
366 
367 /*
368  * [JS API Prototype]
369  * [AsyncCallback]
370  *      deleteBatch(keys: string[], callback: AsyncCallback<void>):void;
371  * [Promise]
372  *      deleteBatch(keys: string[]):Promise<void>;
373  */
DeleteBatch(napi_env env,napi_callback_info info)374 napi_value JsSingleKVStore::DeleteBatch(napi_env env, napi_callback_info info)
375 {
376     struct DeleteBatchContext : public ContextBase {
377         std::vector<std::string> keys;
378     };
379     auto ctxt = std::make_shared<DeleteBatchContext>();
380     auto input = [env, ctxt](size_t argc, napi_value* argv) {
381         // required 1 arguments :: <keys>
382         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
383             "Parameter error:Mandatory parameters are left unspecified");
384         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->keys);
385         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
386             "Parameter error:keys verification must be array");
387     };
388     ctxt->GetCbInfo(env, info, input);
389     ASSERT_NULL(!ctxt->isThrowError, "DeleteBatch exit");
390 
391     auto execute = [ctxt]() {
392         std::vector<DistributedKv::Key> keys;
393         for (auto it : ctxt->keys) {
394             DistributedKv::Key key(it);
395             keys.push_back(key);
396         }
397         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
398         Status status = kvStore->DeleteBatch(keys);
399         ZLOGD("kvStore->DeleteBatch return %{public}d", status);
400         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
401             napi_ok : napi_generic_failure;
402     };
403     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
404 }
405 
406 /*
407  * [JS API Prototype]
408  * [AsyncCallback]
409  *      startTransaction(callback: AsyncCallback<void>):void;
410  * [Promise]
411  *      startTransaction() : Promise<void>;
412  */
StartTransaction(napi_env env,napi_callback_info info)413 napi_value JsSingleKVStore::StartTransaction(napi_env env, napi_callback_info info)
414 {
415     auto ctxt = std::make_shared<ContextBase>();
416     ctxt->GetCbInfo(env, info);
417     auto execute = [ctxt]() {
418         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
419         Status status = kvStore->StartTransaction();
420         ZLOGD("kvStore->StartTransaction return %{public}d", status);
421         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
422             napi_ok : napi_generic_failure;
423     };
424     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
425 }
426 
427 /*
428  * [JS API Prototype]
429  * [AsyncCallback]
430  *      commit(callback: AsyncCallback<void>):void;
431  * [Promise]
432  *      commit() : Promise<void>;
433  */
Commit(napi_env env,napi_callback_info info)434 napi_value JsSingleKVStore::Commit(napi_env env, napi_callback_info info)
435 {
436     auto ctxt = std::make_shared<ContextBase>();
437     ctxt->GetCbInfo(env, info);
438 
439     auto execute = [ctxt]() {
440         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
441         Status status = kvStore->Commit();
442         ZLOGD("kvStore->Commit return %{public}d", status);
443         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
444             napi_ok : napi_generic_failure;
445     };
446     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
447 }
448 
449 /*
450  * [JS API Prototype]
451  * [AsyncCallback]
452  *      rollback(callback: AsyncCallback<void>):void;
453  * [Promise]
454  *      rollback() : Promise<void>;
455  */
Rollback(napi_env env,napi_callback_info info)456 napi_value JsSingleKVStore::Rollback(napi_env env, napi_callback_info info)
457 {
458     auto ctxt = std::make_shared<ContextBase>();
459     ctxt->GetCbInfo(env, info);
460 
461     auto execute = [ctxt]() {
462         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
463         Status status = kvStore->Rollback();
464         ZLOGD("kvStore->Commit return %{public}d", status);
465         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
466             napi_ok : napi_generic_failure;
467     };
468     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
469 }
470 
471 /*
472  * [JS API Prototype]
473  * [AsyncCallback]
474  *      enableSync(enabled:boolean, callback: AsyncCallback<void>):void;
475  * [Promise]
476  *      enableSync(enabled:boolean) : Promise<void>;
477  */
EnableSync(napi_env env,napi_callback_info info)478 napi_value JsSingleKVStore::EnableSync(napi_env env, napi_callback_info info)
479 {
480     struct EnableSyncContext : public ContextBase {
481         bool enable = false;
482     };
483     auto ctxt = std::make_shared<EnableSyncContext>();
484     auto input = [env, ctxt](size_t argc, napi_value* argv) {
485         // required 1 arguments :: <enable>
486         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
487             "Parameter error:Mandatory parameters are left unspecified");
488         ctxt->status = napi_get_value_bool(env, argv[0], &ctxt->enable);
489         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
490             "Parameter error:enable must be boolean");
491     };
492     ctxt->GetCbInfo(env, info, input);
493     ASSERT_NULL(!ctxt->isThrowError, "EnableSync exit");
494 
495     auto execute = [ctxt]() {
496         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
497         Status status = kvStore->SetCapabilityEnabled(ctxt->enable);
498         ZLOGD("kvStore->SetCapabilityEnabled return %{public}d", status);
499         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
500             napi_ok : napi_generic_failure;
501     };
502     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
503 }
504 
505 /*
506  * [JS API Prototype]
507  * [AsyncCallback]
508  *      setSyncRange(localLabels:string[], remoteSupportLabels:string[], callback: AsyncCallback<void>):void;
509  * [Promise]
510  *      setSyncRange(localLabels:string[], remoteSupportLabels:string[]) : Promise<void>;
511  */
SetSyncRange(napi_env env,napi_callback_info info)512 napi_value JsSingleKVStore::SetSyncRange(napi_env env, napi_callback_info info)
513 {
514     struct SyncRangeContext : public ContextBase {
515         std::vector<std::string> localLabels;
516         std::vector<std::string> remoteSupportLabels;
517     };
518     auto ctxt = std::make_shared<SyncRangeContext>();
519     auto input = [env, ctxt](size_t argc, napi_value* argv) {
520         // required 2 arguments :: <localLabels> <remoteSupportLabels>
521         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT,
522             "Parameter error:Mandatory parameters are left unspecified");
523         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->localLabels);
524         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
525             "Parameter error:parameters localLabels must be array");
526         ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->remoteSupportLabels);
527         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
528             "Parameter error:parameters remoteSupportLabels must be array");
529     };
530     ctxt->GetCbInfo(env, info, input);
531     ASSERT_NULL(!ctxt->isThrowError, "SetSyncRange exit");
532 
533     auto execute = [ctxt]() {
534         auto& kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->kvStore_;
535         Status status = kvStore->SetCapabilityRange(ctxt->localLabels, ctxt->remoteSupportLabels);
536         ZLOGD("kvStore->SetCapabilityRange return %{public}d", status);
537         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
538             napi_ok : napi_generic_failure;
539     };
540     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
541 }
542 
543 /*
544  * [JS API Prototype]
545  * [AsyncCallback]
546  *      backup(file:string, callback: AsyncCallback<void>):void;
547  * [Promise]
548  *      backup(file:string): Promise<void>;
549  */
Backup(napi_env env,napi_callback_info info)550 napi_value JsSingleKVStore::Backup(napi_env env, napi_callback_info info)
551 {
552     struct BackupContext : public ContextBase {
553         std::string file;
554     };
555     auto ctxt = std::make_shared<BackupContext>();
556     auto input = [env, ctxt](size_t argc, napi_value* argv) {
557         // required 1 arguments :: <file>
558         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
559             "Parameter error:Mandatory parameters are left unspecified");
560         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->file);
561         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
562             "Parameter error:param file type must be string");
563         ASSERT_BUSINESS_ERR(ctxt, (ctxt->file.size() != 0 && ctxt->file != AUTO_BACKUP_NAME), Status::INVALID_ARGUMENT,
564             "Parameter error:empty file and filename not allow autoBackup");
565     };
566     ctxt->GetCbInfo(env, info, input);
567     ASSERT_NULL(!ctxt->isThrowError, "Backup exit");
568 
569     auto execute = [ctxt]() {
570         auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
571         Status status = jsKvStore->kvStore_->Backup(ctxt->file, jsKvStore->param_->baseDir);
572         ZLOGD("kvStore->Backup return %{public}d", status);
573         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
574             napi_ok : napi_generic_failure;
575     };
576     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
577 }
578 
579 /*
580  * [JS API Prototype]
581  * [AsyncCallback]
582  *      restore(file:string, callback: AsyncCallback<void>):void;
583  * [Promise]
584  *      restore(file:string): Promise<void>;
585  */
Restore(napi_env env,napi_callback_info info)586 napi_value JsSingleKVStore::Restore(napi_env env, napi_callback_info info)
587 {
588     struct RestoreContext : public ContextBase {
589         std::string file;
590     };
591     auto ctxt = std::make_shared<RestoreContext>();
592     auto input = [env, ctxt](size_t argc, napi_value* argv) {
593         // required 1 arguments :: <file>
594         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
595             "Parameter error:Mandatory parameters are left unspecified");
596         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->file);
597         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
598             "Parameter error:get file failed. params type must be string");
599     };
600     ctxt->GetCbInfo(env, info, input);
601     ASSERT_NULL(!ctxt->isThrowError, "Restore exit");
602 
603     auto execute = [ctxt]() {
604         auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
605         Status status = jsKvStore->kvStore_->Restore(ctxt->file, jsKvStore->param_->baseDir);
606         ZLOGD("kvStore->Restore return %{public}d", status);
607         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
608             napi_ok : napi_generic_failure;
609     };
610     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
611 }
612 
613 /*
614  * [JS API Prototype]
615  * [AsyncCallback]
616  *      deleteBackup(files:Array<string>, callback: AsyncCallback<Array<[string, number]>>):void;
617  * [Promise]
618  *      deleteBackup(files:Array<string>): Promise<Array<[string, number]>>;
619  */
DeleteBackup(napi_env env,napi_callback_info info)620 napi_value JsSingleKVStore::DeleteBackup(napi_env env, napi_callback_info info)
621 {
622     struct DeleteBackupContext : public ContextBase {
623         std::vector<std::string> files;
624         std::map<std::string, DistributedKv::Status> results;
625     };
626     auto ctxt = std::make_shared<DeleteBackupContext>();
627     auto input = [env, ctxt](size_t argc, napi_value* argv) {
628         // required 1 arguments :: <files>
629         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
630             "Parameter error:Mandatory parameters are left unspecified");
631         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->files);
632         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
633             "Parameter error:get file failed, params files must be stringArray");
634     };
635     ctxt->GetCbInfo(env, info, input);
636     ASSERT_NULL(!ctxt->isThrowError, "DeleteBackup exit");
637 
638     auto execute = [ctxt]() {
639         auto jsKvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
640         Status status = jsKvStore->kvStore_->DeleteBackup(ctxt->files,
641             jsKvStore->param_->baseDir, ctxt->results);
642         ZLOGD("kvStore->DeleteBackup return %{public}d", status);
643         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
644             napi_ok : napi_generic_failure;
645     };
646     auto output = [env, ctxt](napi_value& result) {
647         ctxt->status = JSUtil::SetValue(env, ctxt->results, result);
648         ASSERT_STATUS(ctxt, "output failed!");
649     };
650     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
651 }
652 
653 /*
654  * [JS API Prototype] JsSingleKVStore::OnDataChange is private non-static.
655  * [Callback]
656  *      on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
657  */
OnDataChange(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)658 void JsSingleKVStore::OnDataChange(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
659 {
660     // required 2 arguments :: <SubscribeType> <observer>
661     ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT,
662         "Parameter error:Mandatory parameters are left unspecified");
663 
664     int32_t type = SUBSCRIBE_COUNT;
665     ctxt->status = napi_get_value_int32(env, argv[0], &type);
666     ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "");
667     ASSERT_BUSINESS_ERR(ctxt, ValidSubscribeType(type), Status::INVALID_ARGUMENT,
668         "Parameter error:parameter event type not exist");
669 
670     napi_valuetype valueType = napi_undefined;
671     ctxt->status = napi_typeof(env, argv[1], &valueType);
672     ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
673         "Parameter error:parameter Callback must be function");
674 
675     ZLOGI("subscribe data change type %{public}d", type);
676     auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
677     std::lock_guard<std::mutex> lck(proxy->listMutex_);
678     for (auto& it : proxy->dataObserver_[type]) {
679         if (JSUtil::Equals(env, argv[1], it->GetCallback())) {
680             ZLOGI("function is already subscribe type");
681             return;
682         }
683     }
684 
685     Status status = proxy->Subscribe(type,
686                                      std::make_shared<DataObserver>(proxy->uvQueue_, argv[1], proxy->IsSchemaStore()));
687     ThrowNapiError(env, status, "", false);
688 }
689 
690 /*
691  * [JS API Prototype] JsSingleKVStore::OffDataChange is private non-static.
692  * [Callback]
693  *      on(event:'dataChange', subType: SubscribeType, observer: Callback<ChangeNotification>): void;
694  * [NOTES!!!]  no SubscribeType while off...
695  *      off(event:'dataChange', observer: Callback<ChangeNotification>): void;
696  */
OffDataChange(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)697 void JsSingleKVStore::OffDataChange(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
698 {
699     // required 1 arguments :: [callback]
700     ASSERT_BUSINESS_ERR(ctxt, argc <= 1, Status::INVALID_ARGUMENT,
701         "Parameter error:Mandatory parameters are left unspecified");
702     // have 1 arguments :: have the callback
703     if (argc == 1) {
704         napi_valuetype valueType = napi_undefined;
705         ctxt->status = napi_typeof(env, argv[0], &valueType);
706         ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
707             "Parameter error:parameter Callback must be function");
708     }
709 
710     ZLOGI("unsubscribe dataChange, %{public}s specified observer.", (argc == 0) ? "without": "with");
711 
712     auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
713     bool found = false;
714     Status status = Status::SUCCESS;
715     auto traverseType = [argc, argv, proxy, env, &found, &status](uint8_t type, auto& observers) {
716         auto it = observers.begin();
717         while (it != observers.end()) {
718             if ((argc == 1) && !JSUtil::Equals(env, argv[0], (*it)->GetCallback())) {
719                 ++it;
720                 continue; // specified observer and not current iterator
721             }
722             found = true;
723             status = proxy->UnSubscribe(type, *it);
724             if (status != Status::SUCCESS) {
725                 break; // stop on fail.
726             }
727             it = observers.erase(it);
728         }
729     };
730 
731     std::lock_guard<std::mutex> lck(proxy->listMutex_);
732     for (uint8_t type = SUBSCRIBE_LOCAL; type < SUBSCRIBE_COUNT; type++) {
733         traverseType(type, proxy->dataObserver_[type]);
734         if (status != Status::SUCCESS) {
735             break; // stop on fail.
736         }
737     }
738     ASSERT_BUSINESS_ERR(ctxt, found || (argc == 0), Status::INVALID_ARGUMENT, "not Subscribed!");
739     ThrowNapiError(env, status, "", false);
740 }
741 
742 /*
743  * [JS API Prototype] JsSingleKVStore::OnSyncComplete is private non-static.
744  * [Callback]
745  *      on(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
746  */
OnSyncComplete(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)747 void JsSingleKVStore::OnSyncComplete(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
748 {
749     // required 1 arguments :: <callback>
750     ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
751         "Parameter error:Mandatory parameters are left unspecified");
752     napi_valuetype valueType = napi_undefined;
753     ctxt->status = napi_typeof(env, argv[0], &valueType);
754     ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
755         "Parameter error:params valueType must be function");
756 
757     auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
758     ctxt->status = proxy->RegisterSyncCallback(std::make_shared<SyncObserver>(proxy->uvQueue_, argv[0]));
759     ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
760         "Parameter error:RegisterSyncCallback params must be function");
761 }
762 
763 /*
764  * [JS API Prototype] JsSingleKVStore::OffSyncComplete is private non-static.
765  * [Callback]
766  *      off(event:'syncComplete',syncCallback: Callback<Array<[string, number]>>):void;
767  */
OffSyncComplete(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextBase> ctxt)768 void JsSingleKVStore::OffSyncComplete(napi_env env, size_t argc, napi_value* argv, std::shared_ptr<ContextBase> ctxt)
769 {
770     // required 1 arguments :: [callback]
771     auto proxy = reinterpret_cast<JsSingleKVStore*>(ctxt->native);
772     // have 1 arguments :: have the callback
773     if (argc == 1) {
774         napi_valuetype valueType = napi_undefined;
775         ctxt->status = napi_typeof(env, argv[0], &valueType);
776         ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && (valueType == napi_function), Status::INVALID_ARGUMENT,
777             "Parameter error:parameter types must be function");
778         std::lock_guard<std::mutex> lck(proxy->listMutex_);
779         auto it = proxy->syncObservers_.begin();
780         while (it != proxy->syncObservers_.end()) {
781             if (JSUtil::Equals(env, argv[0], (*it)->GetCallback())) {
782                 (*it)->Clear();
783                 proxy->syncObservers_.erase(it);
784                 break;
785             }
786         }
787         ctxt->status = napi_ok;
788     }
789     ZLOGI("unsubscribe syncComplete, %{public}s specified observer.", (argc == 0) ? "without": "with");
790     if (argc == 0 || proxy->syncObservers_.empty()) {
791         ctxt->status = proxy->UnRegisterSyncCallback();
792     }
793     ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
794         "Parameter error:params type must be function");
795 }
796 
797 /*
798  * [Internal private non-static]
799  */
RegisterSyncCallback(std::shared_ptr<SyncObserver> callback)800 napi_status JsSingleKVStore::RegisterSyncCallback(std::shared_ptr<SyncObserver> callback)
801 {
802     Status status = kvStore_->RegisterSyncCallback(callback);
803     if (status != Status::SUCCESS) {
804         callback->Clear();
805         return napi_generic_failure;
806     }
807     std::lock_guard<std::mutex> lck(listMutex_);
808     syncObservers_.push_back(callback);
809     return napi_ok;
810 }
811 
UnRegisterSyncCallback()812 napi_status JsSingleKVStore::UnRegisterSyncCallback()
813 {
814     Status status = kvStore_->UnRegisterSyncCallback();
815     if (status != Status::SUCCESS) {
816         return napi_generic_failure;
817     }
818     std::lock_guard<std::mutex> lck(listMutex_);
819     for (auto &syncObserver : syncObservers_) {
820         syncObserver->Clear();
821     }
822     syncObservers_.clear();
823     return napi_ok;
824 }
825 
Subscribe(uint8_t type,std::shared_ptr<DataObserver> observer)826 Status JsSingleKVStore::Subscribe(uint8_t type, std::shared_ptr<DataObserver> observer)
827 {
828     auto subscribeType = ToSubscribeType(type);
829     Status status = kvStore_->SubscribeKvStore(subscribeType, observer);
830     ZLOGD("kvStore_->SubscribeKvStore(%{public}d) return %{public}d", type, status);
831     if (status != Status::SUCCESS) {
832         observer->Clear();
833         return status;
834     }
835     dataObserver_[type].push_back(observer);
836     return status;
837 }
838 
UnSubscribe(uint8_t type,std::shared_ptr<DataObserver> observer)839 Status JsSingleKVStore::UnSubscribe(uint8_t type, std::shared_ptr<DataObserver> observer)
840 {
841     auto subscribeType = ToSubscribeType(type);
842     Status status = kvStore_->UnSubscribeKvStore(subscribeType, observer);
843     ZLOGD("kvStore_->UnSubscribeKvStore(%{public}d) return %{public}d", type, status);
844     if (status == Status::SUCCESS) {
845         observer->Clear();
846         return status;
847     }
848     return status;
849 }
850 
OnChange(const ChangeNotification & notification)851 void JsSingleKVStore::DataObserver::OnChange(const ChangeNotification& notification)
852 {
853     ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu",
854         notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(),
855         notification.GetDeleteEntries().size());
856     KvStoreObserver::OnChange(notification);
857 
858     auto args = [notification, isSchema = isSchema_](napi_env env, int& argc, napi_value* argv) {
859         // generate 1 arguments for callback function.
860         argc = 1;
861         JSUtil::SetValue(env, notification, argv[0], isSchema);
862     };
863     AsyncCall(args);
864 }
865 
SyncCompleted(const std::map<std::string,DistributedKv::Status> & results)866 void JsSingleKVStore::SyncObserver::SyncCompleted(const std::map<std::string, DistributedKv::Status>& results)
867 {
868     auto args = [results](napi_env env, int& argc, napi_value* argv) {
869         // generate 1 arguments for callback function.
870         argc = 1;
871         JSUtil::SetValue(env, results, argv[0]);
872     };
873     AsyncCall(args);
874 }
875 
876 /*
877  * [JS API Prototype]
878  * [AsyncCallback]
879  *      get(key:string, callback:AsyncCallback<boolean|string|number|Uint8Array>):void;
880  * [Promise]
881  *      get(key:string):Promise<boolean|string|number|Uint8Array>;
882  */
Get(napi_env env,napi_callback_info info)883 napi_value JsSingleKVStore::Get(napi_env env, napi_callback_info info)
884 {
885     struct GetContext : public ContextBase {
886         std::string key;
887         JSUtil::KvStoreVariant value;
888     };
889     auto ctxt = std::make_shared<GetContext>();
890     auto input = [env, ctxt](size_t argc, napi_value* argv) {
891         // required 1 arguments :: <key>
892         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
893             "Parameter error:Mandatory parameters are left unspecified");
894         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->key);
895         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
896             "Parameter error:params key must be string and not allow empty");
897     };
898     ctxt->GetCbInfo(env, info, input);
899     ASSERT_NULL(!ctxt->isThrowError, "Get exit");
900 
901     ZLOGD("key=%{public}.8s", ctxt->key.c_str());
902     auto execute = [env, ctxt]() {
903         OHOS::DistributedKv::Key key(ctxt->key);
904         OHOS::DistributedKv::Value value;
905         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
906         bool isSchemaStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
907         Status status = kvStore->Get(key, value);
908         ZLOGD("kvStore->Get return %{public}d", status);
909         ctxt->value = isSchemaStore ? value.ToString() : JSUtil::Blob2VariantValue(value);
910         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
911             napi_ok : napi_generic_failure;
912     };
913     auto output = [env, ctxt](napi_value& result) {
914         ctxt->status = JSUtil::SetValue(env, ctxt->value, result);
915         ASSERT_STATUS(ctxt, "output failed");
916     };
917     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
918 }
919 
920 struct VariantArgs {
921     DataQuery dataQuery;
922     std::string errMsg = "";
923 };
924 
GetVariantArgs(napi_env env,size_t argc,napi_value * argv,VariantArgs & va)925 static JSUtil::StatusMsg GetVariantArgs(napi_env env, size_t argc, napi_value* argv, VariantArgs& va)
926 {
927     // required 1 arguments :: <keyPrefix/query>
928     napi_valuetype type = napi_undefined;
929     JSUtil::StatusMsg statusMsg = napi_typeof(env, argv[0], &type);
930     if (statusMsg != napi_ok || (type != napi_string && type != napi_object)) {
931         va.errMsg = "Parameter error:parameters keyPrefix/query must be string or object";
932         return statusMsg.status != napi_ok ? statusMsg.status : napi_invalid_arg;
933     }
934     if (type == napi_string) {
935         std::string keyPrefix;
936         JSUtil::GetValue(env, argv[0], keyPrefix);
937         if (keyPrefix.empty()) {
938             va.errMsg = "Parameter error:parameters keyPrefix must be string";
939             return napi_invalid_arg;
940         }
941         va.dataQuery.KeyPrefix(keyPrefix);
942     } else if (type == napi_object) {
943         bool result = false;
944         statusMsg = napi_instanceof(env, argv[0], JsQuery::Constructor(env), &result);
945         if ((statusMsg == napi_ok) && (result != false)) {
946             JsQuery *jsQuery = nullptr;
947             statusMsg = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void **>(&jsQuery), JsQuery::Constructor(env));
948             if (jsQuery == nullptr) {
949                 va.errMsg = "Parameter error:parameters query is must be object";
950                 return napi_invalid_arg;
951             }
952             va.dataQuery = jsQuery->GetDataQuery();
953         } else {
954             statusMsg = JSUtil::GetValue(env, argv[0], va.dataQuery);
955             ZLOGD("kvStoreDataShare->GetResultSet return %{public}d", statusMsg.status);
956             statusMsg.jsApiType = JSUtil::DATASHARE;
957         }
958     }
959     return statusMsg;
960 };
961 
962 /*
963  * [JS API Prototype]
964  *  getEntries(keyPrefix:string, callback:AsyncCallback<Entry[]>):void
965  *  getEntries(keyPrefix:string):Promise<Entry[]>
966  *
967  *  getEntries(query:Query, callback:AsyncCallback<Entry[]>):void
968  *  getEntries(query:Query) : Promise<Entry[]>
969  */
GetEntries(napi_env env,napi_callback_info info)970 napi_value JsSingleKVStore::GetEntries(napi_env env, napi_callback_info info)
971 {
972     struct GetEntriesContext : public ContextBase {
973         VariantArgs va;
974         std::vector<Entry> entries;
975     };
976     auto ctxt = std::make_shared<GetEntriesContext>();
977     auto input = [env, ctxt](size_t argc, napi_value* argv) {
978         // required 1 arguments :: <keyPrefix/query>
979         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
980             "Parameter error:Mandatory parameters are left unspecified");
981         ctxt->status = GetVariantArgs(env, argc, argv, ctxt->va);
982         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
983     };
984     ctxt->GetCbInfo(env, info, input);
985     ASSERT_NULL(!ctxt->isThrowError, "GetEntries exit");
986 
987     auto execute = [ctxt]() {
988         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
989         Status status = kvStore->GetEntries(ctxt->va.dataQuery, ctxt->entries);
990         ZLOGD("kvStore->GetEntries() return %{public}d", status);
991         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
992             napi_ok : napi_generic_failure;
993     };
994     auto output = [env, ctxt](napi_value& result) {
995         auto isSchemaStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
996         ctxt->status = JSUtil::SetValue(env, ctxt->entries, result, isSchemaStore);
997         ASSERT_STATUS(ctxt, "output failed!");
998     };
999     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1000 }
1001 
1002 /*
1003  * [JS API Prototype]
1004  *  getResultSet(keyPrefix:string, callback:AsyncCallback<KvStoreResultSet>):void
1005  *  getResultSet(keyPrefix:string):Promise<KvStoreResultSet>
1006  *
1007  *  getResultSet(query:Query, callback:AsyncCallback<KvStoreResultSet>):void
1008  *  getResultSet(query:Query):Promise<KvStoreResultSet>
1009  */
GetResultSet(napi_env env,napi_callback_info info)1010 napi_value JsSingleKVStore::GetResultSet(napi_env env, napi_callback_info info)
1011 {
1012     struct GetResultSetContext : public ContextBase {
1013         VariantArgs va;
1014         JsKVStoreResultSet* resultSet = nullptr;
1015         napi_ref ref = nullptr;
1016     };
1017     auto ctxt = std::make_shared<GetResultSetContext>();
1018     auto input = [env, ctxt](size_t argc, napi_value* argv) {
1019         // required 1 arguments :: <keyPrefix/query>
1020         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
1021             "Parameter error:Mandatory parameters are left unspecified");
1022         JSUtil::StatusMsg statusMsg = GetVariantArgs(env, argc, argv, ctxt->va);
1023         ctxt->status = statusMsg.status;
1024         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, ctxt->va.errMsg);
1025         ASSERT_PERMISSION_ERR(ctxt,
1026             !JSUtil::IsSystemApi(statusMsg.jsApiType) ||
1027             reinterpret_cast<JsSingleKVStore *>(ctxt->native)->IsSystemApp(), Status::PERMISSION_DENIED, "");
1028         ctxt->ref = JSUtil::NewWithRef(env, 0, nullptr, reinterpret_cast<void**>(&ctxt->resultSet),
1029             JsKVStoreResultSet::Constructor(env));
1030         ASSERT_BUSINESS_ERR(ctxt, ctxt->resultSet != nullptr, Status::INVALID_ARGUMENT,
1031             "Parameter error:resultSet nullptr");
1032     };
1033     ctxt->GetCbInfo(env, info, input);
1034     ASSERT_NULL(!ctxt->isThrowError, "GetResultSet exit");
1035 
1036     auto execute = [ctxt]() {
1037         std::shared_ptr<KvStoreResultSet> kvResultSet;
1038         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1039         Status status = kvStore->GetResultSet(ctxt->va.dataQuery, kvResultSet);
1040         ZLOGD("kvStore->GetResultSet() return %{public}d", status);
1041 
1042         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1043             napi_ok : napi_generic_failure;
1044         ctxt->resultSet->SetInstance(kvResultSet);
1045         bool isSchema = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->IsSchemaStore();
1046         ctxt->resultSet->SetSchema(isSchema);
1047     };
1048     auto output = [env, ctxt](napi_value& result) {
1049         ctxt->status = napi_get_reference_value(env, ctxt->ref, &result);
1050         napi_delete_reference(env, ctxt->ref);
1051         ASSERT_STATUS(ctxt, "output kvResultSet failed");
1052     };
1053     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1054 }
1055 
1056 /*
1057  * [JS API Prototype]
1058  *  closeResultSet(resultSet:KVStoreResultSet, callback: AsyncCallback<void>):void
1059  *  closeResultSet(resultSet:KVStoreResultSet):Promise<void>
1060  */
CloseResultSet(napi_env env,napi_callback_info info)1061 napi_value JsSingleKVStore::CloseResultSet(napi_env env, napi_callback_info info)
1062 {
1063     struct CloseResultSetContext : public ContextBase {
1064         JsKVStoreResultSet* resultSet = nullptr;
1065     };
1066     auto ctxt = std::make_shared<CloseResultSetContext>();
1067     auto input = [env, ctxt](size_t argc, napi_value* argv) {
1068         // required 1 arguments :: <resultSet>
1069         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
1070             "Parameter error:Mandatory parameters are left unspecified");
1071         napi_valuetype type = napi_undefined;
1072         ctxt->status = napi_typeof(env, argv[0], &type);
1073         ASSERT_BUSINESS_ERR(ctxt, type == napi_object, Status::INVALID_ARGUMENT,
1074             "Parameter error:Parameters type must be object");
1075         ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&ctxt->resultSet),
1076             JsKVStoreResultSet::Constructor(env));
1077         ASSERT_BUSINESS_ERR(ctxt, ctxt->resultSet != nullptr, Status::INVALID_ARGUMENT,
1078             "Parameter error:resultSet nullptr");
1079     };
1080     ctxt->GetCbInfo(env, info, input);
1081     ASSERT_NULL(!ctxt->isThrowError, "CloseResultSet exit");
1082 
1083     auto execute = [ctxt]() {
1084         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1085         auto resultSet = ctxt->resultSet->GetInstance();
1086         ctxt->resultSet->SetInstance(nullptr);
1087         Status status = kvStore->CloseResultSet(resultSet);
1088         ZLOGD("kvStore->CloseResultSet return %{public}d", status);
1089         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1090             napi_ok : napi_generic_failure;
1091     };
1092     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1093 }
1094 
1095 /*
1096  * [JS API Prototype]
1097  *  getResultSize(query:Query, callback: AsyncCallback<number>):void
1098  *  getResultSize(query:Query):Promise<number>
1099  */
GetResultSize(napi_env env,napi_callback_info info)1100 napi_value JsSingleKVStore::GetResultSize(napi_env env, napi_callback_info info)
1101 {
1102     struct ResultSizeContext : public ContextBase {
1103         JsQuery* query = nullptr;
1104         int resultSize = 0;
1105     };
1106     auto ctxt = std::make_shared<ResultSizeContext>();
1107     auto input = [env, ctxt](size_t argc, napi_value* argv) {
1108         // required 1 arguments :: <query>
1109         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
1110             "Parameter error:Mandatory parameters are left unspecified");
1111         napi_valuetype type = napi_undefined;
1112         ctxt->status = napi_typeof(env, argv[0], &type);
1113         ASSERT_BUSINESS_ERR(ctxt, type == napi_object, Status::INVALID_ARGUMENT,
1114             "Parameter error:Parameters type must be object");
1115         ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&ctxt->query), JsQuery::Constructor(env));
1116         ASSERT_BUSINESS_ERR(ctxt, ctxt->query != nullptr, Status::INVALID_ARGUMENT,
1117             "Parameter error:query nullptr");
1118     };
1119     ctxt->GetCbInfo(env, info, input);
1120     ASSERT_NULL(!ctxt->isThrowError, "GetResultSize exit");
1121 
1122     auto execute = [ctxt]() {
1123         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1124         auto query = ctxt->query->GetDataQuery();
1125         Status status = kvStore->GetCount(query, ctxt->resultSize);
1126         ZLOGD("kvStore->GetCount() return %{public}d", status);
1127         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1128             napi_ok : napi_generic_failure;
1129     };
1130     auto output = [env, ctxt](napi_value& result) {
1131         ctxt->status = JSUtil::SetValue(env, static_cast<int32_t>(ctxt->resultSize), result);
1132         ASSERT_STATUS(ctxt, "output resultSize failed!");
1133     };
1134     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1135 }
1136 
1137 /*
1138  * [JS API Prototype]
1139  *  removeDeviceData(deviceId:string, callback: AsyncCallback<void>):void
1140  *  removeDeviceData(deviceId:string):Promise<void>
1141  */
RemoveDeviceData(napi_env env,napi_callback_info info)1142 napi_value JsSingleKVStore::RemoveDeviceData(napi_env env, napi_callback_info info)
1143 {
1144     struct RemoveDeviceContext : public ContextBase {
1145         std::string deviceId;
1146     };
1147     auto ctxt = std::make_shared<RemoveDeviceContext>();
1148     auto input = [env, ctxt](size_t argc, napi_value* argv) {
1149         // required 1 arguments :: <deviceId>
1150         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
1151             "Parameter error:Mandatory parameters are left unspecified");
1152         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->deviceId);
1153         ASSERT_BUSINESS_ERR(ctxt, (!ctxt->deviceId.empty()) && (ctxt->status == napi_ok), Status::INVALID_ARGUMENT,
1154             "Parameter error:deviceId empty");
1155     };
1156     ctxt->GetCbInfo(env, info, input);
1157     ASSERT_NULL(!ctxt->isThrowError, "RemoveDeviceData exit");
1158 
1159     auto execute = [ctxt]() {
1160         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1161         Status status = kvStore->RemoveDeviceData(ctxt->deviceId);
1162         ZLOGD("kvStore->RemoveDeviceData return %{public}d", status);
1163         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1164             napi_ok : napi_generic_failure;
1165     };
1166     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1167 }
1168 
1169 struct SyncContext : public ContextBase {
1170     std::vector<std::string> deviceIdList;
1171     uint32_t mode = 0;
1172     uint32_t allowedDelayMs = 0;
1173     JsQuery* query = nullptr;
1174     napi_valuetype type = napi_undefined;
1175 
GetInputOHOS::DistributedKVStore::SyncContext1176     void GetInput(napi_env env, napi_callback_info info)
1177     {
1178         auto input = [env, this](size_t argc, napi_value* argv) {
1179             // required 3 arguments :: <deviceIdList> <mode> [allowedDelayMs]
1180             ASSERT_BUSINESS_ERR(this, argc >= 2, Status::INVALID_ARGUMENT,
1181                 "Parameter error:Mandatory parameters are left unspecified");
1182             this->status = JSUtil::GetValue(env, argv[0], this->deviceIdList);
1183             ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1184                 "Parameter error:params deviceIdList must be array");
1185             napi_typeof(env, argv[1], &this->type);
1186             if (this->type == napi_object) {
1187                 this->status = JSUtil::Unwrap(env,
1188                     argv[1], reinterpret_cast<void**>(&this->query), JsQuery::Constructor(env));
1189                 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1190                     "Parameter error:params type must be query");
1191                 this->status = JSUtil::GetValue(env, argv[2], this->mode);
1192                 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1193                     "Parameter error:params mode must be int");
1194                 if (argc == 4) {
1195                     this->status = JSUtil::GetValue(env, argv[3], this->allowedDelayMs);
1196                     ASSERT_BUSINESS_ERR(this, (this->status == napi_ok || JSUtil::IsNull(env, argv[3])),
1197                         Status::INVALID_ARGUMENT, "Parameter error:params delay must be int");
1198                     this->status = napi_ok;
1199                 }
1200             }
1201             if (this->type == napi_number) {
1202                 this->status = JSUtil::GetValue(env, argv[1], this->mode);
1203                 ASSERT_BUSINESS_ERR(this, this->status == napi_ok, Status::INVALID_ARGUMENT,
1204                     "Parameter error:params mode must be int");
1205                 if (argc == 3) {
1206                     this->status = JSUtil::GetValue(env, argv[2], this->allowedDelayMs);
1207                     ASSERT_BUSINESS_ERR(this, (this->status == napi_ok || JSUtil::IsNull(env, argv[2])),
1208                         Status::INVALID_ARGUMENT, "Parameter error:params delay must be int");
1209                     this->status = napi_ok;
1210                 }
1211             }
1212             ASSERT_BUSINESS_ERR(this, (this->mode <= uint32_t(SyncMode::PUSH_PULL)) && (this->status == napi_ok),
1213                 Status::INVALID_ARGUMENT, "Parameter error:Parameters mode must be int");
1214         };
1215         ContextBase::GetCbInfoSync(env, info, input);
1216     }
1217 };
1218 /*
1219  * [JS API Prototype]
1220  *  sync(deviceIdList:string[], mode:SyncMode, allowedDelayMs?:number):void
1221  */
Sync(napi_env env,napi_callback_info info)1222 napi_value JsSingleKVStore::Sync(napi_env env, napi_callback_info info)
1223 {
1224     auto ctxt = std::make_shared<SyncContext>();
1225     ctxt->GetInput(env, info);
1226     ASSERT_NULL(!ctxt->isThrowError, "Sync exit");
1227 
1228     ZLOGD("sync deviceIdList.size=%{public}d, mode:%{public}u, allowedDelayMs:%{public}u",
1229         (int)ctxt->deviceIdList.size(), ctxt->mode, ctxt->allowedDelayMs);
1230 
1231     auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1232     Status status = Status::INVALID_ARGUMENT;
1233     if (ctxt->type == napi_object) {
1234         auto query = ctxt->query->GetDataQuery();
1235         status = kvStore->Sync(ctxt->deviceIdList, static_cast<SyncMode>(ctxt->mode), query,
1236                                nullptr, ctxt->allowedDelayMs);
1237     }
1238     if (ctxt->type == napi_number) {
1239         status = kvStore->Sync(ctxt->deviceIdList, static_cast<SyncMode>(ctxt->mode), ctxt->allowedDelayMs);
1240     }
1241     ZLOGD("kvStore->Sync return %{public}d!", status);
1242     ThrowNapiError(env, status, "", false);
1243     return nullptr;
1244 }
1245 
1246 /*
1247  * [JS API Prototype]
1248  *  setSyncParam(defaultAllowedDelayMs:number, callback: AsyncCallback<number>):void
1249  *  setSyncParam(defaultAllowedDelayMs:number):Promise<void>
1250  */
SetSyncParam(napi_env env,napi_callback_info info)1251 napi_value JsSingleKVStore::SetSyncParam(napi_env env, napi_callback_info info)
1252 {
1253     struct SyncParamContext : public ContextBase {
1254         uint32_t allowedDelayMs;
1255     };
1256     auto ctxt = std::make_shared<SyncParamContext>();
1257     auto input = [env, ctxt](size_t argc, napi_value* argv) {
1258         // required 1 arguments :: <allowedDelayMs>
1259         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT,
1260             "Parameter error:Mandatory parameters are left unspecified");
1261         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->allowedDelayMs);
1262         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
1263             "Parameter error:Parameters delay must be int");
1264     };
1265     ctxt->GetCbInfo(env, info, input);
1266     ASSERT_NULL(!ctxt->isThrowError, "SetSyncParam exit");
1267 
1268     auto execute = [ctxt]() {
1269         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1270         KvSyncParam syncParam { ctxt->allowedDelayMs };
1271         Status status = kvStore->SetSyncParam(syncParam);
1272         ZLOGD("kvStore->SetSyncParam return %{public}d", status);
1273         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1274             napi_ok : napi_generic_failure;
1275     };
1276     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
1277 }
1278 
1279 /*
1280  * [JS API Prototype]
1281  *  getSecurityLevel(callback: AsyncCallback<SecurityLevel>):void
1282  *  getSecurityLevel():Promise<SecurityLevel>
1283  */
GetSecurityLevel(napi_env env,napi_callback_info info)1284 napi_value JsSingleKVStore::GetSecurityLevel(napi_env env, napi_callback_info info)
1285 {
1286     struct SecurityLevelContext : public ContextBase {
1287         SecurityLevel securityLevel;
1288     };
1289     auto ctxt = std::make_shared<SecurityLevelContext>();
1290     ctxt->GetCbInfo(env, info);
1291 
1292     auto execute = [ctxt]() {
1293         auto kvStore = reinterpret_cast<JsSingleKVStore*>(ctxt->native)->GetKvStorePtr();
1294         Status status = kvStore->GetSecurityLevel(ctxt->securityLevel);
1295         ZLOGD("kvStore->GetSecurityLevel return %{public}d", status);
1296         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ?
1297             napi_ok : napi_generic_failure;
1298     };
1299     auto output = [env, ctxt](napi_value& result) {
1300         ctxt->status = JSUtil::SetValue(env, static_cast<uint8_t>(ctxt->securityLevel), result);
1301         ASSERT_STATUS(ctxt, "output failed!");
1302     };
1303     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
1304 }
1305 
New(napi_env env,napi_callback_info info)1306 napi_value JsSingleKVStore::New(napi_env env, napi_callback_info info)
1307 {
1308     ZLOGD("Constructor single kv store!");
1309     std::string storeId;
1310     auto ctxt = std::make_shared<ContextBase>();
1311     auto input = [env, ctxt, &storeId](size_t argc, napi_value* argv) {
1312         // required 2 arguments :: <storeId> <options>
1313         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT,
1314             "Parameter error:Mandatory parameters are left unspecified");
1315         ctxt->status = JSUtil::GetValue(env, argv[0], storeId);
1316         ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok) && !storeId.empty(), Status::INVALID_ARGUMENT,
1317             "Parameter error:Parameters storeId must be string");
1318     };
1319     ctxt->GetCbInfoSync(env, info, input);
1320     ASSERT_NULL(!ctxt->isThrowError, "SingleKVStore new exit");
1321     ASSERT_ERR(env, ctxt->status == napi_ok, Status::INVALID_ARGUMENT,
1322         "Parameter error:get params failed");
1323 
1324     JsSingleKVStore* kvStore = new (std::nothrow) JsSingleKVStore(storeId);
1325     ASSERT_ERR(env, kvStore != nullptr, Status::INVALID_ARGUMENT,
1326         "Parameter error:kvStore nullptr");
1327 
1328     auto finalize = [](napi_env env, void* data, void* hint) {
1329         ZLOGI("singleKVStore finalize.");
1330         auto* kvStore = reinterpret_cast<JsSingleKVStore*>(data);
1331         ASSERT_VOID(kvStore != nullptr, "kvStore is null!");
1332         delete kvStore;
1333     };
1334     ASSERT_CALL(env, napi_wrap(env, ctxt->self, kvStore, finalize, nullptr, nullptr), kvStore);
1335     return ctxt->self;
1336 }
1337 } // namespace OHOS::DistributedKVStore
1338