flowquery 1.0.43 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flowquery.min.js +1 -1
- package/dist/parsing/functions/join.d.ts.map +1 -1
- package/dist/parsing/functions/join.js +6 -3
- package/dist/parsing/functions/join.js.map +1 -1
- package/dist/parsing/functions/keys.d.ts.map +1 -1
- package/dist/parsing/functions/keys.js +3 -5
- package/dist/parsing/functions/keys.js.map +1 -1
- package/dist/parsing/functions/range.d.ts.map +1 -1
- package/dist/parsing/functions/range.js +11 -3
- package/dist/parsing/functions/range.js.map +1 -1
- package/dist/parsing/functions/replace.d.ts.map +1 -1
- package/dist/parsing/functions/replace.js +8 -3
- package/dist/parsing/functions/replace.js.map +1 -1
- package/dist/parsing/functions/round.d.ts.map +1 -1
- package/dist/parsing/functions/round.js +5 -4
- package/dist/parsing/functions/round.js.map +1 -1
- package/dist/parsing/functions/size.d.ts.map +1 -1
- package/dist/parsing/functions/size.js +5 -4
- package/dist/parsing/functions/size.js.map +1 -1
- package/dist/parsing/functions/split.d.ts.map +1 -1
- package/dist/parsing/functions/split.js +12 -4
- package/dist/parsing/functions/split.js.map +1 -1
- package/dist/parsing/functions/string_distance.d.ts.map +1 -1
- package/dist/parsing/functions/string_distance.js +3 -0
- package/dist/parsing/functions/string_distance.js.map +1 -1
- package/dist/parsing/functions/stringify.d.ts.map +1 -1
- package/dist/parsing/functions/stringify.js +7 -6
- package/dist/parsing/functions/stringify.js.map +1 -1
- package/dist/parsing/functions/substring.d.ts.map +1 -1
- package/dist/parsing/functions/substring.js +3 -0
- package/dist/parsing/functions/substring.js.map +1 -1
- package/dist/parsing/functions/to_json.d.ts.map +1 -1
- package/dist/parsing/functions/to_json.js +5 -4
- package/dist/parsing/functions/to_json.js.map +1 -1
- package/dist/parsing/functions/to_lower.d.ts.map +1 -1
- package/dist/parsing/functions/to_lower.js +3 -0
- package/dist/parsing/functions/to_lower.js.map +1 -1
- package/dist/parsing/functions/to_string.js +1 -1
- package/dist/parsing/functions/to_string.js.map +1 -1
- package/dist/parsing/functions/trim.d.ts.map +1 -1
- package/dist/parsing/functions/trim.js +3 -0
- package/dist/parsing/functions/trim.js.map +1 -1
- package/docs/flowquery.min.js +1 -1
- package/flowquery-py/pyproject.toml +1 -1
- package/flowquery-py/src/parsing/functions/join.py +2 -0
- package/flowquery-py/src/parsing/functions/keys.py +1 -1
- package/flowquery-py/src/parsing/functions/range_.py +2 -0
- package/flowquery-py/src/parsing/functions/replace.py +2 -0
- package/flowquery-py/src/parsing/functions/round_.py +2 -0
- package/flowquery-py/src/parsing/functions/size.py +2 -0
- package/flowquery-py/src/parsing/functions/split.py +2 -0
- package/flowquery-py/src/parsing/functions/string_distance.py +5 -1
- package/flowquery-py/src/parsing/functions/stringify.py +2 -0
- package/flowquery-py/src/parsing/functions/substring.py +2 -0
- package/flowquery-py/src/parsing/functions/to_json.py +2 -0
- package/flowquery-py/src/parsing/functions/to_lower.py +2 -0
- package/flowquery-py/src/parsing/functions/to_string.py +1 -1
- package/flowquery-py/src/parsing/functions/trim.py +2 -0
- package/flowquery-py/tests/compute/test_runner.py +128 -0
- package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -1
- package/package.json +1 -1
- package/src/parsing/functions/join.ts +8 -5
- package/src/parsing/functions/keys.ts +4 -6
- package/src/parsing/functions/range.ts +12 -4
- package/src/parsing/functions/replace.ts +11 -4
- package/src/parsing/functions/round.ts +6 -5
- package/src/parsing/functions/size.ts +6 -5
- package/src/parsing/functions/split.ts +14 -6
- package/src/parsing/functions/string_distance.ts +3 -0
- package/src/parsing/functions/stringify.ts +9 -8
- package/src/parsing/functions/substring.ts +3 -0
- package/src/parsing/functions/to_json.ts +6 -5
- package/src/parsing/functions/to_lower.ts +3 -0
- package/src/parsing/functions/to_string.ts +1 -1
- package/src/parsing/functions/trim.ts +3 -0
- package/tests/compute/runner.test.ts +114 -0
|
@@ -42,6 +42,8 @@ class Join(Function):
|
|
|
42
42
|
def value(self) -> Any:
|
|
43
43
|
array = self.get_children()[0].value()
|
|
44
44
|
delimiter = self.get_children()[1].value()
|
|
45
|
+
if array is None:
|
|
46
|
+
return None
|
|
45
47
|
if not isinstance(array, list) or not isinstance(delimiter, str):
|
|
46
48
|
raise ValueError("Invalid arguments for join function")
|
|
47
49
|
return delimiter.join(str(item) for item in array)
|
|
@@ -28,7 +28,7 @@ class Keys(Function):
|
|
|
28
28
|
def value(self) -> Any:
|
|
29
29
|
obj = self.get_children()[0].value()
|
|
30
30
|
if obj is None:
|
|
31
|
-
return
|
|
31
|
+
return None
|
|
32
32
|
if not isinstance(obj, dict):
|
|
33
33
|
raise ValueError("keys() expects an object, not an array or primitive")
|
|
34
34
|
return list(obj.keys())
|
|
@@ -34,6 +34,8 @@ class Range(Function):
|
|
|
34
34
|
def value(self) -> Any:
|
|
35
35
|
start = self.get_children()[0].value()
|
|
36
36
|
end = self.get_children()[1].value()
|
|
37
|
+
if start is None or end is None:
|
|
38
|
+
return None
|
|
37
39
|
if not isinstance(start, (int, float)) or not isinstance(end, (int, float)):
|
|
38
40
|
raise ValueError("Invalid arguments for range function")
|
|
39
41
|
return list(range(int(start), int(end) + 1))
|
|
@@ -32,6 +32,8 @@ class Replace(Function):
|
|
|
32
32
|
text = self.get_children()[0].value()
|
|
33
33
|
pattern = self.get_children()[1].value()
|
|
34
34
|
replacement = self.get_children()[2].value()
|
|
35
|
+
if text is None:
|
|
36
|
+
return None
|
|
35
37
|
if not isinstance(text, str) or not isinstance(pattern, str) or not isinstance(replacement, str):
|
|
36
38
|
raise ValueError("Invalid arguments for replace function")
|
|
37
39
|
return re.sub(re.escape(pattern), replacement, text)
|
|
@@ -47,6 +47,8 @@ class Split(Function):
|
|
|
47
47
|
def value(self) -> Any:
|
|
48
48
|
text = self.get_children()[0].value()
|
|
49
49
|
delimiter = self.get_children()[1].value()
|
|
50
|
+
if text is None:
|
|
51
|
+
return None
|
|
50
52
|
if not isinstance(text, str) or not isinstance(delimiter, str):
|
|
51
53
|
raise ValueError("Invalid arguments for split function")
|
|
52
54
|
return text.split(delimiter)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""String distance function using Levenshtein distance."""
|
|
2
2
|
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
3
5
|
from .function import Function
|
|
4
6
|
from .function_metadata import FunctionDef
|
|
5
7
|
|
|
@@ -80,9 +82,11 @@ class StringDistance(Function):
|
|
|
80
82
|
super().__init__("string_distance")
|
|
81
83
|
self._expected_parameter_count = 2
|
|
82
84
|
|
|
83
|
-
def value(self) -> float:
|
|
85
|
+
def value(self) -> Optional[float]:
|
|
84
86
|
str1 = self.get_children()[0].value()
|
|
85
87
|
str2 = self.get_children()[1].value()
|
|
88
|
+
if str1 is None or str2 is None:
|
|
89
|
+
return None
|
|
86
90
|
if not isinstance(str1, str) or not isinstance(str2, str):
|
|
87
91
|
raise ValueError("Invalid arguments for string_distance function: both arguments must be strings")
|
|
88
92
|
return _levenshtein_distance(str1, str2)
|
|
@@ -42,6 +42,8 @@ class Stringify(Function):
|
|
|
42
42
|
def value(self) -> Any:
|
|
43
43
|
val = self.get_children()[0].value()
|
|
44
44
|
indent = int(self.get_children()[1].value())
|
|
45
|
+
if val is None:
|
|
46
|
+
return None
|
|
45
47
|
if not isinstance(val, (dict, list)):
|
|
46
48
|
raise ValueError("Invalid argument for stringify function")
|
|
47
49
|
return json.dumps(val, indent=indent, default=str)
|
|
@@ -52,6 +52,8 @@ class Substring(Function):
|
|
|
52
52
|
original = children[0].value()
|
|
53
53
|
start = children[1].value()
|
|
54
54
|
|
|
55
|
+
if original is None:
|
|
56
|
+
return None
|
|
55
57
|
if not isinstance(original, str):
|
|
56
58
|
raise ValueError(
|
|
57
59
|
"Invalid argument for substring function: expected a string as the first argument"
|
|
@@ -30,6 +30,8 @@ class ToLower(Function):
|
|
|
30
30
|
|
|
31
31
|
def value(self) -> Any:
|
|
32
32
|
val = self.get_children()[0].value()
|
|
33
|
+
if val is None:
|
|
34
|
+
return None
|
|
33
35
|
if not isinstance(val, str):
|
|
34
36
|
raise ValueError("Invalid argument for toLower function: expected a string")
|
|
35
37
|
return val.lower()
|
|
@@ -849,6 +849,134 @@ class TestRunner:
|
|
|
849
849
|
assert len(results) == 1
|
|
850
850
|
assert results[0] == {"result": ""}
|
|
851
851
|
|
|
852
|
+
# --- Null propagation tests ---
|
|
853
|
+
|
|
854
|
+
@pytest.mark.asyncio
|
|
855
|
+
async def test_to_lower_with_null_returns_null(self):
|
|
856
|
+
"""Test toLower with null returns null."""
|
|
857
|
+
runner = Runner("RETURN toLower(null) as result")
|
|
858
|
+
await runner.run()
|
|
859
|
+
results = runner.results
|
|
860
|
+
assert len(results) == 1
|
|
861
|
+
assert results[0] == {"result": None}
|
|
862
|
+
|
|
863
|
+
@pytest.mark.asyncio
|
|
864
|
+
async def test_trim_with_null_returns_null(self):
|
|
865
|
+
"""Test trim with null returns null."""
|
|
866
|
+
runner = Runner("RETURN trim(null) as result")
|
|
867
|
+
await runner.run()
|
|
868
|
+
results = runner.results
|
|
869
|
+
assert len(results) == 1
|
|
870
|
+
assert results[0] == {"result": None}
|
|
871
|
+
|
|
872
|
+
@pytest.mark.asyncio
|
|
873
|
+
async def test_replace_with_null_returns_null(self):
|
|
874
|
+
"""Test replace with null returns null."""
|
|
875
|
+
runner = Runner("RETURN replace(null, 'a', 'b') as result")
|
|
876
|
+
await runner.run()
|
|
877
|
+
results = runner.results
|
|
878
|
+
assert len(results) == 1
|
|
879
|
+
assert results[0] == {"result": None}
|
|
880
|
+
|
|
881
|
+
@pytest.mark.asyncio
|
|
882
|
+
async def test_substring_with_null_returns_null(self):
|
|
883
|
+
"""Test substring with null returns null."""
|
|
884
|
+
runner = Runner("RETURN substring(null, 0, 3) as result")
|
|
885
|
+
await runner.run()
|
|
886
|
+
results = runner.results
|
|
887
|
+
assert len(results) == 1
|
|
888
|
+
assert results[0] == {"result": None}
|
|
889
|
+
|
|
890
|
+
@pytest.mark.asyncio
|
|
891
|
+
async def test_split_with_null_returns_null(self):
|
|
892
|
+
"""Test split with null returns null."""
|
|
893
|
+
runner = Runner("RETURN split(null, ',') as result")
|
|
894
|
+
await runner.run()
|
|
895
|
+
results = runner.results
|
|
896
|
+
assert len(results) == 1
|
|
897
|
+
assert results[0] == {"result": None}
|
|
898
|
+
|
|
899
|
+
@pytest.mark.asyncio
|
|
900
|
+
async def test_size_with_null_returns_null(self):
|
|
901
|
+
"""Test size with null returns null."""
|
|
902
|
+
runner = Runner("RETURN size(null) as result")
|
|
903
|
+
await runner.run()
|
|
904
|
+
results = runner.results
|
|
905
|
+
assert len(results) == 1
|
|
906
|
+
assert results[0] == {"result": None}
|
|
907
|
+
|
|
908
|
+
@pytest.mark.asyncio
|
|
909
|
+
async def test_round_with_null_returns_null(self):
|
|
910
|
+
"""Test round with null returns null."""
|
|
911
|
+
runner = Runner("RETURN round(null) as result")
|
|
912
|
+
await runner.run()
|
|
913
|
+
results = runner.results
|
|
914
|
+
assert len(results) == 1
|
|
915
|
+
assert results[0] == {"result": None}
|
|
916
|
+
|
|
917
|
+
@pytest.mark.asyncio
|
|
918
|
+
async def test_join_with_null_returns_null(self):
|
|
919
|
+
"""Test join with null returns null."""
|
|
920
|
+
runner = Runner("RETURN join(null, ',') as result")
|
|
921
|
+
await runner.run()
|
|
922
|
+
results = runner.results
|
|
923
|
+
assert len(results) == 1
|
|
924
|
+
assert results[0] == {"result": None}
|
|
925
|
+
|
|
926
|
+
@pytest.mark.asyncio
|
|
927
|
+
async def test_string_distance_with_null_returns_null(self):
|
|
928
|
+
"""Test string_distance with null returns null."""
|
|
929
|
+
runner = Runner("RETURN string_distance(null, 'hello') as result")
|
|
930
|
+
await runner.run()
|
|
931
|
+
results = runner.results
|
|
932
|
+
assert len(results) == 1
|
|
933
|
+
assert results[0] == {"result": None}
|
|
934
|
+
|
|
935
|
+
@pytest.mark.asyncio
|
|
936
|
+
async def test_stringify_with_null_returns_null(self):
|
|
937
|
+
"""Test stringify with null returns null."""
|
|
938
|
+
runner = Runner("RETURN stringify(null) as result")
|
|
939
|
+
await runner.run()
|
|
940
|
+
results = runner.results
|
|
941
|
+
assert len(results) == 1
|
|
942
|
+
assert results[0] == {"result": None}
|
|
943
|
+
|
|
944
|
+
@pytest.mark.asyncio
|
|
945
|
+
async def test_tojson_with_null_returns_null(self):
|
|
946
|
+
"""Test tojson with null returns null."""
|
|
947
|
+
runner = Runner("RETURN tojson(null) as result")
|
|
948
|
+
await runner.run()
|
|
949
|
+
results = runner.results
|
|
950
|
+
assert len(results) == 1
|
|
951
|
+
assert results[0] == {"result": None}
|
|
952
|
+
|
|
953
|
+
@pytest.mark.asyncio
|
|
954
|
+
async def test_range_with_null_returns_null(self):
|
|
955
|
+
"""Test range with null returns null."""
|
|
956
|
+
runner = Runner("RETURN range(null, 5) as result")
|
|
957
|
+
await runner.run()
|
|
958
|
+
results = runner.results
|
|
959
|
+
assert len(results) == 1
|
|
960
|
+
assert results[0] == {"result": None}
|
|
961
|
+
|
|
962
|
+
@pytest.mark.asyncio
|
|
963
|
+
async def test_to_string_with_null_returns_null(self):
|
|
964
|
+
"""Test toString with null returns null."""
|
|
965
|
+
runner = Runner("RETURN toString(null) as result")
|
|
966
|
+
await runner.run()
|
|
967
|
+
results = runner.results
|
|
968
|
+
assert len(results) == 1
|
|
969
|
+
assert results[0] == {"result": None}
|
|
970
|
+
|
|
971
|
+
@pytest.mark.asyncio
|
|
972
|
+
async def test_keys_with_null_returns_null(self):
|
|
973
|
+
"""Test keys with null returns null."""
|
|
974
|
+
runner = Runner("RETURN keys(null) as result")
|
|
975
|
+
await runner.run()
|
|
976
|
+
results = runner.results
|
|
977
|
+
assert len(results) == 1
|
|
978
|
+
assert results[0] == {"result": None}
|
|
979
|
+
|
|
852
980
|
@pytest.mark.asyncio
|
|
853
981
|
async def test_associative_array_with_key_which_is_keyword(self):
|
|
854
982
|
"""Test associative array with key which is keyword."""
|