diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/json_common.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/json_common.h index 7c0f0456d8f747dbaf9e74e51f0677ed35bc50c8..4494f01e9c1e5d8031e924a67ff0428a36303b34 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/json_common.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/json_common.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "json_object.h" namespace DocumentDB { @@ -28,17 +29,19 @@ public: JsonCommon() = default; ~JsonCommon(); - static ResultValue GetValueByFiled(JsonObject *node, const std::string& filed); - static bool CheckJsonField(const std::string &data); - static int ParseNode(JsonObject *Node, std::vector singlePath, std::vector> &resultPath, bool isFirstFloor); - static std::vector> ParsePath(const JsonObject* const node); - static std::vector GetLeafValue(JsonObject *node); + static ValueObject GetValueByFiled(JsonObject &node, const std::string& filed); + static bool CheckJsonField(JsonObject &node); + static bool CheckProjectionField(JsonObject &node); + static int ParseNode(JsonObject &Node, std::vector singlePath, std::vector> &resultPath, bool isFirstFloor); + static std::vector> ParsePath(const JsonObject &node); + static std::vector GetLeafValue(JsonObject &node); static int Append(const JsonObject &src, const JsonObject &add); - + private: - static bool CheckNode(JsonObject *Node, std::set filedSet, bool &errFlag); - static int CheckLeafNode(JsonObject *Node, std::vector &leafValue); + static bool CheckNode(JsonObject &Node, std::set filedSet, bool &errFlag); + static bool CheckProjectionNode(JsonObject &Node, std::set filedSet, bool &errFlag, bool isFirstFloor); + static int CheckLeafNode(JsonObject &Node, std::vector &leafValue); }; } // DocumentDB #endif // JSON_COMMON_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/json_common.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/json_common.cpp index 46370a61ce659220fb023798de5b7996c129113a..47a75e9c19df9005c94aa216b17228b2be4fd734 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/json_common.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/json_common.cpp @@ -21,100 +21,158 @@ #include "securec.h" namespace DocumentDB { -ResultValue JsonCommon::GetValueByFiled(JsonObject *node, const std::string& filed) +ValueObject JsonCommon::GetValueByFiled(JsonObject &node, const std::string& filed) { - if (node == nullptr) { - return ResultValue(); - } - while (node != nullptr) { - if (node->GetItemFiled() == filed) { - auto itemValue = node->GetItemValue(); + while (!node.IsNull()) { + if (node.GetItemFiled() == filed) { + auto itemValue = node.GetItemValue(); return itemValue; } - if (node->GetNext().IsNull() == true) { - return ResultValue(); + if (node.GetNext().IsNull()) { + return ValueObject(); } - auto nodeNew = node->GetNext(); - node = &nodeNew; + auto nodeNew = node.GetNext(); + node = nodeNew; } - return ResultValue(); + return ValueObject(); } -int JsonCommon::CheckLeafNode(JsonObject *node, std::vector &leafValue) +int JsonCommon::CheckLeafNode(JsonObject &node, std::vector &leafValue) { - if (node->GetChild().IsNull() == true) { - auto itemValue = node->GetItemValue(); + if (node.GetChild().IsNull()) { + auto itemValue = node.GetItemValue(); leafValue.emplace_back(itemValue); } - if (node->GetChild().IsNull() != true) { - auto nodeNew = node->GetChild(); - CheckLeafNode(&nodeNew, leafValue); + if (!node.GetChild().IsNull()) { + auto nodeNew = node.GetChild(); + CheckLeafNode(nodeNew, leafValue); } - if (node->GetNext().IsNull() != true) { - auto nodeNew = node->GetNext(); - CheckLeafNode(&nodeNew, leafValue); + if (!node.GetNext().IsNull()) { + auto nodeNew = node.GetNext(); + CheckLeafNode(nodeNew, leafValue); } return E_OK; } -std::vector JsonCommon::GetLeafValue(JsonObject *node) +std::vector JsonCommon::GetLeafValue(JsonObject &node) { - std::vector leafValue; + std::vector leafValue; CheckLeafNode(node, leafValue); return leafValue; } -bool JsonCommon::CheckNode(JsonObject *node, std::set filedSet, bool &errFlag) { - if (errFlag == false) { +bool JsonCommon::CheckNode(JsonObject &node, std::set filedSet, bool &errFlag) +{ + if (!errFlag) { return false; } - std::string fieldName; - if (node->GetItemValue().GetValueType() != ResultValue::ValueType::VALUE_NULL) { - fieldName = node->GetItemFiled(); + std::string fieldName; + if (!node.IsNull()) { + int ret = 0; + fieldName = node.GetItemFiled(ret); if (filedSet.find(fieldName) == filedSet.end()) { - filedSet.insert(fieldName); + if (ret == E_OK) { + filedSet.insert(fieldName); + } + if (ret == E_OK && fieldName.empty()) { + errFlag = false; + return false; + } } else { errFlag = false; return false; } for (int i = 0; i < fieldName.size(); i++) { - if (!(('a'<=fieldName[i] && fieldName[i]<='z')|| ('A'<=fieldName[i] && fieldName[i]<='Z') || ('0'<=fieldName[i] && fieldName[i]<='9') || '_' == fieldName[i])) { + if (!((isalpha(fieldName[i])) || (isdigit(fieldName[i])) || '_' == fieldName[i])) { errFlag = false; return false; } - } + if (i == 0 && (isdigit(fieldName[i]))) { + errFlag = false; + return false; + } + } } - if (node->GetChild().IsNull() != true) { - auto nodeNew = node->GetChild(); + if (!node.GetChild().IsNull()) { + auto nodeNew = node.GetChild(); std::set newFiledSet; - CheckNode(&nodeNew, newFiledSet, errFlag); + CheckNode(nodeNew, newFiledSet, errFlag); } - if (node->GetNext().IsNull() != true) { - auto nodeNew = node->GetNext(); - CheckNode(&nodeNew, filedSet, errFlag); + if (!node.GetNext().IsNull()) { + auto nodeNew = node.GetNext(); + CheckNode(nodeNew, filedSet, errFlag); } return errFlag; } -bool JsonCommon::CheckJsonField(const std::string &data) { - int errCode = E_OK; - JsonObject jsonObj = JsonObject::Parse(data, errCode); - if (errCode != E_OK) { +bool JsonCommon::CheckJsonField(JsonObject &jsonObj) +{ + std::set filedSet; + bool errFlag = true; + return CheckNode(jsonObj, filedSet, errFlag); +} + +bool JsonCommon::CheckProjectionNode(JsonObject &node, std::set filedSet, bool &errFlag, bool isFirstFloor) +{ + if (!errFlag) { return false; } + std::string fieldName; + if (!node.IsNull()) { + int ret = 0; + fieldName = node.GetItemFiled(ret); + if (filedSet.find(fieldName) == filedSet.end()) { + if (ret == E_OK) { + filedSet.insert(fieldName); + } + if (ret == E_OK && fieldName.empty()) { + errFlag = false; + return false; + } + } + else { + errFlag = false; + return false; + } + for (int i = 0; i < fieldName.size(); i++) { + if (!((isalpha(fieldName[i])) || (isdigit(fieldName[i])) || ('_' == fieldName[i]) || (isFirstFloor && '.' == fieldName[i]))) { + errFlag = false; + return false; + } + if (i == 0 && (isdigit(fieldName[i]))) { + errFlag = false; + return false; + } + } + } + if (!node.GetChild().IsNull()) { + auto nodeNew = node.GetChild(); + std::set newFiledSet; + CheckProjectionNode(nodeNew, newFiledSet, errFlag, false); + } + if (!node.GetNext().IsNull()) { + auto nodeNew = node.GetNext(); + CheckProjectionNode(nodeNew, filedSet, errFlag, isFirstFloor); + } + return errFlag; +} + +bool JsonCommon::CheckProjectionField(JsonObject &jsonObj) +{ std::set filedSet; bool errFlag = true; - return CheckNode(&jsonObj, filedSet, errFlag); + bool isFirstFloor = true; + return CheckProjectionNode(jsonObj, filedSet, errFlag, isFirstFloor); } -int JsonCommon::ParseNode(JsonObject* node, std::vector singlePath, std::vector> &resultPath, bool isFirstFloor) +int JsonCommon::ParseNode(JsonObject &node, std::vector singlePath, std::vector> &resultPath, bool isFirstFloor) { std::vector fatherPath; if (isFirstFloor) { std::string tempParseName; std::vector allFiledsName; - std::string priFieldName = node->GetItemFiled(); + std::string priFieldName = node.GetItemFiled(); for (int j = 0; j < priFieldName.size(); j++) { if (priFieldName[j] != '.') { tempParseName = tempParseName + priFieldName[j]; @@ -128,33 +186,33 @@ int JsonCommon::ParseNode(JsonObject* node, std::vector singlePath, singlePath.insert(singlePath.end(), allFiledsName.begin(), allFiledsName.end()); } else { std::vector allFiledsName; - allFiledsName.emplace_back(node->GetItemFiled()); + allFiledsName.emplace_back(node.GetItemFiled()); fatherPath = singlePath; singlePath.insert(singlePath.end(), allFiledsName.begin(), allFiledsName.end()); } - if (node->GetChild().IsNull() != true && node->GetChild().GetItemFiled() != "") { - auto nodeNew = node->GetChild(); - ParseNode(&nodeNew, singlePath, resultPath, false); + if (!node.GetChild().IsNull() && node.GetChild().GetItemFiled() != "") { + auto nodeNew = node.GetChild(); + ParseNode(nodeNew, singlePath, resultPath, false); } else { resultPath.emplace_back(singlePath); } - if (node->GetNext().IsNull() != true) { - auto nodeNew = node->GetNext(); - ParseNode(&nodeNew, fatherPath, resultPath, isFirstFloor); + if (!node.GetNext().IsNull()) { + auto nodeNew = node.GetNext(); + ParseNode(nodeNew, fatherPath, resultPath, isFirstFloor); } return 0; } -std::vector> JsonCommon::ParsePath(const JsonObject* const root) +std::vector> JsonCommon::ParsePath(const JsonObject &root) { std::vector> resultPath; - auto projectionJson = root->GetChild(); - if (projectionJson.IsNull() == true) { + auto projectionJson = root.GetChild(); + if (projectionJson.IsNull()) { GLOGE("projectionJson is null"); } std::vector singlePath; - ParseNode(&projectionJson, singlePath, resultPath, true); + ParseNode(projectionJson, singlePath, resultPath, true); return resultPath; } @@ -228,7 +286,7 @@ int JsonCommon::Append(const JsonObject &src, const JsonObject &add) } return true; // Both array or object } else { - if (isCollapse == true) { + if (isCollapse) { GLOGE("Add collapse item to object failed, path not exist."); externErrCode = -E_DATA_CONFLICT; return false; diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/base/grd_db_api.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/base/grd_db_api.cpp index e6c954e339ba961dc628a31631de76c587d56ab8..a60e53f46fb3c4495fb77797c5adfa0650d0714a 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/base/grd_db_api.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/base/grd_db_api.cpp @@ -17,10 +17,9 @@ #include "doc_errno.h" #include "document_store_manager.h" -#include "document_store.h" #include "grd_base/grd_error.h" -#include "grd_type_inner.h" #include "log_print.h" +#include "grd_type_inner.h" using namespace DocumentDB; diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/doc_common.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.cpp similarity index 42% rename from services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/doc_common.cpp rename to services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.cpp index a3dc9d963f69671df8d8fdc44e5a15b26c16ebcd..e8370c8d4435ebfc89b26718fb247078783a09af 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/src/doc_common.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.cpp @@ -15,16 +15,19 @@ #include #include -#include "doc_common.h" +#include "document_check.h" #include "doc_errno.h" #include "log_print.h" #include "securec.h" namespace DocumentDB { namespace { +constexpr const char *KEY_ID = "_id"; constexpr const char *COLLECTION_PREFIX_GRD = "GRD_"; constexpr const char *COLLECTION_PREFIX_GM_SYS = "GM_SYS_"; -const int MAX_COLLECTION_NAME = 512; +const int MAX_COLLECTION_NAME = 511; +const int MAX_ID_LENS = 899; +const int JSON_DEEP_MAX = 4; bool CheckCollectionNamePrefix(const std::string &name, const std::string &prefix) { @@ -51,16 +54,16 @@ bool CheckCommon::CheckCollectionName(const std::string &collectionName, std::st errCode = -E_INVALID_ARGS; return false; } - if (collectionName.length() + 1 > MAX_COLLECTION_NAME) { + if (collectionName.length() > MAX_COLLECTION_NAME) { errCode = -E_OVER_LIMIT; return false; } if (CheckCollectionNamePrefix(collectionName, COLLECTION_PREFIX_GRD) || CheckCollectionNamePrefix(collectionName, COLLECTION_PREFIX_GM_SYS)) { + GLOGE("Collection name is illegal"); errCode = -E_INVALID_COLL_NAME_FORMAT; return false; } - lowerCaseName = collectionName; std::transform(lowerCaseName.begin(), lowerCaseName.end(), lowerCaseName.begin(), [](unsigned char c){ return std::tolower(c); @@ -68,33 +71,82 @@ bool CheckCommon::CheckCollectionName(const std::string &collectionName, std::st return true; } -bool CheckCommon::CheckFilter(const std::string &filter) +int CheckCommon::CheckFilter(JsonObject &filterObj) +{ + if (filterObj.GetDeep() > JSON_DEEP_MAX) { + GLOGE("filter's json deep is deeper than JSON_DEEP_MAX"); + return -E_INVALID_ARGS; + } + int ret = CheckIdFormat(filterObj); + if (ret != E_OK) { + GLOGE("Filter Id format is illegal"); + return ret; + } + if (!filterObj.GetChild().GetNext().IsNull()) { + return -E_INVALID_ARGS; + } + return E_OK; +} + +int CheckCommon::CheckIdFormat(JsonObject &filterJson) { - // if (JsonCommon::CheckIsJson(filter) == false) { - // return false; - // } - // if (JsonCommon::GetJsonDeep(filter) > 4) { - // return false; - // } - // if (CheckIdFormat(filter) == false) { - // return false; - // } - return true; + auto filterObjChild = filterJson.GetChild(); + auto idValue = JsonCommon::GetValueByFiled(filterObjChild, KEY_ID); + if (idValue.GetValueType() != ValueObject::ValueType::VALUE_STRING) { + return -E_INVALID_ARGS; + } + if (idValue.GetStringValue().length() > MAX_ID_LENS) { + return -E_OVER_LIMIT; + } + return E_OK; } -bool CheckCommon::CheckIdFormat(const std::string &data) +int CheckCommon::CheckDocument(JsonObject &documentObj) { - // CjsonObject filter_json; - // filter_json.Parse(data); - // std::vector id; - // if (JsonCommon::GetIdValue(&filter_json, id) == E_ERROR) { - // return false; - // } - return true; + if (documentObj.GetDeep() > JSON_DEEP_MAX) { + GLOGE("documentObj's json deep is deeper than JSON_DEEP_MAX"); + return -E_INVALID_ARGS; + } + int ret = CheckIdFormat(documentObj); + if (ret != E_OK) { + GLOGE("Document Id format is illegal"); + return ret; + } + if (!documentObj.GetChild().IsNull()) { + auto documentObjChild = documentObj.GetChild(); + if (!JsonCommon::CheckJsonField(documentObjChild)) { + GLOGE("Document json field format is illegal"); + return -E_INVALID_ARGS; + } + } + return E_OK; } -bool CheckCommon::CheckDocument(const std::string &document) +bool CheckCommon::CheckProjection(JsonObject &projectionObj, std::vector> &path) { + if (projectionObj.GetDeep() > JSON_DEEP_MAX) { + GLOGE("projectionObj's json deep is deeper than JSON_DEEP_MAX"); + return -E_INVALID_ARGS; + } + if (!projectionObj.GetChild().IsNull()) { + auto projectionObjChild = projectionObj.GetChild(); + if (!JsonCommon::CheckProjectionField(projectionObjChild)) { + GLOGE("projection json field format is illegal"); + return false; + } + } + for (int i = 0; i < path.size(); i++) { + for (auto fieldName : path[i]) { + for (int i = 0; i < fieldName.size(); i++) { + if (!((isalpha(fieldName[i])) || (isdigit(fieldName[i])) || ('_' == fieldName[i]))) { + return false; + } + if (i == 0 && (isdigit(fieldName[i]))) { + return false; + } + } + } + } return true; } } // namespace DocumentDB \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/doc_common.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.h similarity index 75% rename from services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/doc_common.h rename to services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.h index a0ebfaee4eedf370bc1e0542abcc15279c08e6ab..57769260990a02f236848048ba1e417f175ef46d 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/common/include/doc_common.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/document_check.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef DOC_COMMON_H -#define DOC_COMMON_H +#ifndef DOCUMENT_CHECK_H +#define DOCUMENT_CHECK_H #include #include @@ -29,13 +29,14 @@ public: ~CheckCommon() = default; static bool CheckCollectionName(const std::string &collectionName, std::string &lowerCaseName, int &errCode); - static bool CheckFilter(const std::string &filter); - static bool CheckIdFormat(const std::string &data); - static bool CheckDocument(const std::string &document); + static int CheckFilter(JsonObject &document); + static int CheckIdFormat(JsonObject &data); + static int CheckDocument(JsonObject &document); + static bool CheckProjection(JsonObject &projectionObj, std::vector> &path); }; using Key = std::vector; using Value = std::vector; constexpr const char *COLL_PREFIX = "GRD_COLL_"; } // DocumentDB -#endif // DOC_COMMON_H \ No newline at end of file +#endif // DOCUMENT_CHECK_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_document_api.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_document_api.cpp index 61f50633eb9f8452b0624bb6a4641330316f9288..58ac1f5a9b69547e8d37ce049c3f4a0a950892a6 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_document_api.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_document_api.cpp @@ -16,6 +16,7 @@ #include "grd_document/grd_document_api.h" #include "grd_base/grd_error.h" #include "grd_type_inner.h" +#include "grd_resultset_inner.h" #include "log_print.h" using namespace DocumentDB; @@ -67,3 +68,59 @@ int GRD_UpSertDoc(GRD_DB *db, const char *collectionName, const char *filter, co int ret = db->store_->UpsertDocument(name, filterStr, documentStr, flags); return TrasnferDocErr(ret); } + +int GRD_InsertDoc(GRD_DB *db, const char *collectionName, const char *document, unsigned int flags) +{ + if (db == nullptr || db->store_ == nullptr || collectionName == nullptr || document == nullptr) { + return GRD_INVALID_ARGS; + } + int ret = db->store_->InsertDocument(collectionName, document, flags); + return TrasnferDocErr(ret); +} + +int GRD_DeleteDoc(GRD_DB *db, const char *collectionName, const char *filter, unsigned int flags) +{ + if (db == nullptr || db->store_ == nullptr || filter == nullptr || collectionName == nullptr) { + return GRD_INVALID_ARGS; + } + int ret = db->store_->DeleteDocument(collectionName, filter, flags); + int errCode = TrasnferDocErr(ret); + int deleteCount = 0; + switch (errCode) { + case GRD_OK: + deleteCount = 1; + return deleteCount; + break; + case GRD_NO_DATA: + deleteCount = 0; + return deleteCount; + break; + } + return errCode; +} + +int GRD_FindDoc(GRD_DB *db, const char *collectionName, Query query, unsigned int flags, GRD_ResultSet **resultSet) +{ + if (db == nullptr || db->store_ == nullptr || collectionName == nullptr || resultSet == nullptr || query.filter == nullptr + || query.projection == nullptr) { + return GRD_INVALID_ARGS; + } + GRD_ResultSet *grdResultSet = new (std::nothrow)GRD_ResultSet(); + if (grdResultSet == nullptr) { + GLOGE("Memory allocation failed!" ); + return -E_FAILED_MEMORY_ALLOCATE; + } + int ret = db->store_->FindDocument(collectionName, query.filter, query.projection, flags, grdResultSet); + if (ret != E_OK) { + delete grdResultSet; + *resultSet = nullptr; + return TrasnferDocErr(ret); + } + *resultSet = grdResultSet; + return TrasnferDocErr(ret); +} + +int GRD_Flush(GRD_DB *db, unsigned int flags) +{ + return GRD_OK; +} \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_resultset_api.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_resultset_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6db93e850e6fc3ed641f9e9e35d34de8d18e7104 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/document/grd_resultset_api.cpp @@ -0,0 +1,71 @@ +/* +* Copyright (c) 2023 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. +*/ +#include + +#include "grd_base/grd_error.h" +#include "doc_errno.h" +#include "grd_base/grd_error.h" +#include "grd_resultset_inner.h" +#include "grd_base/grd_resultset_api.h" +#include "log_print.h" + +using namespace DocumentDB; + +int GRD_Next(GRD_ResultSet *resultSet) +{ + if (resultSet == nullptr) { + GLOGE("resultSet is nullptr"); + return GRD_INVALID_ARGS; + }; + std::mutex dbMutex; + std::lock_guard lock(dbMutex); + int ret = resultSet->resultSet_.GetNext(); + return TrasnferDocErr(ret); +} + +int GRD_GetValue(GRD_ResultSet *resultSet, char **value) +{ + if (resultSet == nullptr) { + GLOGE("resultSet is nullptr,cant get value from it"); + return GRD_INVALID_ARGS; + }; + char *val = nullptr; + int ret = resultSet->resultSet_.GetValue(&val); + if (val == nullptr) { + GLOGE("Value that get from resultSet is nullptr"); + return GRD_NOT_AVAILABLE; + } + *value = val; + return TrasnferDocErr(ret); +} + +int GRD_FreeValue(char *value) +{ + if (value == nullptr) { + return GRD_OK; + } + delete[] value; + return GRD_OK; +} + +int GRD_FreeResultSet(GRD_ResultSet *resultSet) +{ + if (resultSet == nullptr) { + return GRD_INVALID_ARGS; + } + resultSet->resultSet_.EraseCollection(); + delete resultSet; + return GRD_OK; +} \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_format_config.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_format_config.h new file mode 100644 index 0000000000000000000000000000000000000000..06e7bbeea54dae8f45f6899cac23bb9d0e5c92dc --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_format_config.h @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2023 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 GRD_FORMAT_CONFIG_H +#define GRD_FORMAT_CONFIG_H + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define COLLECTION_LENS_MAX (512 * 1024) +#define JSON_LENS_MAX (512 * 1024) +#define JSON_DEEP_MAX (4) +#define KEY_ID ("_id") + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // GRD_FORMAT_CONFIG_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_resultset_inner.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_resultset_inner.h new file mode 100644 index 0000000000000000000000000000000000000000..d840ad79370a4cca20b76e5ed877aadde6d1eda8 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/executor/include/grd_resultset_inner.h @@ -0,0 +1,26 @@ +/* +* Copyright (c) 2023 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 GRD_RESULTSET_INNER_H +#define GRD_RESULTSET_INNER_H + +#include "doc_errno.h" +#include "grd_base/grd_error.h" +#include "result_set.h" + +typedef struct GRD_ResultSet { + DocumentDB::ResultSet resultSet_; +} GRD_ResultSet; +#endif // GRD_RESULTSET_INNER_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/collection.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/collection.h index b71feaae45a66196a305e3cc6e8e11800b8f0c2d..602ca359a09bbc3e64f006ad4362e63e1fe7945d 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/collection.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/collection.h @@ -17,21 +17,24 @@ #define COLLECTION_H #include -#include "doc_common.h" +#include "document_check.h" #include "kv_store_executor.h" namespace DocumentDB { class Collection { public: Collection(const std::string &name, KvStoreExecutor *executor); + Collection(const Collection &a) {}; + Collection() {}; ~Collection(); int PutDocument(const Key &key, const Value &document); int GetDocument(const Key &key, Value &document) const; int DeleteDocument(const Key &key); - int UpsertDocument(const std::string &id, const std::string &document, bool isReplace = true); int UpdateDocument(const Key &key, Value &update); + bool FindDocument(); + private: std::string name_; KvStoreExecutor *executor_ = nullptr; diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/doc_errno.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/doc_errno.h index 6c80c6936da3636e0126063426aa8debea05bf28..6f159683b4aa4939307949173f8e37a83b1e4e37 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/doc_errno.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/doc_errno.h @@ -36,6 +36,8 @@ constexpr int E_DATA_CONFLICT = E_BASE + 18; constexpr int E_INVALID_COLL_NAME_FORMAT = E_BASE + 18; constexpr int E_INVALID_JSON_FORMAT = E_BASE + 40; constexpr int E_JSON_PATH_NOT_EXISTS = E_BASE + 41; +constexpr int E_RESOURCE_BUSY = E_BASE + 50; +constexpr int E_FAILED_MEMORY_ALLOCATE = E_BASE + 51; int TrasnferDocErr(int err); } // DocumentDB diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/document_store.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/document_store.h index b1fa3c39ae693e125d3fb8c846ba299d82f953b8..0e06db1f181c058b2e8352fa93232ca95fad801e 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/document_store.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/document_store.h @@ -20,9 +20,10 @@ #include #include -#include "collection.h" #include "kv_store_executor.h" +#include "collection.h" +class GRD_ResultSet; namespace DocumentDB { class DocumentStore { public: @@ -34,12 +35,16 @@ public: int UpdateDocument(const std::string &collection, const std::string &filter, const std::string &update, int flag); int UpsertDocument(const std::string &collection, const std::string &filter, const std::string &document, int flags); - + int InsertDocument(const std::string &collection, const std::string &document, int flag); + int DeleteDocument(const std::string &collection, const std::string &filter, int flag); + int FindDocument(const std::string &collection, const std::string &filter, const std::string &projection, int flags, GRD_ResultSet *grdResultSet); + KvStoreExecutor *GetExecutor(int errCode); + int EraseCollection(const std::string collectionName); private: + int GetViewType(JsonObject &jsonObj, bool &viewType); std::mutex dbMutex_; - KvStoreExecutor *executor_ = nullptr; - std::map collections_; + std::map collections_; }; } // DocumentDB #endif // DOCUMENT_STORE_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/projection_tree.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/projection_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..15920bd41d178faff1529555bbba0bede7e6e581 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/projection_tree.h @@ -0,0 +1,37 @@ +#ifndef PROJECTION_TREE_H +#define PROJECTION_TREE_H + +#include +#include +#include +#include "doc_errno.h" +#include "json_common.h" +#include "log_print.h" + +namespace DocumentDB { +struct ProjectionNode { + std::unordered_map SonNode; + bool isDeepest; + int Deep; + int ViewType; + ProjectionNode() { + Deep = 0; + isDeepest = true; + } + int DeleteProjectionNode(); + ~ProjectionNode () { + DeleteProjectionNode(); + } +}; +class ProjectionTree { +public: + ProjectionTree(); + ~ProjectionTree(); + + int ParseTree(std::vector> &path); + bool SearchTree(std::vector &singlePath, int &index); +private: + ProjectionNode node_; +}; +} // DocumentDB +#endif // PROJECTION_TREE_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set.h new file mode 100644 index 0000000000000000000000000000000000000000..dc87115e27b6e9fcdf544c3fea5d0e831f73e130 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set.h @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2023 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 RESULTSET_H +#define RESULTSET_H + +#include +#include "grd_base/grd_type_export.h" +#include "projection_tree.h" +#include "vector" +#include "doc_errno.h" +#include "json_object.h" +#include "securec.h" +#include "document_check.h" +#include "document_store.h" + +namespace DocumentDB { +class ResultSet { +public: + ResultSet(); + ~ResultSet(); + + int Init(DocumentStore *store, const std::string collectionName, ValueObject &key, std::vector> &path, bool ifShowId, bool viewType); + int GetNext(); + int GetValue(char **value); + int EraseCollection(); +private: + int CutJsonBranch(std::string &jsonData); + int CheckCutNode(JsonObject *node, std::vector singleCutPath, std::vector> &allCutPath); + DocumentStore *store_ = nullptr; + std::string collectionName_; + ValueObject key_; + bool ifShowId_ = false; + bool viewType_ = false; + ProjectionTree projectionTree_; + std::vector> projectionPath_; + int index_ = 0; + std::vector findValue_; +}; +} // DocumentDB +#endif //RESULTSET_H \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set_common.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set_common.h new file mode 100644 index 0000000000000000000000000000000000000000..dfef9c26d88b963d3204ad1f03e0fefafd8278a6 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/include/result_set_common.h @@ -0,0 +1,31 @@ +/* +* Copyright (c) 2023 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 RESULTSET_COMMON_H +#define RESULTSET_COMMON_H + +#include +#include "grd_base/grd_type_export.h" +#include "vector" +#include "doc_errno.h" +#include "result_set.h" + +namespace DocumentDB { +class ValueObject; +int InitResultSet(DocumentStore *store, const std::string collectionName, ValueObject &key, std::vector> &path, bool ifShowId, bool viewType, + ResultSet &resultSet); +} // DocumentDB +#endif //RESULTSET_COMMON_H + diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/collection.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/collection.cpp index d04eb8022ac7fb77f4fb400d1fe0eca2251340d4..e76a2239a8f95d77843bef6ea70eb05cca8c0e68 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/collection.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/collection.cpp @@ -17,7 +17,7 @@ #include -#include "doc_common.h" +#include "document_check.h" #include "doc_errno.h" #include "log_print.h" @@ -44,14 +44,29 @@ int Collection::PutDocument(const Key &key, const Value &document) return executor_->PutData(name_, key, document); } +bool Collection::FindDocument() +{ + if (executor_ == nullptr) { + return -E_INVALID_ARGS; + } + int errCode = 0; + return executor_->IsCollectionExists(name_, errCode); +} + int Collection::GetDocument(const Key &key, Value &document) const { - return E_OK; + if (executor_ == nullptr) { + return -E_INVALID_ARGS; + } + return executor_->GetData(name_, key, document); } int Collection::DeleteDocument(const Key &key) { - return E_OK; + if (executor_ == nullptr) { + return -E_INVALID_ARGS; + } + return executor_->DelData(name_, key); } int Collection::UpsertDocument(const std::string &id, const std::string &document, bool isReplace) diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/doc_errno.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/doc_errno.cpp index 9cedce6ac0faa3c89e7949a3fb89f720e125aef3..24eaca7608808d242c49a3c52cc61b0242a609bd 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/doc_errno.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/doc_errno.cpp @@ -58,6 +58,12 @@ int TrasnferDocErr(int err) case -E_INVALID_COLL_NAME_FORMAT: outErr = GRD_INVALID_COLLECTION_NAME; break; + case -E_RESOURCE_BUSY: + outErr = GRD_RESOURCE_BUSY; + break; + case -E_FAILED_MEMORY_ALLOCATE: + outErr = GRD_FAILED_MEMORY_ALLOCATE; + break; default: outErr = GRD_INNER_ERR; break; diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store.cpp index 98b7031131e4c0706d89208885a9cea3b9b6dd72..67b2c2d4ca5a2373f8c7d233a66b342e70134a42 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store.cpp @@ -14,14 +14,21 @@ */ #include "document_store.h" - #include "collection_option.h" -#include "doc_common.h" +#include "document_check.h" #include "doc_errno.h" #include "grd_base/grd_type_export.h" #include "log_print.h" +#include "result_set_common.h" +#include "grd_resultset_inner.h" namespace DocumentDB { +const int COLLECTION_LENS_MAX = 512 * 1024; +const int JSON_LENS_MAX = 512 * 1024; +const int JSON_DEEP_MAX = 4; +constexpr const char *KEY_ID = "_id"; +const bool caseIsSensitive = true; + DocumentStore::DocumentStore(KvStoreExecutor *executor) : executor_(executor) { } @@ -138,4 +145,214 @@ int DocumentStore::UpsertDocument(const std::string &collection, const std::stri std::lock_guard lock(dbMutex_); return coll.UpsertDocument(docId, document, isReplace); } + +int DocumentStore::InsertDocument(const std::string &collection, const std::string &document, int flag) +{ + if (flag != 0) { + GLOGE("InsertDocument flag is not zero"); + return -E_INVALID_ARGS; + } + std::string lowerCaseCollName; + int errCode = E_OK; + if (!CheckCommon::CheckCollectionName(collection, lowerCaseCollName, errCode)) { + GLOGE("Check collection name invalid. %d", errCode); + return errCode; + } + auto coll = Collection(collection, executor_); + if (document.length() + 1 > JSON_LENS_MAX) { + GLOGE("document's length is larger than JSON_LENS_MAX"); + return -E_OVER_LIMIT; + } + JsonObject documentObj = JsonObject::Parse(document, errCode, caseIsSensitive); + if (errCode != E_OK) { + GLOGE("Document Parsed faild"); + return errCode; + } + errCode = CheckCommon::CheckDocument(documentObj); + if (errCode != E_OK) { + return errCode; + } + auto documentObjChild = documentObj.GetChild(); + auto idValue = JsonCommon::GetValueByFiled(documentObjChild, KEY_ID); + std::string id = idValue.GetStringValue(); + Key key(id.begin(), id.end()); + Value value(document.begin(), document.end()); + std::lock_guard lock(dbMutex_); + return coll.PutDocument(key, value); +} + +int DocumentStore::DeleteDocument(const std::string &collection, const std::string &filter, int flag) +{ + if (flag != 0) { + GLOGE("DeleteDocument flag is not zero"); + return -E_INVALID_ARGS; + } + std::string lowerCaseCollName; + int errCode = E_OK; + if (!CheckCommon::CheckCollectionName(collection, lowerCaseCollName, errCode)) { + GLOGE("Check collection name invalid. %d", errCode); + return errCode; + } + auto coll = Collection(collection, executor_); + if (filter.empty()) { + GLOGE("Filter is empty"); + return -E_INVALID_ARGS; + } + if (filter.length() + 1 > JSON_LENS_MAX) { + GLOGE("filter's length is larger than JSON_LENS_MAX"); + return -E_OVER_LIMIT; + } + JsonObject filterObj = JsonObject::Parse(filter, errCode, caseIsSensitive); + if (errCode != E_OK) { + GLOGE("filter Parsed faild"); + return errCode; + } + errCode = CheckCommon::CheckFilter(filterObj); + if (errCode != E_OK) { + return errCode; + } + auto filterObjChild = filterObj.GetChild(); + auto idValue = JsonCommon::GetValueByFiled(filterObjChild, KEY_ID); + std::string id = idValue.GetStringValue(); + Key key(id.begin(), id.end()); + std::lock_guard lock(dbMutex_); + return coll.DeleteDocument(key); +} +KvStoreExecutor *DocumentStore::GetExecutor(int errCode) +{ + return executor_; +} +int DocumentStore::FindDocument(const std::string &collection, const std::string &filter, const std::string &projection, + int flags, GRD_ResultSet *grdResultSet) +{ + if (flags != 0 && flags != GRD_DOC_ID_DISPLAY) { + GLOGE("FindDocument flag is illegal"); + return -E_INVALID_ARGS;; + } + std::string lowerCaseCollName; + int errCode = E_OK; + if (!CheckCommon::CheckCollectionName(collection, lowerCaseCollName, errCode)) { + GLOGE("Check collection name invalid. %d", errCode); + return errCode; + } + if (filter.length() + 1 > JSON_LENS_MAX) { + GLOGE("filter's length is larger than JSON_LENS_MAX"); + return -E_OVER_LIMIT; + } + JsonObject filterObj = JsonObject::Parse(filter, errCode, caseIsSensitive); + if (errCode != E_OK) { + GLOGE("filter Parsed faild"); + return errCode; + } + errCode = CheckCommon::CheckFilter(filterObj); + if (errCode != E_OK) { + return errCode; + } + auto filterObjChild = filterObj.GetChild(); + auto idValue = JsonCommon::GetValueByFiled(filterObjChild, KEY_ID); + if (projection.length() + 1 > JSON_LENS_MAX) { + GLOGE("projection's length is larger than JSON_LENS_MAX"); + return -E_OVER_LIMIT; + } + JsonObject projectionObj = JsonObject::Parse(projection, errCode, caseIsSensitive); + if (errCode != E_OK) { + GLOGE("projection Parsed faild"); + return errCode; + } + bool viewType = false; + std::vector> allPath; + if (projection != "{}") { + allPath = JsonCommon::ParsePath(projectionObj); + if (!CheckCommon::CheckProjection(projectionObj, allPath)) { + GLOGE("projection format unvalid"); + return -E_INVALID_ARGS; + } + if (GetViewType(projectionObj, viewType) != E_OK) { + GLOGE("GetViewType faild"); + return -E_INVALID_ARGS; + } + } + bool ifShowId = false; + if (flags == GRD_DOC_ID_DISPLAY) { + ifShowId = true; + } + if (collections_.find(collection) != collections_.end()) { + GLOGE("DB is resource busy"); + return -E_RESOURCE_BUSY; + } + auto coll = Collection(collection, executor_); + std::lock_guard lock(dbMutex_); + if (!coll.FindDocument()) { + GLOGE("no corresponding table name"); + return -E_INVALID_ARGS; + } + int ret = InitResultSet(this, collection, idValue, allPath, ifShowId, viewType, grdResultSet->resultSet_); + if (ret == E_OK) { + collections_[collection] = nullptr; + } + if (ret != E_OK) { + collections_.erase(collection); + } + return ret; +} +int DocumentStore::EraseCollection(const std::string collectionName) { + if (collections_.find(collectionName) != collections_.end()) { + collections_.erase(collectionName); + return E_OK; + } + GLOGE("erase collection failed"); +} +int DocumentStore::GetViewType(JsonObject &jsonObj, bool &viewType) { + auto leafValue = JsonCommon::GetLeafValue(jsonObj); + if (leafValue.size() == 0) { + return E_INVALID_ARGS; + } + bool viewFlag = false; + for (int i = 0; i < leafValue.size(); i++) { + switch (leafValue[i].GetValueType()) { + case ValueObject::ValueType::VALUE_BOOL: + if (leafValue[i].GetBoolValue()) { + if (i != 0 && !viewType) { + return -E_INVALID_ARGS; + } + viewType = true; + } + else { + if (i != 0 && viewType) { + return E_INVALID_ARGS; + } + viewType == false; + } + break; + case ValueObject::ValueType::VALUE_STRING: + if (leafValue[i].GetStringValue() == "") { + if (i != 0 && !viewType) { + return -E_INVALID_ARGS; + } + viewType = true; + } + else { + return -E_INVALID_ARGS; + } + break; + case ValueObject::ValueType::VALUE_NUMBER: + if (leafValue[i].GetIntValue() == 0) { + if (i != 0 && viewType) { + return -E_INVALID_ARGS; + } + viewType = false; + } + else { + if (i != 0 && !viewType) { + return E_INVALID_ARGS; + } + viewType = true; + } + break; + default: + return E_INVALID_ARGS; + } + } + return E_OK; +} } // namespace DocumentDB \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store_manager.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store_manager.cpp index 85a73cafb7c5ef43f86d281a24929f2f320ff3cf..f4f2faac4d8a4ea1e9d49bb287b3da4821fb9d8f 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store_manager.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/document_store_manager.cpp @@ -79,6 +79,10 @@ int DocumentStoreManager::GetDocumentStore(const std::string &path, const std::s } store = new (std::nothrow) DocumentStore(executor); + if (store == nullptr) { + GLOGE("Memory allocation failed!" ); + return -E_FAILED_MEMORY_ALLOCATE; + } if (store == nullptr) { return -E_OUT_OF_MEMORY; } diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/projection_tree.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/projection_tree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edf6f3568215d97e258f18658f1b67842f093143 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/projection_tree.cpp @@ -0,0 +1,76 @@ +#include +#include "projection_tree.h" + + +namespace DocumentDB { +const int JSON_DEEP_MAX = 4; + +ProjectionTree::ProjectionTree() { +} + +ProjectionTree::~ProjectionTree() { +} + +int ProjectionTree::ParseTree(std::vector> &path) { + ProjectionNode *node = &node_; + if (node == NULL) { + return E_OK; + } + for (int i = 0; i < path.size(); i++) { + node = &node_; + for (int j = 0; j < path[i].size(); j++) { + if (node->SonNode[path[i][j]] != nullptr) { + node = node->SonNode[path[i][j]]; + if (j < path[i].size() - 1 && node->isDeepest) { + return -E_INVALID_ARGS; + } + if (j == path[i].size() - 1 && !node->isDeepest) { + return -E_INVALID_ARGS; + } + } + else { + auto tempNode = new (std::nothrow) ProjectionNode; + if (tempNode == nullptr) { + GLOGE("Memory allocation failed!" ); + return -E_FAILED_MEMORY_ALLOCATE; + } + tempNode->Deep = node->Deep + 1; + if (tempNode->Deep > JSON_DEEP_MAX) { + delete tempNode; + return -E_INVALID_ARGS; + } + node->isDeepest = false; + node->SonNode[path[i][j]] = tempNode; + node = node->SonNode[path[i][j]]; + } + } + } + return E_OK; +} + +bool ProjectionTree::SearchTree(std::vector &singlePath, int &index) { + ProjectionNode *node = &node_; + for (int i = 0; i < singlePath.size(); i++) { + if (node->isDeepest) { + index = i; + } + if (node->SonNode[singlePath[i]] != nullptr) { + node = node->SonNode[singlePath[i]]; + } + else { + return false; + } + } + return true; +} + +int ProjectionNode::DeleteProjectionNode() { + for (auto item : SonNode) { + if (item.second != nullptr) { + delete item.second; + item.second = nullptr; + } + } + return E_OK; +} +} // namespace DocumentDB \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set.cpp new file mode 100644 index 0000000000000000000000000000000000000000..038ada1d9211182c6fe2b4dfe00834b039f6f803 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set.cpp @@ -0,0 +1,162 @@ +/* +* Copyright (c) 2023 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. +*/ +#include "result_set.h" +#include "log_print.h" + +namespace DocumentDB { +constexpr const char *KEY_ID = "_id"; + +ResultSet::ResultSet() +{ + +} +ResultSet::~ResultSet() +{ + +} +int ResultSet::EraseCollection() +{ + if (store_ != nullptr) { + store_->EraseCollection(collectionName_); + } + return E_OK; +} +int ResultSet::Init(DocumentStore *store, const std::string collectionName, ValueObject &key, std::vector> &path, bool ifShowId, bool viewType) +{ + store_ = store; + collectionName_ = collectionName; + key_ = key; + projectionPath_ = path; + if (projectionTree_.ParseTree(path) == -E_INVALID_ARGS) { + GLOGE("Parse ProjectionTree failed"); + return -E_INVALID_ARGS; + } + ifShowId_ = ifShowId; + viewType_ = viewType; + findValue_.reserve(1 + 1); + return E_OK; +} + +int ResultSet::GetNext() +{ + index_++; + if (index_ != 1) { + if (findValue_.size() != 0) { + findValue_.pop_back(); + } + return -E_NO_DATA; + } + std::string idValue = key_.GetStringValue(); + if (idValue.empty()) { + GLOGE("id is empty"); + return -E_NO_DATA; + } + Key key(idValue.begin(), idValue.end()); + Value document; + int errCode = 0; + auto coll = Collection(collectionName_, store_->GetExecutor(errCode)); + errCode = coll.GetDocument(key, document); + if (errCode == -E_NOT_FOUND) { + GLOGE("Cant get value from db"); + return -E_NO_DATA; + } + std::string jsonData(document.begin(), document.end()); + CutJsonBranch(jsonData); + findValue_.emplace_back(jsonData); + return E_OK; +} + +int ResultSet::GetValue(char **value) +{ + if (findValue_.size() == 0) { + GLOGE("The value vector in resultSet is empty"); + return -E_NO_DATA; + } + auto jsonData = findValue_.back(); + char *jsonstr = new char[jsonData.size() + 1]; + if (jsonstr == nullptr) { + GLOGE("Memory allocation failed!" ); + return -E_FAILED_MEMORY_ALLOCATE; + } + errno_t err = strcpy_s(jsonstr, jsonData.size() + 1, jsonData.c_str()); + if (err != 0) { + GLOGE("strcpy_s failed"); + delete[] jsonstr; + return -E_NO_DATA;; + } + *value = jsonstr; + return E_OK; +} + +int ResultSet::CheckCutNode(JsonObject *node, std::vector singlePath, std::vector> &allCutPath) +{ + if (node == nullptr) { + GLOGE("No node to cut"); + return -E_NO_DATA; + } + singlePath.emplace_back(node->GetItemFiled()); + int index = 0; + if (!projectionTree_.SearchTree(singlePath, index) && index == 0) { + allCutPath.emplace_back(singlePath); + } + if (!node->GetChild().IsNull()) { + auto nodeNew = node->GetChild(); + CheckCutNode(&nodeNew, singlePath, allCutPath); + } + if (!node->GetNext().IsNull()) { + singlePath.pop_back(); + auto nodeNew = node->GetNext(); + CheckCutNode(&nodeNew, singlePath, allCutPath); + } + return E_OK; +} +int ResultSet::CutJsonBranch(std::string &jsonData) +{ + int errCode; + JsonObject cjsonObj = JsonObject::Parse(jsonData, errCode, true); + if (errCode != E_OK) { + GLOGE("jsonData Parsed faild"); + return errCode; + } + std::vector> allCutPath; + bool idFlag = false; + if (viewType_) { + std::vector singlePath; + auto cjsonObjChild = cjsonObj.GetChild(); + errCode = CheckCutNode(&cjsonObjChild, singlePath, allCutPath); + if (errCode != E_OK) { + GLOGE("The node in CheckCutNode is nullptr"); + return errCode; + } + for (int i = 0; i < allCutPath.size(); i++) { + if (!ifShowId_ || allCutPath[i][0] != KEY_ID) { + cjsonObj.DeleteItemDeeplyOnTarget(allCutPath[i]); + } + } + } + if (!viewType_) { + for (int i = 0; i < projectionPath_.size(); i++) { + cjsonObj.DeleteItemDeeplyOnTarget(projectionPath_[i]); + } + if (!ifShowId_) { + std::vector idPath; + idPath.emplace_back(KEY_ID); + cjsonObj.DeleteItemDeeplyOnTarget(idPath); + } + } + jsonData = cjsonObj.Print(); + return E_OK; +} +} // namespace DocumentDB diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set_common.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set_common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad195a6b65a6085fa0e97c467631c0f136a3a0ba --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/interface/src/result_set_common.cpp @@ -0,0 +1,30 @@ +/* +* Copyright (c) 2023 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. +*/ + +#include "doc_errno.h" +#include "grd_base/grd_error.h" +#include "result_set_common.h" +#include +#include + +namespace DocumentDB { +class ValueObject; +int InitResultSet(DocumentStore *store, const std::string collectionName, ValueObject &key, std::vector> &path, bool ifShowId, bool viewType, + ResultSet &resultSet) +{ + return resultSet.Init(store, collectionName, key, path, ifShowId, viewType); +} +} + diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/json_object.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/json_object.h index b2e83a930943673fa6915ade08ec839de22233be..12510f1dc5c85f1784a0c0a5c8d29f9651240a6e 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/json_object.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/json_object.h @@ -53,6 +53,7 @@ private: }; std::string stringValue; }; +using JsonFieldPath = std::vector; using ResultValue = ValueObject; using JsonFieldPath = std::vector; @@ -77,15 +78,17 @@ public: ValueObject GetItemValue() const; void SetItemValue(const ValueObject &value) const; - + std::string GetItemFiled() const; + std::string GetItemFiled(int &errCode) const; bool IsFieldExists(const JsonFieldPath &jsonPath) const; JsonObject FindItem(const JsonFieldPath &jsonPath, int &errCode) const; ValueObject GetObjectByPath(const JsonFieldPath &jsonPath, int &errCode) const; int DeleteItemOnTarget(const JsonFieldPath &path); + int DeleteItemDeeplyOnTarget(const JsonFieldPath &path); bool IsNull() const; - + int GetDeep(); enum class Type { JSON_LEAF, JSON_OBJECT, @@ -98,9 +101,10 @@ private: int Init(const std::string &str); int GetDeep(cJSON *cjson); - + int CheckNumber(cJSON *cjson, int &errCode); cJSON *cjson_ = nullptr; + int jsonDeep_ = 0; bool isOwner_ = false; bool caseSensitive_ = false; }; diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_executor.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_executor.h index 8037fc6bcbf2644e43dccb298e7c774ec9cd1a0b..0f81f5b1f2ac08ca2da726bb2ef8f2f348392742 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_executor.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_executor.h @@ -17,7 +17,7 @@ #define KV_STORE_EXECUTOR_H #include -#include "doc_common.h" +#include "document_check.h" namespace DocumentDB { class KvStoreExecutor { diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_manager.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_manager.h index 97b79f649350a92b31bdc5b4e115e4a02d2f398c..c1df107236329fd3961755f57886aca64e9a8e14 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_manager.h +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/include/kv_store_manager.h @@ -18,7 +18,7 @@ #include #include "db_config.h" -#include "doc_common.h" +#include "document_check.h" #include "kv_store_executor.h" namespace DocumentDB { diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/json_object.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/json_object.cpp index 661dfeeb336a927c683b439e0066ce50f1b0d245..2d3ed07e9d2e4a2cec3d25c5a5d1a77aa4c0c47d 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/json_object.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/json_object.cpp @@ -17,14 +17,12 @@ #include #include "doc_errno.h" #include "log_print.h" -// #include "grd_format_config.h" namespace DocumentDB { namespace { -#define COLLECTION_LENS_MAX (512) -#define JSON_LENS_MAX (512) -#define JSON_DEEP_MAX (4) +const int COLLECTION_LENS_MAX = 512 * 1024; +const int JSON_LENS_MAX = 512 * 1024; bool IsNumber(const std::string &str) { @@ -93,11 +91,12 @@ JsonObject JsonObject::Parse(const std::string &jsonStr, int &errCode, bool case JsonObject::JsonObject() { + cjson_ = nullptr; } JsonObject::~JsonObject() { - if (isOwner_ == true) { + if (isOwner_) { cJSON_Delete(cjson_); } } @@ -119,11 +118,24 @@ JsonObject::Type JsonObject::GetType() const } return JsonObject::Type::JSON_LEAF; } - +int JsonObject::GetDeep() +{ + if (cjson_ == nullptr) { + GLOGE("cJson is nullptr,deep is 0"); + return 0; + } + if (jsonDeep_ != 0) { + return jsonDeep_; + } + jsonDeep_ = GetDeep(cjson_); + return jsonDeep_; + +} int JsonObject::GetDeep(cJSON *cjson) { if (cjson->child == nullptr) { - return 1; // leaf node + jsonDeep_ = 0; + return 0; // leaf node } int depth = -1; @@ -132,26 +144,47 @@ int JsonObject::GetDeep(cJSON *cjson) depth = std::max(depth, GetDeep(child) + 1); child = child->next; } + jsonDeep_ = depth; return depth; } -int JsonObject::Init(const std::string &str) + +int JsonObject::CheckNumber(cJSON *item, int &errCode) { - if (str.length() + 1 > JSON_LENS_MAX) { - return -E_INVALID_ARGS; + if (item != NULL && cJSON_IsNumber(item)) { + double value = cJSON_GetNumberValue(item); + if (value > __DBL_MAX__ || value < -__DBL_MAX__) { + errCode = E_INVALID_ARGS; + } } + if (item->child != nullptr) { + return CheckNumber(item->child, errCode); + } + if (item->next != nullptr) { + return CheckNumber(item->next, errCode); + } + return E_OK; +} + +int JsonObject::Init(const std::string &str) +{ const char *end = NULL; isOwner_ = true; cjson_ = cJSON_ParseWithOpts(str.c_str(), &end, true); if (cjson_ == nullptr) { + GLOGE("Json's format is wrong"); return -E_INVALID_JSON_FORMAT; } if (cjson_->type != cJSON_Object) { + GLOGE("after Parse,cjson_'s type is not cJSON_Object"); return -E_INVALID_ARGS; } - if (GetDeep(cjson_) > JSON_DEEP_MAX) { + int ret = 0; + CheckNumber(cjson_, ret); + if (ret == E_INVALID_ARGS) { + GLOGE("Int value is larger than double"); return -E_INVALID_ARGS; } return E_OK; @@ -234,7 +267,7 @@ JsonObject JsonObject::GetChild() const int JsonObject::DeleteItemFromObject(const std::string &field) { - if (field == "") { + if (field.empty()) { return E_OK; } cJSON_DeleteItemFromObjectCaseSensitive(cjson_, field.c_str()); @@ -345,6 +378,20 @@ std::string JsonObject::GetItemFiled() const } } +std::string JsonObject::GetItemFiled(int &errCode) const +{ + if (cjson_ == nullptr) { + errCode = E_INVALID_ARGS; + return ""; + } + if (cjson_->string == nullptr) { + errCode = E_INVALID_ARGS; + return ""; + } + errCode = E_OK; + return cjson_->string; +} + cJSON *GetChild(cJSON *cjson, const std::string &field, bool caseSens) { if (cjson->type == cJSON_Object) { @@ -448,4 +495,50 @@ int JsonObject::DeleteItemOnTarget(const JsonFieldPath &path) return E_OK; } + +int JsonObject::DeleteItemDeeplyOnTarget(const JsonFieldPath &path) +{ + if (path.empty()) { + return -E_INVALID_ARGS; + } + + std::string fieldName = path.back(); + JsonFieldPath patherPath = path; + patherPath.pop_back(); + + int errCode = E_OK; + cJSON *nodeFather = MoveToPath(cjson_, patherPath, caseSensitive_); + if (nodeFather == nullptr) { + GLOGE("Delete item failed, json field path not found."); + return -E_JSON_PATH_NOT_EXISTS; + } + + if (nodeFather->type == cJSON_Object) { + if (caseSensitive_) { + cJSON_DeleteItemFromObjectCaseSensitive(nodeFather, fieldName.c_str()); + if (nodeFather->child == nullptr && path.size() > 1) { + JsonFieldPath fatherPath(path.begin(), path.end() - 1); + DeleteItemDeeplyOnTarget(fatherPath); + } + } else { + cJSON_DeleteItemFromObject(nodeFather, fieldName.c_str()); + if (nodeFather->child == nullptr && path.size() > 1) { + JsonFieldPath fatherPath(path.begin(), path.end() - 1); + DeleteItemDeeplyOnTarget(fatherPath); + } + } + } else if (nodeFather->type == cJSON_Array) { + if (!IsNumber(fieldName)) { + GLOGW("Invalid json field path, expect array index."); + return -E_JSON_PATH_NOT_EXISTS; + } + cJSON_DeleteItemFromArray(nodeFather, std::stoi(fieldName)); + if (nodeFather->child == nullptr && path.size() > 1) { + JsonFieldPath fatherPath(path.begin(), path.end() - 1); + DeleteItemDeeplyOnTarget(fatherPath); + } + } + + return E_OK; +} } // namespace DocumentDB diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/sqlite_store_executor_impl.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/sqlite_store_executor_impl.cpp index 98dfd182e740f21257426bf81345c1831efdebc2..937a2793808080d53f3e5cc69ac4c61d3f5fdf82 100644 --- a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/sqlite_store_executor_impl.cpp +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/src/oh_adapter/src/sqlite_store_executor_impl.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "doc_common.h" +#include "document_check.h" #include "doc_errno.h" #include "log_print.h" #include "sqlite_utils.h" @@ -95,6 +95,10 @@ int SqliteStoreExecutor::PutData(const std::string &collName, const Key &key, co }, nullptr); if (errCode != SQLITE_OK) { GLOGE("[sqlite executor] Put data failed. err=%d", errCode); + if (errCode == -E_ERROR) { + GLOGE("Cant find the collection"); + return -E_INVALID_ARGS; + } return errCode; } return E_OK; @@ -129,15 +133,26 @@ int SqliteStoreExecutor::DelData(const std::string &collName, const Key &key) GLOGE("Invalid db handle."); return -E_ERROR; } - + int errCode = 0; + if (!IsCollectionExists(collName, errCode)) { + return -E_INVALID_ARGS; + } + Value valueRet; + if (GetData(collName, key, valueRet) != E_OK) { + return -E_NO_DATA; + } std::string sql = "DELETE FROM '" + collName + "' WHERE key=?;"; - int errCode = SQLiteUtils::ExecSql(dbHandle_, sql, [key](sqlite3_stmt *stmt) { + errCode = SQLiteUtils::ExecSql(dbHandle_, sql, [key](sqlite3_stmt *stmt) { SQLiteUtils::BindBlobToStatement(stmt, 1, key); return E_OK; }, nullptr); if (errCode != SQLITE_OK) { GLOGE("[sqlite executor] Delete data failed. err=%d", errCode); + if (errCode == -E_ERROR) { + GLOGE("Cant find the collection"); + return -E_NO_DATA; + } } return errCode; } @@ -241,4 +256,5 @@ int SqliteStoreExecutor::CleanCollectionOption(const std::string &name) Key collOptKey = {collOptKeyStr.begin(), collOptKeyStr.end()}; return DelData("grd_meta", collOptKey); } + } // DocumentDB \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_delete_test.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_delete_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42d4d2d7463cbb2bed72d0edaac6a18dd3fd0fdd --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_delete_test.cpp @@ -0,0 +1,326 @@ +/* +* Copyright (c) 2023 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. +*/ + +#include + +#include "grd_base/grd_db_api.h" +#include "grd_document/grd_document_api.h" +#include "grd_base/grd_error.h" +#include "grd_base/grd_type_export.h" +#include "grd_type_inner.h" +#include "grd_resultset_inner.h" +#include "grd_base/grd_resultset_api.h" + +using namespace testing::ext; +namespace { +constexpr const char *COLLECTION_NAME = "student"; +constexpr const char *NULL_JSON_STR = "{}"; +const int MAX_COLLECTION_LENS = 511; +std::string path = "./document.db"; +GRD_DB *g_db = nullptr; +} + +class DocumentDeleteApiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + void InsertDoc(const char *collectionName, const char *document); +}; +void DocumentDeleteApiTest::SetUpTestCase(void) +{ + std::string path = "./document.db"; + int status = GRD_DBOpen(path.c_str(), nullptr, GRD_DB_OPEN_CREATE, &g_db); + EXPECT_EQ(status, GRD_OK); +} + +void DocumentDeleteApiTest::TearDownTestCase(void) +{ + EXPECT_EQ(GRD_DBClose(g_db, 0), GRD_OK); + remove(path.c_str()); +} + +void DocumentDeleteApiTest::SetUp(void) +{ + /** + * @tc.steps:step1. Create Collection + * @tc.expected: step1. GRD_OK + */ + EXPECT_EQ(GRD_CreateCollection(g_db, "student", "", 0), GRD_OK); + /** + * @tc.steps:step2. Insert many document in order to delete + * @tc.expected: step2. GRD_OK + */ + const char *document1 = + "{ \ + \"_id\" : \"1\", \ + \"name\": \"xiaoming\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"math\", \"English\", \"music\"] \ + }"; + const char *document2 = + "{ \ + \"_id\" : \"2\", \ + \"name\": \"ori\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"math\", \"English\", \"music\"] \ + }"; + const char *document3 = + "{ \ + \"_id\" : \"3\", \ + \"name\": \"David\", \ + \"address\": \"beijing\", \ + \"age\" : 15, \ + \"friend\" : {\"name\" : \"David\", \"sex\" : \"female\", \"age\" : 90}, \ + \"subject\": [\"math\", \"English\", \"music\"] \ + }"; + DocumentDeleteApiTest::InsertDoc(COLLECTION_NAME, document1); + DocumentDeleteApiTest::InsertDoc(COLLECTION_NAME, document2); + DocumentDeleteApiTest::InsertDoc(COLLECTION_NAME, document3); +} + +void DocumentDeleteApiTest::TearDown(void) +{ + /** + * @tc.steps:step1. Call GRD_DropCollection to drop the collection + * @tc.expected: step1. GRD_OK + */ + EXPECT_EQ(GRD_DropCollection(g_db, COLLECTION_NAME, 0), GRD_OK); +} + +static void ChkDeleteResWithFilter(const char *filter) +{ + /** + * @tc.steps:step1. Try to find the deleted document + * @tc.expected: step1. GRD_OK + */ + Query query; + query.filter = filter; + const char *projection = "{}"; + query.projection = projection; + GRD_ResultSet *resultSet = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + /** + * @tc.steps:step2. The resultset should be NULL + * @tc.expected: step2. GRD_OK + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +void DocumentDeleteApiTest::InsertDoc(const char *collectionName, const char *document) +{ + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName, document, 0), GRD_OK); +} + +/** + * @tc.name: DocumentDelete001 + * @tc.desc: Delete with NULL filter + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest001, TestSize.Level1) +{ + /** + * @tc.steps:step1. Delete all the document + * @tc.expected: step1. GRD_INVALID_ARGS + */ + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, NULL_JSON_STR, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentDelete002 + * @tc.desc: Delete with filter which has no _id + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest002, TestSize.Level1) +{ + /** + * @tc.steps:step1. Delete with filter which has no _id + * @tc.expected: step1. GRD_INVALID_ARGS + */ + const char *filter = "{\"age\" : 15}"; + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentDelete003 + * @tc.desc: Delete with filter which has more than one fileds. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest003, TestSize.Level1) +{ + /** + * @tc.steps:step1. Delete with filter which has more than one fileds. + * @tc.expected: step1. GRD_INVALID_ARGS + */ + const char *filter = "{\"_id\" : \"1\", \"age\" : 15}"; + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentDelete004 + * @tc.desc: Test delete with invalid input + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest004, TestSize.Level1) +{ + /** + * @tc.steps:step1. Test delete with un-zero flags + * @tc.expected: step1. GRD_INVALID_ARGS + */ + const char *filter1 = "{\"_id\" : \"1\"}"; + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter1, 1), GRD_INVALID_ARGS); + /** + * @tc.steps:step2. Test delete with NULL collection name + * @tc.expected: step2. GRD_INVALID_ARGS + */ + // const char *filter2 = "{\"_id\" : \"1\"}"; + // EXPECT_EQ(GRD_DeleteDoc(g_db, NULL, filter2, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step3. Test delete with empty collection name + * @tc.expected: step3. GRD_INVALID_ARGS + */ + // const char *filter1 = "{\"_id\" : \"1\"}"; + // EXPECT_EQ(GRD_DeleteDoc(g_db, "", filter1, 1), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentDelete005 + * @tc.desc: Test delete with same collection name + * but one is uppercase(delete) and the other is lowercase(insert) + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest005, TestSize.Level1) +{ + /** + * @tc.step1: Test delete with same collection name + * but one is uppercase(delete) and the other is lowercase(insert) + * @tc.expected: step1. GRD_INVALID_ARGS + */ + const char *filter = "{\"_id\" : \"1\"}"; + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter, 0), 1); + /** + * @tc.step2: Check whether doc has been deleted compeletely + * @tc.expected: step2. GRD_OK + */ + ChkDeleteResWithFilter(filter); +} + +/** + * @tc.name: DocumentDelete006 + * @tc.desc: Test delete after calling find interface + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest006, TestSize.Level1) +{ + /** + * @tc.step1: Create filter with _id and get the record according to filter condition. + * @tc.expected: step1. GRD_OK + */ + const char *filter = "{\"_id\" : \"1\"}"; + GRD_ResultSet *resultSet = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter, 0), 1); + /** + * @tc.step2: Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. Cannot get next record, return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentDelete007 + * @tc.desc: Test delete with too long collectionName. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest007, TestSize.Level1) +{ + const char *filter = "{\"_id\" : \"1\"}"; + string collectionName1(MAX_COLLECTION_LENS, 'a'); + EXPECT_EQ(GRD_CreateCollection(g_db, collectionName1.c_str(), "", 0), GRD_OK); + EXPECT_EQ(GRD_DeleteDoc(g_db, collectionName1.c_str(), filter, 0), 0); + EXPECT_EQ(GRD_DropCollection(g_db, collectionName1.c_str(), 0), GRD_OK); + + string collectionName2(MAX_COLLECTION_LENS + 1, 'a'); + EXPECT_EQ(GRD_DeleteDoc(g_db, collectionName2.c_str(), filter, 0), GRD_OVER_LIMIT); +} + + +/** + * @tc.name: DocumentDelete008 + * @tc.desc: Test delete with invalid NULL input for all parameters. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest008, TestSize.Level1) +{ + /** + * @tc.steps:step1. Delete with filter which has more than one fileds. + * @tc.expected: step1. GRD_INVALID_ARGS + */ + const char *filter = "{\"_id\" : \"1\"}"; + EXPECT_EQ(GRD_DeleteDoc(NULL, COLLECTION_NAME, filter, 0), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_DeleteDoc(g_db, NULL, filter, 0), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_DeleteDoc(g_db, "", filter, 0), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, NULL, 0), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, "", 0), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_DeleteDoc(g_db, "notExisted", filter, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentDelete010 + * @tc.desc: Test delete document when filter _id is int and string + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentDeleteApiTest, DeleteDBTest010, TestSize.Level1) +{ + /** + * @tc.steps:step1. Test delete document when filter _id is int and string. + * @tc.expected: step1. GRD_INVALID_ARGS + */ + std::vector filterVec = {R"({"_id" : 1})", R"({"_id":[1, 2]})", + R"({"_id" : {"t1" : 1}})", R"({"_id":null})", R"({"_id":true})", R"({"_id" : 1.333})", R"({"_id" : -2.0})"}; + for (const auto &item : filterVec) { + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, item.c_str(), 0), GRD_INVALID_ARGS); + } + const char *filter = "{\"_id\" : \"1\"}"; + EXPECT_EQ(GRD_DeleteDoc(g_db, COLLECTION_NAME, filter, 0), 1); + +} + diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_find_test.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_find_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0051493bbfe6176822c3d1b856fc82ca14706dcf --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_find_test.cpp @@ -0,0 +1,1449 @@ +/* +* Copyright (c) 2023 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. +*/ + +#include + +#include "grd_base/grd_db_api.h" +#include "grd_document/grd_document_api.h" +#include "grd_base/grd_error.h" +#include "grd_base/grd_type_export.h" +#include "grd_type_inner.h" +#include "grd_base/grd_resultset_api.h" +#include "doc_errno.h" +#include "log_print.h" +#include "documentdb_test_utils.h" +#include "grd_resultset_inner.h" + +using namespace testing::ext; +namespace { +std::string path = "./document.db"; +GRD_DB *g_db = nullptr; +constexpr const char *COLLECTION_NAME = "student"; +constexpr const char *NULL_JSON_STR = "{}"; +const int E_OK = 0; +const int MAX_COLLECTION_NAME = 511; +const int INT_MAX = 2147483647; +const int INT_MIN = -2147483648; +const int MAX_ID_LENS = 899; +static const char *g_document1 = "{\"_id\" : \"1\", \"name\":\"doc1\",\"item\":\"journal\",\"personInfo\":\ + {\"school\":\"AB\", \"age\" : 51}}"; +static const char *g_document2 = "{\"_id\" : \"2\", \"name\":\"doc2\",\"item\": 1, \"personInfo\":\ + [1, \"my string\", {\"school\":\"AB\", \"age\" : 51}, true, {\"school\":\"CD\", \"age\" : 15}, false]}"; +static const char *g_document3 = "{\"_id\" : \"3\", \"name\":\"doc3\",\"item\":\"notebook\",\"personInfo\":\ + [{\"school\":\"C\", \"age\" : 5}]}"; +static const char *g_document4 = "{\"_id\" : \"4\", \"name\":\"doc4\",\"item\":\"paper\",\"personInfo\":\ + {\"grade\" : 1, \"school\":\"A\", \"age\" : 18}}"; +static const char *g_document5 = "{\"_id\" : \"5\", \"name\":\"doc5\",\"item\":\"journal\",\"personInfo\":\ + [{\"sex\" : \"woma\", \"school\" : \"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *g_document6 = "{\"_id\" : \"6\", \"name\":\"doc6\",\"item\":false,\"personInfo\":\ + [{\"school\":\"B\", \"teacher\" : \"mike\",\"age\" : 15}, {\"school\":\"C\", \"teacher\" : \"moon\",\"age\" : 20}]}"; +static const char *g_document7 = "{\"_id\" : \"7\", \"name\":\"doc7\",\"item\":\"fruit\",\"other_Info\":\ + [{\"school\":\"BX\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *g_document8 = "{\"_id\" : \"8\", \"name\":\"doc8\",\"item\":true,\"personInfo\":\ + [{\"school\":\"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}"; +static const char *g_document9 = "{\"_id\" : \"9\", \"name\":\"doc9\",\"item\": true}"; +static const char *g_document10 = "{\"_id\" : \"10\", \"name\":\"doc10\", \"parent\" : \"kate\"}"; +static const char *g_document11 = "{\"_id\" : \"11\", \"name\":\"doc11\", \"other\" : \"null\"}"; +static const char *g_document12 = "{\"_id\" : \"12\", \"name\":\"doc12\",\"other\" : null}"; +static const char *g_document13 = "{\"_id\" : \"13\", \"name\":\"doc13\",\"item\" : \"shoes\",\"personInfo\":\ + {\"school\":\"AB\", \"age\" : 15}}"; +static const char *g_document14 = "{\"_id\" : \"14\", \"name\":\"doc14\",\"item\" : true,\"personInfo\":\ + [{\"school\":\"B\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 85}]}"; +static const char *g_document15 = "{\"_id\" : \"15\", \"name\":\"doc15\",\"personInfo\":[{\"school\":\"C\", \"age\" : 5}]}"; +static const char *g_document16 = "{\"_id\" : \"16\", \"name\":\"doc16\", \"nested1\":{\"nested2\":{\"nested3\":\ + {\"nested4\":\"ABC\", \"field2\":\"CCC\"}}}}"; +static const char *g_document17 = "{\"_id\" : \"17\", \"name\":\"doc17\",\"personInfo\":\"oh,ok\"}"; +static const char *g_document18 = "{\"_id\" : \"18\", \"name\":\"doc18\",\"item\" : \"mobile phone\",\"personInfo\":\ + {\"school\":\"DD\", \"age\":66}, \"color\":\"blue\"}"; +static const char *g_document19 = "{\"_id\" : \"19\", \"name\":\"doc19\",\"ITEM\" : true,\"PERSONINFO\":\ + {\"school\":\"AB\", \"age\":15}}"; +static const char *g_document20 = "{\"_id\" : \"20\", \"name\":\"doc20\",\"ITEM\" : true,\"personInfo\":\ + [{\"SCHOOL\":\"B\", \"AGE\":15}, {\"SCHOOL\":\"C\", \"AGE\":35}]}"; +static std::vectorg_data = {g_document1, g_document2, g_document3, g_document4, g_document5, g_document6, g_document7, + g_document8, g_document9, g_document10, g_document11, g_document12, g_document13, g_document14, g_document15, g_document16, g_document17, g_document18, g_document19, g_document20}; + +static void InsertData(GRD_DB *g_db, const char *collectionName) +{ + for (const auto &item : g_data) { + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName, item, 0), GRD_OK); + } +} + +static void CompareValue(const char *value, const char *targetValue) +{ + int errCode; + DocumentDB::JsonObject valueObj = DocumentDB::JsonObject::Parse(value, errCode); + EXPECT_EQ(errCode, E_OK); + DocumentDB::JsonObject targetValueObj = DocumentDB::JsonObject::Parse(targetValue, errCode); + EXPECT_EQ(errCode, E_OK); + EXPECT_EQ(valueObj.Print(), targetValueObj.Print()); +} +} + +class DocumentFindApiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + void InsertDoc(const char *collectionName, const char *document); +}; +void DocumentFindApiTest::SetUpTestCase(void) +{ + std::string path = "./document.db"; + int status = GRD_DBOpen(path.c_str(), nullptr, GRD_DB_OPEN_CREATE, &g_db); + EXPECT_EQ(status, GRD_OK); + EXPECT_EQ(GRD_CreateCollection(g_db, COLLECTION_NAME, "", 0), GRD_OK); + EXPECT_NE(g_db, nullptr); +} + +void DocumentFindApiTest::TearDownTestCase(void) +{ + EXPECT_EQ(GRD_DBClose(g_db, 0), GRD_OK); + remove(path.c_str()); +} + +void DocumentFindApiTest::SetUp(void) +{ + InsertData(g_db, "student"); +} + +void DocumentFindApiTest::TearDown(void) +{ +} + + +/** + * @tc.name: DocumentFindApiTest001 + * @tc.desc: Test Insert document db + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest001, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with _id and get the record according to filter condition. + * @tc.expected: step1. Succeed to get the record, the matching record is g_document6. + */ + const char *filter = "{\"_id\" : \"6\"}"; + GRD_ResultSet *resultSet = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, g_document6); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + /** + * @tc.steps: step2. Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. Cannot get next record, return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest002 + * @tc.desc: Test filter with multiple fields and _id. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest002, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with multiple and _id. and get the record according to filter condition. + * @tc.expected: step1. Faild to get the record, the result is GRD_INVALID_ARGS, GRD_GetValue return GRD_NOT_AVAILABLE and GRD_Next return GRD_NO_DATA. + */ + const char *filter = "{\"_id\" : \"6\", \"name\":\"doc6\"}"; + GRD_ResultSet *resultSet = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_INVALID_ARGS); + /** + * @tc.steps: step2. Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. GRD_GetValue return GRD_INVALID_ARGS and GRD_Next return GRD_INVALID_ARGS. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_INVALID_ARGS); + char *value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest004 + * @tc.desc: test filter with string filter without _id. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest004, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter without _id and get the record according to filter condition. + * @tc.expected: step1. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + const char *filter = "{\"name\":\"doc6\"}"; + GRD_ResultSet *resultSet = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. GRD_GetValue return GRD_INVALID_ARGS and GRD_Next return GRD_INVALID_ARGS. + */ + char *value = NULL; + EXPECT_EQ(GRD_Next(resultSet), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest005 + * @tc.desc: test filter field with other word. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest005, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with _id and number + * @tc.expected: step1. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet1 = nullptr; + const char *filter1 = "{\"_id\" : \"1\", \"info\" : 1}"; + Query query1 = {filter1, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query1, 1, &resultSet1), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Create filter with two _id + * @tc.expected: step2. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet2 = nullptr; + const char *filter2 = "{\"_id\" : \"1\", \"_id\" : \"2\"}"; + Query query2 = {filter2, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query2, 1, &resultSet2), GRD_INVALID_ARGS); + + /** + * @tc.steps: step3. Create filter with array and _id + * @tc.expected: step3. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet3 = nullptr; + const char *filter3 = "{\"_id\" : \"1\", \"info\" : [\"2\", 1]}"; + Query query3 = {filter3, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query3, 1, &resultSet3), GRD_INVALID_ARGS); + + /** + * @tc.steps: step4. Create filter with object and _id + * @tc.expected: step4. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet4 = nullptr; + const char *filter4 = "{\"_id\" : \"1\", \"info\" : {\"info_val\" : \"1\"}}"; + Query query4 = {filter4, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query4, 1, &resultSet4), GRD_INVALID_ARGS); + + /** + * @tc.steps: step5. Create filter with bool and _id + * @tc.expected: step5. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet5 = nullptr; + const char *filter5 = "{\"_id\" : \"1\", \"info\" : true}"; + Query query5 = {filter5, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query5, 1, &resultSet5), GRD_INVALID_ARGS); + + /** + * @tc.steps: step6. Create filter with null and _id + * @tc.expected: step6. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet6 = nullptr; + const char *filter6 = "{\"_id\" : \"1\", \"info\" : null}"; + Query query6 = {filter6, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query6, 1, &resultSet6), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest006 + * @tc.desc: test filter field with id which has different type of value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest006, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with _id which value is string + * @tc.expected: step1. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet1 = nullptr; + const char *filter1 = "{\"_id\" : \"valstring\"}"; + Query query1 = {filter1, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query1, 1, &resultSet1), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet1), GRD_OK); + + /** + * @tc.steps: step2. Create filter with _id which value is number + * @tc.expected: step2. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet2 = nullptr; + const char *filter2 = "{\"_id\" : 1}"; + Query query2 = {filter2, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query2, 1, &resultSet2), GRD_INVALID_ARGS); + + /** + * @tc.steps: step3. Create filter with _id which value is array + * @tc.expected: step3. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet3 = nullptr; + const char *filter3 = "{\"_id\" : [\"2\", 1]}"; + Query query3 = {filter3, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query3, 1, &resultSet3), GRD_INVALID_ARGS); + + /** + * @tc.steps: step4. Create filter with _id which value is object + * @tc.expected: step4. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet4 = nullptr; + const char *filter4 = "{\"_id\" : {\"info_val\" : \"1\"}}"; + Query query4 = {filter4, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query4, 1, &resultSet4), GRD_INVALID_ARGS); + + /** + * @tc.steps: step5. Create filter with _id which value is bool + * @tc.expected: step5. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet5 = nullptr; + const char *filter5 = "{\"_id\" : true}"; + Query query5 = {filter5, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query5, 1, &resultSet5), GRD_INVALID_ARGS); + + /** + * @tc.steps: step6. Create filter with _id which value is null + * @tc.expected: step6. Faild to get the record, the result is GRD_INVALID_ARGS, + */ + GRD_ResultSet *resultSet6 = nullptr; + const char *filter6 = "{\"_id\" : null}"; + Query query6 = {filter6, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query6, 1, &resultSet6), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest016 + * @tc.desc: Test filter with collection Name is invalid. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest016, TestSize.Level1) +{ + const char *colName1 = "grd_type"; + const char *colName2 = "GM_SYS_sysfff"; + GRD_ResultSet *resultSet = NULL; + const char *filter = "{\"_id\" : \"1\"}"; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, colName1, query, 1, &resultSet), GRD_INVALID_FORMAT); + EXPECT_EQ(GRD_FindDoc(g_db, colName2, query, 1, &resultSet), GRD_INVALID_FORMAT); +} + +// /** +// * @tc.name: DocumentFindApiTest017 +// * @tc.desc: Test filter field with large filter +// * @tc.type: FUNC +// * @tc.require: +// * @tc.author: mazhao +// */ +// HWTEST_F(DocumentFindApiTest, DocumentFindApiTest017, TestSize.Level1) +// { +// GRD_ResultSet *resultSet = nullptr; +// string documentPart1 = "{\"_id\" : \"18\", \"item\" :\" "; +// string documentPart2 = "\" }"; +// string jsonVal = string(512 * 1024 - documentPart1.size() - documentPart2.size() - 1, 'k'); +// string document = documentPart1 + jsonVal + documentPart2; +// string jsonVal1 = string(512 * 1024 - documentPart1.size() - documentPart2.size(), 'k'); +// string document1 = documentPart1 + jsonVal1 + documentPart2; + +// Query query = {document.c_str(), "{}"}; +// EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); +// EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); +// char *value = NULL; +// EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); +// EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + +// query = {document1.c_str(), "{}"}; +// EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OVER_LIMIT); +// } + +/** + * @tc.name: DocumentFindApiTest019 + * @tc.desc: Test filter field with no result + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest019, TestSize.Level1) +{ + const char *filter = "{\"_id\" : \"100\"}"; + GRD_ResultSet *resultSet = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + char *value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest023 + * @tc.desc: Test filter field with double find. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest023, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with _id and get the record according to filter condition. + * @tc.expected: step1. succeed to get the record, the matching record is g_document6. + */ + const char *filter = "{\"_id\" : \"6\"}"; + GRD_ResultSet *resultSet = nullptr; + GRD_ResultSet *resultSet2 = nullptr; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet2), GRD_RESOURCE_BUSY); + + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, g_document6); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + /** + * @tc.steps: step2. Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. Cannot get next record, return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, g_document6); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest024 + * @tc.desc: Test filter field with multi collections + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest024, TestSize.Level1) +{ + const char *filter = "{\"_id\" : \"6\"}"; + GRD_ResultSet *resultSet = nullptr; + GRD_ResultSet *resultSet2 = nullptr; + Query query = {filter, "{}"}; + const char* collectionName = "DocumentFindApiTest024"; + EXPECT_EQ(GRD_CreateCollection(g_db, collectionName, "", 0), GRD_OK); + InsertData(g_db, collectionName); + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_FindDoc(g_db, collectionName, query, 1, &resultSet2), GRD_OK); + + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, g_document6); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + + EXPECT_EQ(GRD_Next(resultSet2), GRD_OK); + char *value2 = NULL; + EXPECT_EQ(GRD_GetValue(resultSet2, &value2), GRD_OK); + CompareValue(value2, g_document6); + EXPECT_EQ(GRD_FreeValue(value2), GRD_OK); + + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_Next(resultSet2), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_GetValue(resultSet2, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet2), GRD_OK); + + EXPECT_EQ(GRD_DropCollection(g_db, collectionName, 0), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest025 + * @tc.desc: Test nested projection, with viewType equals to 1. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest025, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document16, _id flag is 0. + * Create projection to display name,nested4. + * @tc.expected: step1. resultSet init successfuly, the result is GRD_OK, + */ + const char *filter = "{\"_id\" : \"16\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\": true, \"nested1.nested2.nested3.nested4\":true}"; + const char *targetDocument = "{\"name\":\"doc16\", \"nested1\":{\"nested2\":{\"nested3\":\ + {\"nested4\":\"ABC\"}}}}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + /** + * @tc.steps: step2. After loop, cannot get more record. + * @tc.expected: step2. Return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + /** + * @tc.steps: step3. Create filter to match g_document16, _id flag is 0; + * Create projection to display name、nested4 with different projection format. + * @tc.expected: step3. succeed to get the record. + */ + projectionInfo = "{\"name\": true, \"nested1\":{\"nested2\":{\"nested3\":{\"nested4\":true}}}}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + /** + * @tc.steps: step4. After loop, cannot get more record. + * @tc.expected: step4. return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + /** + * @tc.steps: step5. Create filter to match g_document16, _id flag is 0. + * Create projection to conceal name,nested4 with different projection format. + * @tc.expected: step5. succeed to get the record. + */ + projectionInfo = "{\"name\": 0, \"nested1.nested2.nested3.nested4\":0}"; + targetDocument = "{\"nested1\":{\"nested2\":{\"nested3\":{\"field2\":\"CCC\"}}}}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} +#include +/** + * @tc.name: DocumentFindApiTest026 + * @tc.desc: Test nested projection, with _id flag equals to 1. Projection is 5 level. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest026, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document16, _id flag is 0. + * Create projection to display name,nested5 + * @tc.expected: step1. Error GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"16\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\": true, \"nested1.nested2.nested3.nested4.nested5\":true}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + // EXPECT_EQ(GRD_Next(resultSet), GRD_INVALID_ARGS); + // char *value = nullptr; + // EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_INVALID_ARGS); + /** + * @tc.steps: step2. After loop, cannot get more record. + * @tc.expected: step2. Return GRD_NO_DATA. + */ + // EXPECT_EQ(GRD_Next(resultSet), GRD_INVALID_ARGS); + // EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest027 + * @tc.desc: Test projection with invalid field, _id field equals to 1. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest027, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, other _info and non existing field. + * @tc.expected: step1. Match the g_document7 and display name, other_info + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\": true, \"other_Info\":true, \"non_exist_field\":true}"; + const char *targetDocument = "{\"name\": \"doc7\", \"other_Info\":[{\"school\":\"BX\", \"age\":15},\ + {\"school\":\"C\", \"age\":35}]}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, other _info and existing field with space. + * @tc.expected: step2. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\": true, \"other_Info\":true, \" item \":true}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step3. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, other _info and existing field with different case. + * @tc.expected: step3. Match the g_document7 and display name, other_Info. + */ + projectionInfo = "{\"name\": true, \"other_Info\":true, \"ITEM\": true}"; + query = {filter, projectionInfo}; + resultSet = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest028 + * @tc.desc: Test projection with invalid field in Array,_id field equals to 1. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest028, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, non existing field in array. + * @tc.expected: step1. Match the g_document7 and display name, other_info. + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\": true, \"other_Info.non_exist_field\":true}"; + const char *targetDocument = "{\"name\": \"doc7\"}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, other _info and existing field with space. + * @tc.expected: step2. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\": true, \"other_Info\":{\"non_exist_field\":true}}"; + query = {filter, projectionInfo}; + resultSet = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step3. Create filter to match g_document7, _id flag is 0. + * Create projection to display name, non existing field in array with index format. + * @tc.expected: step3. Match the g_document7 and display name, other_Info. + */ + projectionInfo = "{\"name\": true, \"other_Info.0\": true}"; + query = {filter, projectionInfo}; + resultSet = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest029 + * @tc.desc: Test projection with path conflict._id field equals to 0. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest029, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document4, _id flag is 0. + * Create projection to display conflict path. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"4\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"personInfo\": true, \"personInfo.grade\": true}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest030 + * @tc.desc: Test _id flag and field.None exist field. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest030, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * @tc.expected: step1. Match the g_document7 and return empty json. + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"non_exist_field\":true}"; + int flag = 0; + const char *targetDocument = "{}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 1. + * @tc.expected: step2. Match g_document7, and return a json with _id. + */ + resultSet = nullptr; + flag = 1; + targetDocument = "{\"_id\": \"7\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest031 + * @tc.desc: Test _id flag and field.Exist field with 1 value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest031, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * @tc.expected: step1. Match the g_document7 and return json with name, item. + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":true, \"item\":true}"; + int flag = 0; + const char *targetDocument = "{\"name\":\"doc7\", \"item\":\"fruit\"}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 1. + * @tc.expected: step2. Match g_document7, and return a json with _id. + */ + resultSet = nullptr; + flag = 1; + projectionInfo = "{\"name\": 1, \"item\": 1}"; + targetDocument = "{\"_id\":\"7\", \"name\":\"doc7\", \"item\":\"fruit\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest032 + * @tc.desc: Test _id flag and field.Exist field with 1 value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest032, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * @tc.expected: step1. Match the g_document7 and return json with name, item. + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":true, \"item\":true}"; + int flag = 0; + const char *targetDocument = "{\"name\":\"doc7\", \"item\":\"fruit\"}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 1. + * @tc.expected: step2. Match g_document7, and return a json with _id. + */ + resultSet = nullptr; + flag = 1; + projectionInfo = "{\"name\": 1, \"item\": 1}"; + targetDocument = "{\"_id\":\"7\", \"name\":\"doc7\", \"item\":\"fruit\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + /** + * @tc.steps: step3. Create filter to match g_document7, _id flag is 1.Projection value is not 0. + * @tc.expected: step3. Match g_document7, and return a json with name, item and _id. + */ + resultSet = nullptr; + flag = 1; + projectionInfo = "{\"name\": 10, \"item\": 10}"; + targetDocument = "{\"_id\":\"7\", \"name\":\"doc7\", \"item\":\"fruit\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest033 + * @tc.desc: Test _id flag and field.Exist field with 0 value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest033, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document7, _id flag is 0. + * @tc.expected: step1. Match the g_document7 and return json with name, item and _id + */ + const char *filter = "{\"_id\" : \"7\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":false, \"item\":false}"; + int flag = 0; + const char *targetDocument = "{\"other_Info\":[{\"school\":\"BX\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}";; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + /** + * @tc.steps: step2. Create filter to match g_document7, _id flag is 1. + * @tc.expected: step2. Match g_document7, and return a json without name and item. + */ + resultSet = nullptr; + flag = 1; + projectionInfo = "{\"name\": 0, \"item\": 0}"; + targetDocument = "{\"_id\": \"7\", \"other_Info\":[{\"school\":\"BX\", \"age\" : 15}, {\"school\":\"C\", \"age\" : 35}]}";; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + value = NULL; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest034 + * @tc.desc: Test projection with nonexist field in nested structure. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest034, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter to match g_document4, _id flag is 0. + * @tc.expected: step1. Match the g_document4 and return json without name + */ + const char *filter = "{\"_id\" : \"4\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\": 1, \"personInfo.grade1\": 1, \ + \"personInfo.shool1\": 1, \"personInfo.age1\": 1}"; + int flag = 0; + const char *targetDocument = "{\"name\":\"doc4\"}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Create filter to match g_document4, _id flag is 0, display part of fields in nested structure. + * @tc.expected: step2. Match the g_document4 and return json without name + */ + projectionInfo = "{\"name\": false, \"personInfo.grade1\": false, \ + \"personInfo.shool1\": false, \"personInfo.age1\": false}"; + const char *targetDocument2 = "{\"item\":\"paper\",\"personInfo\":{\"grade\" : 1, \"school\":\"A\", \"age\" : 18}}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument2); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step3. Create filter to match g_document4, _id flag is 0, display part of fields in nested structure. + * @tc.expected: step3. Match the g_document4 and return json with name, personInfo.school and personInfo.age. + */ + projectionInfo = "{\"name\": 1, \"personInfo.school\": 1, \"personInfo.age\": 1}"; + const char *targetDocument3 = "{\"name\":\"doc4\", \"personInfo\": {\"school\":\"A\", \"age\" : 18}}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument3); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step4. Create filter to match g_document4, _id flag is 0, display part of fields in nested structure. + * @tc.expected: step4. Match the g_document4 and return json with name, personInfo.school + */ + projectionInfo = "{\"name\": 1, \"personInfo.school\": 1, \"personInfo.age1\": 1}"; + const char *targetDocument4 = "{\"name\":\"doc4\", \"personInfo\": {\"school\":\"A\"}}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument4); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest035 + * @tc.desc: test filter with id string filter + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest035, TestSize.Level1) +{ + /** + * @tc.steps: step1. Create filter with _id and get the record according to filter condition. + * @tc.expected: step1. succeed to get the record, the matching record is g_document17 + */ + const char *filter = "{\"_id\" : \"17\"}"; + GRD_ResultSet *resultSet = nullptr; + int flag = 0; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, GRD_DOC_ID_DISPLAY, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, g_document17); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + /** + * @tc.steps: step2. Invoke GRD_Next to get the next matching value. Release resultSet. + * @tc.expected: step2. Cannot get next record, return GRD_NO_DATA. + */ + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_NOT_AVAILABLE); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest036 + * @tc.desc: Test with invalid collectionName. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest036, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with invalid collectionName. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"17\"}"; + GRD_ResultSet *resultSet = nullptr; + int flag = 0; + Query query = {filter, "{}"}; + EXPECT_EQ(GRD_FindDoc(g_db, "", query, 0, &resultSet), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_FindDoc(g_db, NULL, query, 0, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest037 + * @tc.desc: Test filed with different value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest037, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test filed with different value.some are 1, other are 0. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"4\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":1, \"personInfo\":0, \"item\":1}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Test filed with different value.some are 2, other are 0. + * @tc.expected: step2. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":2, \"personInfo\":0, \"item\":2}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step3. Test filed with different value.some are 0, other are true. + * @tc.expected: step3. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":true, \"personInfo\":0, \"item\":true}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step4. Test filed with different value.some are 0, other are "". + * @tc.expected: step4. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":\"\", \"personInfo\":0, \"item\":\"\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step5. Test filed with different value.some are 1, other are false. + * @tc.expected: step5. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":false, \"personInfo\":1, \"item\":false"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_FORMAT); + + /** + * @tc.steps: step6. Test filed with different value.some are -1.123, other are false. + * @tc.expected: step6. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":false, \"personInfo\":-1.123, \"item\":false"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_FORMAT); + + /** + * @tc.steps: step7. Test filed with different value.some are true, other are false. + * @tc.expected: step7. Return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"name\":false, \"personInfo\":true, \"item\":false"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_FORMAT); +} + +/** + * @tc.name: DocumentFindApiTest038 + * @tc.desc: Test field with false value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest038, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test field with different false value. Some are false, other are 0. flag is 0. + * @tc.expected: step1. Match the g_document6 and return empty json. + */ + const char *filter = "{\"_id\" : \"6\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":false, \"personInfo\": 0, \"item\":0}"; + int flag = 0; + const char *targetDocument = "{}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Test field with different false value.Some are false, others are 0. flag is 1. + * @tc.expected: step2. Match g_document6, Return json with _id. + */ + targetDocument = "{\"_id\": \"6\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest039 + * @tc.desc: Test field with true value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest039, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test field with different true value. Some are true, other are 1. flag is 0. + * @tc.expected: step1. Match the g_document18 and return json with name, item, personInfo.age and color. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"name\":true, \"personInfo.age\": \"\", \"item\":1, \"color\":10, \"nonExist\" : -100}"; + const char *targetDocument = "{\"name\":\"doc18\", \"item\":\"mobile phone\", \"personInfo\":\ + {\"age\":66}, \"color\":\"blue\"}"; + int flag = 0; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + char *value = nullptr; + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + + /** + * @tc.steps: step2. Test field with different true value.Some are false, others are 0. flag is 1. + * @tc.expected: step2. Match g_document18, Return json with name, item, personInfo.age, color and _id. + */ + targetDocument = "{\"_id\" : \"18\", \"name\":\"doc18\",\"item\" : \"mobile phone\",\"personInfo\":\ + {\"age\":66}, \"color\":\"blue\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest040 + * @tc.desc: Test field with invalid value. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest040, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test field with invalid value.Value is array. + * @tc.expected: step1. Match the g_document18 and return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"personInfo\":[true, 1]}"; + int flag = 1; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Test field with invalid value.Value is null. + * @tc.expected: step2. Match the g_document18 and return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"personInfo\":null}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step3. Test field with invalid value.Value is invalid string. + * @tc.expected: step3. Match the g_document18 and return GRD_INVALID_ARGS. + */ + projectionInfo = "{\"personInfo\":\"invalid string.\"}"; + query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest042 + * @tc.desc: Test field with no existed uppercase filter + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest042, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test field with no existed uppercase filter. + * @tc.expected: step1. not match any item. + */ + const char *filter = "{\"_iD\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"Name\":true, \"personInfo.age\": \"\", \"item\":1, \"COLOR\":10, \"nonExist\" : -100}"; + int flag = 0; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, flag, &resultSet), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_Next(resultSet), GRD_INVALID_ARGS); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Test field with upper projection. + * @tc.expected: step2. Match g_document18, Return json with item, personInfo.age, color and _id. + */ + const char *filter1 = "{\"_id\" : \"18\"}"; + const char* targetDocument = "{\"_id\" : \"18\", \"item\" : \"mobile phone\",\"personInfo\":\ + {\"age\":66}}"; + query = {filter1, projectionInfo}; + char *value = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest044 + * @tc.desc: Test field with uppercase projection + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest044, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with false uppercase projection + * @tc.expected: step1. Match g_document18, Return json with item, personInfo.age and _id. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{\"Name\":0, \"personInfo.age\": false, \"personInfo.SCHOOL\": false, \"item\":\ + false, \"COLOR\":false, \"nonExist\" : false}"; + const char *targetDocument = "{\"_id\" : \"18\", \"name\":\"doc18\", \"personInfo\":\ + {\"school\":\"DD\"}, \"color\":\"blue\"}"; + int flag = 0; + Query query = {filter, projectionInfo}; + char *value = nullptr; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_OK); + EXPECT_EQ(GRD_GetValue(resultSet, &value), GRD_OK); + CompareValue(value, targetDocument); + EXPECT_EQ(GRD_FreeValue(value), GRD_OK); + EXPECT_EQ(GRD_Next(resultSet), GRD_NO_DATA); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} + +/** + * @tc.name: DocumentFindApiTest045 + * @tc.desc: Test field with too long collectionName + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest045, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with false uppercase projection + * @tc.expected: step1. Match g_document18, Return json with item, personInfo.age and _id. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + int flag = 0; + Query query = {filter, "{}"}; + string collectionName1(MAX_COLLECTION_NAME, 'a'); + ASSERT_EQ(GRD_CreateCollection(g_db, collectionName1.c_str(), "", 0), GRD_OK); + EXPECT_EQ(GRD_FindDoc(g_db, collectionName1.c_str(), query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + ASSERT_EQ(GRD_DropCollection(g_db, collectionName1.c_str(), 0), GRD_OK); + + string collectionName2(MAX_COLLECTION_NAME + 1, 'a'); + EXPECT_EQ(GRD_FindDoc(g_db, collectionName2.c_str(), query, 1, &resultSet), GRD_OVER_LIMIT); + EXPECT_EQ(GRD_FindDoc(g_db, "", query, 1, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest052 + * @tc.desc: Test field when id string len is large than max + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest052, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with false uppercase projection + * @tc.expected: step1. Match g_document18, Return json with item, personInfo.age and _id. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + int flag = 0; + Query query = {filter, "{}"}; + string collectionName1(MAX_COLLECTION_NAME, 'a'); + ASSERT_EQ(GRD_CreateCollection(g_db, collectionName1.c_str(), "", 0), GRD_OK); + EXPECT_EQ(GRD_FindDoc(g_db, collectionName1.c_str(), query, 1, &resultSet), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); + ASSERT_EQ(GRD_DropCollection(g_db, collectionName1.c_str(), 0), GRD_OK); + + string collectionName2(MAX_COLLECTION_NAME + 1, 'a'); + EXPECT_EQ(GRD_FindDoc(g_db, collectionName2.c_str(), query, 1, &resultSet), GRD_OVER_LIMIT); + EXPECT_EQ(GRD_FindDoc(g_db, "", query, 1, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest053 + * @tc.desc: Test with invalid flags + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest053, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with invalid flags which is 3. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 3, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps:step1.parameter flags is int_max + * @tc.expected:step1.GRD_INVALID_ARGS + */ + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, INT_MAX, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps:step1.parameter flags is INT_MIN + * @tc.expected:step1.GRD_INVALID_ARGS + */ + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, INT_MIN, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest054 + * @tc.desc: Test with null g_db and resultSet, filter. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest054, TestSize.Level1) +{ + /** + * @tc.steps: step1. Test with null g_db. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + const char *filter = "{\"_id\" : \"18\"}"; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{}"; + Query query = {filter, projectionInfo}; + EXPECT_EQ(GRD_FindDoc(nullptr, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); + + /** + * @tc.steps: step2. Test with null resultSet. + * @tc.expected: step2. Return GRD_INVALID_ARGS. + */ + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, nullptr), GRD_INVALID_ARGS); + + /** + * @tc.steps: step1. Test with query that has two nullptr data. + * @tc.expected: step1. Return GRD_INVALID_ARGS. + */ + query = {nullptr, nullptr}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentFindApiTest055 + * @tc.desc: Find doc, but filter' _id value lens is larger than MAX_ID_LENS + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentFindApiTest, DocumentFindApiTest055, TestSize.Level1) +{ + /** + * @tc.steps:step1.Find doc, but filter' _id value lens is larger than MAX_ID_LENS + * @tc.expected:step1.GRD_OVER_LIMIT. + */ + string document1 = "{\"_id\" : "; + string document2 = "\""; + string document4 = "\""; + string document5 = "}"; + string document_midlle(MAX_ID_LENS + 1, 'k'); + string filter = document1 + document2 + document_midlle + document4 + document5; + GRD_ResultSet *resultSet = nullptr; + const char *projectionInfo = "{}"; + Query query = {filter.c_str(), projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OVER_LIMIT); + + /** + * @tc.steps:step1.Find doc, filter' _id value lens is equal as MAX_ID_LENS + * @tc.expected:step1.GRD_OK. + */ + string document_midlle2(MAX_ID_LENS, 'k'); + filter = document1 + document2 + document_midlle2 + document4 + document5; + query = {filter.c_str(), projectionInfo}; + EXPECT_EQ(GRD_FindDoc(g_db, COLLECTION_NAME, query, 0, &resultSet), GRD_OK); + EXPECT_EQ(GRD_FreeResultSet(resultSet), GRD_OK); +} \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_insert_test.cpp b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_insert_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..393c4bbc4753e73e3c59af5548392cdbbba175a4 --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/ documentdb_insert_test.cpp @@ -0,0 +1,754 @@ +/* +* Copyright (c) 2023 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. +*/ + +#include + +#include "grd_base/grd_db_api.h" +#include "grd_document/grd_document_api.h" +#include "grd_base/grd_error.h" +using namespace testing::ext; +namespace { +std::string path = "./document.db"; +GRD_DB *g_db = nullptr; +const char *RIGHT_COLLECTION_NAME = "student"; +const char *NO_EXIST_COLLECTION_NAME = "no_exisit"; +const int INT_MAX = 2147483647; +const int INT_MIN = -2147483648; +const int MAX_COLLECTION_LENS = 511; +const int MAX_ID_LENS = 899; + +static void TestInsertDocIntoCertainColl(const char *collectionName, const char *projection, int expectedResult) +{ + /** * @tc.steps: step1. Create Collection + * @tc.expected: step1. GRD_OK + */ + EXPECT_EQ(GRD_CreateCollection(g_db, collectionName, "", 0), expectedResult); + /** + * @tc.steps: step2. Insert projection into colloction. + * @tc.expected: step2. GRD_OK + */ + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName, projection, 0), expectedResult); + /** + * @tc.steps: step3. Call GRD_DroCollection to drop the collection. + * @tc.expected: step3. GRD_OK + */ + EXPECT_EQ(GRD_DropCollection(g_db, collectionName, 0), expectedResult); +} + +const char* SetRandomDocument(int i) +{ + string document1 = "{\"_id\" : "; + string document2 = "\""; + string document3 = {'2','6'}; + string document4 = "\""; + string document5 = ", \"name\" : \"Ori\"}"; + string document = document1 + document2 + document3 + document4 + document5; + return document.c_str(); +} +} + +class DocumentInsertApiTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; +void DocumentInsertApiTest::SetUpTestCase(void) +{ + std::string path = "./document.db"; + int status = GRD_DBOpen(path.c_str(), nullptr, GRD_DB_OPEN_CREATE, &g_db); + EXPECT_EQ(status, GRD_OK); + EXPECT_EQ(GRD_CreateCollection(g_db, "student", "", 0), GRD_OK); + EXPECT_NE(g_db, nullptr); +} + +void DocumentInsertApiTest::TearDownTestCase(void) +{ + EXPECT_EQ(GRD_DBClose(g_db, 0), GRD_OK); + remove(path.c_str()); +} + +void DocumentInsertApiTest::SetUp(void) +{ +} + +void DocumentInsertApiTest::TearDown(void) +{ +} + + +/** + * @tc.name: DocumentInsertApiTest001 + * @tc.desc: Insert documents into collection which dose not exist + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest001, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert document into collection which dose not exist + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"1\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, NO_EXIST_COLLECTION_NAME, document1, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest002 + * @tc.desc: Insert documents into collection which _id is not string + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest002, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a document whose _id is integer + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : 2, \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Insert a document whose _id is bool + * @tc.expected:step2.GRD_INVALID_ARGS + */ + const char *document2 = "{\"_id\" : true, \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Insert a document whose _id is NULL + * @tc.expected:step2.GRD_INVALID_ARGS + */ + const char *document3 = "{\"_id\" : null, \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document3, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Insert a document whose _id is ARRAY + * @tc.expected:step2.GRD_INVALID_ARGS + */ + const char *document4 = "{\"_id\" : [\"2\"], \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document4, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Insert a document whose _id is OBJECT + * @tc.expected:step2.GRD_INVALID_ARGS + */ + const char *document5 = "{\"_id\" : {\"val\" : \"2\"}, \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document5, 0), GRD_INVALID_ARGS); +} + + +/** + * @tc.name: DocumentInsertApiTest003 + * @tc.desc: Insert a document whose _id has appeared before + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest003, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a document whose _id is string + * @tc.expected:step1.GRD_OK + */ + const char *document1 = "{\"_id\" : \"3\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); + + /** + * @tc.steps:step2.Insert a document whose _id has appeared before + * @tc.expected:step2.GRD_DATA_CONFLICT + */ + // const char *document2 = "{\"_id\" : \"3\", \"name\" : \"Chuan\"}"; + // EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_DATA_CONFLICT); +} + +/** + * @tc.name: DocumentInsertApiTest004 + * @tc.desc: Test Insert with null parameter. parameter db is NULL + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest004, TestSize.Level1) +{ + /** + * @tc.steps:step1.step1.parameter db is NULL + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"4\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(NULL, RIGHT_COLLECTION_NAME, document1, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest005 + * @tc.desc: Test insert with null parameter. parameter collectionName is NULL. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest005, TestSize.Level1) +{ + /** + * @tc.steps:step1.Parameter collectionName is NULL + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"5\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, NULL, document1, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Parameter collectionName is empty string + * @tc.expected:step2.GRD_INVALID_ARGS + */ + const char *document2 = "{\"_id\" : \"5\", \"name\" : \"Chuang\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, "", document2, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest006 + * @tc.desc: parameter flags is not zero + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest006, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter flags is not zero + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"6\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 1), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest007 + * @tc.desc: parameter flags is INT_MAX + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest007, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter flags is int_max + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"7\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, INT_MAX), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest008 + * @tc.desc: parameter flags is int_min + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest008, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter flags is int_min + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"_id\" : \"8\", \"name\" : \"Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, INT_MIN), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest009 + * @tc.desc: parameter collectionName and document is NULL or invalid + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest009, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter collectionName and document is NULL; + * @tc.expected:step1.GRD_INVALID_ARGS + */ + EXPECT_EQ(GRD_InsertDoc(g_db, NULL, NULL, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.parameter collectionName is larger than max_collectionName_lens; + * @tc.expected:step2.GRD_OVER_LIMIT + */ + const char *document1 = "{\"_id\" : \"9\", \"name\" : \"Ori\"}"; + std::string collectionName2(MAX_COLLECTION_LENS + 1, 'a'); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName2.c_str(), document1, 0), GRD_OVER_LIMIT); +} + +/** + * @tc.name: DocumentInsertApiTest010 + * @tc.desc: parameter collectionName contains irregular charactor + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest010, TestSize.Level1) +{ + /** + * @tc.steps:step1.Create Collection whose parameter collectionName contains irregular charactor + * @tc.expected:step1.GRD_OK + */ + const char *collectionName = "collction@!#"; + const char *document1 = "{\"_id\" : \"10\", \"name\" : \"Ori\"}"; + TestInsertDocIntoCertainColl(collectionName, document1, GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest011 + * @tc.desc: parameter collectionName is longer than 256 charactors + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest011, TestSize.Level1) +{ + /** + * @tc.steps:step1.Create Collection whose parameter collectionName contains irregular charactor + * @tc.expected:step1.GRD_OK + */ + string collectionName(257, 'k'); + const char *document1 = "{\"_id\" : \"10\", \"name\" : \"Ori\"}"; + TestInsertDocIntoCertainColl(collectionName.c_str(), document1, GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest014 + * @tc.desc: Inserted document's JSON depth is larger than 4, which is 5. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest014, TestSize.Level1) +{ + /** + * @tc.steps:step1.document's JSON depth is larger than 4, which is 5. + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document1 = "{\"level1\" : {\"level2\" : {\"level3\" : {\"level4\": {\"level5\" : 1}}, \"level3_2\" : \"level3_2_val\"\ + }},\"_id\":\"14\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step1.document's JSON depth is larger than 4, which is 5.But with array type. + * @tc.expected:step1.GRD_INVALID_ARGS + */ + const char *document2 = "{\"level1\" : {\"level2\" : {\"level3\" : [{ \"level5\" : \"level5_1val\", \"level5_2\":\ + \"level5_2_val\"}, \"level4_val1\",\"level4_val2\"], \"level3_2\" : \"level3_2_val\"\ + }},\"_id\":\"14\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step1.document's JSON depth is 4 + * @tc.expected:step1.GRD_OK + */ + const char *document3 = "{\"level1\" : {\"level2\" : {\"level3\" : { \"level4\" : \"level5_1val\"}, \"level3_2\" : \"level3_2_val\"\ + }},\"_id\":\"14\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document3, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest015 + * @tc.desc: Inserted document with all kinds of size + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest015, TestSize.Level1) +{ + /** + * @tc.steps:step1.document's JSON is bigger than 512k - 1 + * @tc.expected:step1.GRD_INVALID_ARGS + */ + string documentPart1 = "{ \"_id\" : \"15\", \"textVal\" : \" "; + string documentPart2 = "\" }"; + string jsonVal = string(512 * 1024 - documentPart1.size() - documentPart2.size(), 'k'); + string document = documentPart1 + jsonVal + documentPart2; + //EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document.c_str(), 0), GRD_OVER_LIMIT); + /** + * @tc.steps:step2.Insert document's JSON is a large data but lower than 512k - 1 + * @tc.expected:step2.GRD_OK + */ + string jsonVal2 = string(512 * 1024 - 1 - documentPart1.size() - documentPart2.size(), 'k'); + string document2 = documentPart1 + jsonVal2 + documentPart2; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2.c_str(), 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest016 + * @tc.desc: document JSON string contains irregular char + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest016, TestSize.Level1) +{ + /** + * @tc.steps:step1.document JSON string contains irregular char. + * @tc.expected:step1.GRD_OK + */ + const char *document1 = "{\"_id\" : \"16\", \"name\" : \"!@#Ori\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest017 + * @tc.desc: document JSON string contains invalid value type such as BLOB type + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest017, TestSize.Level1) +{ + /** + * @tc.steps:step1.document JSON string contains invalid value type such as BLOB type. + * @tc.expected:step1.GRD_INVALID_FORMAT. + */ + const char *document = "{\"_id\" : \"17\", \"level1\" : {\"level2\" : {\"level3\" : {\"level4\" : x'1234'\ + } } }, \"level1_2\" : \"level1_2Val\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document, 0), GRD_INVALID_FORMAT); +} + +/** + * @tc.name: DocumentInsertApiTest018 + * @tc.desc: The Inserted document is not JSON format + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest018, TestSize.Level1) +{ + /** + * @tc.steps:step1.The Inserted document is not JSON format + * @tc.expected:step1.GRD_INVALID_FORMAT. + */ + const char *document = "some random string not JSON format"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document, 0), GRD_INVALID_FORMAT); +} + +/** + * @tc.name: DocumentInsertApiTest019 + * @tc.desc: Insert a normal documents + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest019, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a normal documents which _id is in the end of the string + * @tc.expected:step1.GRD_OK. + */ + const char *document1 = "{\"name\" : \"Jack\", \"age\" : 18, \"friend\" : {\"name\" : \" lucy\"}, \"_id\" : \"19\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest022 + * @tc.desc: parameter collectionName is equal to 256 charactors + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest022, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter collectionName is equal to 256 charactors + * @tc.expected:step1.GRD_OK. + */ + string collectionName = string(256, 'k'); + string collectionName1(MAX_COLLECTION_LENS, 'a'); + const char *document1 = "{\"_id\" : \"22\", \"name\" : \"Ori\"}"; + TestInsertDocIntoCertainColl(collectionName.c_str(), document1, GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest023 + * @tc.desc: parameter collectionName contains upper & lower case charactors, + * numbers and underline + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest023, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter collectionName contains upper & lower case charactors, + * numbers and underline + * @tc.expected:step1.GRD_OK. + */ + string collectionName = "Aads_sd__23Asb_"; + const char *document1 = "{\"_id\" : \"23\", \"name\" : \"Ori\"}"; + TestInsertDocIntoCertainColl(collectionName.c_str(), document1, GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest024 + * @tc.desc: parameter collectionName's head is GRD_ or GM_SYS_ + * numbers and underline + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest024, TestSize.Level1) +{ + /** + * @tc.steps:step1.parameter collectionName's head is GRD_ + * @tc.expected:step1.GRD_INVALID_FORMAT. + */ + string collectionName = "GRD_collectionName"; + const char *document1 = "{\"_id\" : \"24\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document1, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step2.parameter collectionName's head is GM_SYS_ + * @tc.expected:step2.GRD_INVALID_FORMAT. + */ + collectionName = "GM_SYS__collectionName"; + const char *document2 = "{\"_id\" : \"24_2\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document2, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step3.parameter collectionName's head is grd_ + * @tc.expected:step3.GRD_INVALID_FORMAT. + */ + collectionName = "grd_collectionName"; + const char *document3 = "{\"_id\" : \"24_3\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document3, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step4.parameter collectionName's head is gm_sys_ + * @tc.expected:step4.GRD_INVALID_FORMAT. + */ + collectionName = "gm_sys_collectionName"; + const char *document4 = "{\"_id\" : \"24_4\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document4, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step5.parameter collectionName's head is gM_sYs_ that has Uppercase and lowercase at the same time. + * @tc.expected:step5.GRD_INVALID_FORMAT. + */ + collectionName = "gM_sYs_collectionName"; + const char *document5 = "{\"_id\" : \"24_5\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document5, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step6.parameter collectionName's head is gRd_ that has Uppercase and lowercase at the same time. + * @tc.expected:step6.GRD_INVALID_FORMAT. + */ + collectionName = "gRd_collectionName"; + const char *document6 = "{\"_id\" : \"24_6\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document6, 0), GRD_INVALID_FORMAT); + + /** + * @tc.steps:step7.parameter collectionName's head is grd@ that has no '_' + * @tc.expected:step7.GRD_INVALID_FORMAT. + */ + collectionName = "gRd@collectionName"; + const char *document7 = "{\"_id\" : \"24_7\", \"name\" : \"Ori\"}"; + GRD_CreateCollection(g_db, collectionName.c_str(), "", 0); + EXPECT_EQ(GRD_InsertDoc(g_db, collectionName.c_str(), document7, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest025 + * @tc.desc: Insert document whose depth is 4, which is allowed + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest025, TestSize.Level1) +{ + /** + * @tc.steps:step1.documents JSON depth is 4, which is allowed. + * @tc.expected:step1.GRD_OK. + */ + const char *document1 = "{\"_id\" : \"25_0\", \"level1\" : { \"level2\" : {\"level3\" :\ + {\"level4\" : \"level4Val\" } } } , \"level1_2\" : \"level1_2Val\" }"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); + /** + * @tc.steps:step2.documents JSON depth is exactly 4. + * @tc.expected:step2.GRD_OK. + */ + const char *document2 = "{\"_id\" : \"25_1\", \"class_name\" : \"计算机科学一班\", \"signed_info\" : true, \"student_info\" : [{\"name\":\"张三\", \ + \"age\" : 18, \"sex\" : \"男\"}, { \"newName1\" : [\"qw\", \"dr\", 0, \"ab\"] }]}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_OK); + /** + * @tc.steps:step3.documents JSON depth is exactly 4, but the last field in array contains leading number + * @tc.expected:step3.GRD_INVALID_ARGS. + */ + const char *document3 = "{\"_id\" : \"25_2\", \"class_name\" : \"计算机科学一班\", \"signed_info\" : true, \"student_info\" : [{\"name\":\"张三\", \ + \"age\" : 18, \"sex\" : \"男\"}, [\"qw\", \"dr\", 0, \"ab\", {\"0ab\" : null}]]}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document3, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step4.documents JSON depth is exactly 5. + * @tc.expected:step4.GRD_INVALID_ARGS. + */ + const char *document4 = "{\"_id\" : \"25_3\", \"class_name\" : \"计算机科学一班\", \"signed_info\" : true, \"student_info\" : [{\"name\":\"张三\", \ + \"age\" : 18, \"sex\" : \"男\"}, { \"newName1\" : [\"qw\", \"dr\", 0, \"ab\", {\"level5\" : 1}] }]}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document4, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest026 + * @tc.desc: Insert 100 normal documents continuously + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert 100 normal documents continuously + * @tc.expected:step1.GRD_OK. + */ + string document1 = "{\"_id\" : "; + string document2 = "\""; + string document4 = "\""; + string document5 = ", \"name\" : \"Ori\"}"; + for (int i = 0; i < 5; i++) { + string document_midlle = {'2','6' + i}; + string document = document1 + document2 + document_midlle + document4 + document5; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document.c_str(), 0), GRD_OK); + } +} + +/** + * @tc.name: DocumentInsertApiTest035 + * @tc.desc: Insert a document whose value contains + * upper &lower case charactors, numbers and underline. + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest035, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a document whose value contains + * upper &lower case charactors, numbers and underline. + * @tc.expected:step1.GRD_OK. + */ + const char *document1 = "{\"_id\" : \"35\", \"A_aBdk_324_\" : \"value\", \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); + /** + * @tc.steps:step1.Insert a document whose value contains + * upper &lower case charactors, numbers and underline. + * But the field started with number, which is not allowed. + * @tc.expected:step1.GRD_OK. + */ + const char *document2 = "{\"_id\" : \"35_2\", \"1A_aBdk_324_\" : \"value\", \"name\" : \"Chuan\"}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_INVALID_ARGS); +} + +/** + * @tc.name: DocumentInsertApiTest036 + * @tc.desc: Insert a document whose value contains + * string, number, bool, null, array and object type + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest036, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a document whose value contains + * string, number, bool, null, array and object type + * @tc.expected:step1.GRD_OK. + */ + const char *document1 = "{\"_id\" : \"36_0\", \"stringType\" : \"stringVal\", \"numType\" : 1, \"BoolType\" : true,\ + \"nullType\" : null, \"arrayType\" : [1, 2, 3, 4], \"objectType\" : {\"A\" : 3}}"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest038 + * @tc.desc: Insert document whose value is over the range of double + * string, number, bool, null, array and object type + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest038, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert document whose value is over the range of double + * @tc.expected:step1.GRD_INVALID_ARGS. + */ + const char *document1 = R"({"_id" : "38_0", "field2" : 1.79769313486232e308})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document1, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step2.Insert document whose value is over the range of double + * @tc.expected:step2.GRD_INVALID_ARGS. + */ + const char *document2 = R"({"_id" : "38_1", "t1" : {"field2" : 1.79769313486232e308}})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step3.Insert document whose value is over the range of double + * @tc.expected:step3.GRD_INVALID_ARGS. + */ + const char *document3 = R"({"_id" : "38_2", "t1" : [1, 2, 1.79769313486232e308]})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document3, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step4.Insert document whose value is over the range of double + * @tc.expected:step4.GRD_INVALID_ARGS. + */ + const char *document4 = R"({"_id" : "38_3", "t1" : [1, 2, -1.7976931348623167E+308]})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document2, 0), GRD_INVALID_ARGS); + /** + * @tc.steps:step5.Insert document with minimum double value + * @tc.expected:step5.GRD_INVALID_ARGS. + */ + const char *document5 = R"({"_id" : "38_4", "t1" : [1, 2, -1.79769313486231570E+308]})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document5, 0), GRD_OK); + /** + * @tc.steps:step6.Insert document with maxium double value + * @tc.expected:step6.GRD_INVALID_ARGS. + */ + const char *document6 = R"({"_id" : "38_5", "t1" : [1, 2, 1.79769313486231570E+308]})"; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document6, 0), GRD_OK); +} + +/** + * @tc.name: DocumentInsertApiTest039 + * @tc.desc: Insert a filter which _id value's lens is larger than MAX_ID_LENS + * @tc.type: FUNC + * @tc.require: + * @tc.author: mazhao + */ +HWTEST_F(DocumentInsertApiTest, DocumentInsertApiTest039, TestSize.Level1) +{ + /** + * @tc.steps:step1.Insert a filter which _id value's lens is larger than MAX_ID_LENS. + * @tc.expected:step1.GRD_OVER_LIMIT. + */ + string document1 = "{\"_id\" : "; + string document2 = "\""; + string document4 = "\""; + string document5 = ", \"name\" : \"Ori\"}"; + string document_midlle(MAX_ID_LENS + 1, 'k'); + string document = document1 + document2 + document_midlle + document4 + document5; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document.c_str(), 0), GRD_OVER_LIMIT); + + /** + * @tc.steps:step1.Insert a filter which _id value's lens is equal as MAX_ID_LENS. + * @tc.expected:step1.GRD_OK. + */ + string document_midlle2(MAX_ID_LENS, 'k'); + document = document1 + document2 + document_midlle2 + document4 + document5; + EXPECT_EQ(GRD_InsertDoc(g_db, RIGHT_COLLECTION_NAME, document.c_str(), 0), GRD_OK); +} \ No newline at end of file diff --git a/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/documentdb_test_utils.h b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/documentdb_test_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a513875ef87a922f39132229a2e9e620f2bda17c --- /dev/null +++ b/services/distributeddataservice/service/data_share/gaussdb_rd_Simple/test/unittest/api/documentdb_test_utils.h @@ -0,0 +1,27 @@ +/* +* Copyright (c) 2023 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 DOCUMENTDB_TEST_UTILS_H +#define DOCUMENTDB_TEST_UTILS_H +#include + + +namespace DocumentDBUnitTest { +class DocumentDBTestUtils { +public: + static int RemoveTestDbFiles(const std::string &dir); +}; +} // namespace DocumentDBUnitTest +#endif // DOCUMENTDB_TEST_UTILS_H \ No newline at end of file