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