Allow specifying collator options (case sensitivity etc.) for “in” expressions #9339
Description
It should be possible for an expression to test whether a string appears in an array or another string while ignoring case or diacritic distinctions, or while following the collation rules of a language other than the current language.
Problem
#6270 added an optional third argument to expression operators such as ==
and <
to override the default collator when comparing two strings, for example to compare the strings case-insensitively or diacritic-insensitively. #8876 implements an in
expression operator that streamlines comparing a string against a large or indefinite number of other strings. Unfortunately, this operator takes only two arguments and doesn’t accept a collator, so the developer has to choose between comparing case-insensitively or easily comparing multiple strings.
This issue is surfacing when porting in
to NSExpression for iOS/macOS (mapbox/mapbox-gl-native-ios#168), because NSExpression supports [c]
and [d]
modifiers on the IN
operator just as on the ==
and <
operators.
Proposed design
The in
expression operator should accept a collator object as an optional third argument:
["in", needle: (boolean, string or number), haystack: (array or string)]: boolean
["in", needle: (boolean, string or number), haystack: (array or string), collator]: boolean
The same issue affects the match
operator, but it’s less clear where a collator object would go in a match
expression without creating ambiguity for the expression evaluator.
Implementation notes
Here’s where the in
comparisons currently take place:
Here’s how custom collators are evaluated in ==
expressions:
mapbox-gl-js/src/style-spec/expression/definitions/comparison.js
Lines 154 to 156 in a6e8598
mapbox-gl-js/src/style-spec/expression/types/collator.js
Lines 51 to 53 in a6e8598
mapbox-gl-js/src/style-spec/expression/types/collator.js
Lines 47 to 48 in a6e8598
/ref #6484 mapbox/mapbox-gl-native#11786
/cc @mapbox/gl-js @chloekraw @fabian-guerra