1 /*
2 * Copyright (c) 2024 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
16 #include <cstdlib>
17 #include <string>
18 #include <variant>
19 #include <vector>
20 #include <map>
21 #include <iomanip>
22 #include "securec.h"
23 #include "ffi_remote_data.h"
24
25 #include "distributed_kv_store_impl.h"
26 #include "distributed_kv_store_utils.h"
27
28 using namespace OHOS::FFI;
29
30 namespace OHOS::DistributedKVStore {
31
ConvertCJErrCode(Status status)32 static int32_t ConvertCJErrCode(Status status)
33 {
34 switch (status) {
35 case PERMISSION_DENIED:
36 // 202
37 return CJ_ERROR_PERMISSION_DENIED;
38 case INVALID_ARGUMENT:
39 // 401
40 return CJ_ERROR_INVALID_ARGUMENT;
41 case OVER_MAX_LIMITS:
42 // 15100001
43 return CJ_ERROR_OVER_MAX_LIMITS;
44 case STORE_META_CHANGED:
45 case SECURITY_LEVEL_ERROR:
46 // 15100002
47 return CJ_ERROR_STORE_META_CHANGED;
48 case CRYPT_ERROR:
49 // 15100003
50 return CJ_ERROR_CRYPT_ERROR;
51 case NOT_FOUND:
52 case DB_ERROR:
53 // 15100004
54 return CJ_ERROR_NOT_FOUND;
55 case ALREADY_CLOSED:
56 // 15100005
57 return CJ_ERROR_ALREADY_CLOSED;
58 default:
59 return static_cast<int32_t>(status);
60 }
61 }
62
VectorToByteArray(std::vector<uint8_t> bytes)63 static CArrByte VectorToByteArray(std::vector<uint8_t> bytes)
64 {
65 uint8_t* head = static_cast<uint8_t*>(malloc(bytes.size() * sizeof(uint8_t)));
66 if (head == nullptr) {
67 return CArrByte{};
68 }
69 for (unsigned long i = 0; i < bytes.size(); i++) {
70 head[i] = bytes[i];
71 }
72 CArrByte byteArray = { head, bytes.size() };
73 return byteArray;
74 }
75
KVValueToValueType(const DistributedKv::Blob & blob)76 static ValueType KVValueToValueType(const DistributedKv::Blob& blob)
77 {
78 auto& data = blob.Data();
79 ValueType v = { 0 };
80 // number 2 means: valid Blob must have more than 2 bytes.
81 if (data.size() < 1) {
82 LOGI("Blob have no data!");
83 return {0};
84 }
85 // number 1 means: skip the first byte, byte[0] is real data type.
86 std::vector<uint8_t> real(data.begin() + 1, data.end());
87 if (data[0] == STRING) {
88 v.string = MallocCString(std::string(real.begin(), real.end()));
89 v.tag = STRING;
90 } else if (data[0] == INTEGER) {
91 uint32_t tmp4int = be32toh(*reinterpret_cast<uint32_t*>(&(real[0])));
92 v.integer = *reinterpret_cast<int32_t*>(&tmp4int);
93 v.tag = INTEGER;
94 } else if (data[0] == FLOAT) {
95 uint32_t tmp4flt = be32toh(*reinterpret_cast<uint32_t*>(&(real[0])));
96 v.flo = *reinterpret_cast<float*>((void*)(&tmp4flt));
97 v.tag = FLOAT;
98 } else if (data[0] == BYTE_ARRAY) {
99 v.byteArray = VectorToByteArray(std::vector<uint8_t>(real.begin(), real.end()));
100 v.tag = BYTE_ARRAY;
101 } else if (data[0] == BOOLEAN) {
102 v.boolean = static_cast<bool>(real[0]);
103 v.tag = BOOLEAN;
104 } else if (data[0] == DOUBLE) {
105 uint64_t tmp4dbl = be64toh(*reinterpret_cast<uint64_t*>(&(real[0])));
106 v.dou = *reinterpret_cast<double*>((void*)(&tmp4dbl));
107 v.tag = DOUBLE;
108 } else {
109 // for schema-db, if (data[0] == STRING), no beginning byte!
110 v.string = MallocCString(std::string(data.begin(), data.end()));
111 v.tag = STRING;
112 }
113 return v;
114 }
115
PushData(const ValueType & value,std::vector<uint8_t> & data,uint8_t tag)116 static void PushData(const ValueType &value, std::vector<uint8_t> &data, uint8_t tag)
117 {
118 switch (tag) {
119 case INTEGER: {
120 int32_t tmp = value.integer; // copy value, and make it available in stack space.
121 uint32_t tmp32 = htobe32(*reinterpret_cast<uint32_t*>(&tmp));
122 uint8_t *res = reinterpret_cast<uint8_t*>(&tmp32);
123 data.push_back(INTEGER);
124 data.insert(data.end(), res, res + sizeof(int32_t) / sizeof(uint8_t));
125 break;
126 }
127 case FLOAT: {
128 float tmp = value.flo; // copy value, and make it available in stack space.
129 uint32_t tmp32 = htobe32(*reinterpret_cast<uint32_t*>(&tmp));
130 uint8_t *res = reinterpret_cast<uint8_t*>(&tmp32);
131 data.push_back(FLOAT);
132 data.insert(data.end(), res, res + sizeof(float) / sizeof(uint8_t));
133 break;
134 }
135 case DOUBLE: {
136 double tmp = value.dou; // copy value, and make it available in stack space.
137 uint64_t tmp64 = htobe64(*reinterpret_cast<uint64_t*>(&tmp));
138 uint8_t *res = reinterpret_cast<uint8_t*>(&tmp64);
139 data.push_back(DOUBLE);
140 data.insert(data.end(), res, res + sizeof(double) / sizeof(uint8_t));
141 break;
142 }
143 default:
144 break;
145 }
146 }
147
ValueTypeToKVValue(const ValueType & value)148 static DistributedKv::Value ValueTypeToKVValue(const ValueType &value)
149 {
150 std::vector<uint8_t> data;
151 switch (value.tag) {
152 case STRING: {
153 std::string str = value.string;
154 data.push_back(STRING);
155 data.insert(data.end(), str.begin(), str.end());
156 break;
157 }
158 case INTEGER: {
159 PushData(value, data, value.tag);
160 break;
161 }
162 case FLOAT: {
163 PushData(value, data, value.tag);
164 break;
165 }
166 case BYTE_ARRAY: {
167 std::vector<uint8_t> bytes = std::vector<uint8_t>();
168 for (int64_t i = 0; i < value.byteArray.size; i++) {
169 bytes.push_back(value.byteArray.head[i]);
170 }
171 data.push_back(BYTE_ARRAY);
172 data.insert(data.end(), bytes.begin(), bytes.end());
173 break;
174 }
175 case BOOLEAN: {
176 data.push_back(BOOLEAN);
177 data.push_back(static_cast<uint8_t>(value.boolean));
178 break;
179 }
180 case DOUBLE: {
181 PushData(value, data, value.tag);
182 break;
183 }
184 default:
185 break;
186 }
187 return DistributedKv::Blob(data);
188 }
189
CJKVManager()190 CJKVManager::CJKVManager() {};
CJKVManager(const char * boudleName,OHOS::AbilityRuntime::Context * context)191 CJKVManager::CJKVManager(const char* boudleName, OHOS::AbilityRuntime::Context* context)
192 {
193 ContextParam param;
194 param.area = context->GetArea();
195 param.baseDir = context->GetDatabaseDir();
196 auto hapInfo = context->GetHapModuleInfo();
197 if (hapInfo != nullptr) {
198 param.hapName = hapInfo->moduleName;
199 }
200 param_ = std::make_shared<ContextParam>(std::move(param));
201 bundleName_ = boudleName;
202 }
203
GetKVStore(const char * cStoreId,const CJOptions cjOptions,int32_t & errCode)204 uint64_t CJKVManager::GetKVStore(const char* cStoreId, const CJOptions cjOptions, int32_t& errCode)
205 {
206 Options options;
207 options.createIfMissing = cjOptions.createIfMissing;
208 options.encrypt = cjOptions.encrypt;
209 options.backup = cjOptions.backup;
210 options.autoSync = cjOptions.autoSync;
211 options.kvStoreType = static_cast<KvStoreType>(cjOptions.kvStoreType);
212 options.securityLevel = cjOptions.securityLevel;
213 AppId appId = { bundleName_ };
214 std::string sStoreId = cStoreId;
215 StoreId storeId = { sStoreId };
216 options.baseDir = param_->baseDir;
217 options.area = param_->area + 1;
218 options.hapName = param_->hapName;
219 std::shared_ptr<DistributedKv::SingleKvStore> kvStore;
220 Status status = kvDataManager_.GetSingleKvStore(options, appId, storeId, kvStore);
221 if (status == CRYPT_ERROR) {
222 options.rebuild = true;
223 status = kvDataManager_.GetSingleKvStore(options, appId, storeId, kvStore);
224 LOGE("Data has corrupted, rebuild db");
225 }
226 errCode = ConvertCJErrCode(status);
227 if (errCode != 0) {
228 return 0;
229 }
230 if (cjOptions.kvStoreType == 1) {
231 auto nativeKVStore = FFIData::Create<CJSingleKVStore>(sStoreId);
232 if (nativeKVStore == nullptr) {
233 errCode = -1;
234 return -1;
235 }
236 nativeKVStore->SetKvStorePtr(kvStore);
237 nativeKVStore->SetContextParam(param_);
238 return nativeKVStore->GetID();
239 }
240 auto nativeKVStore = FFIData::Create<CJDeviceKVStore>(sStoreId);
241 if (nativeKVStore == nullptr) {
242 errCode = -1;
243 return -1;
244 }
245 nativeKVStore->SetKvStorePtr(kvStore);
246 nativeKVStore->SetContextParam(param_);
247 return nativeKVStore->GetID();
248 }
249
CloseKVStore(const char * appId,const char * storeId)250 int32_t CJKVManager::CloseKVStore(const char* appId, const char* storeId)
251 {
252 std::string sAppId = appId;
253 std::string sStoreId = storeId;
254 AppId appIdBox = { sAppId };
255 StoreId storeIdBox { sStoreId };
256 Status status = kvDataManager_.CloseKvStore(appIdBox, storeIdBox);
257 if ((status == Status::SUCCESS) || (status == Status::STORE_NOT_FOUND) || (status == Status::STORE_NOT_OPEN)) {
258 status = Status::SUCCESS;
259 }
260 return ConvertCJErrCode(status);
261 }
262
DeleteKVStore(const char * appId,const char * storeId)263 int32_t CJKVManager::DeleteKVStore(const char* appId, const char* storeId)
264 {
265 std::string sAppId = appId;
266 std::string sStoreId = storeId;
267 AppId appIdBox = { sAppId };
268 StoreId storeIdBox { sStoreId };
269 std::string databaseDir = param_->baseDir;
270 Status status = kvDataManager_.DeleteKvStore(appIdBox, storeIdBox, databaseDir);
271 return ConvertCJErrCode(status);
272 }
273
VectorAppIdToCArr(const std::vector<StoreId> & storeIdList)274 static CArrStr VectorAppIdToCArr(const std::vector<StoreId>& storeIdList)
275 {
276 CArrStr strArray;
277 strArray.size = static_cast<int64_t>(storeIdList.size());
278 strArray.head = static_cast<char**>(malloc(strArray.size * sizeof(char*)));
279 if (strArray.head == nullptr) {
280 return CArrStr{0};
281 }
282 for (int64_t i = 0; i < strArray.size; i++) {
283 strArray.head[i] = MallocCString(storeIdList[i].storeId);
284 }
285 return strArray;
286 }
287
GetAllKVStoreId(const char * appId,int32_t & errCode)288 CArrStr CJKVManager::GetAllKVStoreId(const char* appId, int32_t& errCode)
289 {
290 std::string sAppId = appId;
291 AppId appIdBox = { sAppId };
292 std::vector<StoreId> storeIdList;
293 Status status = kvDataManager_.GetAllKvStoreId(appIdBox, storeIdList);
294 errCode = ConvertCJErrCode(status);
295 if (errCode != 0) {
296 return CArrStr{0};
297 }
298 return VectorAppIdToCArr(storeIdList);
299 }
300
CJSingleKVStore(const std::string & storeId)301 CJSingleKVStore::CJSingleKVStore(const std::string& storeId)
302 {
303 storeId_ = storeId;
304 }
305
GetKvStorePtr()306 std::shared_ptr<SingleKvStore> CJSingleKVStore::GetKvStorePtr()
307 {
308 return kvStore_;
309 }
310
SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)311 void CJSingleKVStore::SetKvStorePtr(std::shared_ptr<SingleKvStore> kvStore)
312 {
313 kvStore_ = kvStore;
314 }
315
SetContextParam(std::shared_ptr<ContextParam> param)316 void CJSingleKVStore::SetContextParam(std::shared_ptr<ContextParam> param)
317 {
318 param_ = param;
319 }
320
Put(const std::string & key,const ValueType & value)321 int32_t CJSingleKVStore::Put(const std::string &key, const ValueType &value)
322 {
323 auto tempKey = DistributedKv::Key(key);
324 Status status = kvStore_->Put(tempKey, ValueTypeToKVValue(value));
325 return ConvertCJErrCode(status);
326 }
327
CEntryToEntry(const CEntry & cEntry)328 static Entry CEntryToEntry(const CEntry &cEntry)
329 {
330 std::string key = cEntry.key;
331 Entry entry = {DistributedKv::Key(key), ValueTypeToKVValue(cEntry.value)};
332 return entry;
333 }
334
CArrayEntryToEntries(const CArrEntry & cArrEntry)335 static std::vector<Entry> CArrayEntryToEntries(const CArrEntry &cArrEntry)
336 {
337 std::vector<Entry> entrys;
338 int64_t arrSize = cArrEntry.size;
339
340 for (int64_t i = 0; i < arrSize; i++) {
341 Entry entry = CEntryToEntry(cArrEntry.head[i]);
342 entrys.push_back(entry);
343 }
344 return entrys;
345 }
346
PutBatch(const CArrEntry & cArrEntry)347 int32_t CJSingleKVStore::PutBatch(const CArrEntry &cArrEntry)
348 {
349 Status status = kvStore_->PutBatch(CArrayEntryToEntries(cArrEntry));
350 return ConvertCJErrCode(status);
351 }
352
Delete(const std::string & key)353 int32_t CJSingleKVStore::Delete(const std::string &key)
354 {
355 auto tempKey = DistributedKv::Key(key);
356 Status status = kvStore_->Delete(tempKey);
357 return ConvertCJErrCode(status);
358 }
359
CArrStrToVectorKey(const CArrStr & cArrStr)360 static std::vector<Key> CArrStrToVectorKey(const CArrStr &cArrStr)
361 {
362 std::vector<Key> keys;
363 int64_t size = cArrStr.size;
364 for (int64_t i = 0; i < size; i++) {
365 std::string str = cArrStr.head[i];
366 keys.push_back(DistributedKv::Key(str));
367 }
368 return keys;
369 }
370
DeleteBatch(const CArrStr & cArrStr)371 int32_t CJSingleKVStore::DeleteBatch(const CArrStr &cArrStr)
372 {
373 Status status = kvStore_->DeleteBatch(CArrStrToVectorKey(cArrStr));
374 return ConvertCJErrCode(status);
375 }
376
Get(const std::string & key,int32_t & errCode)377 ValueType CJSingleKVStore::Get(const std::string &key, int32_t& errCode)
378 {
379 auto s_key = DistributedKv::Key(key);
380 OHOS::DistributedKv::Value value;
381 Status status = kvStore_->Get(key, value);
382 errCode = ConvertCJErrCode(status);
383 if (errCode != 0) {
384 return ValueType{0};
385 }
386 return KVValueToValueType(value);
387 }
388
Backup(const std::string & file)389 int32_t CJSingleKVStore::Backup(const std::string &file)
390 {
391 Status status = kvStore_->Backup(file, param_->baseDir);
392 return ConvertCJErrCode(status);
393 }
394
Restore(const std::string & file)395 int32_t CJSingleKVStore::Restore(const std::string &file)
396 {
397 Status status = kvStore_->Restore(file, param_->baseDir);
398 return ConvertCJErrCode(status);
399 }
400
StartTransaction()401 int32_t CJSingleKVStore::StartTransaction()
402 {
403 Status status = kvStore_->StartTransaction();
404 return ConvertCJErrCode(status);
405 }
406
Commit()407 int32_t CJSingleKVStore::Commit()
408 {
409 Status status = kvStore_->Commit();
410 return ConvertCJErrCode(status);
411 }
412
Rollback()413 int32_t CJSingleKVStore::Rollback()
414 {
415 Status status = kvStore_->Rollback();
416 return ConvertCJErrCode(status);
417 }
418
EnableSync(bool enabled)419 int32_t CJSingleKVStore::EnableSync(bool enabled)
420 {
421 Status status = kvStore_->SetCapabilityEnabled(enabled);
422 return ConvertCJErrCode(status);
423 }
424
SetSyncParam(uint32_t defaultAllowedDelayMs)425 int32_t CJSingleKVStore::SetSyncParam(uint32_t defaultAllowedDelayMs)
426 {
427 KvSyncParam syncParam { defaultAllowedDelayMs };
428 Status status = kvStore_->SetSyncParam(syncParam);
429 return ConvertCJErrCode(status);
430 }
431
432 constexpr int DEVICEID_WIDTH = 4;
433
GetDeviceKey(const std::string & deviceId,const std::string & key)434 static std::string GetDeviceKey(const std::string& deviceId, const std::string& key)
435 {
436 std::ostringstream oss;
437 if (!deviceId.empty()) {
438 oss << std::setfill('0') << std::setw(DEVICEID_WIDTH) << deviceId.length() << deviceId;
439 }
440 oss << key;
441 return oss.str();
442 }
443
CJDeviceKVStore(const std::string & storeId)444 CJDeviceKVStore::CJDeviceKVStore(const std::string& storeId)
445 : CJSingleKVStore(storeId)
446 {
447 }
448
Get(const std::string & deviceId,const std::string & key,int32_t & errCode)449 ValueType CJDeviceKVStore::Get(const std::string &deviceId, const std::string &key, int32_t& errCode)
450 {
451 std::string deviceKey = GetDeviceKey(deviceId, key);
452 auto s_key = DistributedKv::Key(deviceKey);
453 OHOS::DistributedKv::Value value;
454 Status status = GetKvStorePtr()->Get(key, value);
455 errCode = ConvertCJErrCode(status);
456 if (errCode != 0) {
457 return ValueType{0};
458 }
459 return KVValueToValueType(value);
460 }
461
GetEntriesByDataQuery(DistributedKVStore::DataQuery dataQuery,int32_t & errCode)462 CArrEntry CJDeviceKVStore::GetEntriesByDataQuery(DistributedKVStore::DataQuery dataQuery, int32_t& errCode)
463 {
464 std::vector<DistributedKVStore::Entry> entries;
465 Status status = GetKvStorePtr()->GetEntries(dataQuery, entries);
466 errCode = ConvertCJErrCode(status);
467 if (errCode != 0) {
468 return CArrEntry{};
469 }
470 CEntry *cEntries = static_cast<CEntry*>(malloc(entries.size() * sizeof(CEntry)));
471 if (cEntries == nullptr) {
472 errCode = -1;
473 return CArrEntry{};
474 }
475 for (size_t i = 0; i < entries.size(); i++) {
476 cEntries[i].key = MallocCString(entries[i].key.ToString());
477 cEntries[i].value = KVValueToValueType(entries[i].value);
478 }
479 return CArrEntry{.head = cEntries, .size = int64_t(entries.size())};
480 }
481
GetEntries(const std::string & deviceId,const std::string & keyPrefix,int32_t & errCode)482 CArrEntry CJDeviceKVStore::GetEntries(const std::string &deviceId, const std::string &keyPrefix, int32_t& errCode)
483 {
484 DistributedKVStore::DataQuery dataQuery;
485 dataQuery.KeyPrefix(keyPrefix);
486 dataQuery.DeviceId(deviceId);
487
488 return GetEntriesByDataQuery(dataQuery, errCode);
489 }
490
GetEntries(const std::string & deviceId,OHOS::sptr<CQuery> query,int32_t & errCode)491 CArrEntry CJDeviceKVStore::GetEntries(const std::string &deviceId, OHOS::sptr<CQuery> query, int32_t& errCode)
492 {
493 DistributedKVStore::DataQuery dataQuery = query->GetDataQuery();
494 dataQuery.DeviceId(deviceId);
495
496 return GetEntriesByDataQuery(dataQuery, errCode);
497 }
498
GetResultSet(const std::string & deviceId,const std::string & keyPrefix,int32_t & errCode)499 int64_t CJDeviceKVStore::GetResultSet(const std::string &deviceId, const std::string &keyPrefix, int32_t& errCode)
500 {
501 DistributedKVStore::DataQuery dataQuery;
502 dataQuery.KeyPrefix(keyPrefix);
503 dataQuery.DeviceId(deviceId);
504
505 std::shared_ptr<DistributedKv::KvStoreResultSet> kvResultSet;
506 Status status = GetKvStorePtr()->GetResultSet(dataQuery, kvResultSet);
507 errCode = ConvertCJErrCode(status);
508 if (errCode != 0) {
509 return -1;
510 }
511 auto nativeCKvStoreResultSet = FFIData::Create<OHOS::DistributedKVStore::CKvStoreResultSet>(kvResultSet);
512 if (nativeCKvStoreResultSet == nullptr) {
513 errCode = -1;
514 return -1;
515 }
516 return nativeCKvStoreResultSet->GetID();
517 }
518
GetResultSetQuery(const std::string & deviceId,OHOS::sptr<CQuery> query,int32_t & errCode)519 int64_t CJDeviceKVStore::GetResultSetQuery(const std::string &deviceId, OHOS::sptr<CQuery> query, int32_t& errCode)
520 {
521 DistributedKVStore::DataQuery dataQuery = query->GetDataQuery();
522 dataQuery.DeviceId(deviceId);
523
524 std::shared_ptr<DistributedKv::KvStoreResultSet> kvResultSet;
525 Status status = GetKvStorePtr()->GetResultSet(dataQuery, kvResultSet);
526 errCode = ConvertCJErrCode(status);
527 if (errCode != 0) {
528 return -1;
529 }
530 auto nativeCKvStoreResultSet = FFIData::Create<OHOS::DistributedKVStore::CKvStoreResultSet>(kvResultSet);
531 if (nativeCKvStoreResultSet == nullptr) {
532 errCode = -1;
533 return -1;
534 }
535 return nativeCKvStoreResultSet->GetID();
536 }
537
GetResultSize(const std::string & deviceId,OHOS::sptr<CQuery> query,int32_t & errCode)538 int32_t CJDeviceKVStore::GetResultSize(const std::string &deviceId, OHOS::sptr<CQuery> query, int32_t& errCode)
539 {
540 DistributedKVStore::DataQuery dataQuery = query->GetDataQuery();
541 dataQuery.DeviceId(deviceId);
542
543 int32_t resultSize = 0;
544 Status status = GetKvStorePtr()->GetCount(dataQuery, resultSize);
545 errCode = ConvertCJErrCode(status);
546 return resultSize;
547 }
548
CKvStoreResultSet(std::shared_ptr<DistributedKv::KvStoreResultSet> cKvResultSet)549 CKvStoreResultSet::CKvStoreResultSet(std::shared_ptr<DistributedKv::KvStoreResultSet> cKvResultSet)
550 {
551 kvResultSet = cKvResultSet;
552 }
553
GetKvStoreResultSet()554 std::shared_ptr<DistributedKv::KvStoreResultSet> CKvStoreResultSet::GetKvStoreResultSet()
555 {
556 return kvResultSet;
557 }
558
GetCount()559 int32_t CKvStoreResultSet::GetCount()
560 {
561 return kvResultSet->GetCount();
562 }
563
GetDataQuery() const564 const DistributedKv::DataQuery& CQuery::GetDataQuery() const
565 {
566 return query_;
567 }
568
Reset()569 void CQuery::Reset()
570 {
571 query_.Reset();
572 }
573
EqualTo(const std::string & field,ValueType & value)574 void CQuery::EqualTo(const std::string &field, ValueType &value)
575 {
576 switch (value.tag) {
577 case STRING: {
578 query_.EqualTo(field, value.string);
579 break;
580 }
581 case INTEGER: {
582 query_.EqualTo(field, value.integer);
583 break;
584 }
585 case FLOAT: {
586 query_.EqualTo(field, value.flo);
587 break;
588 }
589 case BOOLEAN: {
590 query_.EqualTo(field, value.boolean);
591 break;
592 }
593 case DOUBLE: {
594 query_.EqualTo(field, value.dou);
595 break;
596 }
597 default: {
598 break;
599 }
600 }
601 }
602 }
603