From a1a639120d7662cb68f0ba5770e4f42cc9415069 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 9 Feb 2017 16:18:57 -0600 Subject: [core] Introduce dedicated filter types for $type and $id special cases (#7971) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [core] Introduce dedicated filter types for $type and $id special cases * [ios, macos] Special-case $id, $type in predicates Also support $id ≟ nil. --- include/mbgl/style/conversion/filter.hpp | 144 +++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 26 deletions(-) (limited to 'include/mbgl/style/conversion') diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 3ab91e5bbc..2c4eeb4ac7 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -27,9 +27,9 @@ public: } if (*op == "==") { - return convertBinaryFilter(value); + return convertEqualityFilter(value); } else if (*op == "!=") { - return convertBinaryFilter(value); + return convertEqualityFilter(value); } else if (*op == ">") { return convertBinaryFilter(value); } else if (*op == ">=") { @@ -39,9 +39,9 @@ public: } else if (*op == "<=") { return convertBinaryFilter(value); } else if (*op == "in") { - return convertSetFilter(value); + return convertSetFilter(value); } else if (*op == "!in") { - return convertSetFilter(value); + return convertSetFilter(value); } else if (*op == "all") { return convertCompoundFilter(value); } else if (*op == "any") { @@ -49,32 +49,57 @@ public: } else if (*op == "none") { return convertCompoundFilter(value); } else if (*op == "has") { - return convertUnaryFilter(value); + return convertUnaryFilter(value); } else if (*op == "!has") { - return convertUnaryFilter(value); + return convertUnaryFilter(value); } return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" }; } private: - Result normalizeValue(const std::string& key, const optional& value) const { + Result normalizeValue(const optional& value) const { if (!value) { return Error { "filter expression value must be a boolean, number, or string" }; - } else if (key != "$type") { + } else { return *value; - } else if (*value == std::string("Point")) { - return Value(uint64_t(FeatureType::Point)); - } else if (*value == std::string("LineString")) { - return Value(uint64_t(FeatureType::LineString)); - } else if (*value == std::string("Polygon")) { - return Value(uint64_t(FeatureType::Polygon)); + } + } + + template + Result toFeatureType(const V& value) const { + optional type = toString(value); + if (!type) { + return Error { "value for $type filter must be a string" }; + } else if (*type == "Point") { + return FeatureType::Point; + } else if (*type == "LineString") { + return FeatureType::LineString; + } else if (*type == "Polygon") { + return FeatureType::Polygon; } else { return Error { "value for $type filter must be Point, LineString, or Polygon" }; } } - template + template + Result toFeatureIdentifier(const V& value) const { + optional identifier = toValue(value); + if (!identifier) { + return Error { "filter expression value must be a boolean, number, or string" }; + } else { + return (*identifier).match( + [] (uint64_t t) -> Result { return t; }, + [] ( int64_t t) -> Result { return t; }, + [] ( double t) -> Result { return t; }, + [] (const std::string& t) -> Result { return t; }, + [] (const auto&) -> Result { + return Error { "filter expression value must be a boolean, number, or string" }; + }); + } + } + + template Result convertUnaryFilter(const V& value) const { if (arrayLength(value) < 2) { return Error { "filter expression must have 2 elements" }; @@ -85,7 +110,48 @@ private: return Error { "filter expression key must be a string" }; } - return FilterType { *key }; + if (*key == "$id") { + return IdentifierFilterType {}; + } else { + return FilterType { *key }; + } + } + + template + Result convertEqualityFilter(const V& value) const { + if (arrayLength(value) < 3) { + return Error { "filter expression must have 3 elements" }; + } + + optional key = toString(arrayMember(value, 1)); + if (!key) { + return Error { "filter expression key must be a string" }; + } + + if (*key == "$type") { + Result filterValue = toFeatureType(arrayMember(value, 2)); + if (!filterValue) { + return filterValue.error(); + } + + return TypeFilterType { *filterValue }; + + } else if (*key == "$id") { + Result filterValue = toFeatureIdentifier(arrayMember(value, 2)); + if (!filterValue) { + return filterValue.error(); + } + + return IdentifierFilterType { *filterValue }; + + } else { + Result filterValue = normalizeValue(toValue(arrayMember(value, 2))); + if (!filterValue) { + return filterValue.error(); + } + + return FilterType { *key, *filterValue }; + } } template @@ -99,7 +165,7 @@ private: return Error { "filter expression key must be a string" }; } - Result filterValue = normalizeValue(*key, toValue(arrayMember(value, 2))); + Result filterValue = normalizeValue(toValue(arrayMember(value, 2))); if (!filterValue) { return filterValue.error(); } @@ -107,7 +173,7 @@ private: return FilterType { *key, *filterValue }; } - template + template Result convertSetFilter(const V& value) const { if (arrayLength(value) < 2) { return Error { "filter expression must at least 2 elements" }; @@ -118,16 +184,42 @@ private: return Error { "filter expression key must be a string" }; } - std::vector values; - for (std::size_t i = 2; i < arrayLength(value); ++i) { - Result filterValue = normalizeValue(*key, toValue(arrayMember(value, i))); - if (!filterValue) { - return filterValue.error(); + if (*key == "$type") { + std::vector values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result filterValue = toFeatureType(arrayMember(value, i)); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); } - values.push_back(*filterValue); - } - return FilterType { *key, std::move(values) }; + return TypeFilterType { std::move(values) }; + + } else if (*key == "$id") { + std::vector values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result filterValue = toFeatureIdentifier(arrayMember(value, i)); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); + } + + return IdentifierFilterType { std::move(values) }; + + } else { + std::vector values; + for (std::size_t i = 2; i < arrayLength(value); ++i) { + Result filterValue = normalizeValue(toValue(arrayMember(value, i))); + if (!filterValue) { + return filterValue.error(); + } + values.push_back(*filterValue); + } + + return FilterType { *key, std::move(values) }; + } } template -- cgit v1.2.1