diff options
author | Tor Brede Vekterli <vekterli@yahooinc.com> | 2023-02-21 14:24:27 +0000 |
---|---|---|
committer | Tor Brede Vekterli <vekterli@yahooinc.com> | 2023-02-21 14:24:27 +0000 |
commit | da0b9d14547e6c98b0472f1834f086a0e1efd717 (patch) | |
tree | da20bd8a069c68f96a80f1110e8a9057904a6eaf /document | |
parent | 813df553bcf33a6fe161a22b6f6b93b2780308b5 (diff) |
Fix regression where supertype in field expression would not resolve
A change between 7 and 8 to use exact-matching for document types was
implemented a tad too aggressively, as it should still be possible to
match against supertypes in a document selection field expression.
Let type `B` inherit `A`, and `A` have a field `foo`, and matching a
document of type `B`:
Prior to this fix:
* `B.foo` _would_ match (implicit supertype field resolving)
* `A.foo` would _not_ match due to exact type mismatch
After this fix, both will match as generally expected.
Diffstat (limited to 'document')
-rw-r--r-- | document/src/tests/documentselectparsertest.cpp | 5 | ||||
-rw-r--r-- | document/src/vespa/document/select/valuenodes.cpp | 20 |
2 files changed, 18 insertions, 7 deletions
diff --git a/document/src/tests/documentselectparsertest.cpp b/document/src/tests/documentselectparsertest.cpp index ce4b69419a3..5e14a080f27 100644 --- a/document/src/tests/documentselectparsertest.cpp +++ b/document/src/tests/documentselectparsertest.cpp @@ -673,8 +673,9 @@ TEST_F(DocumentSelectParserTest, operators_1) // Inherited doctypes PARSE("testdoctype2", *_doc[4], True); PARSE("testdoctype2", *_doc[3], False); - PARSE("testdoctype1", *_doc[4], False); // testdoctype2 inherits testdoctype1, but we use exact matching for types - PARSE("testdoctype1.headerval = 10", *_doc[4], Invalid); + PARSE("testdoctype1", *_doc[4], False); // testdoctype2 inherits testdoctype1, but we use exact matching for "standalone" doctype matches. + PARSE("testdoctype1.headerval = 10", *_doc[4], True); // But _field lookups_ use is-a type matching semantics. + PARSE("testdoctype2.headerval = 10", *_doc[4], True); // Exact type match with parent field also works transparently } TEST_F(DocumentSelectParserTest, operators_2) diff --git a/document/src/vespa/document/select/valuenodes.cpp b/document/src/vespa/document/select/valuenodes.cpp index 8102a944ff0..b3052cc07e2 100644 --- a/document/src/vespa/document/select/valuenodes.cpp +++ b/document/src/vespa/document/select/valuenodes.cpp @@ -20,10 +20,20 @@ LOG_SETUP(".document.select.valuenode"); namespace document::select { namespace { - bool documentTypeEqualsName(const DocumentType& type, vespalib::stringref name) - { - return (type.getName() == name); + +[[nodiscard]] bool document_type_is_a(const DocumentType& type, vespalib::stringref name) { + if (type.getName() == name) { + return true; + } + // No exact match; try to recursively match name against any types inherited from. + for (const auto* parent : type.getInheritedTypes()) { + if (document_type_is_a(*parent, name)) { + return true; + } } + return false; +} + } InvalidValueNode::InvalidValueNode(vespalib::stringref name) @@ -409,7 +419,7 @@ FieldValueNode::getValue(const Context& context) const const Document& doc = *context._doc; - if (!documentTypeEqualsName(doc.getType(), _doctype)) { + if (!document_type_is_a(doc.getType(), _doctype)) { return std::make_unique<InvalidValue>(); } // Imported fields can only be meaningfully evaluated inside Proton, so we @@ -473,7 +483,7 @@ FieldValueNode::traceValue(const Context &context, std::ostream& out) const return defaultTrace(getValue(context), out); } const Document &doc(*context._doc); - if (!documentTypeEqualsName(doc.getType(), _doctype)) { + if (!document_type_is_a(doc.getType(), _doctype)) { out << "Document is of type " << doc.getType() << " which isn't a " << _doctype << " document, thus resolving invalid.\n"; return std::make_unique<InvalidValue>(); |