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