-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Ádám Barancsuk <[email protected]> Co-authored-by: Ryan Hamley <[email protected]>
- Loading branch information
Showing
10 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// @flow | ||
|
||
import {ValueType, BooleanType, toString} from '../types'; | ||
import RuntimeError from '../runtime_error'; | ||
import {typeOf} from '../values'; | ||
|
||
import type {Expression} from '../expression'; | ||
import type ParsingContext from '../parsing_context'; | ||
import type EvaluationContext from '../evaluation_context'; | ||
import type {Type} from '../types'; | ||
import type {Value} from '../values'; | ||
|
||
function isComparableType(type: Type) { | ||
return type.kind === 'boolean' || | ||
type.kind === 'string' || | ||
type.kind === 'number' || | ||
type.kind === 'null' || | ||
type.kind === 'value'; | ||
} | ||
|
||
function isComparableRuntimeValue(needle: boolean | string | number | null) { | ||
return typeof needle === 'boolean' || | ||
typeof needle === 'string' || | ||
typeof needle === 'number'; | ||
} | ||
|
||
function isSearchableRuntimeValue(haystack: Array<Value> | string) { | ||
return Array.isArray(haystack) || | ||
typeof haystack === 'string'; | ||
} | ||
|
||
class In implements Expression { | ||
type: Type; | ||
needle: Expression; | ||
haystack: Expression; | ||
|
||
constructor(needle: Expression, haystack: Expression) { | ||
this.type = BooleanType; | ||
this.needle = needle; | ||
this.haystack = haystack; | ||
} | ||
|
||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext) { | ||
if (args.length !== 3) { | ||
return context.error(`Expected 2 arguments, but found ${args.length - 1} instead.`); | ||
} | ||
|
||
const needle = context.parse(args[1], 1, ValueType); | ||
|
||
const haystack = context.parse(args[2], 2, ValueType); | ||
|
||
if (!needle || !haystack) return null; | ||
|
||
if (!isComparableType(needle.type)) { | ||
return context.error(`Expected first argument to be of type boolean, string, number or null, but found ${toString(needle.type)} instead`); | ||
} | ||
|
||
return new In(needle, haystack); | ||
} | ||
|
||
evaluate(ctx: EvaluationContext) { | ||
const needle = (this.needle.evaluate(ctx): any); | ||
const haystack = (this.haystack.evaluate(ctx): any); | ||
|
||
if (!needle || !haystack) return false; | ||
|
||
if (!isComparableRuntimeValue(needle)) { | ||
throw new RuntimeError(`Expected first argument to be of type boolean, string or number, but found ${toString(typeOf(needle))} instead.`); | ||
} | ||
|
||
if (!isSearchableRuntimeValue(haystack)) { | ||
throw new RuntimeError(`Expected second argument to be of type array or string, but found ${toString(typeOf(haystack))} instead.`); | ||
} | ||
|
||
return haystack.indexOf(needle) >= 0; | ||
} | ||
|
||
eachChild(fn: (Expression) => void) { | ||
fn(this.needle); | ||
fn(this.haystack); | ||
} | ||
|
||
possibleOutputs() { | ||
return [true, false]; | ||
} | ||
|
||
serialize() { | ||
return ["in", this.needle.serialize(), this.haystack.serialize()]; | ||
} | ||
} | ||
|
||
export default In; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
test/integration/expression-tests/in/assert-array/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "i"], ["array", ["get", "arr"]]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"i": null, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": 1, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": 9, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": 1, "arr": null}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
false, | ||
false, | ||
true, | ||
{"error":"Expected value to be of type array, but found null instead."} | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "i"], ["array", ["get", "arr"]]] | ||
] | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
test/integration/expression-tests/in/assert-string/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "substr"], ["string", ["get", "str"]]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"substr": null, "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": "foo", "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": "low", "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": "low", "str": null}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
false, | ||
false, | ||
true, | ||
{"error":"Expected value to be of type string, but found null instead."} | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "substr"], ["string", ["get", "str"]]] | ||
] | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
test/integration/expression-tests/in/basic-array/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "i"], ["get", "arr"]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"i": null, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": 1, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": 9, "arr": [9, 8, 7]}}], | ||
[{}, {"properties": {"i": "foo", "arr": ["baz", "bar", "hello", "foo", "world"]}}], | ||
[{}, {"properties": {"i": true, "arr": ["foo", 123, null, 456, false, {}, true]}}], | ||
[{}, {"properties": {"i": 1, "arr": null}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
false, | ||
false, | ||
true, | ||
true, | ||
true, | ||
false | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "i"], ["get", "arr"]] | ||
] | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
test/integration/expression-tests/in/basic-string/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "substr"], ["get", "str"]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"substr": null, "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": "foo", "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": "low", "str": "helloworld"}}], | ||
[{}, {"properties": {"substr": true, "str": "falsetrue"}}], | ||
[{}, {"properties": {"substr": false, "str": "falsetrue"}}], | ||
[{}, {"properties": {"substr": 123, "str": "hello123world"}}], | ||
[{}, {"properties": {"substr": "low", "str": null}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
false, | ||
false, | ||
true, | ||
true, | ||
false, | ||
true, | ||
false | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "substr"], ["get", "str"]] | ||
] | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
test/integration/expression-tests/in/invalid-haystack/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "needle"], ["get", "haystack"]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"needle": 1, "haystack": 123}}], | ||
[{}, {"properties": {"needle": "foo", "haystack": {}}}], | ||
[{}, {"properties": {"needle": "foo", "haystack": null}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
{"error":"Expected second argument to be of type array or string, but found number instead."}, | ||
{"error":"Expected second argument to be of type array or string, but found object instead."}, | ||
false | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "needle"], ["get", "haystack"]] | ||
] | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
test/integration/expression-tests/in/invalid-needle/test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"expression": [ | ||
"boolean", | ||
["in", ["get", "needle"], ["get", "haystack"]] | ||
], | ||
"inputs": [ | ||
[{}, {"properties": {"needle": {}, "haystack": [9, 8, 7]}}], | ||
[{}, {"properties": {"needle": {}, "haystack": "helloworld"}}] | ||
], | ||
"expected": { | ||
"compiled": { | ||
"result": "success", | ||
"isFeatureConstant": false, | ||
"isZoomConstant": true, | ||
"type": "boolean" | ||
}, | ||
"outputs": [ | ||
{"error":"Expected first argument to be of type boolean, string or number, but found object instead."}, | ||
{"error":"Expected first argument to be of type boolean, string or number, but found object instead."} | ||
], | ||
"serialized": [ | ||
"boolean", | ||
["in", ["get", "needle"], ["get", "haystack"]] | ||
] | ||
} | ||
} |