1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #define LOG_TAG "JsSchema"
16 #include "js_schema.h"
17 #include <nlohmann/json.hpp>
18
19 #include "js_util.h"
20 #include "log_print.h"
21 #include "napi_queue.h"
22 #include "uv_queue.h"
23
24 using namespace OHOS::DistributedKv;
25 using json = nlohmann::json;
26
27 namespace OHOS::DistributedKVStore {
28 static std::string LABEL = "Schema";
29 static std::string SCHEMA_VERSION = "SCHEMA_VERSION";
30 static std::string SCHEMA_MODE = "SCHEMA_MODE";
31 static std::string SCHEMA_DEFINE = "SCHEMA_DEFINE";
32 static std::string SCHEMA_INDEXES = "SCHEMA_INDEXES";
33 static std::string SCHEMA_SKIPSIZE = "SCHEMA_SKIPSIZE";
34 static std::string DEFAULT_SCHEMA_VERSION = "1.0";
35
JsSchema(napi_env env)36 JsSchema::JsSchema(napi_env env)
37 : env_(env)
38 {
39 }
40
~JsSchema()41 JsSchema::~JsSchema()
42 {
43 ZLOGD("no memory leak for JsSchema");
44 if (ref_ != nullptr) {
45 napi_delete_reference(env_, ref_);
46 }
47 }
48
Constructor(napi_env env)49 napi_value JsSchema::Constructor(napi_env env)
50 {
51 ZLOGD("Init JsSchema");
52 auto lambda = []() -> std::vector<napi_property_descriptor> {
53 std::vector<napi_property_descriptor> properties = {
54 DECLARE_NAPI_GETTER_SETTER("root", JsSchema::GetRootNode, JsSchema::SetRootNode),
55 DECLARE_NAPI_GETTER_SETTER("indexes", JsSchema::GetIndexes, JsSchema::SetIndexes),
56 DECLARE_NAPI_GETTER_SETTER("mode", JsSchema::GetMode, JsSchema::SetMode),
57 DECLARE_NAPI_GETTER_SETTER("skip", JsSchema::GetSkip, JsSchema::SetSkip),
58 };
59 return properties;
60 };
61 return JSUtil::DefineClass(env, "ohos.data.distributedKVStore", "Schema", lambda, JsSchema::New);
62 }
63
New(napi_env env,napi_callback_info info)64 napi_value JsSchema::New(napi_env env, napi_callback_info info)
65 {
66 ZLOGD("Schema::New");
67 auto ctxt = std::make_shared<ContextBase>();
68 ctxt->GetCbInfoSync(env, info);
69 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
70
71 JsSchema* schema = new (std::nothrow) JsSchema(env);
72 NAPI_ASSERT(env, schema !=nullptr, "no memory for schema");
73
74 auto finalize = [](napi_env env, void* data, void* hint) {
75 ZLOGD("Schema finalize.");
76 auto* schema = reinterpret_cast<JsSchema*>(data);
77 ASSERT_VOID(schema != nullptr, "schema is null!");
78 delete schema;
79 };
80 ASSERT_CALL(env, napi_wrap(env, ctxt->self, schema, finalize, nullptr, nullptr), schema);
81 return ctxt->self;
82 }
83
ToJson(napi_env env,napi_value inner,JsSchema * & out)84 napi_status JsSchema::ToJson(napi_env env, napi_value inner, JsSchema*& out)
85 {
86 ZLOGD("Schema::ToJson");
87 return JSUtil::Unwrap(env, inner, reinterpret_cast<void**>(&out), JsSchema::Constructor(env));
88 }
89
GetSchema(napi_env env,napi_callback_info info,std::shared_ptr<ContextBase> & ctxt)90 JsSchema* JsSchema::GetSchema(napi_env env, napi_callback_info info, std::shared_ptr<ContextBase>& ctxt)
91 {
92 ctxt->GetCbInfoSync(env, info);
93 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
94 return reinterpret_cast<JsSchema*>(ctxt->native);
95 }
96
97 template <typename T>
GetContextValue(napi_env env,std::shared_ptr<ContextBase> & ctxt,T & value)98 napi_value JsSchema::GetContextValue(napi_env env, std::shared_ptr<ContextBase>& ctxt, T& value)
99 {
100 JSUtil::SetValue(env, value, ctxt->output);
101 return ctxt->output;
102 }
103
GetRootNode(napi_env env,napi_callback_info info)104 napi_value JsSchema::GetRootNode(napi_env env, napi_callback_info info)
105 {
106 ZLOGD("Schema::GetRootNode");
107 auto ctxt = std::make_shared<ContextBase>();
108 auto schema = GetSchema(env, info, ctxt);
109 ASSERT(schema != nullptr, "getSchema nullptr!", nullptr);
110 if (schema->rootNode_ == nullptr) {
111 int argc = 1;
112 napi_value argv[1] = { nullptr };
113 std::string root(SCHEMA_DEFINE);
114 JSUtil::SetValue(env, root, argv[0]);
115 schema->ref_ = JSUtil::NewWithRef(env, argc, argv,
116 reinterpret_cast<void**>(&schema->rootNode_), JsFieldNode::Constructor(env));
117 }
118 NAPI_ASSERT(env, schema->ref_ != nullptr, "no root, please set first!");
119 NAPI_CALL(env, napi_get_reference_value(env, schema->ref_, &ctxt->output));
120 return ctxt->output;
121 }
122
SetRootNode(napi_env env,napi_callback_info info)123 napi_value JsSchema::SetRootNode(napi_env env, napi_callback_info info)
124 {
125 ZLOGD("Schema::SetRootNode");
126 auto ctxt = std::make_shared<ContextBase>();
127 auto input = [env, ctxt](size_t argc, napi_value* argv) {
128 // required 2 arguments :: <root-node>
129 ASSERT_ARGS(ctxt, argc == 1, "invalid arguments!");
130 JsFieldNode* node = nullptr;
131 ctxt->status = JSUtil::Unwrap(env, argv[0], reinterpret_cast<void**>(&node), JsFieldNode::Constructor(env));
132 ASSERT_STATUS(ctxt, "napi_unwrap to FieldNode failed");
133 ASSERT_ARGS(ctxt, node != nullptr, "invalid arg[0], i.e. invalid node!");
134
135 auto schema = reinterpret_cast<JsSchema*>(ctxt->native);
136 if (schema->ref_ != nullptr) {
137 napi_delete_reference(env, schema->ref_);
138 }
139 ctxt->status = napi_create_reference(env, argv[0], 1, &schema->ref_);
140 ASSERT_STATUS(ctxt, "napi_create_reference to FieldNode failed");
141 schema->rootNode_ = node;
142 };
143 ctxt->GetCbInfoSync(env, info, input);
144 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
145 return ctxt->self;
146 }
147
GetMode(napi_env env,napi_callback_info info)148 napi_value JsSchema::GetMode(napi_env env, napi_callback_info info)
149 {
150 ZLOGD("Schema::GetMode");
151 auto ctxt = std::make_shared<ContextBase>();
152 auto schema = GetSchema(env, info, ctxt);
153 ASSERT(schema != nullptr, "schema is nullptr!", nullptr);
154 return GetContextValue(env, ctxt, schema->mode_);
155 }
156
SetMode(napi_env env,napi_callback_info info)157 napi_value JsSchema::SetMode(napi_env env, napi_callback_info info)
158 {
159 auto ctxt = std::make_shared<ContextBase>();
160 uint32_t mode = false;
161 auto input = [env, ctxt, &mode](size_t argc, napi_value* argv) {
162 // required 1 arguments :: <mode>
163 ASSERT_ARGS(ctxt, argc == 1, "invalid arguments!");
164 ctxt->status = JSUtil::GetValue(env, argv[0], mode);
165 ASSERT_STATUS(ctxt, "invalid arg[0], i.e. invalid mode!");
166 };
167 ctxt->GetCbInfoSync(env, info, input);
168 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
169
170 auto schema = reinterpret_cast<JsSchema*>(ctxt->native);
171 schema->mode_ = mode;
172 return nullptr;
173 }
174
GetSkip(napi_env env,napi_callback_info info)175 napi_value JsSchema::GetSkip(napi_env env, napi_callback_info info)
176 {
177 ZLOGD("Schema::GetSkip");
178 auto ctxt = std::make_shared<ContextBase>();
179 auto schema = GetSchema(env, info, ctxt);
180 ASSERT(schema != nullptr, "schema is nullptr!", nullptr);
181 return GetContextValue(env, ctxt, schema->skip_);
182 }
183
SetSkip(napi_env env,napi_callback_info info)184 napi_value JsSchema::SetSkip(napi_env env, napi_callback_info info)
185 {
186 auto ctxt = std::make_shared<ContextBase>();
187 uint32_t skip = false;
188 auto input = [env, ctxt, &skip](size_t argc, napi_value* argv) {
189 // required 1 arguments :: <skip size>
190 ASSERT_ARGS(ctxt, argc == 1, "invalid arguments!");
191 ctxt->status = JSUtil::GetValue(env, argv[0], skip);
192 ASSERT_STATUS(ctxt, "invalid arg[0], i.e. invalid skip size!");
193 };
194 ctxt->GetCbInfoSync(env, info, input);
195 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
196
197 auto schema = reinterpret_cast<JsSchema*>(ctxt->native);
198 schema->skip_ = skip;
199 return nullptr;
200 }
201
GetIndexes(napi_env env,napi_callback_info info)202 napi_value JsSchema::GetIndexes(napi_env env, napi_callback_info info)
203 {
204 ZLOGD("Schema::GetIndexes");
205 auto ctxt = std::make_shared<ContextBase>();
206 auto schema = GetSchema(env, info, ctxt);
207 ASSERT(schema != nullptr, "getSchema nullptr!", nullptr);
208 return GetContextValue(env, ctxt, schema->indexes_);
209 }
210
SetIndexes(napi_env env,napi_callback_info info)211 napi_value JsSchema::SetIndexes(napi_env env, napi_callback_info info)
212 {
213 auto ctxt = std::make_shared<ContextBase>();
214 std::vector<std::string> indexes;
215 auto input = [env, ctxt, &indexes](size_t argc, napi_value* argv) {
216 // required 1 arguments :: <indexes>
217 ASSERT_ARGS(ctxt, argc == 1, "invalid arguments!");
218 ctxt->status = JSUtil::GetValue(env, argv[0], indexes, false);
219 ASSERT_STATUS(ctxt, "invalid arg[0], i.e. invalid indexes!");
220 };
221 ctxt->GetCbInfoSync(env, info, input);
222 NAPI_ASSERT(env, ctxt->status == napi_ok, "invalid arguments!");
223
224 auto schema = reinterpret_cast<JsSchema*>(ctxt->native);
225 schema->indexes_ = indexes;
226 return nullptr;
227 }
228
Dump()229 std::string JsSchema::Dump()
230 {
231 json jsIndexes = nlohmann::json::array();
232 for (auto idx : indexes_) {
233 jsIndexes.push_back(idx);
234 }
235 json js = {
236 { SCHEMA_VERSION, DEFAULT_SCHEMA_VERSION },
237 { SCHEMA_MODE, (mode_ == SCHEMA_MODE_STRICT) ? "STRICT" : "COMPATIBLE" },
238 { SCHEMA_DEFINE, rootNode_->GetValueForJson() },
239 { SCHEMA_INDEXES, jsIndexes },
240 { SCHEMA_SKIPSIZE, skip_ },
241 };
242 return js.dump();
243 }
244 } // namespace OHOS::DistributedKVStore
245