Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] Introduce dedicated filter types for $type and $id special cases #7971

Merged
merged 2 commits into from
Feb 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 118 additions & 26 deletions include/mbgl/style/conversion/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ struct Converter<Filter> {
}

if (*op == "==") {
return convertBinaryFilter<EqualsFilter>(value);
return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value);
} else if (*op == "!=") {
return convertBinaryFilter<NotEqualsFilter>(value);
return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value);
} else if (*op == ">") {
return convertBinaryFilter<GreaterThanFilter>(value);
} else if (*op == ">=") {
Expand All @@ -39,42 +39,67 @@ struct Converter<Filter> {
} else if (*op == "<=") {
return convertBinaryFilter<LessThanEqualsFilter>(value);
} else if (*op == "in") {
return convertSetFilter<InFilter>(value);
return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value);
} else if (*op == "!in") {
return convertSetFilter<NotInFilter>(value);
return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value);
} else if (*op == "all") {
return convertCompoundFilter<AllFilter>(value);
} else if (*op == "any") {
return convertCompoundFilter<AnyFilter>(value);
} else if (*op == "none") {
return convertCompoundFilter<NoneFilter>(value);
} else if (*op == "has") {
return convertUnaryFilter<HasFilter>(value);
return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value);
} else if (*op == "!has") {
return convertUnaryFilter<NotHasFilter>(value);
return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value);
}

return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
}

private:
Result<Value> normalizeValue(const std::string& key, const optional<Value>& value) const {
Result<Value> normalizeValue(const optional<Value>& 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 <class V>
Result<FeatureType> toFeatureType(const V& value) const {
optional<std::string> 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 <class FilterType, class V>
template <class V>
Result<FeatureIdentifier> toFeatureIdentifier(const V& value) const {
optional<Value> 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<FeatureIdentifier> { return t; },
[] ( int64_t t) -> Result<FeatureIdentifier> { return t; },
[] ( double t) -> Result<FeatureIdentifier> { return t; },
[] (const std::string& t) -> Result<FeatureIdentifier> { return t; },
[] (const auto&) -> Result<FeatureIdentifier> {
return Error { "filter expression value must be a boolean, number, or string" };
});
}
}

template <class FilterType, class IdentifierFilterType, class V>
Result<Filter> convertUnaryFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must have 2 elements" };
Expand All @@ -85,7 +110,48 @@ struct Converter<Filter> {
return Error { "filter expression key must be a string" };
}

return FilterType { *key };
if (*key == "$id") {
return IdentifierFilterType {};
} else {
return FilterType { *key };
}
}

template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
Result<Filter> convertEqualityFilter(const V& value) const {
if (arrayLength(value) < 3) {
return Error { "filter expression must have 3 elements" };
}

optional<std::string> key = toString(arrayMember(value, 1));
if (!key) {
return Error { "filter expression key must be a string" };
}

if (*key == "$type") {
Result<FeatureType> filterValue = toFeatureType(arrayMember(value, 2));
if (!filterValue) {
return filterValue.error();
}

return TypeFilterType { *filterValue };

} else if (*key == "$id") {
Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2));
if (!filterValue) {
return filterValue.error();
}

return IdentifierFilterType { *filterValue };

} else {
Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
if (!filterValue) {
return filterValue.error();
}

return FilterType { *key, *filterValue };
}
}

template <class FilterType, class V>
Expand All @@ -99,15 +165,15 @@ struct Converter<Filter> {
return Error { "filter expression key must be a string" };
}

Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2)));
Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
if (!filterValue) {
return filterValue.error();
}

return FilterType { *key, *filterValue };
}

template <class FilterType, class V>
template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
Result<Filter> convertSetFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must at least 2 elements" };
Expand All @@ -118,16 +184,42 @@ struct Converter<Filter> {
return Error { "filter expression key must be a string" };
}

std::vector<Value> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, i)));
if (!filterValue) {
return filterValue.error();
if (*key == "$type") {
std::vector<FeatureType> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
Result<FeatureType> 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<FeatureIdentifier> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i));
if (!filterValue) {
return filterValue.error();
}
values.push_back(*filterValue);
}

return IdentifierFilterType { std::move(values) };

} else {
std::vector<Value> values;
for (std::size_t i = 2; i < arrayLength(value); ++i) {
Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)));
if (!filterValue) {
return filterValue.error();
}
values.push_back(*filterValue);
}

return FilterType { *key, std::move(values) };
}
}

template <class FilterType, class V>
Expand Down
101 changes: 100 additions & 1 deletion include/mbgl/style/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,95 @@ class NotHasFilter {
}
};


class TypeEqualsFilter {
public:
FeatureType value;

friend bool operator==(const TypeEqualsFilter& lhs, const TypeEqualsFilter& rhs) {
return lhs.value == rhs.value;
}
};

class TypeNotEqualsFilter {
public:
FeatureType value;

friend bool operator==(const TypeNotEqualsFilter& lhs, const TypeNotEqualsFilter& rhs) {
return lhs.value == rhs.value;
}
};

class TypeInFilter {
public:
std::vector<FeatureType> values;

friend bool operator==(const TypeInFilter& lhs, const TypeInFilter& rhs) {
return lhs.values == rhs.values;
}
};

class TypeNotInFilter {
public:
std::vector<FeatureType> values;

friend bool operator==(const TypeNotInFilter& lhs, const TypeNotInFilter& rhs) {
return lhs.values == rhs.values;
}
};


class IdentifierEqualsFilter {
public:
FeatureIdentifier value;

friend bool operator==(const IdentifierEqualsFilter& lhs, const IdentifierEqualsFilter& rhs) {
return lhs.value == rhs.value;
}
};

class IdentifierNotEqualsFilter {
public:
FeatureIdentifier value;

friend bool operator==(const IdentifierNotEqualsFilter& lhs, const IdentifierNotEqualsFilter& rhs) {
return lhs.value == rhs.value;
}
};

class IdentifierInFilter {
public:
std::vector<FeatureIdentifier> values;

friend bool operator==(const IdentifierInFilter& lhs, const IdentifierInFilter& rhs) {
return lhs.values == rhs.values;
}
};

class IdentifierNotInFilter {
public:
std::vector<FeatureIdentifier> values;

friend bool operator==(const IdentifierNotInFilter& lhs, const IdentifierNotInFilter& rhs) {
return lhs.values == rhs.values;
}
};

class HasIdentifierFilter {
public:
friend bool operator==(const HasIdentifierFilter&, const HasIdentifierFilter&) {
return true;
}
};

class NotHasIdentifierFilter {
public:
friend bool operator==(const NotHasIdentifierFilter&, const NotHasIdentifierFilter&) {
return true;
}
};


using FilterBase = variant<
class NullFilter,
class EqualsFilter,
Expand All @@ -159,7 +248,17 @@ using FilterBase = variant<
class AllFilter,
class NoneFilter,
class HasFilter,
class NotHasFilter>;
class NotHasFilter,
class TypeEqualsFilter,
class TypeNotEqualsFilter,
class TypeInFilter,
class TypeNotInFilter,
class IdentifierEqualsFilter,
class IdentifierNotEqualsFilter,
class IdentifierInFilter,
class IdentifierNotInFilter,
class HasIdentifierFilter,
class NotHasIdentifierFilter>;

class Filter : public FilterBase {
public:
Expand Down
Loading