diff options
Diffstat (limited to 'document')
-rw-r--r-- | document/CMakeLists.txt | 1 | ||||
-rw-r--r-- | document/src/tests/select/CMakeLists.txt | 9 | ||||
-rw-r--r-- | document/src/tests/select/select_test.cpp | 119 | ||||
-rw-r--r-- | document/src/vespa/document/select/valuenodes.cpp | 10 |
4 files changed, 139 insertions, 0 deletions
diff --git a/document/CMakeLists.txt b/document/CMakeLists.txt index 574ac98f845..8c49f7bd7bf 100644 --- a/document/CMakeLists.txt +++ b/document/CMakeLists.txt @@ -34,6 +34,7 @@ vespa_define_module( src/tests/fieldvalue src/tests/predicate src/tests/repo + src/tests/select src/tests/serialization src/tests/struct_anno src/tests/tensor_fieldvalue diff --git a/document/src/tests/select/CMakeLists.txt b/document/src/tests/select/CMakeLists.txt new file mode 100644 index 00000000000..02f4f50b883 --- /dev/null +++ b/document/src/tests/select/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(document_select_test_app TEST + SOURCES + select_test.cpp + DEPENDS + document + GTest::GTest +) +vespa_add_test(NAME document_select_test_app COMMAND document_select_test_app) diff --git a/document/src/tests/select/select_test.cpp b/document/src/tests/select/select_test.cpp new file mode 100644 index 00000000000..fa42487cd1b --- /dev/null +++ b/document/src/tests/select/select_test.cpp @@ -0,0 +1,119 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/gtest/gtest.h> +#include <vespa/document/base/documentid.h> +#include <vespa/document/datatype/documenttype.h> +#include <vespa/document/datatype/referencedatatype.h> +#include <vespa/document/fieldvalue/document.h> +#include <vespa/document/fieldvalue/referencefieldvalue.h> +#include <vespa/document/repo/configbuilder.h> +#include <vespa/document/repo/documenttyperepo.h> +#include <vespa/document/repo/document_type_repo_factory.h> +#include <vespa/document/select/parser.h> + +#include <vespa/log/log.h> +LOG_SETUP("document_select_test"); + +using document::Document; +using document::DocumentId; +using document::DocumenttypesConfig; +using document::DocumentType; +using document::DocumentTypeRepo; +using document::DocumentTypeRepoFactory; +using document::Field; +using document::ReferenceDataType; +using document::ReferenceFieldValue; +using document::BucketIdFactory; +using document::select::Parser; +using document::select::Result; +using document::select::ResultList; + +std::shared_ptr<DocumenttypesConfig> make_document_types() { + using Struct = document::config_builder::Struct; + document::config_builder::DocumenttypesConfigBuilderHelper builder; + constexpr int parent_doctype_id = 42; + constexpr int child_doctype_id = 43; + constexpr int ref_type_id = 44; + builder.document(parent_doctype_id, "parent", + Struct("parent.header"), + Struct("parent.body")); + builder.document(child_doctype_id, "child", + Struct("child.header"). + addField("ref", ref_type_id), + Struct("child.body")). + referenceType(ref_type_id, parent_doctype_id); + return std::make_shared<DocumenttypesConfig>(builder.config()); +} + +class DocumentSelectTest : public ::testing::Test +{ +protected: + std::shared_ptr<DocumenttypesConfig> _document_types; + std::shared_ptr<const DocumentTypeRepo> _repo; + const DocumentType* _child_document_type; + const Field& _child_ref_field; + const ReferenceDataType& _child_ref_field_type; + BucketIdFactory _bucket_id_factory; + std::unique_ptr<Parser> _parser; +public: + DocumentSelectTest(); + ~DocumentSelectTest() override; + void check_select(const Document &doc, const vespalib::string &expression, const Result &exp_result); +}; + +DocumentSelectTest::DocumentSelectTest() + : ::testing::Test(), + _document_types(make_document_types()), + _repo(DocumentTypeRepoFactory::make(*_document_types)), + _child_document_type(_repo->getDocumentType("child")), + _child_ref_field(_child_document_type->getField("ref")), + _child_ref_field_type(dynamic_cast<const ReferenceDataType&>(_child_ref_field.getDataType())), + _bucket_id_factory(), + _parser(std::make_unique<Parser>(*_repo, _bucket_id_factory)) +{ +} + +DocumentSelectTest::~DocumentSelectTest() = default; + +void +DocumentSelectTest::check_select(const Document& doc, const vespalib::string& expression, const Result &exp_result) +{ + auto node = _parser->parse(expression); + EXPECT_EQ(node->contains(doc), exp_result); +} + + +TEST_F(DocumentSelectTest, check_existing_reference_field) +{ + auto document = std::make_unique<Document>(*_child_document_type, DocumentId("id::child::0")); + document->setFieldValue(_child_ref_field, std::make_unique<ReferenceFieldValue>(_child_ref_field_type, DocumentId("id::parent::1"))); + EXPECT_TRUE(document->hasValue(_child_ref_field)); + check_select(*document, "child.ref == null", Result::False); + check_select(*document, "child.ref != null", Result::True); + check_select(*document, "child.ref == \"id::parent::1\"", Result::True); + check_select(*document, "child.ref != \"id::parent::1\"", Result::False); + check_select(*document, "child.ref == \"id::parent::2\"", Result::False); + check_select(*document, "child.ref != \"id::parent::2\"", Result::True); + check_select(*document, "child.ref < \"id::parent::0\"", Result::False); + check_select(*document, "child.ref < \"id::parent::2\"", Result::True); + check_select(*document, "child.ref > \"id::parent::0\"", Result::True); + check_select(*document, "child.ref > \"id::parent::2\"", Result::False); +} + +TEST_F(DocumentSelectTest, check_missing_reference_field) +{ + auto document = std::make_unique<Document>(*_child_document_type, DocumentId("id::child::0")); + EXPECT_FALSE(document->hasValue(_child_ref_field)); + check_select(*document, "child.ref == null", Result::True); + check_select(*document, "child.ref != null", Result::False); + check_select(*document, "child.ref == \"id::parent::1\"", Result::False); + check_select(*document, "child.ref != \"id::parent::1\"", Result::True); + check_select(*document, "child.ref == \"id::parent::2\"", Result::False); + check_select(*document, "child.ref != \"id::parent::2\"", Result::True); + check_select(*document, "child.ref < \"id::parent::0\"", Result::Invalid); + check_select(*document, "child.ref < \"id::parent::2\"", Result::Invalid); + check_select(*document, "child.ref > \"id::parent::0\"", Result::Invalid); + check_select(*document, "child.ref > \"id::parent::2\"", Result::Invalid); +} + +GTEST_MAIN_RUN_ALL_TESTS() diff --git a/document/src/vespa/document/select/valuenodes.cpp b/document/src/vespa/document/select/valuenodes.cpp index 026623cf83c..73fc1c6486b 100644 --- a/document/src/vespa/document/select/valuenodes.cpp +++ b/document/src/vespa/document/select/valuenodes.cpp @@ -6,6 +6,7 @@ #include <vespa/document/base/exceptions.h> #include <vespa/document/update/documentupdate.h> #include <vespa/document/fieldvalue/fieldvalues.h> +#include <vespa/document/fieldvalue/referencefieldvalue.h> #include <vespa/document/fieldvalue/iteratorhandler.h> #include <vespa/document/datatype/documenttype.h> #include <vespa/vespalib/util/md5.h> @@ -303,6 +304,15 @@ IteratorHandler::getInternalValue(const FieldValue& fval) const const StringFieldValue& val(dynamic_cast<const StringFieldValue&>(fval)); return std::make_unique<StringValue>(val.getAsString()); } + case ReferenceFieldValue::classId: + { + const ReferenceFieldValue& val(dynamic_cast<const ReferenceFieldValue&>(fval)); + if (val.hasValidDocumentId()) { + return std::make_unique<StringValue>(val.getDocumentId().toString()); + } else { + return std::make_unique<InvalidValue>(); + } + } case ArrayFieldValue::classId: { const ArrayFieldValue& val(dynamic_cast<const ArrayFieldValue&>(fval)); |