• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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