diff --git a/frameworks/jskitsimpl/distributeddata/include/async_call.h b/frameworks/jskitsimpl/distributeddata/include/async_call.h index 892ff9c3b615c83860ca20afcb5fbabb6eede698..848971892de25a95394b4a8744d475b999b844d7 100644 --- a/frameworks/jskitsimpl/distributeddata/include/async_call.h +++ b/frameworks/jskitsimpl/distributeddata/include/async_call.h @@ -18,88 +18,72 @@ #include #include #include "js_util.h" -#include "napi/native_common.h" + #include "napi/native_api.h" +#include "napi/native_common.h" #include "napi/native_node_api.h" namespace OHOS::DistributedData { -class AsyncCall final { +constexpr size_t REQUIRED_NO_ARGS = 0; +constexpr size_t REQUIRED_1_ARGS = 1; +constexpr size_t REQUIRED_2_ARGS = 2; +constexpr size_t REQUIRED_3_ARGS = 3; + +using NapiCbInfoParser = std::function; +using NapiAsyncExecute = std::function; +using NapiAsyncComplete = std::function; + +struct ContextBase { + virtual ~ContextBase(); + + void GetCbInfo(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(), + bool sync = false); + + inline void GetCbInfoSync(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser()) + { + /* sync = true, means no callback, not AsyncWork. */ + return GetCbInfo(env, info, parse, true); + } + + inline napi_value Self() + { + return self; + } + + template + inline T* As() + { + NAPI_ASSERT_BASE(env, boundObj != nullptr, "bad boundObj", nullptr); + return reinterpret_cast(boundObj); + } + + napi_env env = nullptr; + napi_status status = napi_invalid_arg; + napi_value output = nullptr; + +private: + napi_deferred deferred = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + + NapiAsyncExecute execute = nullptr; + NapiAsyncComplete complete = nullptr; + std::shared_ptr hold; /* cross thread data */ + + napi_value self = nullptr; + void* boundObj = nullptr; + + friend class AsyncCall; +}; + +class AsyncCall { public: - class Context { - public: - using InputAction = std::function; - using OutputAction = std::function; - using ExecAction = std::function; - Context(InputAction input, OutputAction output): input_(std::move(input)), output_(std::move(output)) {}; - virtual ~Context() {}; - void SetAction(InputAction input, OutputAction output = nullptr) - { - input_ = input; - output_ = output; - } - - void SetAction(OutputAction output) - { - SetAction(nullptr, std::move(output)); - } - - virtual napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) - { - if (input_ == nullptr) { - return napi_ok; - } - return input_(env, argc, argv, self); - } - - virtual napi_status operator()(napi_env env, napi_value *result) - { - if (output_ == nullptr) { - *result = nullptr; - return napi_ok; - } - return output_(env, result); - } - - virtual void Exec() - { - if (exec_ == nullptr) { - return; - } - exec_(this); - }; - protected: - friend class AsyncCall; - InputAction input_ = nullptr; - OutputAction output_ = nullptr; - ExecAction exec_ = nullptr; - }; - - // The default AsyncCallback in the parameters is at the end position. - static constexpr size_t ASYNC_DEFAULT_POS = -1; - AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr context, size_t pos = ASYNC_DEFAULT_POS); - ~AsyncCall(); - napi_value Call(napi_env env, Context::ExecAction exec = nullptr); - napi_value SyncCall(napi_env env, Context::ExecAction exec = nullptr); + static napi_value DoAsyncWork(napi_env env, std::shared_ptr context, const std::string& name, + NapiAsyncExecute execute = NapiAsyncExecute(), + NapiAsyncComplete complete = NapiAsyncComplete()); + private: - enum { - ARG_ERROR, - ARG_DATA, - ARG_BUTT - }; - static void OnExecute(napi_env env, void *data); - static void OnComplete(napi_env env, napi_status status, void *data); - struct AsyncContext { - std::shared_ptr ctx = nullptr; - napi_ref callback = nullptr; - napi_ref self = nullptr; - napi_deferred defer = nullptr; - napi_async_work work = nullptr; - }; - static void DeleteContext(napi_env env, AsyncContext *context); - - AsyncContext *context_ = nullptr; - napi_env env_ = nullptr; + static void GenerateOutput(ContextBase* context); }; } - #endif // OHOS_ASYNC_CALL_H diff --git a/frameworks/jskitsimpl/distributeddata/include/device_kv_store.h b/frameworks/jskitsimpl/distributeddata/include/device_kv_store.h new file mode 100644 index 0000000000000000000000000000000000000000..e8a08a558c9fa042645b700d13945791fa27815b --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/include/device_kv_store.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_DEVICE_KV_STORE_H +#define OHOS_DEVICE_KV_STORE_H +#include +#include "kv_manager.h" +#include "kv_store.h" +#include "single_kv_store.h" + +namespace OHOS::DistributedData { +class DeviceKVStore final : public SingleKVStore { +public: + DeviceKVStore() = default; + ~DeviceKVStore(); + DeviceKVStore &operator=(std::shared_ptr &&DeviceKVStore); + bool operator==(const std::shared_ptr &DeviceKVStore); + static napi_value GetCtor(napi_env env); + + static napi_value Get(napi_env env, napi_callback_info info); + static napi_value GetEntries(napi_env env, napi_callback_info info); + static napi_value GetResultSet(napi_env env, napi_callback_info info); + static napi_value CloseResultSet(napi_env env, napi_callback_info info); + static napi_value GetResultSize(napi_env env, napi_callback_info info); + static napi_value RemoveDeviceData(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + + + static napi_value Initialize(napi_env env, napi_callback_info info); + + static std::string GetDeviceKey(std::string deviceId, std::string key); + + static napi_status OnSyncComplete(napi_env env, size_t argc, napi_value *argv, napi_value self, napi_value *result); + + +private: + static std::map eventHandlers_; +}; +} +#endif // OHOS_DEVICE_KV_STORE_H diff --git a/frameworks/jskitsimpl/distributeddata/include/js_util.h b/frameworks/jskitsimpl/distributeddata/include/js_util.h index c47682a4aa9af7b89741cb6b73269bcef5f422c8..842e6eed4b751cbcb3b8fe200536bf49ae7f8db2 100644 --- a/frameworks/jskitsimpl/distributeddata/include/js_util.h +++ b/frameworks/jskitsimpl/distributeddata/include/js_util.h @@ -16,39 +16,102 @@ #define OHOS_JS_UTIL_H #include -#include #include -#include "napi/native_common.h" +#include + +#include "change_notification.h" #include "napi/native_api.h" +#include "napi/native_common.h" #include "napi/native_node_api.h" #include "types.h" -#define DECLARE_NAPI_METHOD(name, func) { name, 0, func, 0, 0, 0, napi_default, 0 } namespace OHOS::DistributedData { class JSUtil { public: static constexpr int32_t MAX_ARGC = 6; static constexpr int32_t MAX_NUMBER_BYTES = 8; static constexpr int32_t MAX_LEN = 4096; + static constexpr int32_t TUPLE_SIZE = 2; + + /* for kvStore Put/Get : boolean|string|number|Uint8Array */ + using VariantValue = std::variant, bool, double>; + static VariantValue Blob2VariantValue(const DistributedKv::Blob& blob); + static DistributedKv::Blob VariantValue2Blob(VariantValue& value); + + /* for query : number|string|boolean*/ + using VariantValue3 = std::variant; + + /* napi_value <-> bool */ + static napi_status FromNapiValue(napi_env env, napi_value in, bool& out); + static napi_status ToNapiValue(napi_env env, const bool& in, napi_value& out); + /* napi_value <-> int32_t */ + static napi_status FromNapiValue(napi_env env, napi_value in, int32_t& out); + static napi_status ToNapiValue(napi_env env, const int32_t& in, napi_value& out); + /* napi_value <-> uint32_t */ + static napi_status FromNapiValue(napi_env env, napi_value in, uint32_t& out); + static napi_status ToNapiValue(napi_env env, const uint32_t& in, napi_value& out); + /* napi_value <-> int64_t */ + static napi_status FromNapiValue(napi_env env, napi_value in, int64_t& out); + static napi_status ToNapiValue(napi_env env, const int64_t& in, napi_value& out); + /* napi_value <-> double */ + static napi_status FromNapiValue(napi_env env, napi_value in, double& out); + static napi_status ToNapiValue(napi_env env, const double& in, napi_value& out); + /* napi_value <-> std::string */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::string& out); + static napi_status ToNapiValue(napi_env env, const std::string& in, napi_value& out); + /* napi_value <-> VariantValue */ + static napi_status FromNapiValue(napi_env env, napi_value in, VariantValue& out); + static napi_status ToNapiValue(napi_env env, const VariantValue& in, napi_value& out); + /* napi_value <-> VariantValue3 */ + static napi_status FromNapiValue(napi_env env, napi_value in, VariantValue3& out); + static napi_status ToNapiValue(napi_env env, const VariantValue3& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> DistributedKv::ChangeNotification */ + static napi_status FromNapiValue(napi_env env, napi_value in, DistributedKv::ChangeNotification& out); + static napi_status ToNapiValue(napi_env env, const DistributedKv::ChangeNotification& in, napi_value& out); + /* napi_value <-> DistributedKv::Options */ + static napi_status FromNapiValue(napi_env env, napi_value in, DistributedKv::Options& out); + static napi_status ToNapiValue(napi_env env, const DistributedKv::Options& in, napi_value& out); + /* napi_value <-> DistributedKv::Entry */ + static napi_status FromNapiValue(napi_env env, napi_value in, DistributedKv::Entry& out); + static napi_status ToNapiValue(napi_env env, const DistributedKv::Entry& in, napi_value& out); + /* napi_value <-> DistributedKv::Options */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::list& out); + static napi_status ToNapiValue(napi_env env, const std::list& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> std::vector */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::vector& out); + static napi_status ToNapiValue(napi_env env, const std::vector& in, napi_value& out); + /* napi_value <-> std::map */ + static napi_status FromNapiValue(napi_env env, napi_value in, std::map& out); + static napi_status ToNapiValue(napi_env env, const std::map& in, napi_value& out); + + template + static inline napi_status GetNamedProperty(napi_env env, napi_value in, const std::string& prop, cpp_value& value) + { + napi_value inner = nullptr; + napi_status status = napi_get_named_property(env, in, prop.data(), &inner); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (inner != nullptr), "get_named_property fail", status); + status = FromNapiValue(env, inner, value); + NAPI_ASSERT_BASE(env, (status == napi_ok), "get property fail", status); + return status; + }; - static std::string Convert2String(napi_env env, napi_value jsString); - static napi_value Convert2JSString(napi_env env, const std::string &cString); - static napi_value Convert2JSString(napi_env env, const std::vector &key); - static napi_value Convert2JSValue(napi_env env, const std::vector &data); - static napi_value Convert2JSNumber(napi_env env, const std::vector &data); - static napi_value Convert2JSNotification(napi_env env, const DistributedKv::ChangeNotification ¬ification); - static napi_value Convert2JSTupleArray(napi_env env, std::map &data); - static DistributedKv::Options Convert2Options(napi_env env, napi_value jsOptions); - static std::vector Convert2Vector(napi_env env, napi_value jsValue); - static std::vector ConvertUint8Array2Vector(napi_env env, napi_value jsValue); - static std::vector ConvertString2Vector(napi_env env, napi_value jsValue); - static std::vector ConvertNumber2Vector(napi_env env, napi_value jsValue); - static std::vector ConvertBool2Vector(napi_env env, napi_value jsValue); - static std::vector Convert2StringArray(napi_env env, napi_value jsValue); private: - static napi_value GetJSEntries(napi_env env, const std::list &entries); - static napi_value GetJSEntries(napi_env env, const std::vector &entries); - enum ValueType : uint8_t { + enum VariantType : uint8_t { /** Indicates that the value type is string. */ STRING = 0, /** Indicates that the value type is int. */ @@ -61,12 +124,8 @@ private: BOOLEAN = 4, /** Indicates that the value type is double. */ DOUBLE = 5, - INVALID = 255, }; - static constexpr int32_t TYPE_POS = 0; - static constexpr int32_t DATA_POS = TYPE_POS + 1; - static constexpr int32_t TUPLE_SIZE = 2; }; } #endif // OHOS_JS_UTIL_H diff --git a/frameworks/jskitsimpl/distributeddata/include/kv_manager.h b/frameworks/jskitsimpl/distributeddata/include/kv_manager.h index 90bd20c578f590baa725956844193b56cd5dd84e..579ce523eed279a6e068508f24cd628063200fed 100644 --- a/frameworks/jskitsimpl/distributeddata/include/kv_manager.h +++ b/frameworks/jskitsimpl/distributeddata/include/kv_manager.h @@ -20,17 +20,39 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "distributed_kv_data_manager.h" +#include "kvstore_death_recipient.h" namespace OHOS::DistributedData { class KVManager { public: static napi_value CreateKVManager(napi_env env, napi_callback_info info); static napi_value GetKVStore(napi_env env, napi_callback_info info); + static napi_value CloseKVStore(napi_env env, napi_callback_info info); + static napi_value DeleteKVStore(napi_env env, napi_callback_info info); + static napi_value GetAllKVStoreId(napi_env env, napi_callback_info info); + static napi_value On(napi_env env, napi_callback_info info); + static napi_value Off(napi_env env, napi_callback_info info); private: static napi_value GetCtor(napi_env env); static napi_value Initialize(napi_env env, napi_callback_info info); DistributedKv::DistributedKvDataManager kvDataManager_ {}; std::string bundleName_ {}; + std::mutex deathMutex_ {}; + std::map> mapDeathRecipient_ {}; +}; + +class DeathRecipient : public DistributedKv::KvStoreDeathRecipient { +public: + DeathRecipient(napi_env env, napi_value callback); + virtual ~DeathRecipient(); + virtual void OnRemoteDied() override; +private: + struct EventDataWorker { + const DeathRecipient *deathRecipient = nullptr; + }; + napi_ref callback_ = nullptr; + napi_env env_; + uv_loop_s *loop_ = nullptr; }; } #endif // OHOS_KV_MANAGER_H diff --git a/frameworks/jskitsimpl/distributeddata/include/kv_store.h b/frameworks/jskitsimpl/distributeddata/include/kv_store.h new file mode 100644 index 0000000000000000000000000000000000000000..0df084150f465083f45a45bad61b2d07aafcfe70 --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/include/kv_store.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_KV_STORE_H +#define OHOS_KV_STORE_H +#include +#include "async_call.h" +#include "kv_manager.h" +#include "single_kvstore.h" +/* [NOTES] + * OHOS::DistributedData::KVStore is NOT related to DistributedKv::KvStore!!! + * OHOS::DistributedData::KVStore is wrapped for DistributedKv::SingleKvStore... + */ +namespace OHOS::DistributedData { +class KVStore { +public: + KVStore() = default; + ~KVStore(); + KVStore &operator=(std::shared_ptr &&singleKvStore); + bool operator==(const std::shared_ptr &singleKvStore); + static napi_value GetCtor(napi_env env); + + static napi_value Put(napi_env env, napi_callback_info info); + static napi_value Delete(napi_env env, napi_callback_info info); + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + static napi_value PutBatch(napi_env env, napi_callback_info info); + static napi_value DeleteBatch(napi_env env, napi_callback_info info); + static napi_value StartTransaction(napi_env env, napi_callback_info info); + static napi_value Commit(napi_env env, napi_callback_info info); + static napi_value Rollback(napi_env env, napi_callback_info info); + static napi_value EnableSync(napi_env env, napi_callback_info info); + static napi_value SetSyncRange(napi_env env, napi_callback_info info); + + static napi_status OnDataChange(napi_env env, size_t argc, napi_value *argv, napi_value self, napi_value *result); + + using Exec = std::function; + enum JSSubscribeType { + SUBSCRIBE_LOCAL = 0, + SUBSCRIBE_REMOTE = 1, + SUBSCRIBE_ALL = 2, + }; + +private: + static napi_value Initialize(napi_env env, napi_callback_info info); + + static std::map eventHandlers_; + std::shared_ptr kvStore_ = nullptr; + std::shared_ptr syncObserver_ = nullptr; + std::shared_ptr dataObserver_[SUBSCRIBE_ALL + 1]; +}; + +class DataObserver : public DistributedKv::KvStoreObserver { +public: + DataObserver(napi_env env, napi_value callback); + virtual ~DataObserver(); + void OnChange(const DistributedKv::ChangeNotification ¬ification, + std::shared_ptr snapshot) override; + void OnChange(const DistributedKv::ChangeNotification ¬ification) override; +private: + struct EventDataWorker { + const DataObserver *observer = nullptr; + const DistributedKv::ChangeNotification data; + EventDataWorker(const DataObserver * const & observerIn, const DistributedKv::ChangeNotification &dataIn) + : observer(observerIn), + data(dataIn) {} + }; + napi_ref callback_ = nullptr; + napi_env env_; + uv_loop_s *loop_ = nullptr; +}; + +class SyncObserver : public DistributedKv::KvStoreSyncCallback { +public: + SyncObserver(napi_env env, napi_value callback); + virtual ~SyncObserver(); + void SyncCompleted(const std::map &results) override; +private: + struct EventDataWorker { + const SyncObserver *observer = nullptr; + std::map data; + }; + napi_ref callback_ = nullptr; + napi_env env_; + uv_loop_s *loop_ = nullptr; +}; +} // namespace OHOS::DistributedData +#endif // OHOS_SINGLE_KV_STORE_H diff --git a/frameworks/jskitsimpl/distributeddata/include/kv_store_resultset.h b/frameworks/jskitsimpl/distributeddata/include/kv_store_resultset.h new file mode 100644 index 0000000000000000000000000000000000000000..0f0ec596949c7fb1762a220a263a70a98f8c954e --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/include/kv_store_resultset.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_KV_STORE_RESELTSET_H +#define OHOS_KV_STORE_RESELTSET_H + +#include +#include "async_call.h" +#include "napi/native_common.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "kvstore_result_set.h" + +namespace OHOS::DistributedData { +class KVStoreResultSet { +public: + KVStoreResultSet() = default; + ~KVStoreResultSet(); + KVStoreResultSet &operator=(std::shared_ptr &&singleKvStore); + bool operator==(const std::shared_ptr &singleKvStore); + + static napi_value GetCtor(napi_env env); + static napi_value GetCount(napi_env env, napi_callback_info info); /* number */ + static napi_value GetPosition(napi_env env, napi_callback_info info); /* number */ + static napi_value MoveToFirst(napi_env env, napi_callback_info info); /* boolean */ + static napi_value MoveToLast(napi_env env, napi_callback_info info); /* boolean */ + static napi_value MoveToNext(napi_env env, napi_callback_info info); /* boolean */ + static napi_value MoveToPrevious(napi_env env, napi_callback_info info); /* boolean */ + static napi_value Move(napi_env env, napi_callback_info info); /* boolean */ + static napi_value MoveToPosition(napi_env env, napi_callback_info info); /* boolean */ + static napi_value IsFirst(napi_env env, napi_callback_info info); /* boolean */ + static napi_value IsLast(napi_env env, napi_callback_info info); /* boolean */ + static napi_value IsBeforeFirst(napi_env env, napi_callback_info info); /* boolean */ + static napi_value IsAfterLast(napi_env env, napi_callback_info info); /* boolean */ + static napi_value GetEntry(napi_env env, napi_callback_info info); /* Entry */ + +private: + static napi_value Initialize(napi_env env, napi_callback_info info); + std::shared_ptr resultSet_ = nullptr; +}; +} +#endif // OHOS_KV_STORE_RESELTSET_H + diff --git a/frameworks/jskitsimpl/distributeddata/include/query.h b/frameworks/jskitsimpl/distributeddata/include/query.h new file mode 100644 index 0000000000000000000000000000000000000000..00089949f025dc45ac0380bdd409154364f245ab --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/include/query.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef OHOS_KV_STORE_RESELTSET_H +#define OHOS_KV_STORE_RESELTSET_H + +#include +#include "async_call.h" +#include "napi/native_common.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "data_query.h" + +namespace OHOS::DistributedData { +class Query { +public: + Query() = default; + ~Query(); + Query &operator=(std::shared_ptr &&singleKvStore); + bool operator==(const std::shared_ptr &singleKvStore); + + static napi_value CreateQueryObject(napi_env env); + static napi_value GetCtor(napi_env env); + +private: + static napi_value Reset(napi_env env, napi_callback_info info); // Query + static napi_value EqualTo(napi_env env, napi_callback_info info); // Query + static napi_value NotEqualTo(napi_env env, napi_callback_info info); // Query + static napi_value GreaterThan(napi_env env, napi_callback_info info); // Query + static napi_value LessThan(napi_env env, napi_callback_info info); // Query + static napi_value GreaterThanOrEqualTo(napi_env env, napi_callback_info info); // Query + static napi_value LessThanOrEqualTo(napi_env env, napi_callback_info info); // Query + static napi_value IsNull(napi_env env, napi_callback_info info); // Query + static napi_value InNumber(napi_env env, napi_callback_info info); // Query + static napi_value InString(napi_env env, napi_callback_info info); // Query + static napi_value NotInNumber(napi_env env, napi_callback_info info); // Query + static napi_value NotInString(napi_env env, napi_callback_info info); // Query + static napi_value Like(napi_env env, napi_callback_info info); // Query + static napi_value Unlike(napi_env env, napi_callback_info info); // Query + static napi_value And(napi_env env, napi_callback_info info); // Query + static napi_value Or(napi_env env, napi_callback_info info); // Query + static napi_value OrderByAsc(napi_env env, napi_callback_info info); // Query + static napi_value OrderByDesc(napi_env env, napi_callback_info info); // Query + static napi_value Limit(napi_env env, napi_callback_info info); // Query + static napi_value IsNotNull(napi_env env, napi_callback_info info); // Query + static napi_value BeginGroup(napi_env env, napi_callback_info info); // Query + static napi_value EndGroup(napi_env env, napi_callback_info info); // Query + static napi_value PrefixKey(napi_env env, napi_callback_info info); // Query + static napi_value SetSuggestIndex(napi_env env, napi_callback_info info); // string) + static napi_value DeviceId(napi_env env, napi_callback_info info); // Query + static napi_value GetSqlLike(napi_env env, napi_callback_info info); // string + + static napi_value Initialize(napi_env env, napi_callback_info info); + + std::shared_ptr query_ = nullptr; + napi_ref ref = nullptr; + +}; +} +#endif // OHOS_KV_STORE_RESELTSET_H + diff --git a/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h b/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h index f9a2737513cbf51b7c71d0f8713868884ed279de..e5e551530b9edfbc377c0088b0f86a17cb46a4d3 100644 --- a/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h +++ b/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h @@ -14,104 +14,42 @@ */ #ifndef OHOS_SINGLE_KV_STORE_H #define OHOS_SINGLE_KV_STORE_H -#include -#include "napi/native_common.h" -#include "napi/native_api.h" -#include "napi/native_node_api.h" -#include "kv_manager.h" #include "async_call.h" +#include "kv_manager.h" +#include "kv_store.h" #include "single_kvstore.h" namespace OHOS::DistributedData { -class SingleKVStore final { +class SingleKVStore : public KVStore { public: SingleKVStore() = default; ~SingleKVStore(); - SingleKVStore &operator=(std::shared_ptr &&singleKvStore); - bool operator==(const std::shared_ptr &singleKvStore); + SingleKVStore& operator=(std::shared_ptr&& singleKvStore); + bool operator==(const std::shared_ptr& singleKvStore); static napi_value GetCtor(napi_env env); - static napi_value OnEvent(napi_env env, napi_callback_info info); - static napi_value Sync(napi_env env, napi_callback_info info); - static napi_value Put(napi_env env, napi_callback_info info); - static napi_value Get(napi_env env, napi_callback_info info); - static napi_value Delete(napi_env env, napi_callback_info info); -private: - enum JSSubscribeType { - SUBSCRIBE_LOCAL = 0, - SUBSCRIBE_REMOTE = 1, - SUBSCRIBE_ALL = 2, - }; - - struct ContextInfo : public AsyncCall::Context { - SingleKVStore *proxy = nullptr; - std::string key; - std::vector value; - napi_status status = napi_generic_failure; - ContextInfo() : Context(nullptr, nullptr) { }; - ContextInfo(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)) { }; - virtual ~ContextInfo() {}; - napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override - { - NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); - NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); - NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", napi_invalid_arg); - return Context::operator()(env, argc, argv, self); - } - napi_status operator()(napi_env env, napi_value *result) override - { - if (status != napi_ok) { - return status; - } - return Context::operator()(env, result); - } - }; + static napi_value Get(napi_env env, napi_callback_info info); + static napi_value GetEntries(napi_env env, napi_callback_info info); + static napi_value GetResultSet(napi_env env, napi_callback_info info); + static napi_value CloseResultSet(napi_env env, napi_callback_info info); + static napi_value GetResultSize(napi_env env, napi_callback_info info); + static napi_value RemoveDeviceData(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + static napi_value SetSyncParam(napi_env env, napi_callback_info info); + static napi_value GetSecurityLevel(napi_env env, napi_callback_info info); - using Exec = std::function; static napi_value Initialize(napi_env env, napi_callback_info info); - - static napi_status OnDataChange(napi_env env, size_t argc, napi_value *argv, napi_value self, napi_value *result); - static napi_status OnSyncComplete(napi_env env, size_t argc, napi_value *argv, napi_value self, napi_value *result); - static std::map eventHandlers_; + static napi_status OnSyncComplete(napi_env env, size_t argc, napi_value* argv, napi_value self, napi_value* result); std::shared_ptr kvStore_ = nullptr; std::shared_ptr syncObserver_ = nullptr; std::shared_ptr dataObserver_[SUBSCRIBE_ALL + 1]; -}; -class DataObserver : public DistributedKv::KvStoreObserver { -public: - DataObserver(napi_env env, napi_value callback); - virtual ~DataObserver(); - void OnChange(const DistributedKv::ChangeNotification ¬ification, - std::shared_ptr snapshot) override; - void OnChange(const DistributedKv::ChangeNotification ¬ification) override; private: - struct EventDataWorker { - const DataObserver *observer = nullptr; - const DistributedKv::ChangeNotification data; - EventDataWorker(const DataObserver * const & observerIn, const DistributedKv::ChangeNotification &dataIn) - : observer(observerIn), - data(dataIn) {} - }; - napi_ref callback_ = nullptr; - napi_env env_; - uv_loop_s *loop_ = nullptr; + static std::map eventHandlers_; }; -class SyncObserver : public DistributedKv::KvStoreSyncCallback { -public: - SyncObserver(napi_env env, napi_value callback); - virtual ~SyncObserver(); - void SyncCompleted(const std::map &results) override; -private: - struct EventDataWorker { - const SyncObserver *observer = nullptr; - std::map data; - }; - napi_ref callback_ = nullptr; - napi_env env_; - uv_loop_s *loop_ = nullptr; -}; } #endif // OHOS_SINGLE_KV_STORE_H diff --git a/frameworks/jskitsimpl/distributeddata/src/async_call.cpp b/frameworks/jskitsimpl/distributeddata/src/async_call.cpp index 41f588809b4b8cf0556b8c5c882609da1daa264f..8337024ef67adee138a88d0f87d51acb3f5b5b2b 100644 --- a/frameworks/jskitsimpl/distributeddata/src/async_call.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/async_call.cpp @@ -14,136 +14,127 @@ */ #define LOG_TAG "AsyncCall" #include "async_call.h" -#include #include "log_print.h" using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { -AsyncCall::AsyncCall(napi_env env, napi_callback_info info, std::shared_ptr context, size_t pos) - : env_(env) +ContextBase::~ContextBase() { - context_ = new AsyncContext(); - size_t argc = JSUtil::MAX_ARGC; - napi_value self = nullptr; - napi_value argv[JSUtil::MAX_ARGC] = {nullptr}; - NAPI_CALL_RETURN_VOID(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); - NAPI_ASSERT_BASE(env, pos <= argc, " Invalid Args!", NAPI_RETVAL_NOTHING); - pos = ((pos == ASYNC_DEFAULT_POS) ? (argc - 1) : pos); - if (pos >= 0 && pos < argc) { - napi_valuetype valueType = napi_undefined; - napi_typeof(env, argv[pos], &valueType); - if (valueType == napi_function) { - napi_create_reference(env, argv[pos], 1, &context_->callback); - argc = pos; + ZLOGD(" ~ContextBase "); + if (env != nullptr) { + if (work != nullptr) { + napi_delete_async_work(env, work); } + if (callbackRef != nullptr) { + napi_delete_reference(env, callbackRef); + } + env = nullptr; } - NAPI_CALL_RETURN_VOID(env, (*context)(env, argc, argv, self)); - context_->ctx = std::move(context); - napi_create_reference(env, self, 1, &context_->self); } - -AsyncCall::~AsyncCall() +void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync) { - if (context_ == nullptr) { - return; - } - - DeleteContext(env_, context_); -} + env = envi; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr); + NAPI_ASSERT_RETURN_VOID(env, status == napi_ok, "napi_get_cb_info fail!"); + NAPI_ASSERT_RETURN_VOID(env, argc <= JSUtil::MAX_ARGC, "too many arguments!"); + NAPI_ASSERT_RETURN_VOID(env, self != nullptr, "no JavaScript this argument!"); + status = napi_unwrap(env, self, &boundObj); + NAPI_ASSERT_RETURN_VOID(env, (status == napi_ok) && (boundObj != nullptr), "self unwrap fail!"); -napi_value AsyncCall::Call(napi_env env, Context::ExecAction exec) -{ - if ((context_ == nullptr) || (context_->ctx == nullptr)) { - ZLOGD("context_ or context_->ctx is null"); - return nullptr; + if (!sync && (argc >= REQUIRED_1_ARGS)) { + size_t index = argc - REQUIRED_1_ARGS; + napi_valuetype type = napi_undefined; + napi_status tyst = napi_typeof(env, argv[index], &type); + if ((tyst == napi_ok) && (type == napi_function)) { + status = napi_create_reference(env, argv[index], 1, &callbackRef); + NAPI_ASSERT_RETURN_VOID(env, status == napi_ok, "ref callback fail!"); + argc -= REQUIRED_1_ARGS; + ZLOGD("async callback, no promise"); + } else { + ZLOGD("no callback, async pormose"); + } } - ZLOGD("async call exec"); - context_->ctx->exec_ = std::move(exec); - napi_value promise = nullptr; - if (context_->callback == nullptr) { - napi_create_promise(env, &context_->defer, &promise); - } else { - napi_get_undefined(env, &promise); + + if (parse && (argc >= 0)) { + parse(argc, argv); } - napi_async_work work = context_->work; - napi_value resource = nullptr; - napi_create_string_utf8(env, "AsyncCall", NAPI_AUTO_LENGTH, &resource); - napi_create_async_work(env, nullptr, resource, AsyncCall::OnExecute, AsyncCall::OnComplete, context_, &work); - context_->work = work; - context_ = nullptr; - napi_queue_async_work(env, work); - ZLOGD("async call exec"); - return promise; } -napi_value AsyncCall::SyncCall(napi_env env, AsyncCall::Context::ExecAction exec) +napi_value AsyncCall::DoAsyncWork(napi_env env, std::shared_ptr context, const std::string& name, + NapiAsyncExecute execute, NapiAsyncComplete complete) { - if ((context_ == nullptr) || (context_->ctx == nullptr)) { - ZLOGD("context_ or context_->ctx is null"); - return nullptr; - } - context_->ctx->exec_ = std::move(exec); - napi_value promise = nullptr; - if (context_->callback == nullptr) { - napi_create_promise(env, &context_->defer, &promise); + NAPI_ASSERT(env, context, "context is nullptr"); + NAPI_ASSERT(env, context->status == napi_ok, "status is not napi_ok"); + ZLOGD("DoAsyncWork name=%{public}s", name.c_str()); + context->execute = std::move(execute); + context->complete = std::move(complete); + + napi_value ret = nullptr; + if (context->callbackRef == nullptr) { + napi_create_promise(context->env, &context->deferred, &ret); } else { - napi_get_undefined(env, &promise); + napi_get_undefined(context->env, &ret); } - AsyncCall::OnExecute(env, context_); - AsyncCall::OnComplete(env, napi_ok, context_); - return promise; -} -void AsyncCall::OnExecute(napi_env env, void *data) -{ - ZLOGD("run the async runnable"); - AsyncContext *context = reinterpret_cast(data); - context->ctx->Exec(); + napi_value resource = nullptr; + napi_create_string_utf8(context->env, name.c_str(), NAPI_AUTO_LENGTH, &resource); + context->status = napi_create_async_work( + context->env, nullptr, resource, + [](napi_env env, void* data) { + // NAPI_ASSERT_RETURN_VOID(env, data != nullptr, "execute no data"); + ZLOGD("DoAsyncWork execute"); + auto ctxt = reinterpret_cast(data); + if (ctxt->execute) { + ZLOGD("DoAsyncWork execute inner"); + ctxt->execute(); + } + }, + [](napi_env env, napi_status status, void* data) { + // NAPI_ASSERT_RETURN_VOID(env, data != nullptr, "complete no data"); + ZLOGD("DoAsyncWork complete"); + auto ctxt = reinterpret_cast(data); + if (ctxt->complete) { + ZLOGD("DoAsyncWork complete"); + ctxt->complete(ctxt->output); + } + GenerateOutput(ctxt); + }, + (void*)(context.get()), &context->work); + NAPI_ASSERT(context->env, context->status == napi_ok, "create async work fail!"); + context->status = napi_queue_async_work(context->env, context->work); + NAPI_ASSERT(context->env, context->status == napi_ok, "queue async work fail!"); + context->hold = context; + return ret; } -void AsyncCall::OnComplete(napi_env env, napi_status status, void *data) +void AsyncCall::GenerateOutput(ContextBase* context) { - ZLOGD("run the js callback function"); - AsyncContext *context = reinterpret_cast(data); - napi_value output = nullptr; - napi_status runStatus = (*context->ctx)(env, &output); - napi_value result[ARG_BUTT] = { 0 }; - if (status == napi_ok && runStatus == napi_ok) { - napi_get_undefined(env, &result[ARG_ERROR]); - if (output != nullptr) { - result[ARG_DATA] = output; - } else { - napi_get_undefined(env, &result[ARG_DATA]); - } + ZLOGD("GenerateOutput in"); + napi_value result[JSUtil::TUPLE_SIZE] = { 0 }; + if (context->status == napi_ok) { + napi_get_undefined(context->env, &result[0]); + result[1] = context->output; } else { napi_value message = nullptr; - napi_create_string_utf8(env, "async call failed", NAPI_AUTO_LENGTH, &message); - napi_create_error(env, nullptr, message, &result[ARG_ERROR]); - napi_get_undefined(env, &result[ARG_DATA]); + napi_create_string_utf8(context->env, "async call failed", NAPI_AUTO_LENGTH, &message); + napi_create_error(context->env, nullptr, message, &result[0]); + napi_get_undefined(context->env, &result[1]); } - if (context->defer != nullptr) { - // promise - if (status == napi_ok && runStatus == napi_ok) { - napi_resolve_deferred(env, context->defer, result[ARG_DATA]); + if (context->deferred) { + if (context->status == napi_ok) { + napi_resolve_deferred(context->env, context->deferred, result[1]); } else { - napi_reject_deferred(env, context->defer, result[ARG_ERROR]); + napi_reject_deferred(context->env, context->deferred, result[0]); } } else { - // callback napi_value callback = nullptr; - napi_get_reference_value(env, context->callback, &callback); - napi_value returnValue; - napi_call_function(env, nullptr, callback, ARG_BUTT, result, &returnValue); - } - DeleteContext(env, context); -} -void AsyncCall::DeleteContext(napi_env env, AsyncContext *context) -{ - if (env != nullptr) { - napi_delete_reference(env, context->callback); - napi_delete_reference(env, context->self); - napi_delete_async_work(env, context->work); + napi_get_reference_value(context->env, context->callbackRef, &callback); + napi_value callbackResult = nullptr; + napi_call_function(context->env, nullptr, callback, JSUtil::TUPLE_SIZE, result, &callbackResult); } - delete context; + ZLOGD("GenerateOutput out"); + context->hold.reset(); // release context. } -} \ No newline at end of file +} // namespace OHOS::DistributedData diff --git a/frameworks/jskitsimpl/distributeddata/src/device_kv_store.cpp b/frameworks/jskitsimpl/distributeddata/src/device_kv_store.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c222ca756df387607f89704d8f294b988bea230d --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/src/device_kv_store.cpp @@ -0,0 +1,506 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "DeviceKVStore" +#include "device_kv_store.h" +#include +#include +#include "async_call.h" +#include "js_util.h" +#include "kv_store_resultset.h" +#include "log_print.h" +#include "single_kvstore.h" + +using namespace OHOS::DistributedKv; +namespace OHOS::DistributedData { +static __thread napi_ref g_ctor = nullptr; +std::map DeviceKVStore::eventHandlers_ = { + { "dataChange", KVStore::OnDataChange }, + { "syncComplete", DeviceKVStore::OnSyncComplete }, +}; + +DeviceKVStore::~DeviceKVStore() +{ + if (kvStore_ == nullptr) { + return; + } + + for (int i = 0; i < SUBSCRIBE_ALL + 1; ++i) { + if (dataObserver_[i] == nullptr) { + continue; + } + kvStore_->UnSubscribeKvStore(static_cast(i + 1), dataObserver_[i]); + } + + if (syncObserver_ != nullptr) { + kvStore_->UnRegisterSyncCallback(); + } +} + +napi_value DeviceKVStore::GetCtor(napi_env env) +{ + ZLOGD("DeviceKVStore::GetCtor()"); + if (g_ctor != nullptr) { + napi_value cons = nullptr; + NAPI_CALL(env, napi_get_reference_value(env, g_ctor, &cons)); + return cons; + } + + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_FUNCTION("put", KVStore::Put), + DECLARE_NAPI_FUNCTION("delete", KVStore::Delete), + DECLARE_NAPI_FUNCTION("putBatch", KVStore::PutBatch), + DECLARE_NAPI_FUNCTION("deleteBatch", KVStore::DeleteBatch), + DECLARE_NAPI_FUNCTION("startTransaction", KVStore::StartTransaction), + DECLARE_NAPI_FUNCTION("commit", KVStore::Commit), + DECLARE_NAPI_FUNCTION("rollback", KVStore::Rollback), + DECLARE_NAPI_FUNCTION("enableSync", KVStore::EnableSync), + DECLARE_NAPI_FUNCTION("setSyncRange", KVStore::SetSyncRange), + /* DeviceKVStore externs KVStore */ + DECLARE_NAPI_FUNCTION("get", DeviceKVStore::Get), + DECLARE_NAPI_FUNCTION("getEntries", DeviceKVStore::GetEntries), + DECLARE_NAPI_FUNCTION("getResultSet", DeviceKVStore::GetResultSet), + DECLARE_NAPI_FUNCTION("closeResultSet", DeviceKVStore::CloseResultSet), + DECLARE_NAPI_FUNCTION("getResultSize", DeviceKVStore::GetResultSize), + DECLARE_NAPI_FUNCTION("removeDeviceData", DeviceKVStore::RemoveDeviceData), + DECLARE_NAPI_FUNCTION("sync", DeviceKVStore::Sync), + DECLARE_NAPI_FUNCTION("on", DeviceKVStore::OnEvent), + DECLARE_NAPI_FUNCTION("off", DeviceKVStore::OffEvent), + + }; + napi_value cons; + NAPI_CALL(env, + napi_define_class(env, "DeviceKVStore", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_ctor)); + return cons; +} + +std::string DeviceKVStore::GetDeviceKey(std::string deviceId, std::string key) +{ + std::ostringstream oss; + oss << std::setfill('0') << std::setw(4) << deviceId.length(); + oss << deviceId << key; + return oss.str(); +} + +/* + get(deviceId:string, key:string, callback:AsyncCallback):void + get(deviceId:string, key:string):Promise +*/ +napi_value DeviceKVStore::Get(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::get()"); + struct GetContext : public ContextBase { + std::string deviceId; + std::string key; + JSUtil::VariantValue value; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + ZLOGD("GetCbInfo"); + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->deviceId); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get deviceId fail"); + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->key); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get key fail"); + }; + context->GetCbInfo(env, info, input); + ZLOGD("Get deviceId=%{public}s, key=%{public}s,", context->deviceId.c_str(), context->key.c_str()); + + auto execute = [ctxt = context.get()]() { + std::string deviceKey = GetDeviceKey(ctxt->deviceId, ctxt->key); + OHOS::DistributedKv::Key key(deviceKey); + OHOS::DistributedKv::Value value; + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->Get(deviceKey, value); + ctxt->value = JSUtil::Blob2VariantValue(value); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, ctxt->value, result); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +enum class ArgsType { + DEVICEID_KEYPREFIX, + DEVICEID_QUERY, + QUERY, + UNKNOWN +}; +struct VariantInputArgs { + std::string deviceId; + std::string keyPrefix; + DataQuery query; + ArgsType type = ArgsType::UNKNOWN; +}; + +static napi_status GetVariantContext(napi_env env, size_t argc, napi_value* argv, VariantInputArgs& via) +{ + NAPI_ASSERT_BASE(env, argc >= REQUIRED_1_ARGS, "invalid arguments!", napi_invalid_arg); + size_t index = 0; + napi_valuetype type; + napi_status status = napi_typeof(env, argv[index], &type); + NAPI_ASSERT_BASE(env, status == napi_ok, "invalid arguments!", napi_invalid_arg); + if (type == napi_string) { + status = JSUtil::FromNapiValue(env, argv[index++], via.deviceId); + if (index < argc) { + status = napi_typeof(env, argv[index], &type); + NAPI_ASSERT_BASE(env, status == napi_ok, "invalid arguments!", napi_invalid_arg); + if (type == napi_string) { + status = JSUtil::FromNapiValue(env, argv[index++], via.keyPrefix); + via.type = ArgsType::DEVICEID_KEYPREFIX; + } else if (type == napi_object) { + status = JSUtil::FromNapiValue(env, argv[index++], via.deviceId /* todo get query */); + via.type = ArgsType::DEVICEID_QUERY; + } + } + } else if (type == napi_object) { + status = JSUtil::FromNapiValue(env, argv[index++], via.deviceId /* todo get query */); + via.type = ArgsType::QUERY; + } else { + NAPI_ASSERT_BASE(env, type == napi_string, "invalid arguments!", napi_invalid_arg); + } + return status; +}; + +static std::string VariantInputArgsToString(const VariantInputArgs& via) { + return via.deviceId; // todo +} + +/* + * getEntries(deviceId:string, keyPrefix:string, callback:AsyncCallback):void + * getEntries(deviceId:string, keyPrefix:string):Promise + * + * getEntries(query:Query, callback:AsyncCallback):void + * getEntries(query:Query) : Promise + * + * getEntries(deviceId:string, query:Query):callback:AsyncCallback):void + * getEntries(deviceId:string, query:Query):Promise + */ +napi_value DeviceKVStore::GetEntries(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::GetEntries()"); + struct GetEntriesContext : public ContextBase { + VariantInputArgs via; + std::vector entries; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + ctxt->status = GetVariantContext(ctxt->env, argc, argv, ctxt->via); + }; + context->GetCbInfo(env, info, input); + ZLOGD("GetEntries %{public}s,", VariantInputArgsToString(context->via).c_str()); + + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = Status::INVALID_ARGUMENT; + if (ctxt->via.type == ArgsType::DEVICEID_KEYPREFIX) { + std::string deviceKey = GetDeviceKey(ctxt->via.deviceId, ctxt->via.keyPrefix); + OHOS::DistributedKv::Key keyPrefix(deviceKey); + status = kvStore->GetEntries(keyPrefix, ctxt->entries); + } else if (ctxt->via.type == ArgsType::DEVICEID_QUERY) { + OHOS::DistributedKv::Key keyPrefix(ctxt->via.keyPrefix); + status = kvStore->GetEntries(keyPrefix, ctxt->entries); // todo + } else if (ctxt->via.type == ArgsType::QUERY) { + OHOS::DistributedKv::Key keyPrefix(ctxt->via.keyPrefix); + status = kvStore->GetEntries(keyPrefix, ctxt->entries); // todo + } + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, ctxt->entries, result); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +/* + getResultSet(deviceId:string, keyPrefix:string, callback:AsyncCallback):void + getResultSet(deviceId:string, keyPrefix:string):Promise + getResultSet(query:Query, callback:AsyncCallback):void + getResultSet(query:Query):Promise + getResultSet(deviceId:string, query:Query, callback:AsyncCallback):void + getResultSet(deviceId:string, query:Query):Promise +*/ +napi_value DeviceKVStore::GetResultSet(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::GetResultSet()"); + struct ResultSetContext : public ContextBase { + VariantInputArgs via; + KVStoreResultSet* resultSet = nullptr; + napi_ref ref = nullptr; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + ctxt->status = GetVariantContext(ctxt->env, argc, argv, ctxt->via); + napi_value jsObject = nullptr; + ctxt->status = napi_new_instance(ctxt->env, GetCtor(ctxt->env), argc, argv, &jsObject); + NAPI_ASSERT_RETURN_VOID(ctxt->env, jsObject != nullptr, "new KVStoreResultSet fail"); + napi_unwrap(ctxt->env, jsObject, reinterpret_cast(&ctxt->resultSet)); + NAPI_ASSERT_RETURN_VOID(ctxt->env, jsObject != nullptr, "unwrap KVStoreResultSet fail"); + ctxt->status = napi_create_reference(ctxt->env, jsObject, 1, &(ctxt->ref)); + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + std::shared_ptr result; + std::string deviceKey = GetDeviceKey(ctxt->via.deviceId, ctxt->via.keyPrefix); + OHOS::DistributedKv::Key keyPrefix(deviceKey); + // TODO GetResultSet( query, ....) + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->GetResultSet(keyPrefix, result); + if (status == Status::SUCCESS) { + *(ctxt->resultSet) = std::move(result); + } + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = napi_get_reference_value(ctxt->env, ctxt->ref, &result); + napi_delete_reference(ctxt->env, ctxt->ref); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +/* +closeResultSet(resultSet:KVStoreResultSet, callback: AsyncCallback):void +closeResultSet(resultSet:KVStoreResultSet):Promise +*/ +napi_value DeviceKVStore::CloseResultSet(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::CloseResultSet()"); + struct CloseResultSetContext : public ContextBase { + std::shared_ptr resultSet = nullptr; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + napi_valuetype type; + ctxt->status = napi_typeof(ctxt->env, argv[index], &type); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get napi_typeof fail"); + if (type == napi_object) { + // status = JSUtil::FromNapiValue(ctxt->env, argv[index++], via.deviceId /* todo get KvStoreResultSet */); + } + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->CloseResultSet(ctxt->resultSet); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} + +/* + getResultSize(query:Query, callback: AsyncCallback):void + getResultSize(query:Query):Promise + getResultSize(deviceId:string, query:Query, callback: AsyncCallback):void + getResultSize(deviceId:string, query:Query):Promise +*/ +napi_value DeviceKVStore::GetResultSize(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::GetResultSize()"); + struct ResultSizeContext : public ContextBase { + std::string query; + int resultSize = 0; + }; + + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + napi_valuetype type; + ctxt->status = napi_typeof(ctxt->env, argv[index], &type); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get napi_typeof fail"); + if (type == napi_object) { + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->query /* todo get query */); + } + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }; + context->GetCbInfo(env, info, input); + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->GetCountWithQuery(ctxt->query, ctxt->resultSize); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, static_cast(ctxt->resultSize), result); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +/* + removeDeviceData(deviceId:string, callback: AsyncCallback):void + removeDeviceData(deviceId:string):Promise +*/ +napi_value DeviceKVStore::RemoveDeviceData(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::RemoveDeviceData()"); + struct RemoveDeviceContext : public ContextBase { + std::string deviceId; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + // todo + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->deviceId /* todo get query */); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->RemoveDeviceData(ctxt->deviceId); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} + +napi_value DeviceKVStore::OnEvent(napi_env env, napi_callback_info info) +{ /* +on(event:'syncComplete',syncCallback: Callback>):void */ + ZLOGD("DeviceKVStore::OnEvent()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc > 0, "there is no args"); + napi_valuetype type; + NAPI_CALL(env, napi_typeof(env, argv[0], &type)); + NAPI_ASSERT(env, type == napi_string, "key not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + + ZLOGI("subscribe event:%{public}s", event.c_str()); + auto handle = eventHandlers_.find(event); + NAPI_ASSERT(env, handle != eventHandlers_.end(), "invalid event"); + napi_value result = nullptr; + handle->second(env, argc - 1, &argv[1], self, &result); + return nullptr; +} + +napi_value DeviceKVStore::OffEvent(napi_env env, napi_callback_info info) +{ /* +off(event:'syncComplete', syncCallback: Callback>):void */ + ZLOGD("DeviceKVStore::OffEvent()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc > 0, "there is no args"); + napi_valuetype type; + NAPI_CALL(env, napi_typeof(env, argv[0], &type)); + NAPI_ASSERT(env, type == napi_string, "key not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + + ZLOGI("subscribe event:%{public}s", event.c_str()); + auto handle = eventHandlers_.find(event); + NAPI_ASSERT(env, handle != eventHandlers_.end(), "invalid event"); + napi_value result = nullptr; + handle->second(env, argc - 1, &argv[1], self, &result); + return nullptr; +} + +napi_value DeviceKVStore::Sync(napi_env env, napi_callback_info info) +{ /* +sync(deviceIdList:string[], mode:SyncMode):void */ + ZLOGD("DeviceKVStore::Sync()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + DeviceKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + std::vector devices; + JSUtil::FromNapiValue(env, argv[0], devices); + int32_t mode = int32_t(SyncMode::PUSH_PULL); + napi_get_value_int32(env, argv[1], &mode); + uint32_t delay = 0; + // 3 is the max number of parameters + if (argc >= 3) { + napi_get_value_uint32(env, argv[2], &delay); // argv[2] is the third parameter + } + ZLOGD("sync data %{public}d, mode:%{public}d, devices:%{public}zu", static_cast(argc), mode, devices.size()); + + Status status = proxy->kvStore_->Sync(devices, static_cast(mode), delay); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + +napi_value DeviceKVStore::Initialize(napi_env env, napi_callback_info info) +{ + ZLOGD("DeviceKVStore::Initialize()"); + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + auto* proxy = new DeviceKVStore(); + auto release = [proxy]() -> napi_value { + delete proxy; + return nullptr; + }; + auto finalize = [](napi_env env, void* data, void* hint) { + auto* proxy = reinterpret_cast(data); + delete proxy; + }; + NAPI_CALL_BASE(env, napi_wrap(env, self, proxy, finalize, nullptr, nullptr), release()); + return self; +} + +napi_status DeviceKVStore::OnSyncComplete( + napi_env env, size_t argc, napi_value* argv, napi_value self, napi_value* result) +{ + // on(event: 'syncComplete', syncCallback: Callback>): void; + // except event, there is 1 arg + ZLOGD("DeviceKVStore::OnSyncComplete()"); + NAPI_ASSERT_BASE(env, argc >= REQUIRED_1_ARGS, "args is out of range", napi_invalid_arg); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[0], &valueType); + NAPI_ASSERT_BASE(env, valueType == napi_function, "callback is not function", napi_invalid_arg); + + DeviceKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", napi_invalid_arg); + std::shared_ptr observer = std::make_shared(env, argv[0]); + Status status = proxy->kvStore_->RegisterSyncCallback(observer); + if (status != Status::SUCCESS) { + return napi_generic_failure; + } + proxy->syncObserver_ = observer; + return napi_ok; +} + +DeviceKVStore& DeviceKVStore::operator=(std::shared_ptr&& singleKvStore) +{ + if (kvStore_ == singleKvStore) { + return *this; + } + kvStore_ = std::move(singleKvStore); + return *this; +} + +bool DeviceKVStore::operator==(const std::shared_ptr& singleKvStore) +{ + return kvStore_ == singleKvStore; +} +} // namespace OHOS::DistributedData diff --git a/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp b/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp index ce56ad52e7159b9310b8716829fd82bf7b87b90c..5845b43aec4700f6712622ad6af1fdea6c26854d 100644 --- a/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/entry_point.cpp @@ -16,6 +16,7 @@ #include "napi/native_api.h" #include "napi/native_node_api.h" #include "kv_manager.h" +#include "query.h" #include "js_util.h" #include "log_print.h" using namespace OHOS::DistributedData; @@ -26,8 +27,11 @@ extern const char _binary_distributed_data_js_end[]; static napi_value Init(napi_env env, napi_value exports) { - napi_property_descriptor desc = DECLARE_NAPI_METHOD("createKVManager", KVManager::CreateKVManager); - napi_status status = napi_define_properties(env, exports, 1, &desc); + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("createKVManager", KVManager::CreateKVManager), + DECLARE_NAPI_PROPERTY("Query", Query::CreateQueryObject(env)) + }; + napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); ZLOGI("init distributedData %{public}d", status); return exports; } diff --git a/frameworks/jskitsimpl/distributeddata/src/js_util.cpp b/frameworks/jskitsimpl/distributeddata/src/js_util.cpp index 3e2f913d1be87fc3dcea8878259f56ef69dabb48..7852509570795faa63096cecdcac50212e000888 100644 --- a/frameworks/jskitsimpl/distributeddata/src/js_util.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/js_util.cpp @@ -13,316 +13,570 @@ * limitations under the License. */ #define LOG_TAG "JSUtil" - #include "js_util.h" #include #include "log_print.h" - using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { -DistributedKv::Options JSUtil::Convert2Options(napi_env env, napi_value jsOptions) +constexpr size_t STR_TAIL_LENGTH = 1; + +/* napi_value <-> bool */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, bool& out) { - DistributedKv::Options options; - napi_value value = nullptr; - napi_get_named_property(env, jsOptions, "createIfMissing", &value); - if (value != nullptr) { - napi_get_value_bool(env, value, &options.createIfMissing); - } - value = nullptr; - napi_get_named_property(env, jsOptions, "encrypt", &value); - if (value != nullptr) { - napi_get_value_bool(env, value, &options.encrypt); - } - value = nullptr; - napi_get_named_property(env, jsOptions, "backup", &value); - if (value != nullptr) { - napi_get_value_bool(env, value, &options.backup); - } - value = nullptr; - options.autoSync = false; - napi_get_named_property(env, jsOptions, "autoSync", &value); - if (value != nullptr) { - napi_get_value_bool(env, value, &options.autoSync); - } - value = nullptr; - napi_get_named_property(env, jsOptions, "kvStoreType", &value); - if (value != nullptr) { - int32_t storeType = DistributedKv::DEVICE_COLLABORATION; - napi_get_value_int32(env, value, &storeType); - options.kvStoreType = static_cast(storeType); - } - value = nullptr; - napi_get_named_property(env, jsOptions, "securityLevel", &value); - if (value != nullptr) { - napi_get_value_int32(env, value, &options.securityLevel); - } - return options; + return napi_get_value_bool(env, in, &out); +} +napi_status JSUtil::ToNapiValue(napi_env env, const bool& in, napi_value& out) +{ + return napi_get_boolean(env, in, &out); } -std::string JSUtil::Convert2String(napi_env env, napi_value jsString) +/* napi_value <-> int32_t */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, int32_t& out) { - size_t maxLen = JSUtil::MAX_LEN; - napi_status status = napi_get_value_string_utf8(env, jsString, NULL, 0, &maxLen); - if (status != napi_ok) { - GET_AND_THROW_LAST_ERROR((env)); - maxLen = JSUtil::MAX_LEN; - } - if (maxLen <= 0) { - return std::string(); - } - char *buf = new char[maxLen + 1]; - if (buf == nullptr) { - return std::string(); - } - size_t len = 0; - status = napi_get_value_string_utf8(env, jsString, buf, maxLen + 1, &len); - if (status != napi_ok) { - GET_AND_THROW_LAST_ERROR((env)); - } - buf[len] = 0; - std::string value(buf); - delete[] buf; - return value; + return napi_get_value_int32(env, in, &out); +} +napi_status JSUtil::ToNapiValue(napi_env env, const int32_t& in, napi_value& out) +{ + return napi_create_int32(env, in, &out); } -napi_value JSUtil::Convert2JSNotification(napi_env env, const DistributedKv::ChangeNotification ¬ification) +/* napi_value <-> uint32_t */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, uint32_t& out) { - napi_value result = nullptr; - napi_create_object(env, &result); - napi_set_named_property(env, result, "deviceId", Convert2JSString(env, notification.GetDeviceId())); - napi_set_named_property(env, result, "insertEntries", GetJSEntries(env, notification.GetInsertEntries())); - napi_set_named_property(env, result, "updateEntries", GetJSEntries(env, notification.GetUpdateEntries())); - napi_set_named_property(env, result, "deleteEntries", GetJSEntries(env, notification.GetDeleteEntries())); - return result; + return napi_get_value_uint32(env, in, &out); +} +napi_status JSUtil::ToNapiValue(napi_env env, const uint32_t& in, napi_value& out) +{ + return napi_create_uint32(env, in, &out); } -napi_value JSUtil::Convert2JSTupleArray(napi_env env, std::map &data) +/* napi_value <-> int64_t */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, int64_t& out) { - napi_value result = nullptr; - napi_create_array_with_length(env, data.size(), &result); - int index = 0; - for (const auto &[key, value] : data) { - napi_value element = nullptr; - napi_create_array_with_length(env, TUPLE_SIZE, &element); - napi_value jsKey = nullptr; - napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); - napi_set_element(env, element, 0, jsKey); - napi_value jsValue = nullptr; - napi_create_int32(env, value, &jsValue); - napi_set_element(env, element, 1, jsValue); - napi_set_element(env, result, index++, element); + return napi_get_value_int64(env, in, &out); +} +napi_status JSUtil::ToNapiValue(napi_env env, const int64_t& in, napi_value& out) +{ + return napi_create_int64(env, in, &out); +} + +/* napi_value <-> double */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, double& out) +{ + return napi_get_value_double(env, in, &out); +} +napi_status JSUtil::ToNapiValue(napi_env env, const double& in, napi_value& out) +{ + return napi_create_double(env, in, &out); +} + +/* napi_value <-> std::string */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::string& out) +{ + size_t length = JSUtil::MAX_LEN; + napi_status status = napi_get_value_string_utf8(env, in, NULL, 0, &length); + if (status == napi_ok) { + out.assign(length + STR_TAIL_LENGTH, '\0'); + status = napi_get_value_string_utf8(env, in, out.data(), length + STR_TAIL_LENGTH, &length); + ZLOGD("FromNapiValue napi_value <-> std::string [%{public}.8s] len={public}%d", out.c_str(), length); } - return result; + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::string& in, napi_value& out) +{ + return napi_create_string_utf8(env, in.c_str(), in.size(), &out); } -std::vector JSUtil::Convert2StringArray(napi_env env, napi_value jsValue) +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) { bool isArray = false; - napi_is_array(env, jsValue, &isArray); - NAPI_ASSERT_BASE(env, isArray, "not array", { }); + napi_status status = napi_is_array(env, in, &isArray); + NAPI_ASSERT_BASE(env, isArray && (status == napi_ok), "not array", status); uint32_t length = 0; - napi_get_array_length(env, jsValue, &length); - std::vector devices; + status = napi_get_array_length(env, in, &length); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (length > 0), "get_array fail", status); for (uint32_t i = 0; i < length; ++i) { - napi_value deviceId = nullptr; - napi_get_element(env, jsValue, i, &deviceId); - if (deviceId == nullptr) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + NAPI_ASSERT_BASE(env, isArray && (status == napi_ok), "no element", status); + if ((status != napi_ok) || (item == nullptr)) { continue; } - devices.push_back(Convert2String(env, deviceId)); + std::string v; + status = FromNapiValue(env, item, v); + out.push_back(v); + } + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) +{ + napi_status status = napi_create_array_with_length(env, in.size(), &out); + NAPI_ASSERT_BASE(env, status == napi_ok, "create array fail", status); + int index = 0; + for (auto& item : in) { + napi_value element = nullptr; + ToNapiValue(env, item, element); + status = napi_set_element(env, out, index++, element); + NAPI_ASSERT_BASE(env, (status == napi_ok), "not array", status); } - return devices; + return status; } -napi_value JSUtil::Convert2JSString(napi_env env, const std::vector &key) +JSUtil::VariantValue JSUtil::Blob2VariantValue(const DistributedKv::Blob& blob) { - std::string realkey(key.begin(), key.end()); - napi_value jsKey = nullptr; - napi_create_string_utf8(env, realkey.c_str(), realkey.size(), &jsKey); - return jsKey; + JSUtil::VariantValue value; + auto& data = blob.Data(); + auto it = data.begin(); + if (it != data.end()) { + ++it; // skip data[0] + if (it != data.end()) { + std::vector tmpv(it, data.end()); + switch (data[0]) { + case STRING: + value = std::string(tmpv.begin(), tmpv.end()); + break; + case INTEGER: + value = TransferByteArrayToType(tmpv); + break; + case FLOAT: + value = TransferByteArrayToType(tmpv); + break; + case BYTE_ARRAY: + value = tmpv; + break; + case BOOLEAN: + value = TransferByteArrayToType(tmpv); + break; + case DOUBLE: + value = TransferByteArrayToType(tmpv); + break; + default: + break; + } + } + } + return value; } +DistributedKv::Blob JSUtil::VariantValue2Blob(JSUtil::VariantValue& value) +{ + std::vector out; + auto joinType = [&out](const std::vector& tmpv, JSUtil::VariantType type) { + out.resize(tmpv.size() + 1); + out.push_back(type); + out.insert(out.end(), tmpv.begin(), tmpv.end()); + }; -napi_value JSUtil::Convert2JSValue(napi_env env, const std::vector &data) + if (auto pval = std::get_if(&value)) { + joinType(std::vector((*pval).begin(), (*pval).end()), JSUtil::VariantType::STRING); + } else if (auto pval = std::get_if(&value)) { + joinType(TransferTypeToByteArray(*pval), JSUtil::VariantType::INTEGER); + } else if (auto pval = std::get_if(&value)) { + joinType(TransferTypeToByteArray(*pval), JSUtil::VariantType::FLOAT); + } else if (auto pval = std::get_if>(&value)) { + joinType(*pval, JSUtil::VariantType::BYTE_ARRAY); + } else if (auto pval = std::get_if(&value)) { + joinType(TransferTypeToByteArray(*pval), JSUtil::VariantType::BOOLEAN); + } else if (auto pval = std::get_if(&value)) { + joinType(TransferTypeToByteArray(*pval), JSUtil::VariantType::DOUBLE); + } else { + ZLOGE("VariantType is INVALID"); + } + return out; +} + +/* napi_value <-> VariantValue */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, JSUtil::VariantValue& out) { - napi_value result = nullptr; - napi_get_undefined(env, &result); - NAPI_ASSERT_BASE(env, data.size() > 1, "invalid data", result); - napi_create_object(env, &result); - napi_value jsType = nullptr; - napi_create_int32(env, data[0], &jsType); - napi_set_named_property(env, result, "type", jsType); - napi_value jsValue = nullptr; - switch (data[0]) { - case STRING: - napi_create_string_utf8(env, reinterpret_cast(data.data() + DATA_POS), data.size() - DATA_POS, - &jsValue); + napi_valuetype type; + napi_status status = napi_typeof(env, in, &type); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid type", status); + + switch (type) { + case napi_boolean: { + bool vBool = false; + status = JSUtil::FromNapiValue(env, in, vBool); + out = vBool; break; - case BOOLEAN: - napi_get_boolean(env, *(reinterpret_cast(data.data() + DATA_POS)), &jsValue); + } + case napi_number: { + double vNum = false; + status = JSUtil::FromNapiValue(env, in, vNum); + out = vNum; break; - case BYTE_ARRAY: { - uint8_t *native = nullptr; - napi_value buffer = nullptr; - napi_create_arraybuffer(env, data.size() - DATA_POS, reinterpret_cast(&native), &buffer); - memcpy_s(native, data.size() - DATA_POS, data.data() + DATA_POS, data.size() - DATA_POS); - napi_create_typedarray(env, napi_uint8_array, data.size() - DATA_POS, buffer, 0, &jsValue); + } + case napi_string: { + double vString = false; + status = JSUtil::FromNapiValue(env, in, vString); + out = vString; + break; + } + case napi_object: { + // out = JSUtil::FromNapiValue>(env, in); break; } default: - jsValue = Convert2JSNumber(env, data); + status = napi_invalid_arg; break; } - napi_set_named_property(env, result, "value", jsValue); - return result; -} - -std::vector JSUtil::Convert2Vector(napi_env env, napi_value jsValue) -{ - napi_valuetype valueType; - napi_typeof(env, jsValue, &valueType); - switch (valueType) { - case napi_boolean: - return ConvertBool2Vector(env, jsValue); - case napi_number: - return ConvertNumber2Vector(env, jsValue); - case napi_string: - return ConvertString2Vector(env, jsValue); - case napi_object: - return ConvertUint8Array2Vector(env, jsValue); + NAPI_ASSERT_BASE(env, (status == napi_ok), "bad value!", status); + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const JSUtil::VariantValue& in, napi_value& out) +{ + napi_status status = napi_invalid_arg; + if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if>(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else { + ZLOGE("VariantType is INVALID"); + } + return status; +} + +/* napi_value <-> VariantValue3 */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, JSUtil::VariantValue3& out) +{ + napi_valuetype type; + napi_status status = napi_typeof(env, in, &type); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid type", status); + + switch (type) { + case napi_boolean: { + bool vBool = false; + status = JSUtil::FromNapiValue(env, in, vBool); + out = vBool; + break; + } + case napi_number: { + double vNum = false; + status = JSUtil::FromNapiValue(env, in, vNum); + out = vNum; + break; + } + case napi_string: { + double vString = false; + status = JSUtil::FromNapiValue(env, in, vString); + out = vString; + break; + } default: + status = napi_invalid_arg; break; } - return {INVALID}; + NAPI_ASSERT_BASE(env, (status == napi_ok), "bad value!", status); + return status; } - -std::vector JSUtil::ConvertUint8Array2Vector(napi_env env, napi_value jsValue) +napi_status JSUtil::ToNapiValue(napi_env env, const JSUtil::VariantValue3& in, napi_value& out) { - bool isTypedArray = false; - if (napi_is_typedarray(env, jsValue, &isTypedArray) != napi_ok || !isTypedArray) { - return {INVALID}; + napi_status status = napi_invalid_arg; + if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else if (auto pval = std::get_if(&in)) { + status = ToNapiValue(env, *pval, out); + } else { + ZLOGE("VariantType is INVALID"); } + return status; +} +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) +{ napi_typedarray_type type; size_t length = 0; napi_value buffer = nullptr; size_t offset = 0; - uint8_t *data = nullptr; - NAPI_CALL_BASE(env, napi_get_typedarray_info(env, jsValue, &type, - &length, reinterpret_cast(&data), &buffer, &offset), { INVALID }); - if (type != napi_uint8_array || length == 0 || data == nullptr) { - return {INVALID}; + void* data = nullptr; + napi_status status = napi_get_typedarray_info(env, in, &type, &length, &data, &buffer, &offset); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_uint8_array) && (length > 0) && (data != nullptr), + "get_typedarray fail", status); + out.assign((uint8_t*)data, ((uint8_t*)data) + length); + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) +{ + NAPI_ASSERT_BASE(env, in.size() > 0, "invalid std::vector", napi_invalid_arg); + void* data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, in.size(), &data, &buffer); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid buffer", status); + + if (memcpy_s(data, in.size(), in.data(), in.size()) != EOK) { + ZLOGE("memcpy_s not EOK"); + return napi_invalid_arg; } - std::vector result(sizeof(uint8_t) + length); - result[TYPE_POS] = BYTE_ARRAY; - memcpy_s(result.data() + DATA_POS, result.size() - DATA_POS, data, length); - return result; + status = napi_create_typedarray(env, napi_uint8_array, in.size(), buffer, 0, &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid buffer", status); + return status; } -std::vector JSUtil::ConvertString2Vector(napi_env env, napi_value jsValue) +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) +{ + napi_typedarray_type type; + size_t length = 0; + napi_value buffer = nullptr; + size_t offset = 0; + uint32_t* data = nullptr; + napi_status status = napi_get_typedarray_info(env, in, &type, &length, (void**)&data, &buffer, &offset); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_uint32_array) && (length > 0) && (data != nullptr), + "get_typedarray fail", status); + out.assign(data, data + length); + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) { - std::string value = Convert2String(env, jsValue); - std::vector result(sizeof(uint8_t) + value.size()); - result[TYPE_POS] = STRING; - if (memcpy_s(result.data() + DATA_POS, result.size() - DATA_POS, value.data(), value.size()) != EOK) { - result[TYPE_POS] = INVALID; + size_t bytes = in.size() * sizeof(uint32_t); + NAPI_ASSERT_BASE(env, bytes > 0, "invalid std::vector", napi_invalid_arg); + void* data = nullptr; + napi_value buffer = nullptr; + napi_status status = napi_create_arraybuffer(env, bytes, &data, &buffer); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid buffer", status); + + if (memcpy_s(data, bytes, in.data(), bytes) != EOK) { + ZLOGE("memcpy_s not EOK"); + return napi_invalid_arg; } - return result; + status = napi_create_typedarray(env, napi_uint32_array, in.size(), buffer, 0, &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid buffer", status); + return status; } -std::vector JSUtil::ConvertNumber2Vector(napi_env env, napi_value jsValue) +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) { - // the JavaScript number is 64 bits double. - double value = 0; - auto status = napi_get_value_double(env, jsValue, &value); - if (status == napi_ok) { - std::vector result(sizeof(uint8_t) + sizeof(double)); - result[TYPE_POS] = DOUBLE; - uint8_t byteValue[MAX_NUMBER_BYTES]; - errno_t err = memcpy_s(byteValue, MAX_NUMBER_BYTES, &value, sizeof(double)); - if (err != EOK) { - return {INVALID}; - } - err = memcpy_s(result.data() + DATA_POS, sizeof(double), byteValue, sizeof(byteValue)); - if (err != EOK) { - return {INVALID}; - } - return result; + napi_typedarray_type type; + size_t length = 0; + napi_value buffer = nullptr; + size_t offset = 0; + uint32_t* data = nullptr; + napi_status status = napi_get_typedarray_info(env, in, &type, &length, (void**)&data, &buffer, &offset); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (type == napi_uint8_array) && (length > 0) && (data != nullptr), + "get_typedarray fail", status); + out.assign(data, data + length); + return status; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "std::vector to napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +/* napi_value <-> std::map */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::map& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "std::map from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} + +napi_status JSUtil::ToNapiValue(napi_env env, const std::map& in, napi_value& out) +{ + napi_status status = napi_create_array_with_length(env, in.size(), &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : in) { + napi_value element = nullptr; + napi_create_array_with_length(env, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); + napi_set_element(env, element, 0, jsKey); + napi_value jsValue = nullptr; + napi_create_int32(env, value, &jsValue); + napi_set_element(env, element, 1, jsValue); + napi_set_element(env, out, index++, element); } + return status; +} - return {INVALID}; +/* napi_value <-> DistributedKv::Entry */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, DistributedKv::Entry& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "DistributedKv::Entry from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; } -std::vector JSUtil::ConvertBool2Vector(napi_env env, napi_value jsValue) +napi_status JSUtil::ToNapiValue(napi_env env, const DistributedKv::Entry& in, napi_value& out) { - std::vector result; - result.resize(sizeof(uint8_t) + sizeof(int32_t)); - result[TYPE_POS] = BOOLEAN; - bool value = false; - napi_get_value_bool(env, jsValue, &value); - *reinterpret_cast(result.data() + DATA_POS) = value ? 1 : 0; - return result; + napi_status status = napi_invalid_arg; + status = napi_create_object(env, &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid object", status); + + napi_value kValue = nullptr; + ToNapiValue(env, in.key.ToString(), kValue); + status = napi_set_named_property(env, out, "key", kValue); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid key", status); + + napi_value vValue = nullptr; + ToNapiValue(env, in.value.ToString(), vValue); + status = napi_set_named_property(env, out, "value", vValue); + NAPI_ASSERT_BASE(env, (status == napi_ok), "invalid value", status); + return status; } -napi_value JSUtil::GetJSEntries(napi_env env, const std::list &entries) +/* napi_value <-> std::list */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::list& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "DistributedKv::Entry from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::list& in, napi_value& out) { - napi_value jsValue = nullptr; - napi_create_array_with_length(env, entries.size(), &jsValue); + NAPI_ASSERT_BASE(env, in.size() > 0, "invalid std::list", napi_invalid_arg); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + NAPI_ASSERT_BASE(env, status == napi_ok, "create array fail", status); int index = 0; - for (const auto &data : entries) { + for (const auto& item : in) { napi_value entry = nullptr; - napi_create_object(env, &entry); - napi_set_named_property(env, entry, "key", Convert2JSString(env, data.key.Data())); - napi_set_named_property(env, entry, "value", Convert2JSValue(env, data.value.Data())); - napi_set_element(env, jsValue, index++, entry); + ToNapiValue(env, item, entry); + napi_set_element(env, out, index++, entry); } - return jsValue; + return status; } -napi_value JSUtil::GetJSEntries(napi_env env, const std::vector &entries) +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "DistributedKv::Entry from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) { - napi_value jsValue = nullptr; - napi_create_array_with_length(env, entries.size(), &jsValue); + NAPI_ASSERT_BASE(env, in.size() > 0, "invalid std::vector", napi_invalid_arg); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + NAPI_ASSERT_BASE(env, status == napi_ok, "create array fail", status); int index = 0; - for (const auto &data : entries) { + for (const auto& item : in) { napi_value entry = nullptr; - napi_create_object(env, &entry); - napi_set_named_property(env, entry, "key", Convert2JSString(env, data.key.Data())); - napi_set_named_property(env, entry, "value", Convert2JSValue(env, data.value.Data())); - napi_set_element(env, jsValue, index++, entry); + ToNapiValue(env, item, entry); + napi_set_element(env, out, index++, entry); } - return jsValue; + return status; } -napi_value JSUtil::Convert2JSString(napi_env env, const std::string &cString) +/* napi_value <-> std::vector */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, std::vector& out) { - napi_value jsValue = nullptr; - napi_create_string_utf8(env, cString.c_str(), cString.size(), &jsValue); - return jsValue; + bool isArray = false; + napi_status status = napi_is_array(env, in, &isArray); + NAPI_ASSERT_BASE(env, isArray && (status == napi_ok), "not array", status); + uint32_t length = 0; + status = napi_get_array_length(env, in, &length); + NAPI_ASSERT_BASE(env, (status == napi_ok) && (length > 0), "get_array fail", status); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + NAPI_ASSERT_BASE(env, (status == napi_ok), "no element", status); + if ((status != napi_ok) || (item == nullptr)) { + continue; + } + std::string v; + status = FromNapiValue(env, item, v); + DistributedKv::StoreId storeId {v}; + out.push_back(storeId); + } + return status; } - -napi_value JSUtil::Convert2JSNumber(napi_env env, const std::vector &data) +napi_status JSUtil::ToNapiValue(napi_env env, const std::vector& in, napi_value& out) { - napi_value jsValue = nullptr; - uint8_t byteValue[MAX_NUMBER_BYTES]; - double value; - switch (data[0]) { - case INTEGER: - memcpy_s(byteValue, sizeof(byteValue), data.data() + DATA_POS, sizeof(int32_t)); - value = *(reinterpret_cast(byteValue)); - break; - case FLOAT: - memcpy_s(byteValue, sizeof(byteValue), data.data() + DATA_POS, sizeof(float)); - value = *(reinterpret_cast(byteValue)); - break; - case DOUBLE: - memcpy_s(byteValue, sizeof(byteValue), data.data() + DATA_POS, sizeof(double)); - value = *(reinterpret_cast(byteValue)); - break; - default: - napi_get_undefined(env, &jsValue); - return jsValue; + NAPI_ASSERT_BASE(env, in.size() > 0, "invalid std::vector", napi_invalid_arg); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "create_array fail", status); + int index = 0; + for (const auto& item : in) { + napi_value entry = nullptr; + ToNapiValue(env, item.storeId, entry); + napi_set_element(env, out, index++, entry); } - napi_create_double(env, value, &jsValue); - return jsValue; + return status; +} + +/* napi_value <-> DistributedKv::ChangeNotification */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, DistributedKv::ChangeNotification& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "DistributedKv::ChangeNotification from napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; +} +napi_status JSUtil::ToNapiValue(napi_env env, const DistributedKv::ChangeNotification& in, napi_value& out) +{ + napi_status status = napi_create_object(env, &out); + NAPI_ASSERT_BASE(env, (status == napi_ok), "napi_create_object for DistributedKv::ChangeNotification fail", status); + napi_value deviceId = nullptr; + status = ToNapiValue(env, in.GetDeviceId(), deviceId); + NAPI_ASSERT_BASE(env, (status == napi_ok) || (deviceId == nullptr), "GetDeviceId fail", status); + status = napi_set_named_property(env, out, "deviceId", deviceId); + NAPI_ASSERT_BASE(env, (status == napi_ok), "set_named_property deviceId fail", status); + + napi_value insertEntries = nullptr; + status = ToNapiValue(env, in.GetInsertEntries(), insertEntries); + NAPI_ASSERT_BASE(env, (status == napi_ok) || (insertEntries == nullptr), "GetInsertEntries fail", status); + status = napi_set_named_property(env, out, "insertEntries", insertEntries); + NAPI_ASSERT_BASE(env, (status == napi_ok), "set_named_property insertEntries fail", status); + + napi_value updateEntries = nullptr; + status = ToNapiValue(env, in.GetUpdateEntries(), deviceId); + NAPI_ASSERT_BASE(env, (status == napi_ok) || (insertEntries == nullptr), "GetUpdateEntries fail", status); + status = napi_set_named_property(env, out, "updateEntries", updateEntries); + NAPI_ASSERT_BASE(env, (status == napi_ok), "set_named_property updateEntries fail", status); + + napi_value deleteEntries = nullptr; + status = ToNapiValue(env, in.GetDeleteEntries(), deleteEntries); + NAPI_ASSERT_BASE(env, (status == napi_ok) || (insertEntries == nullptr), "GetDeleteEntries fail", status); + status = napi_set_named_property(env, out, "deleteEntries", deleteEntries); + NAPI_ASSERT_BASE(env, (status == napi_ok), "set_named_property deleteEntries fail", status); + return status; +} + +/* napi_value <-> DistributedKv::Options */ +napi_status JSUtil::FromNapiValue(napi_env env, napi_value in, DistributedKv::Options& options) +{ + GetNamedProperty(env, in, "createIfMissing", options.createIfMissing); + GetNamedProperty(env, in, "encrypt", options.encrypt); + GetNamedProperty(env, in, "backup", options.backup); + GetNamedProperty(env, in, "autoSync", options.autoSync); + int32_t kvStoreType = 0; + GetNamedProperty(env, in, "kvStoreType", kvStoreType); + options.kvStoreType = static_cast(kvStoreType); + int32_t level = 0; + GetNamedProperty(env, in, "securityLevel", level); + options.securityLevel = level; + return napi_ok; +} +napi_status JSUtil::ToNapiValue(napi_env env, const DistributedKv::Options& in, napi_value& out) +{ + (void)(env); + (void)(in); + (void)(out); + NAPI_ASSERT_BASE(env, false, "DistributedKv::Options to napi_value, unsupported!", napi_invalid_arg); + return napi_invalid_arg; } -} \ No newline at end of file +} // OHOS::DistributedData diff --git a/frameworks/jskitsimpl/distributeddata/src/kv_manager.cpp b/frameworks/jskitsimpl/distributeddata/src/kv_manager.cpp index 520b731d69e57c4c938f13792dd6cccc54ba6cb6..57460500f8e84bdf911c04cd887bf45e3369a430 100644 --- a/frameworks/jskitsimpl/distributeddata/src/kv_manager.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/kv_manager.cpp @@ -13,108 +13,297 @@ * limitations under the License. */ #define LOG_TAG "KVManager" - #include "kv_manager.h" -#include -#include "js_util.h" -#include "distributed_kv_data_manager.h" #include "async_call.h" -#include "single_kv_store.h" +#include "device_kv_store.h" +#include "distributed_kv_data_manager.h" +#include "js_util.h" #include "log_print.h" +#include "single_kv_store.h" +#include +#include using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { static __thread napi_ref g_ctor = nullptr; + +/* + * [JS API Prototype] + * [AsyncCB] createKVManager(config: KVManagerConfig, callback: AsyncCallback): void; + * [Promise] createKVManager(config: KVManagerConfig) : Promise; + */ napi_value KVManager::CreateKVManager(napi_env env, napi_callback_info info) { - ZLOGD("get kv manager!"); - struct ContextInfo { + ZLOGD("CreateKVManager in"); + struct ContextInfo : public ContextBase { napi_ref ref = nullptr; }; - auto ctxInfo = std::make_shared(); - auto input = [ctxInfo](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { - ZLOGD("CreateKVManager parser to native params %{public}d!", static_cast(argc)); - NAPI_ASSERT_BASE(env, (argc > 0) && (argc <= 2), " should 1 or 2 parameters!", napi_invalid_arg); - napi_value bundle = nullptr; - napi_status retStatus = napi_get_named_property(env, argv[0], "bundleName", &bundle); - NAPI_ASSERT_BASE(env, - ((retStatus == napi_ok) && (bundle != nullptr) && !(JSUtil::Convert2String(env, bundle).empty())), - " bundleName is null!", napi_invalid_arg); + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + std::string bundleName; + ctxt->status = JSUtil::GetNamedProperty(env, argv[0], "bundleName", bundleName); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && !bundleName.empty(), "invalid bundleName!"); + ZLOGD("CreateKVManager(%{public}s)", bundleName.c_str()); + napi_value kvManger = nullptr; - napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &kvManger); - if ((kvManger == nullptr) || (status != napi_ok)) { - return napi_generic_failure; - } - napi_create_reference(env, kvManger, 1, &(ctxInfo->ref)); - return napi_ok; - }; - auto output = [ctxInfo](napi_env env, napi_value *result) -> napi_status { - napi_status status = napi_get_reference_value(env, ctxInfo->ref, result); - napi_delete_reference(env, ctxInfo->ref); - return status; - }; - auto context = std::make_shared(input, output); - // function createKVManager(config: KVManagerConfig, callback: AsyncCallback): void; - // AsyncCallback at position 1 - AsyncCall asyncCall(env, info, context, 1); - return asyncCall.Call(env); + ctxt->status = napi_new_instance(env, GetCtor(env), argc, argv, &kvManger); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "new kvManger fail!"); + ctxt->status = napi_create_reference(env, kvManger, 1, &(ctxt->ref)); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "ref kvManger fail!"); + }; + context->GetCbInfo(env, info, input); + + auto noExecute = NapiAsyncExecute(); + auto output = [env, ctxt = context.get()](napi_value& result) { + ZLOGD("CreateKVManager() output"); + ctxt->status = napi_get_reference_value(env, ctxt->ref, &result); + napi_delete_reference(env, ctxt->ref); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), noExecute, output); } +struct GetKVStoreContext : public ContextBase { + std::string storeId; + Options options; + SingleKVStore* kvStore = nullptr; + napi_ref ref = nullptr; +}; + +/* + * [JS API Prototype] + * [AsyncCB] getKVStore(options: Options, storeId: string, callback: AsyncCallback): void; + * [Promise] getKVStore(options: Options, storeId: string): Promise; + */ napi_value KVManager::GetKVStore(napi_env env, napi_callback_info info) { - ZLOGD("get kv store!"); - struct ContextInfo { - std::string storeId; - Options options; - KVManager *proxy = nullptr; - SingleKVStore *kvStore = nullptr; - napi_ref ref = nullptr; + ZLOGD("GetKVStore in"); + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->storeId); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && !ctxt->storeId.empty(), "invalid storeId!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->options); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "invalid options!"); + NAPI_ASSERT_RETURN_VOID(env, + (ctxt->options.kvStoreType == KvStoreType::DEVICE_COLLABORATION) || + (ctxt->options.kvStoreType == KvStoreType::SINGLE_VERSION), "invalid KvStoreType"); + ZLOGD("GetKVStore storeId:%{public}s, %d", ctxt->storeId.c_str(), ctxt->options.kvStoreType); + napi_value result = nullptr; + if (ctxt->options.kvStoreType == KvStoreType::DEVICE_COLLABORATION) { + ctxt->status = napi_new_instance(env, DeviceKVStore::GetCtor(env), argc, argv, &result); + } else if (ctxt->options.kvStoreType == KvStoreType::SINGLE_VERSION) { + ctxt->status = napi_new_instance(env, SingleKVStore::GetCtor(env), argc, argv, &result); + } + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) , "new kvStore fail!"); + ctxt->status = napi_unwrap(env, result, reinterpret_cast(&ctxt->kvStore)); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && (ctxt->kvStore != nullptr), "unwrap kvStore fail!"); + ctxt->status = napi_create_reference(env, result, 1, &ctxt->ref); }; - auto ctxInfo = std::make_shared(); - auto input = [ctxInfo](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { - ZLOGD("GetKVStore parser to native params %{public}d!", static_cast(argc)); - NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); - NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&ctxInfo->proxy)), napi_invalid_arg); - NAPI_ASSERT_BASE(env, ctxInfo->proxy != nullptr, "there is no native kv store", napi_invalid_arg); - ctxInfo->storeId = JSUtil::Convert2String(env, argv[0]); - ctxInfo->options = JSUtil::Convert2Options(env, argv[1]); - napi_value kvStore = nullptr; - napi_status status = napi_new_instance(env, SingleKVStore::GetCtor(env), argc, argv, &kvStore); - napi_unwrap(env, kvStore, reinterpret_cast(&ctxInfo->kvStore)); - if (ctxInfo->kvStore == nullptr) { - return napi_invalid_arg; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + std::shared_ptr kvStore; + AppId appId = { ctxt->As()->bundleName_ }; + StoreId storeId = { ctxt->storeId }; + Status status = ctxt->As()->kvDataManager_.GetSingleKvStore(ctxt->options, appId, storeId, kvStore); + if (status == Status::SUCCESS) { + *(ctxt->kvStore) = std::move(kvStore); } - napi_create_reference(env, kvStore, 1, &(ctxInfo->ref)); - return status; - }; - auto output = [ctxInfo](napi_env env, napi_value *result) -> napi_status { - if (*(ctxInfo->kvStore) == nullptr) { - ZLOGE("get kv store failed!"); - *result = nullptr; - napi_delete_reference(env, ctxInfo->ref); - return napi_object_expected; + ZLOGD("GetSingleKvStore return status:%{public}d", status); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + if (*(ctxt->kvStore) == nullptr) { + result = nullptr; + } else { + ctxt->status = napi_get_reference_value(ctxt->env, ctxt->ref, &result); + ZLOGD("GetKVStore status:%{public}d", ctxt->status); } - ZLOGD("get kv store success!"); - napi_status status = napi_get_reference_value(env, ctxInfo->ref, result); - napi_delete_reference(env, ctxInfo->ref); - return status; + napi_delete_reference(ctxt->env, ctxt->ref); }; - auto exec = [ctxInfo](AsyncCall::Context *ctx) { - std::shared_ptr kvStore; - ctxInfo->proxy->kvDataManager_.GetSingleKvStore( - ctxInfo->options, {ctxInfo->proxy->bundleName_}, {ctxInfo->storeId}, - kvStore); - *(ctxInfo->kvStore) = std::move(kvStore); - }; - auto context = std::make_shared(input, output); - // getKVStore(storeId: string, options: Options, callback: AsyncCallback): void; - // AsyncCallback at position 2 - AsyncCall asyncCall(env, info, context, 2); - return asyncCall.Call(env, exec); + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +/* + * [JS API Prototype] + * [AsyncCB] closeKVStore(appId: string, storeId: string, kvStore: KVStore, callback: AsyncCallback):void + * [Promise] closeKVStore(appId: string, storeId: string, kvStore: KVStore):Promise + */ +napi_value KVManager::CloseKVStore(napi_env env, napi_callback_info info) +{ + ZLOGD("CloseKVStore in"); + struct ContextInfo : public ContextBase { + std::string appId; + std::string storeId; + }; + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS || argc == REQUIRED_3_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->appId); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && !ctxt->appId.empty(), "invalid appId!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->storeId); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && !ctxt->storeId.empty(), "invalid storeId!"); + // get KVStore... optional... + }; + context->GetCbInfo(env, info, input); + ZLOGD("CloseKVStore appId=%{public}s storeId=%{public}s", context->appId.c_str(), context->storeId.c_str()); + + auto execute = [ctxt = context.get()]() { + AppId appId { ctxt->appId }; + StoreId storeId { ctxt->storeId }; + Status status = ctxt->As()->kvDataManager_.CloseKvStore(appId, storeId); + ZLOGD("CloseKVStore return status:%{public}d", status); + ctxt->status = ((status == Status::SUCCESS) || + (status == Status::STORE_NOT_FOUND) || + (status == Status::STORE_NOT_OPEN)) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCB] deleteKVStore(appId: string, storeId: string, callback: AsyncCallback): void + * [Promise] deleteKVStore(appId: string, storeId: string):Promise + */ +napi_value KVManager::DeleteKVStore(napi_env env, napi_callback_info info) +{ + ZLOGD("DeleteKVStore in"); + struct ContextInfo : public ContextBase { + std::string appId; + std::string storeId; + }; + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->appId); + NAPI_ASSERT_RETURN_VOID(env, !ctxt->appId.empty(), "invalid appId"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->storeId); + NAPI_ASSERT_RETURN_VOID(env, !ctxt->storeId.empty(), "invalid storeId"); + }; + context->GetCbInfo(env, info, input); + ZLOGD("DeleteKVStore appId=%{public}s storeId=%{public}s", context->appId.c_str(), context->storeId.c_str()); + + auto execute = [ctxt = context.get()]() { + AppId appId { ctxt->appId }; + StoreId storeId { ctxt->storeId }; + Status status = ctxt->As()->kvDataManager_.DeleteKvStore(appId, storeId); + ZLOGD("DeleteKVStore status:%{public}d", status); + ctxt->status = ((status == Status::SUCCESS) || + (status == Status::STORE_NOT_FOUND)) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCB] getAllKVStoreId(appId: string, callback: AsyncCallback):void + * [Promise] getAllKVStoreId(appId: string):Promise + */ +napi_value KVManager::GetAllKVStoreId(napi_env env, napi_callback_info info) +{ + ZLOGD("GetAllKVStoreId in"); + struct ContextInfo : public ContextBase { + std::string appId; + std::vector storeIdList; + }; + + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], ctxt->appId); + NAPI_ASSERT_RETURN_VOID(env, !ctxt->appId.empty(), "invalid appid"); + }; + context->GetCbInfo(env, info, input); + ZLOGD("GetAllKVStoreId appId=%{public}s", context->appId.c_str()); + + auto execute = [ctxt = context.get()]() { + AppId appId { ctxt->appId }; + Status status = ctxt->As()->kvDataManager_.GetAllKvStoreId(appId, ctxt->storeIdList); + ZLOGD("GetAllKvStoreId status:%{public}d", status); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, ctxt->storeIdList, result); + ZLOGD("GetAllKvStoreId output status:%{public}d", ctxt->status); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +napi_value KVManager::On(napi_env env, napi_callback_info info) +{ + ZLOGD("KVManager::On()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc == REQUIRED_2_ARGS, "args is out of range"); + NAPI_ASSERT(env, self != nullptr, "self is nullptr"); + napi_valuetype type; + napi_typeof(env, argv[0], &type); + NAPI_ASSERT(env, type == napi_string, "event not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + napi_valuetype valueType; + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_function, "callback is not a function"); + + KVManager* proxy = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&proxy))); + NAPI_ASSERT(env, proxy != nullptr, "there is no native kv manager"); + + std::lock_guard lck(proxy->deathMutex_); + auto it = proxy->mapDeathRecipient_.find(argv[1]); + if (it != proxy->mapDeathRecipient_.end()) { + ZLOGD("KVManager::On callback already registe!"); + } else { + std::shared_ptr kvStoreDeathRecipientPtr + = std::make_shared(env, argv[1]); + proxy->kvDataManager_.RegisterKvStoreServiceDeathRecipient(kvStoreDeathRecipientPtr); + proxy->mapDeathRecipient_.insert({ argv[1], kvStoreDeathRecipientPtr }); + } + return nullptr; +} + +napi_value KVManager::Off(napi_env env, napi_callback_info info) +{ + ZLOGD("KVManager::Off()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc == REQUIRED_2_ARGS, "args is out of range"); + NAPI_ASSERT(env, self != nullptr, "self is nullptr"); + napi_valuetype type; + napi_typeof(env, argv[0], &type); + NAPI_ASSERT(env, type == napi_string, "event not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + napi_valuetype valueType; + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT(env, valueType == napi_function, "callback is not a function"); + + KVManager* proxy = nullptr; + NAPI_CALL(env, napi_unwrap(env, self, reinterpret_cast(&proxy))); + NAPI_ASSERT(env, proxy != nullptr, "there is no native kv manager"); + + std::lock_guard lck(proxy->deathMutex_); + auto it = proxy->mapDeathRecipient_.find(argv[1]); + if (it != proxy->mapDeathRecipient_.end()) { + proxy->kvDataManager_.UnRegisterKvStoreServiceDeathRecipient(it->second); + proxy->mapDeathRecipient_.erase(argv[1]); + } else { + ZLOGD("KVManager::On callback already unregiste!"); + } + return nullptr; } napi_value KVManager::GetCtor(napi_env env) { + ZLOGD("KVManager::GetCtor()"); napi_value cons; if (g_ctor != nullptr) { NAPI_CALL(env, napi_get_reference_value(env, g_ctor, &cons)); @@ -122,10 +311,16 @@ napi_value KVManager::GetCtor(napi_env env) } napi_property_descriptor clzDes[] = { - DECLARE_NAPI_METHOD("getKVStore", GetKVStore) + DECLARE_NAPI_FUNCTION("getKVStore", GetKVStore), + DECLARE_NAPI_FUNCTION("closeKVStore", CloseKVStore), + DECLARE_NAPI_FUNCTION("deleteKVStore", DeleteKVStore), + DECLARE_NAPI_FUNCTION("getAllKVStoreId", GetAllKVStoreId), + DECLARE_NAPI_FUNCTION("on", On), + DECLARE_NAPI_FUNCTION("off", Off), }; - NAPI_CALL(env, napi_define_class(env, "KVManager", NAPI_AUTO_LENGTH, Initialize, nullptr, - sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + NAPI_CALL(env, + napi_define_class(env, "KVManager", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_ctor)); return cons; } @@ -135,14 +330,17 @@ napi_value KVManager::Initialize(napi_env env, napi_callback_info info) ZLOGD("constructor kv manager!"); napi_value self = nullptr; size_t argc = JSUtil::MAX_ARGC; - napi_value argv[JSUtil::MAX_ARGC] = {nullptr}; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); - napi_value bundle = nullptr; - NAPI_CALL(env, napi_get_named_property(env, argv[0], "bundleName", &bundle)); - auto *proxy = new KVManager(); - proxy->bundleName_ = JSUtil::Convert2String(env, bundle); + auto* proxy = new KVManager(); + NAPI_CALL(env, JSUtil::GetNamedProperty(env, argv[0], "bundleName", proxy->bundleName_)); auto finalize = [](napi_env env, void* data, void* hint) { - KVManager *proxy = reinterpret_cast(data); + KVManager* proxy = reinterpret_cast(data); + for (auto& it : proxy->mapDeathRecipient_) { + proxy->kvDataManager_.UnRegisterKvStoreServiceDeathRecipient(it.second); + } + std::lock_guard lck(proxy->deathMutex_); + proxy->mapDeathRecipient_.clear(); delete proxy; }; if (napi_wrap(env, self, proxy, finalize, nullptr, nullptr) != napi_ok) { @@ -151,4 +349,37 @@ napi_value KVManager::Initialize(napi_env env, napi_callback_info info) } return self; } + +DeathRecipient::DeathRecipient(napi_env env, napi_value callback) + : env_(env) +{ + napi_create_reference(env, callback, 1, &callback_); + napi_get_uv_event_loop(env, &loop_); +} + +DeathRecipient::~DeathRecipient() { napi_delete_reference(env_, callback_); } + +void DeathRecipient::OnRemoteDied() +{ + EventDataWorker* eventDataWorker = new EventDataWorker(); + eventDataWorker->deathRecipient = this; + uv_work_t* work = new uv_work_t; + work->data = eventDataWorker; + uv_queue_work( + loop_, work, [](uv_work_t* work) {}, + [](uv_work_t* work, int status) { + EventDataWorker* eventDataInner = reinterpret_cast(work->data); + napi_value callback = nullptr; + napi_get_reference_value( + eventDataInner->deathRecipient->env_, eventDataInner->deathRecipient->callback_, &callback); + napi_value global = nullptr; + napi_value result = nullptr; + napi_get_global(eventDataInner->deathRecipient->env_, &global); + napi_call_function(eventDataInner->deathRecipient->env_, global, callback, 0, nullptr, &result); + delete eventDataInner; + eventDataInner = nullptr; + delete work; + work = nullptr; + }); +} } diff --git a/frameworks/jskitsimpl/distributeddata/src/kv_store.cpp b/frameworks/jskitsimpl/distributeddata/src/kv_store.cpp new file mode 100644 index 0000000000000000000000000000000000000000..025eb1a7610418379c8175ec2347e4c75a552912 --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/src/kv_store.cpp @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "KVStore" +#include "kv_store.h" +#include +#include "async_call.h" +#include "js_util.h" +#include "kv_store_resultset.h" +#include "log_print.h" +#include "single_kvstore.h" + +using namespace OHOS::DistributedKv; +namespace OHOS::DistributedData { +static __thread napi_ref g_ctor = nullptr; + +std::map KVStore::eventHandlers_ = { + { "dataChange", KVStore::OnDataChange }, +}; + +KVStore::~KVStore() +{ + if (kvStore_ == nullptr) { + return; + } + + for (int i = 0; i < SUBSCRIBE_ALL + 1; ++i) { + if (dataObserver_[i] == nullptr) { + continue; + } + kvStore_->UnSubscribeKvStore(static_cast(i + 1), dataObserver_[i]); + } + + if (syncObserver_ != nullptr) { + kvStore_->UnRegisterSyncCallback(); + } +} + +napi_value KVStore::GetCtor(napi_env env) +{ + ZLOGD("KVStore::GetCtor()"); + if (g_ctor != nullptr) { + napi_value cons = nullptr; + NAPI_CALL(env, napi_get_reference_value(env, g_ctor, &cons)); + return cons; + } + + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_FUNCTION("put", KVStore::Put), + DECLARE_NAPI_FUNCTION("delete", KVStore::Delete), + DECLARE_NAPI_FUNCTION("on", KVStore::OnEvent), + DECLARE_NAPI_FUNCTION("off", KVStore::OffEvent), + DECLARE_NAPI_FUNCTION("putBatch", KVStore::PutBatch), + DECLARE_NAPI_FUNCTION("deleteBatch", KVStore::DeleteBatch), + DECLARE_NAPI_FUNCTION("startTransaction", KVStore::StartTransaction), + DECLARE_NAPI_FUNCTION("commit", KVStore::Commit), + DECLARE_NAPI_FUNCTION("rollback", KVStore::Rollback), + DECLARE_NAPI_FUNCTION("enableSync", KVStore::EnableSync), + DECLARE_NAPI_FUNCTION("setSyncRange", KVStore::SetSyncRange), + }; + napi_value cons; + NAPI_CALL(env, + napi_define_class(env, "KVStore", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_ctor)); + return cons; +} + +/* +put(key:string, value:Uint8Array | string | boolean | number, callback: AsyncCallback):void +put(key:string, value:Uint8Array | string | boolean | number):Promise +*/ +napi_value KVStore::Put(napi_env env, napi_callback_info info) +{ + ZLOGD("KVStore::Put()"); + struct PutContext : public ContextBase { + std::string key; + std::vector value; + }; + + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->key); + JSUtil::VariantValue vv; + JSUtil::FromNapiValue(env, argv[index++], vv); + DistributedKv::Blob blob = JSUtil::VariantValue2Blob(vv); + ctxt->value = blob.Data(); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), [ctxt = context.get()]() { + OHOS::DistributedKv::Key key(ctxt->key); + OHOS::DistributedKv::Value value(ctxt->value); + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->Put(key, value); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }); +} + +napi_value KVStore::Delete(napi_env env, napi_callback_info info) +{ + ZLOGD("KVStore::Delete()"); + struct DeleteContext : public ContextBase { + std::string key; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->key); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), [ctxt = context.get()]() { + OHOS::DistributedKv::Key key(ctxt->key); + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->Delete(key); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }); +} + +napi_value KVStore::OnEvent(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc > 0, "there is no args"); + napi_valuetype type; + NAPI_CALL(env, napi_typeof(env, argv[0], &type)); + NAPI_ASSERT(env, type == napi_string, "key not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + + ZLOGI("subscribe event:%{public}s", event.c_str()); + auto handle = eventHandlers_.find(event); + NAPI_ASSERT(env, handle != eventHandlers_.end(), "invalid event"); + napi_value result = nullptr; + handle->second(env, argc - 1, &argv[1], self, &result); + return nullptr; +} + +napi_value KVStore::OffEvent(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + NAPI_ASSERT(env, argc > 0, "there is no args"); + napi_valuetype type; + NAPI_CALL(env, napi_typeof(env, argv[0], &type)); + NAPI_ASSERT(env, type == napi_string, "key not string type"); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); + + ZLOGI("subscribe event:%{public}s", event.c_str()); + auto handle = eventHandlers_.find(event); + NAPI_ASSERT(env, handle != eventHandlers_.end(), "invalid event"); + napi_value result = nullptr; + handle->second(env, argc - 1, &argv[1], self, &result); + return nullptr; +} + +/* + putBatch(entries: Entry[], callback: AsyncCallback):void + putBatch(entries: Entry[]):Promise +*/ +napi_value KVStore::PutBatch(napi_env env, napi_callback_info info) +{ + struct PutBatchContext : public ContextBase { + std::vector entries; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->entries); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->PutBatch(ctxt->entries); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }); +} + +/* + deleteBatch(keys: string[], callback: AsyncCallback):void + deleteBatch(keys: string[]):Promise +*/ +napi_value KVStore::DeleteBatch(napi_env env, napi_callback_info info) +{ + struct DeleteBatchContext : public ContextBase { + std::vector keys; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->keys); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + NAPI_ASSERT_BASE(env, context->status == napi_ok, "get cb info fail", nullptr); + + auto execute = [ctxt = context.get()]() { + std::vector keys; + for (auto it : ctxt->keys) { + DistributedKv::Key key(it); + keys.push_back(key); + } + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->DeleteBatch(keys); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} + +/* + startTransaction(callback: AsyncCallback):void + startTransaction() : Promise +*/ +napi_value KVStore::StartTransaction(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + KVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + Status status = proxy->kvStore_->StartTransaction(); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + +/* + commit(callback: AsyncCallback):void + commit() : Promise +*/ +napi_value KVStore::Commit(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + KVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + Status status = proxy->kvStore_->Commit(); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + +/* + rollback(callback: AsyncCallback):void + rollback():Promise +*/ +napi_value KVStore::Rollback(napi_env env, napi_callback_info info) +{ + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + KVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + Status status = proxy->kvStore_->Rollback(); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + +/* + enableSync(enabled:boolean, callback: AsyncCallback):void + enableSync(enabled:boolean):Promise +*/ +napi_value KVStore::EnableSync(napi_env env, napi_callback_info info) +{ + struct EnableSyncContext : public ContextBase { + bool enable = false; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + napi_get_value_bool(env, argv[index++], &ctxt->enable); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->SetCapabilityEnabled(ctxt->enable); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }); +} + +/* + setSyncRange(localLabels:string[], remoteSupportLabels:string[], callback: AsyncCallback):void + setSyncRange(localLabels:string[], remoteSupportLabels:string[]):Promise +*/ +napi_value KVStore::SetSyncRange(napi_env env, napi_callback_info info) +{ + struct SyncRangeContext : public ContextBase { + std::vector localLabels; + std::vector remoteSupportLabels; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->localLabels); + JSUtil::FromNapiValue(env, argv[index++], ctxt->remoteSupportLabels); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->SetCapabilityRange(ctxt->localLabels, ctxt->remoteSupportLabels); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }); +} + +napi_value KVStore::Initialize(napi_env env, napi_callback_info info) +{ + ZLOGD("constructor single kv store!"); + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + auto* proxy = new KVStore(); + auto release = [proxy]() -> napi_value { + delete proxy; + return nullptr; + }; + auto finalize = [](napi_env env, void* data, void* hint) { + auto* proxy = reinterpret_cast(data); + delete proxy; + }; + NAPI_CALL_BASE(env, napi_wrap(env, self, proxy, finalize, nullptr, nullptr), release()); + return self; +} + +// on(event: 'dataChange', type: SubscribeType, observer: Callback): void; +napi_status KVStore::OnDataChange(napi_env env, size_t argc, napi_value* argv, napi_value self, napi_value* result) +{ + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", napi_invalid_arg); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); + int32_t type = 0; + napi_get_value_int32(env, argv[0], &type); + NAPI_ASSERT_BASE(env, SUBSCRIBE_LOCAL <= type && type <= SUBSCRIBE_ALL, "type is out of range", napi_invalid_arg); + napi_valuetype valueType = napi_undefined; + napi_typeof(env, argv[1], &valueType); + NAPI_ASSERT_BASE(env, valueType == napi_function, "callback is not a function", napi_invalid_arg); + + KVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", napi_invalid_arg); + + ZLOGI("subscribe data change type %{public}d", type); + std::shared_ptr observer = std::make_shared(env, argv[1]); + Status status = proxy->kvStore_->SubscribeKvStore(static_cast(type + 1), observer); + if (status != Status::SUCCESS) { + return napi_generic_failure; + } + if (proxy->dataObserver_[type] != nullptr) { + proxy->kvStore_->UnSubscribeKvStore(static_cast(type + 1), proxy->dataObserver_[type]); + } + proxy->dataObserver_[type] = std::move(observer); + return napi_ok; +} + +KVStore& KVStore::operator=(std::shared_ptr&& singleKvStore) +{ + if (kvStore_ == singleKvStore) { + return *this; + } + kvStore_ = std::move(singleKvStore); + return *this; +} + +bool KVStore::operator==(const std::shared_ptr& singleKvStore) +{ + return kvStore_ == singleKvStore; +} + +DataObserver::DataObserver(napi_env env, napi_value callback) + : env_(env) +{ + napi_create_reference(env, callback, 1, &callback_); + napi_get_uv_event_loop(env, &loop_); +} + +DataObserver::~DataObserver() { napi_delete_reference(env_, callback_); } + +void DataObserver::OnChange(const ChangeNotification& notification, std::shared_ptr snapshot) +{ + ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu", + notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(), + notification.GetDeleteEntries().size()); +} + +void DataObserver::OnChange(const ChangeNotification& notification) +{ + ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu", + notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(), + notification.GetDeleteEntries().size()); + KvStoreObserver::OnChange(notification); + EventDataWorker* eventDataWorker = new EventDataWorker(this, notification); + uv_work_t* work = new uv_work_t; + work->data = eventDataWorker; + uv_queue_work( + loop_, work, [](uv_work_t* work) {}, + [](uv_work_t* work, int status) { + EventDataWorker* eventDataInner = reinterpret_cast(work->data); + napi_value jsNotification = nullptr; + JSUtil::ToNapiValue(eventDataInner->observer->env_, eventDataInner->data, jsNotification); + napi_value callback = nullptr; + napi_value args[1] = { jsNotification }; + napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); + napi_value global = nullptr; + napi_get_global(eventDataInner->observer->env_, &global); + napi_value result; + napi_status callStatus + = napi_call_function(eventDataInner->observer->env_, global, callback, 1, args, &result); + if (callStatus != napi_ok) { + ZLOGE("notify data change failed callStatus:%{public}d callback:%{public}p", callStatus, callback); + } + delete eventDataInner; + eventDataInner = nullptr; + delete work; + work = nullptr; + }); +} + +SyncObserver::SyncObserver(napi_env env, napi_value callback) + : env_(env) +{ + napi_create_reference(env, callback, 1, &callback_); + napi_get_uv_event_loop(env, &loop_); +} + +SyncObserver::~SyncObserver() { napi_delete_reference(env_, callback_); } + +void SyncObserver::SyncCompleted(const std::map& results) +{ + EventDataWorker* eventDataWorker = new EventDataWorker(); + eventDataWorker->observer = this; + eventDataWorker->data = results; + uv_work_t* work = new uv_work_t; + work->data = eventDataWorker; + uv_queue_work( + loop_, work, [](uv_work_t* work) {}, + [](uv_work_t* work, int status) { + EventDataWorker* eventDataInner = reinterpret_cast(work->data); + std::map dataMap; + for (const auto& [key, value] : eventDataInner->data) { + dataMap.emplace(key, int32_t(value)); + } + napi_value notification = nullptr; + JSUtil::ToNapiValue(eventDataInner->observer->env_, dataMap, notification); + napi_value callback = nullptr; + napi_value args[1] = { notification }; + napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); + napi_value global = nullptr; + napi_value result = nullptr; + napi_get_global(eventDataInner->observer->env_, &global); + napi_call_function(eventDataInner->observer->env_, global, callback, 1, args, &result); + delete eventDataInner; + eventDataInner = nullptr; + delete work; + work = nullptr; + }); +} +} // namespace OHOS::DistributedData diff --git a/frameworks/jskitsimpl/distributeddata/src/kv_store_resultset.cpp b/frameworks/jskitsimpl/distributeddata/src/kv_store_resultset.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67a574423e8ff4649c3e4ba976db737e875369ba --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/src/kv_store_resultset.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "KVStoreResultSet" +#include +#include "kv_store_resultset.h" +#include "async_call.h" +#include "js_util.h" +#include "log_print.h" + +using namespace OHOS::DistributedKv; +namespace OHOS::DistributedData { +static __thread napi_ref g_ctor = nullptr; + +KVStoreResultSet::~KVStoreResultSet() +{ +} + +KVStoreResultSet& KVStoreResultSet::operator=(std::shared_ptr&& resultSet) +{ + if (resultSet_ == resultSet) { + return *this; + } + resultSet_ = std::move(resultSet); + return *this; +} + +bool KVStoreResultSet::operator==(const std::shared_ptr& resultSet) +{ + return resultSet_ == resultSet; +} + +napi_value KVStoreResultSet::GetCtor(napi_env env) +{ + ZLOGD("KVStoreResultSet::GetCtor()"); + if (g_ctor != nullptr) { + napi_value cons = nullptr; + NAPI_CALL(env, napi_get_reference_value(env, g_ctor, &cons)); + return cons; + } + + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_FUNCTION("getCount", KVStoreResultSet::GetCount), /* number */ + DECLARE_NAPI_FUNCTION("getPosition", KVStoreResultSet::GetPosition), /* number */ + DECLARE_NAPI_FUNCTION("moveToFirst", KVStoreResultSet::MoveToFirst), /* boolean */ + DECLARE_NAPI_FUNCTION("moveToLast", KVStoreResultSet::MoveToLast), /* boolean */ + DECLARE_NAPI_FUNCTION("moveToNext", KVStoreResultSet::MoveToNext), /* boolean */ + DECLARE_NAPI_FUNCTION("moveToPrevious", KVStoreResultSet::MoveToPrevious), /* boolean */ + DECLARE_NAPI_FUNCTION("move", KVStoreResultSet::Move), /* boolean */ + DECLARE_NAPI_FUNCTION("moveToPosition", KVStoreResultSet::MoveToPosition), /* boolean */ + DECLARE_NAPI_FUNCTION("isFirst", KVStoreResultSet::IsFirst), /* boolean */ + DECLARE_NAPI_FUNCTION("isLast", KVStoreResultSet::IsLast), /* boolean */ + DECLARE_NAPI_FUNCTION("isBeforeFirst", KVStoreResultSet::IsBeforeFirst), /* boolean */ + DECLARE_NAPI_FUNCTION("isAfterLast", KVStoreResultSet::IsAfterLast), /* boolean */ + DECLARE_NAPI_FUNCTION("getEntry", KVStoreResultSet::GetEntry), /* Entry */ + }; + napi_value cons; + NAPI_CALL(env, + napi_define_class(env, "KVStoreResultSet", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_ctor)); + return cons; +} + +napi_value KVStoreResultSet::Initialize(napi_env env, napi_callback_info info) +{ + ZLOGD("constructor KVStoreResultSet!"); + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + auto* proxy = new KVStoreResultSet(); + auto release = [proxy]() -> napi_value { + delete proxy; + return nullptr; + }; + auto finalize = [](napi_env env, void* data, void* hint) { + auto* proxy = reinterpret_cast(data); + delete proxy; + }; + NAPI_CALL_BASE(env, napi_wrap(env, self, proxy, finalize, nullptr, nullptr), release()); + return self; +} + +napi_value KVStoreResultSet::GetCount(napi_env env, napi_callback_info info) /* number */ +{ + ZLOGD("KVStoreResultSet::GetCount()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + int count = resultSet->GetCount(); + + napi_create_int32(env, count, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::GetPosition(napi_env env, napi_callback_info info) /* number */ +{ + ZLOGD("KVStoreResultSet::GetPosition()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + int position = resultSet->GetPosition(); + + napi_create_int32(env, position, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::MoveToFirst(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::MoveToFirst()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->MoveToFirst(); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::MoveToLast(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::MoveToFirst()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->MoveToLast(); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::MoveToNext(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::MoveToNext()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->MoveToNext(); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::MoveToPrevious(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::MoveToPrevious()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->MoveToPrevious(); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::Move(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::Move()"); + int offset = 0; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, &offset](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + napi_get_value_int32(env, argv[0], (int32_t*)&offset); + }); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->Move(offset); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::MoveToPosition(napi_env env, napi_callback_info info) /* boolean */ +{ + int position = 0; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, &position](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + napi_get_value_int32(env, argv[0], (int32_t*)&position); + }); + ZLOGD("KVStoreResultSet::MoveToPosition(%{public}d)", position); + + auto& resultSet = context->As()->resultSet_; + bool isMoved = resultSet->MoveToPosition(position); + + napi_get_boolean(env, isMoved, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::IsFirst(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::IsFirst()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isFirst = resultSet->IsFirst(); + + napi_get_boolean(env, isFirst, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::IsLast(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::IsLast()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isLast = resultSet->IsLast(); + + napi_get_boolean(env, isLast, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::IsBeforeFirst(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::IsBeforeFirst()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isBeforeFirst = resultSet->IsBeforeFirst(); + + napi_get_boolean(env, isBeforeFirst, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::IsAfterLast(napi_env env, napi_callback_info info) /* boolean */ +{ + ZLOGD("KVStoreResultSet::IsAfterLast()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + auto& resultSet = context->As()->resultSet_; + bool isAfterLast = resultSet->IsAfterLast(); + + napi_get_boolean(env, isAfterLast, &context->output); + return context->output; +} + +napi_value KVStoreResultSet::GetEntry(napi_env env, napi_callback_info info) /* Entry */ +{ + ZLOGD("KVStoreResultSet::GetEntry()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + + DistributedKv::Entry entry; + auto& resultSet = context->As()->resultSet_; + auto status = resultSet->GetEntry(entry); + if (status != Status::SUCCESS) { + return nullptr; + } + + context->status = JSUtil::ToNapiValue(env, entry, context->output); + NAPI_ASSERT_BASE(env, context->status == napi_ok, "GetEntry fail!", nullptr); + return context->output; +} +} // \ No newline at end of file diff --git a/frameworks/jskitsimpl/distributeddata/src/query.cpp b/frameworks/jskitsimpl/distributeddata/src/query.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6031f5330c03201406285d99ef759510c074b0ec --- /dev/null +++ b/frameworks/jskitsimpl/distributeddata/src/query.cpp @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define LOG_TAG "Query" +#include "query.h" +#include +#include "async_call.h" +#include "js_util.h" +#include "log_print.h" + +using namespace OHOS::DistributedKv; +namespace OHOS::DistributedData { + +Query::~Query() +{ +} + +Query& Query::operator=(std::shared_ptr&& query) +{ + if (query_ == query) { + return *this; + } + query_ = std::move(query); + return *this; +} + +bool Query::operator==(const std::shared_ptr& query) +{ + return query_ == query; +} + + +napi_value Query::CreateQueryObject(napi_env env) +{ + napi_value result = nullptr; + napi_status status = napi_new_instance(env, GetCtor(env), 0, nullptr, &result); + ZLOGD("Query::CreateQueryObject status=%{public}d", (int)status); + return result; +} + +napi_value Query::GetCtor(napi_env env) +{ + ZLOGD("Query::GetCtor()"); + napi_property_descriptor clzDes[] = { + DECLARE_NAPI_FUNCTION("reset", Query::Reset), + DECLARE_NAPI_FUNCTION("equalTo", Query::EqualTo), + DECLARE_NAPI_FUNCTION("notEqualTo", Query::NotEqualTo), + DECLARE_NAPI_FUNCTION("greaterThan", Query::GreaterThan), + DECLARE_NAPI_FUNCTION("lessThan", Query::LessThan), + DECLARE_NAPI_FUNCTION("greaterThanOrEqualTo", Query::GreaterThanOrEqualTo), + DECLARE_NAPI_FUNCTION("lessThanOrEqualTo", Query::LessThanOrEqualTo), + DECLARE_NAPI_FUNCTION("isNull", Query::IsNull), + DECLARE_NAPI_FUNCTION("inNumber", Query::InNumber), + DECLARE_NAPI_FUNCTION("inString", Query::InString), + DECLARE_NAPI_FUNCTION("notInNumber", Query::NotInNumber), + DECLARE_NAPI_FUNCTION("notInString", Query::NotInString), + DECLARE_NAPI_FUNCTION("like", Query::Like), + DECLARE_NAPI_FUNCTION("unlike", Query::Unlike), + DECLARE_NAPI_FUNCTION("and", Query::And), + DECLARE_NAPI_FUNCTION("or", Query::Or), + DECLARE_NAPI_FUNCTION("orderByAsc", Query::OrderByAsc), + DECLARE_NAPI_FUNCTION("orderByDesc", Query::OrderByDesc), + DECLARE_NAPI_FUNCTION("limit", Query::Limit), + DECLARE_NAPI_FUNCTION("isNotNull", Query::IsNotNull), + DECLARE_NAPI_FUNCTION("beginGroup", Query::BeginGroup), + DECLARE_NAPI_FUNCTION("endGroup", Query::EndGroup), + DECLARE_NAPI_FUNCTION("prefixKey", Query::PrefixKey), + DECLARE_NAPI_FUNCTION("setSuggestIndex", Query::SetSuggestIndex), + DECLARE_NAPI_FUNCTION("deviceId", Query::DeviceId), + DECLARE_NAPI_FUNCTION("getSqlLike", Query::GetSqlLike), + }; + napi_value cons; + NAPI_CALL(env, + napi_define_class(env, "Query", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + return cons; +} + +napi_value Query::Initialize(napi_env env, napi_callback_info info) +{ + ZLOGD("constructor Query!"); + napi_value self = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); + auto* proxy = new Query(); + auto release = [proxy]() -> napi_value { + delete proxy; + return nullptr; + }; + auto finalize = [](napi_env env, void* data, void* hint) { + auto* proxy = reinterpret_cast(data); + delete proxy; + }; + NAPI_CALL_BASE(env, napi_wrap(env, self, proxy, finalize, nullptr, nullptr), release()); + NAPI_CALL_BASE(env, napi_create_reference(env, self, 1, &proxy->ref), release()); + return self; +} + +napi_value Query::Reset(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::Reset()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info); + auto& query = context->As()->query_; + query->Reset(); + return context->Self(); +} + +struct ValueContext : public ContextBase { + std::string field; + JSUtil::VariantValue3 vv; +}; + +/* [js] equalTo(field:string, value:number|string|boolean):Query */ +napi_value Query::EqualTo(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::EqualTo()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get vv fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->EqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->EqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->EqualTo(context->field, *pval); + } else { + ZLOGD("Query::EqualTo() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::NotEqualTo(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::NotEqualTo()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get vv fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->NotEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->NotEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->NotEqualTo(context->field, *pval); + } else { + ZLOGD("Query::NotEqualTo() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::GreaterThan(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::GreaterThan()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get vv fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->GreaterThan(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->GreaterThan(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->GreaterThan(context->field, *pval); + } else { + ZLOGD("Query::GreaterThan() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::LessThan(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::LessThan()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get vv fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->LessThan(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->LessThan(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->LessThan(context->field, *pval); + } else { + ZLOGD("Query::LessThan() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::GreaterThanOrEqualTo(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::GreaterThanOrEqualTo()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get vv fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->GreaterThanOrEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->GreaterThanOrEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->GreaterThanOrEqualTo(context->field, *pval); + } else { + ZLOGD("Query::GreaterThanOrEqualTo() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::LessThanOrEqualTo(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::LessThanOrEqualTo()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + auto& query = context->As()->query_; + if (auto pval = std::get_if(&context->vv)) { + query->LessThanOrEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->LessThanOrEqualTo(context->field, *pval); + } else if (auto pval = std::get_if(&context->vv)) { + query->LessThanOrEqualTo(context->field, *pval); + } else { + ZLOGD("Query::LessThanOrEqualTo() unreachable branch!"); + } + return context->Self(); +} +napi_value Query::IsNull(napi_env env, napi_callback_info info) +{ + std::string field; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &field](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + }); + + auto& query = context->As()->query_; + query->IsNull(field); + return context->Self(); +} + +napi_value Query::InNumber(napi_env env, napi_callback_info info) +{ + struct NumbersContext : public ContextBase { + std::string field; + std::vector valueList; // todo valueList:number[] + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status =JSUtil::FromNapiValue(env, argv[index++], ctxt->valueList); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get valueList fail"); + }); + + auto& query = context->As()->query_; + query->InDouble(context->field, context->valueList); + return context->Self(); +} +napi_value Query::InString(napi_env env, napi_callback_info info) +{ + struct StringsContext : public ContextBase { + std::string field; + std::vector valueList; + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status =JSUtil::FromNapiValue(env, argv[index++], ctxt->valueList); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get valueList fail"); + }); + + auto& query = context->As()->query_; + query->InString(context->field, context->valueList); + return context->Self(); +} +napi_value Query::NotInNumber(napi_env env, napi_callback_info info) +{ + struct NumbersContext : public ContextBase { + std::string field; + std::vector valueList; // todo valueList:number[] + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status =JSUtil::FromNapiValue(env, argv[index++], ctxt->valueList); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get valueList fail"); + }); + + auto& query = context->As()->query_; + query->NotInDouble(context->field, context->valueList); + return context->Self(); +} +napi_value Query::NotInString(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::NotInString()"); + struct StringsContext : public ContextBase { + std::string field; + std::vector valueList; + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->valueList); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + auto& query = context->As()->query_; + query->NotInString(context->field, context->valueList); + return context->Self(); +} +napi_value Query::Like(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::Like()"); + struct LikeContext : public ContextBase { + std::string field; + std::string value; + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->value); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + auto& query = context->As()->query_; + query->Like(context->field, context->value); + return context->Self(); +} +napi_value Query::Unlike(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::Unlike()"); + struct UnlikeContext : public ContextBase { + std::string field; + std::string value; + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->value); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + + auto& query = context->As()->query_; + query->Unlike(context->field, context->value); + return context->Self(); +} +napi_value Query::And(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::And()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + auto& query = context->As()->query_; + query->And(); + return context->Self(); +} +napi_value Query::Or(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::Or()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->vv); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }); + auto& query = context->As()->query_; + query->Or(); + return context->Self(); +} +napi_value Query::OrderByAsc(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::OrderByAsc()"); + std::string field; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &field](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + }); + + auto& query = context->As()->query_; + query->OrderByAsc(field); + return context->Self(); +} +napi_value Query::OrderByDesc(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::OrderByAsc()"); + std::string field; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &field](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], field); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get field fail"); + }); + + auto& query = context->As()->query_; + query->OrderByDesc(field); + return context->Self(); +} +napi_value Query::Limit(napi_env env, napi_callback_info info) +{ + struct LimitContext : public ContextBase { + int number; + int offset; + }; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = napi_get_value_int32(env, argv[index++], &ctxt->number); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get number fail"); + ctxt->status = napi_get_value_int32(env, argv[index++], &ctxt->offset); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get offset fail"); + }); + auto& query = context->As()->query_; + query->Limit(context->number, context->offset); + return context->Self(); +} +napi_value Query::IsNotNull(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::IsNotNull()"); + std::string field; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &field](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], field); + }); + + auto& query = context->As()->query_; + query->IsNotNull(field); + return context->Self(); +} +napi_value Query::BeginGroup(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::BeginGroup()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env](size_t argc, napi_value*) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_NO_ARGS, "invalid arguments!"); + }); + auto& query = context->As()->query_; + query->BeginGroup(); + return context->Self(); +} +napi_value Query::EndGroup(napi_env env, napi_callback_info info) +{ + ZLOGD("Query::EndGroup()"); + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env](size_t argc, napi_value*) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_NO_ARGS, "invalid arguments!"); + }); + auto& query = context->As()->query_; + query->EndGroup(); + return context->Self(); +} +napi_value Query::PrefixKey(napi_env env, napi_callback_info info) +{ + std::string prefix; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &prefix](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], prefix); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "get prefix fail"); + }); + + auto& query = context->As()->query_; + query->KeyPrefix(prefix); + return context->Self(); +} +napi_value Query::SetSuggestIndex(napi_env env, napi_callback_info info) +{ + std::string suggestIndex; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &suggestIndex](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], suggestIndex); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "get suggestIndex fail"); + }); + + auto& query = context->As()->query_; + query->SetSuggestIndex(suggestIndex); + return context->Self(); +} +napi_value Query::DeviceId(napi_env env, napi_callback_info info) +{ + std::string deviceId; + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env, ctxt = context.get(), &deviceId](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_1_ARGS, "invalid arguments!"); + ctxt->status = JSUtil::FromNapiValue(env, argv[0], deviceId); + }); + + auto& query = context->As()->query_; + query->EqualTo(DataQuery::DEVICE_ID, deviceId); + return context->Self(); +} +// getSqlLike():string +napi_value Query::GetSqlLike(napi_env env, napi_callback_info info) +{ + auto context = std::make_shared(); + context->GetCbInfoSync(env, info, [env](size_t argc, napi_value*) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_NO_ARGS, "invalid arguments!"); + }); + + auto& query = context->As()->query_; + JSUtil::ToNapiValue(env, query->ToString(), context->output); + return context->output; +} +} // \ No newline at end of file diff --git a/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp b/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp index 64692d9588123d98e002f761370185cba1f0ceef..21b906f28452ba4341c2bf551e7829124863e78d 100644 --- a/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp @@ -17,15 +17,17 @@ #include #include "async_call.h" #include "js_util.h" +#include "kv_store_resultset.h" #include "log_print.h" #include "single_kvstore.h" using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { static __thread napi_ref g_ctor = nullptr; + std::map SingleKVStore::eventHandlers_ = { - {"dataChange", SingleKVStore::OnDataChange}, - {"syncComplete", SingleKVStore::OnSyncComplete}, + { "dataChange", KVStore::OnDataChange }, + { "syncComplete", SingleKVStore::OnSyncComplete }, }; SingleKVStore::~SingleKVStore() @@ -48,6 +50,7 @@ SingleKVStore::~SingleKVStore() napi_value SingleKVStore::GetCtor(napi_env env) { + ZLOGD("SingleKVStore::GetCtor()"); if (g_ctor != nullptr) { napi_value cons = nullptr; NAPI_CALL(env, napi_get_reference_value(env, g_ctor, &cons)); @@ -55,98 +58,284 @@ napi_value SingleKVStore::GetCtor(napi_env env) } napi_property_descriptor clzDes[] = { - DECLARE_NAPI_METHOD("put", SingleKVStore::Put), - DECLARE_NAPI_METHOD("get", SingleKVStore::Get), - DECLARE_NAPI_METHOD("delete", SingleKVStore::Delete), - DECLARE_NAPI_METHOD("on", SingleKVStore::OnEvent), - DECLARE_NAPI_METHOD("sync", SingleKVStore::Sync), + DECLARE_NAPI_FUNCTION("put", KVStore::Put), + DECLARE_NAPI_FUNCTION("delete", KVStore::Delete), + DECLARE_NAPI_FUNCTION("putBatch", KVStore::PutBatch), + DECLARE_NAPI_FUNCTION("deleteBatch", KVStore::DeleteBatch), + DECLARE_NAPI_FUNCTION("startTransaction", KVStore::StartTransaction), + DECLARE_NAPI_FUNCTION("commit", KVStore::Commit), + DECLARE_NAPI_FUNCTION("rollback", KVStore::Rollback), + DECLARE_NAPI_FUNCTION("enableSync", KVStore::EnableSync), + DECLARE_NAPI_FUNCTION("setSyncRange", KVStore::SetSyncRange), + /* SingleKVStore externs KVStore */ + DECLARE_NAPI_FUNCTION("get", SingleKVStore::Get), + DECLARE_NAPI_FUNCTION("getEntries", SingleKVStore::GetEntries), + DECLARE_NAPI_FUNCTION("getResultSet", SingleKVStore::GetResultSet), + DECLARE_NAPI_FUNCTION("closeResultSet", SingleKVStore::CloseResultSet), + DECLARE_NAPI_FUNCTION("getResultSize", SingleKVStore::GetResultSize), + DECLARE_NAPI_FUNCTION("removeDeviceData", SingleKVStore::RemoveDeviceData), + DECLARE_NAPI_FUNCTION("sync", SingleKVStore::Sync), + DECLARE_NAPI_FUNCTION("on", SingleKVStore::OnEvent), + DECLARE_NAPI_FUNCTION("off", SingleKVStore::OffEvent), + DECLARE_NAPI_FUNCTION("setSyncParam", SingleKVStore::SetSyncParam), + DECLARE_NAPI_FUNCTION("getSecurityLevel", SingleKVStore::GetSecurityLevel), }; napi_value cons; - NAPI_CALL(env, napi_define_class(env, "SingleKVStore", NAPI_AUTO_LENGTH, Initialize, nullptr, - sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); + NAPI_CALL(env, + napi_define_class(env, "SingleKVStore", NAPI_AUTO_LENGTH, Initialize, nullptr, + sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons)); NAPI_CALL(env, napi_create_reference(env, cons, 1, &g_ctor)); return cons; } -napi_value SingleKVStore::Put(napi_env env, napi_callback_info info) +napi_value SingleKVStore::Get(napi_env env, napi_callback_info info) { - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { - // 2 is the max number of parameters - NAPI_ASSERT_BASE(env, argc >= 2, " should 2 or more parameters!", napi_invalid_arg); - context->key = JSUtil::Convert2String(env, argv[0]); - context->value = JSUtil::Convert2Vector(env, argv[1]); - return napi_ok; + ZLOGD("SingleKVStore::Get()"); + struct GetContext : public ContextBase { + std::string key; + JSUtil::VariantValue value; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + ZLOGD("GetCbInfo"); + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_2_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->key); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get key fail"); + }; + context->GetCbInfo(env, info, input); + ZLOGD("Get key=%{public}s,", context->key.c_str()); + + auto execute = [ctxt = context.get()]() { + OHOS::DistributedKv::Key key(ctxt->key); + OHOS::DistributedKv::Value value; + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->Get(key, value); + ZLOGD("Get key=%{public}s return %{public}d", ctxt->key.c_str(), status); + ctxt->value = JSUtil::Blob2VariantValue(value); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; }; - auto exec = [context](AsyncCall::Context *ctx) { - OHOS::DistributedKv::Key key(context->key); - OHOS::DistributedKv::Value value(context->value); - Status status = context->proxy->kvStore_->Put(key, value); - context->status = (status != Status::SUCCESS) ? napi_generic_failure : napi_ok; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, ctxt->value, result); }; - context->SetAction(std::move(input)); - // 2 is the callback position - AsyncCall asyncCall(env, info, std::dynamic_pointer_cast(context), 2); - return asyncCall.Call(env, exec); + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); } -napi_value SingleKVStore::Get(napi_env env, napi_callback_info info) +/* + getEntries(keyPrefix:string, callback:AsyncCallback):void + getEntries(keyPrefix:string):Promise + getEntries(query:Query, callback:AsyncCallback):void + getEntries(query:Query) : Promise +*/ +napi_value SingleKVStore::GetEntries(napi_env env, napi_callback_info info) { - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { - NAPI_ASSERT_BASE(env, argc >= 1, " should 1 or more parameters!", napi_invalid_arg); - context->key = JSUtil::Convert2String(env, argv[0]); - return napi_ok; + ZLOGD("SingleKVStore::GetEntries()"); + struct GetEntriesContext : public ContextBase { + std::string key; + // todo query:Query + std::vector entries; }; - auto output = [context](napi_env env, napi_value *result) -> napi_status { - napi_value data = JSUtil::Convert2JSValue(env, context->value); - return napi_get_named_property(env, data, "value", result); + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->key); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); }; - auto exec = [context](AsyncCall::Context *ctx) { - OHOS::DistributedKv::Key key(context->key); - OHOS::DistributedKv::Value value; - Status status = context->proxy->kvStore_->Get(key, value); + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + OHOS::DistributedKv::Key key(ctxt->key); + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->GetEntries(key, ctxt->entries); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + return JSUtil::ToNapiValue(ctxt->env, ctxt->entries, result); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); +} + +/* + getResultSet(keyPrefix:string, callback:AsyncCallback):void + getResultSet(keyPrefix:string):Promise + getResultSet(query:Query, callback:AsyncCallback):void + getResultSet(query:Query):Promise +*/ +napi_value SingleKVStore::GetResultSet(napi_env env, napi_callback_info info) +{ + ZLOGD("SingleKVStore::GetResultSet()"); + struct ResultSetContext : public ContextBase { + std::string keyPrefix; + // TODO DataQuery query; + KVStoreResultSet* resultSet = nullptr; + napi_ref ref = nullptr; + }; + auto context = std::make_shared(); + auto input = [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + ctxt->status = JSUtil::FromNapiValue(env, argv[index++], ctxt->keyPrefix); + NAPI_ASSERT_RETURN_VOID(env, ctxt->status == napi_ok, "get keyPrefix fail"); + ctxt->status = napi_new_instance(env, KVStoreResultSet::GetCtor(env), argc, argv, &ctxt->output); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && (ctxt->output != nullptr), "napi_new_instance fail"); + ctxt->status = napi_unwrap(env, ctxt->output, reinterpret_cast(&ctxt->resultSet)); + NAPI_ASSERT_RETURN_VOID(env, (ctxt->status == napi_ok) && (ctxt->resultSet != nullptr), "napi_unwrap fail"); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + std::shared_ptr result; + OHOS::DistributedKv::Key keyPrefix(ctxt->keyPrefix); + // TODO GetResultSet( query, ....) + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->GetResultSet(keyPrefix, result); if (status == Status::SUCCESS) { - context->status = napi_ok; - context->value = value.Data(); + *(ctxt->resultSet) = std::move(result); } + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = napi_get_reference_value(ctxt->env, ctxt->ref, &result); + napi_delete_reference(ctxt->env, ctxt->ref); }; - context->SetAction(std::move(input), std::move(output)); - AsyncCall asyncCall(env, info, std::dynamic_pointer_cast(context), 1); - return asyncCall.Call(env, exec); + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); } -napi_value SingleKVStore::Delete(napi_env env, napi_callback_info info) +/* +closeResultSet(resultSet:KVStoreResultSet, callback: AsyncCallback):void +closeResultSet(resultSet:KVStoreResultSet):Promise +*/ +napi_value SingleKVStore::CloseResultSet(napi_env env, napi_callback_info info) { - auto context = std::make_shared(); - auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { - NAPI_ASSERT_BASE(env, argc >= 1, " should 1 or more parameters!", napi_invalid_arg); - context->key = JSUtil::Convert2String(env, argv[0]); - return napi_ok; + ZLOGD("SingleKVStore::CloseResultSet()"); + struct CloseResultSetContext : public ContextBase { + std::shared_ptr resultSet = nullptr; }; - auto exec = [context](AsyncCall::Context *ctx) { - OHOS::DistributedKv::Key key(context->key); - Status status = context->proxy->kvStore_->Delete(key); - if (status == Status::SUCCESS) { - context->status = napi_ok; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + napi_valuetype type; + ctxt->status = napi_typeof(ctxt->env, argv[index], &type); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get napi_typeof fail"); + if (type == napi_object) { + // status = JSUtil::FromNapiValue(ctxt->env, argv[index++], via.deviceId /* todo get KvStoreResultSet */); + } + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->CloseResultSet(ctxt->resultSet); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} +/* +getResultSize(query:Query, callback: AsyncCallback):void +getResultSize(query:Query):Promise +*/ +napi_value SingleKVStore::GetResultSize(napi_env env, napi_callback_info info) +{ + ZLOGD("SingleKVStore::GetResultSize()"); + struct ResultSizeContext : public ContextBase { + std::string query; + int resultSize = 0; + }; + + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + napi_valuetype type; + ctxt->status = napi_typeof(ctxt->env, argv[index], &type); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get napi_typeof fail"); + if (type == napi_object) { + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->query /* todo get query */); } + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); }; - context->SetAction(std::move(input)); - AsyncCall asyncCall(env, info, std::dynamic_pointer_cast(context), 1); - return asyncCall.Call(env, exec); + context->GetCbInfo(env, info, input); + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->GetCountWithQuery(ctxt->query, ctxt->resultSize); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + auto output = [ctxt = context.get()](napi_value& result) { + ctxt->status = JSUtil::ToNapiValue(ctxt->env, static_cast(ctxt->resultSize), result); + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute, output); } +napi_value SingleKVStore::RemoveDeviceData(napi_env env, napi_callback_info info) +{ /* +"removeDeviceData(deviceId:string, callback: AsyncCallback):void +removeDeviceData(deviceId:string):Promise" +*/ + ZLOGD("SingleKVStore::RemoveDeviceData()"); + struct RemoveDeviceContext : public ContextBase { + std::string deviceId; + }; + auto context = std::make_shared(); + auto input = [ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(ctxt->env, argc >= REQUIRED_1_ARGS, "invalid arguments!"); + size_t index = 0; + // todo + ctxt->status = JSUtil::FromNapiValue(ctxt->env, argv[index++], ctxt->deviceId /* todo get query */); + NAPI_ASSERT_RETURN_VOID(ctxt->env, ctxt->status == napi_ok, "get cb_info fail"); + }; + context->GetCbInfo(env, info, input); + + auto execute = [ctxt = context.get()]() { + auto& kvStore = ctxt->As()->kvStore_; + Status status = kvStore->RemoveDeviceData(ctxt->deviceId); + ctxt->status = (status == Status::SUCCESS) ? napi_ok : napi_generic_failure; + }; + return AsyncCall::DoAsyncWork(env, context, std::string(__FUNCTION__), execute); +} +/* + on(event:'dataChange', subType: SubscribeType, observer: Callback): void + on(event:'syncComplete', syncCallback: Callback>):void +*/ napi_value SingleKVStore::OnEvent(napi_env env, napi_callback_info info) { + ZLOGD("SingleKVStore::OnEvent()"); + struct EventContext : public ContextBase { + std::string event; + }; + auto context = std::make_shared(); + + context->GetCbInfo(env, info, [env, ctxt = context.get()](size_t argc, napi_value* argv) { + NAPI_ASSERT_RETURN_VOID(env, argc == REQUIRED_3_ARGS, "invalid arguments!"); + size_t index = 0; + JSUtil::FromNapiValue(env, argv[index++], ctxt->event); + ZLOGI("subscribe event:%{public}s", ctxt->event.c_str()); + auto handle = eventHandlers_.find(ctxt->event); + NAPI_ASSERT_RETURN_VOID(env, handle != eventHandlers_.end(), "unsupported event"); + + /* handle->second(env, argc - index, &argv[index], self, &ctxt->output); */ + }); + return nullptr; +} + +/* + off(event:'syncComplete', syncCallback: Callback>):void +*/ +napi_value SingleKVStore::OffEvent(napi_env env, napi_callback_info info) +{ + ZLOGD("SingleKVStore::OffEvent()"); napi_value self = nullptr; size_t argc = JSUtil::MAX_ARGC; - napi_value argv[JSUtil::MAX_ARGC] = {nullptr}; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); NAPI_ASSERT(env, argc > 0, "there is no args"); napi_valuetype type; NAPI_CALL(env, napi_typeof(env, argv[0], &type)); NAPI_ASSERT(env, type == napi_string, "key not string type"); - std::string event = JSUtil::Convert2String(env, argv[0]); + std::string event; + JSUtil::FromNapiValue(env, argv[0], event); ZLOGI("subscribe event:%{public}s", event.c_str()); auto handle = eventHandlers_.find(event); @@ -158,18 +347,20 @@ napi_value SingleKVStore::OnEvent(napi_env env, napi_callback_info info) napi_value SingleKVStore::Sync(napi_env env, napi_callback_info info) { + ZLOGD("SingleKVStore::Sync()"); napi_value self = nullptr; size_t argc = JSUtil::MAX_ARGC; - napi_value argv[JSUtil::MAX_ARGC] = {nullptr}; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); // the number of parameters is greater than 2 is error - NAPI_ASSERT_BASE(env, argc >= 2, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); - SingleKVStore *proxy = nullptr; - NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + SingleKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); - std::vector devices = JSUtil::Convert2StringArray(env, argv[0]); + std::vector devices; + JSUtil::FromNapiValue(env, argv[0], devices); int32_t mode = int32_t(SyncMode::PUSH_PULL); napi_get_value_int32(env, argv[1], &mode); uint32_t delay = 0; @@ -184,68 +375,101 @@ napi_value SingleKVStore::Sync(napi_env env, napi_callback_info info) return nullptr; } +napi_value SingleKVStore::SetSyncParam(napi_env env, napi_callback_info info) +{ + ZLOGD("SingleKVStore::SetSyncParam()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + SingleKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + std::vector devices; + JSUtil::FromNapiValue(env, argv[0], devices); + int32_t mode = int32_t(SyncMode::PUSH_PULL); + napi_get_value_int32(env, argv[1], &mode); + uint32_t delay = 0; + // 3 is the max number of parameters + if (argc >= 3) { + napi_get_value_uint32(env, argv[2], &delay); // argv[2] is the third parameter + } + ZLOGD("sync data %{public}d, mode:%{public}d, devices:%{public}zu", static_cast(argc), mode, devices.size()); + + KvSyncParam syncParam; // TODO + Status status = proxy->kvStore_->SetSyncParam(syncParam); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + +napi_value SingleKVStore::GetSecurityLevel(napi_env env, napi_callback_info info) +{ + ZLOGD("SingleKVStore::GetSecurityLevel()"); + napi_value self = nullptr; + size_t argc = JSUtil::MAX_ARGC; + napi_value argv[JSUtil::MAX_ARGC] = { nullptr }; + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error + NAPI_ASSERT_BASE(env, argc >= REQUIRED_2_ARGS, "args is out of range", nullptr); + NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); + SingleKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), nullptr); + NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", nullptr); + + std::vector devices; + JSUtil::FromNapiValue(env, argv[0], devices); + int32_t mode = int32_t(SyncMode::PUSH_PULL); + napi_get_value_int32(env, argv[1], &mode); + uint32_t delay = 0; + // 3 is the max number of parameters + if (argc >= 3) { + napi_get_value_uint32(env, argv[2], &delay); // argv[2] is the third parameter + } + ZLOGD("sync data %{public}d, mode:%{public}d, devices:%{public}zu", static_cast(argc), mode, devices.size()); + + SecurityLevel securityLevel; // TODO + Status status = proxy->kvStore_->GetSecurityLevel(securityLevel); + NAPI_ASSERT_BASE(env, status == Status::SUCCESS, "call sync failed", nullptr); + return nullptr; +} + napi_value SingleKVStore::Initialize(napi_env env, napi_callback_info info) { ZLOGD("constructor single kv store!"); napi_value self = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr)); - auto *proxy = new SingleKVStore(); + // + + auto* proxy = new SingleKVStore(); auto release = [proxy]() -> napi_value { delete proxy; return nullptr; }; - auto finalize = [](napi_env env, void *data, void *hint) { - auto *proxy = reinterpret_cast(data); + auto finalize = [](napi_env env, void* data, void* hint) { + auto* proxy = reinterpret_cast(data); delete proxy; }; NAPI_CALL_BASE(env, napi_wrap(env, self, proxy, finalize, nullptr, nullptr), release()); return self; } -napi_status SingleKVStore::OnDataChange(napi_env env, size_t argc, napi_value *argv, napi_value self, - napi_value *result) -{ - // on(event: 'dataChange', type: SubscribeType, observer: Callback): void; - // except event, there are 2 args - NAPI_ASSERT_BASE(env, argc >= 2, "args is out of range", napi_invalid_arg); - NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); - int32_t type = 0; - napi_get_value_int32(env, argv[0], &type); - NAPI_ASSERT_BASE(env, SUBSCRIBE_LOCAL <= type && type <= SUBSCRIBE_ALL, "type is out of range", napi_invalid_arg); - napi_valuetype valueType = napi_undefined; - napi_typeof(env, argv[1], &valueType); - NAPI_ASSERT_BASE(env, valueType == napi_function, "callback is not a function", napi_invalid_arg); - - SingleKVStore *proxy = nullptr; - NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); - NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", napi_invalid_arg); - - ZLOGI("subscribe data change type %{public}d", type); - std::shared_ptr observer = std::make_shared(env, argv[1]); - Status status = proxy->kvStore_->SubscribeKvStore(static_cast(type + 1), observer); - if (status != Status::SUCCESS) { - return napi_generic_failure; - } - if (proxy->dataObserver_[type] != nullptr) { - proxy->kvStore_->UnSubscribeKvStore(static_cast(type + 1), proxy->dataObserver_[type]); - } - proxy->dataObserver_[type] = std::move(observer); - return napi_ok; -} - -napi_status SingleKVStore::OnSyncComplete(napi_env env, size_t argc, napi_value *argv, napi_value self, - napi_value *result) +napi_status SingleKVStore::OnSyncComplete( + napi_env env, size_t argc, napi_value* argv, napi_value self, napi_value* result) { // on(event: 'syncComplete', syncCallback: Callback>): void; // except event, there is 1 arg - NAPI_ASSERT_BASE(env, argc >= 1, "args is out of range", napi_invalid_arg); + NAPI_ASSERT_BASE(env, argc >= REQUIRED_1_ARGS, "args is out of range", napi_invalid_arg); NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", napi_invalid_arg); napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[0], &valueType); NAPI_ASSERT_BASE(env, valueType == napi_function, "callback is not function", napi_invalid_arg); - SingleKVStore *proxy = nullptr; - NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); + SingleKVStore* proxy = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast(&proxy)), napi_invalid_arg); NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native kv store", napi_invalid_arg); std::shared_ptr observer = std::make_shared(env, argv[0]); Status status = proxy->kvStore_->RegisterSyncCallback(observer); @@ -256,7 +480,7 @@ napi_status SingleKVStore::OnSyncComplete(napi_env env, size_t argc, napi_value return napi_ok; } -SingleKVStore &SingleKVStore::operator=(std::shared_ptr &&singleKvStore) +SingleKVStore& SingleKVStore::operator=(std::shared_ptr&& singleKvStore) { if (kvStore_ == singleKvStore) { return *this; @@ -265,102 +489,8 @@ SingleKVStore &SingleKVStore::operator=(std::shared_ptr &singleKvStore) +bool SingleKVStore::operator==(const std::shared_ptr& singleKvStore) { return kvStore_ == singleKvStore; } - -DataObserver::DataObserver(napi_env env, napi_value callback) - : env_(env) -{ - napi_create_reference(env, callback, 1, &callback_); - napi_get_uv_event_loop(env, &loop_); -} - -DataObserver::~DataObserver() -{ - napi_delete_reference(env_, callback_); -} - -void DataObserver::OnChange(const ChangeNotification ¬ification, std::shared_ptr snapshot) -{ - ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu", - notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(), - notification.GetDeleteEntries().size()); -} - -void DataObserver::OnChange(const ChangeNotification ¬ification) -{ - ZLOGD("data change insert:%{public}zu, update:%{public}zu, delete:%{public}zu", - notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(), - notification.GetDeleteEntries().size()); - KvStoreObserver::OnChange(notification); - EventDataWorker *eventDataWorker = new EventDataWorker(this, notification); - uv_work_t *work = new uv_work_t; - work->data = eventDataWorker; - uv_queue_work(loop_, work, - [](uv_work_t *work) {}, - [](uv_work_t *work, int status) { - EventDataWorker *eventDataInner = reinterpret_cast(work->data); - napi_value jsNotification = JSUtil::Convert2JSNotification(eventDataInner->observer->env_, - eventDataInner->data); - napi_value callback = nullptr; - napi_value args[1] = {jsNotification}; - napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); - napi_value global = nullptr; - napi_get_global(eventDataInner->observer->env_, &global); - napi_value result; - napi_status callStatus = napi_call_function(eventDataInner->observer->env_, global, callback, - 1, args, &result); - if (callStatus != napi_ok) { - ZLOGE("notify data change failed callStatus:%{public}d callback:%{public}p", callStatus, callback); - } - delete eventDataInner; - eventDataInner = nullptr; - delete work; - work = nullptr; - }); -} - -SyncObserver::SyncObserver(napi_env env, napi_value callback) - : env_(env) -{ - napi_create_reference(env, callback, 1, &callback_); - napi_get_uv_event_loop(env, &loop_); -} - -SyncObserver::~SyncObserver() -{ - napi_delete_reference(env_, callback_); -} - -void SyncObserver::SyncCompleted(const std::map &results) -{ - EventDataWorker *eventDataWorker = new EventDataWorker(); - eventDataWorker->observer = this; - eventDataWorker->data = results; - uv_work_t *work = new uv_work_t; - work->data = eventDataWorker; - uv_queue_work(loop_, work, - [](uv_work_t *work) {}, - [](uv_work_t *work, int status) { - EventDataWorker *eventDataInner = reinterpret_cast(work->data); - std::map dataMap; - for (const auto &[key, value] : eventDataInner->data) { - dataMap.emplace(key, int32_t(value)); - } - napi_value notification = JSUtil::Convert2JSTupleArray(eventDataInner->observer->env_, dataMap); - napi_value callback = nullptr; - napi_value args[1] = {notification}; - napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); - napi_value global = nullptr; - napi_value result = nullptr; - napi_get_global(eventDataInner->observer->env_, &global); - napi_call_function(eventDataInner->observer->env_, global, callback, 1, args, &result); - delete eventDataInner; - eventDataInner = nullptr; - delete work; - work = nullptr; - }); -} -} +} // namespace OHOS::DistributedData diff --git a/interfaces/jskits/distributeddata/BUILD.gn b/interfaces/jskits/distributeddata/BUILD.gn index 109fcc69fc3bed23331012d336b380c5b1c2eb27..8264c35076d31d0b2cc4b410801b0ba83b38aa7a 100644 --- a/interfaces/jskits/distributeddata/BUILD.gn +++ b/interfaces/jskits/distributeddata/BUILD.gn @@ -45,9 +45,13 @@ ohos_shared_library("distributeddata") { sources = [ "../../../frameworks/jskitsimpl/distributeddata/src/async_call.cpp", + "../../../frameworks/jskitsimpl/distributeddata/src/device_kv_store.cpp", "../../../frameworks/jskitsimpl/distributeddata/src/entry_point.cpp", "../../../frameworks/jskitsimpl/distributeddata/src/js_util.cpp", "../../../frameworks/jskitsimpl/distributeddata/src/kv_manager.cpp", + "../../../frameworks/jskitsimpl/distributeddata/src/kv_store.cpp", + "../../../frameworks/jskitsimpl/distributeddata/src/kv_store_resultset.cpp", + "../../../frameworks/jskitsimpl/distributeddata/src/query.cpp", "../../../frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp", ]