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