From 12cc00131e8c3d12ecc14f6e1336a1dcdfe86f80 Mon Sep 17 00:00:00 2001 From: Sam Millar Date: Tue, 29 May 2018 11:19:28 +0100 Subject: [PATCH 1/4] Add replace function --- tinyquery/evaluator_test.py | 5 +++++ tinyquery/runtime.py | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/tinyquery/evaluator_test.py b/tinyquery/evaluator_test.py index f635efa..38545af 100644 --- a/tinyquery/evaluator_test.py +++ b/tinyquery/evaluator_test.py @@ -1339,6 +1339,11 @@ def test_other_timestamp_functions(self): self.make_context([ ('f0_', tq_types.INT, [1262304000000000])])) + def test_replace(self): + self.assert_query_result( + "SELECT REPLACE(str, 'o', 'e') FROM string_table_with_null", + self.make_context([('f0_', tq_types.STRING, ["helle", "werld", null])])) + def test_first(self): # Test over the equivalent of a GROUP BY self.assert_query_result( diff --git a/tinyquery/runtime.py b/tinyquery/runtime.py index bd2c35f..76860b7 100644 --- a/tinyquery/runtime.py +++ b/tinyquery/runtime.py @@ -1011,6 +1011,20 @@ def apply(*args): values=values) +class ReplaceFunction(ScalarFunction): + def check_types(self, *arg_types): + if any(arg_type != tq_types.STRING for arg_type in arg_types): + raise TypeError('REPLACE only takes string arguments.') + return tq_types.STRING + + def _evaluate(self, num_rows, values, old, new): + replace_fn = pass_through_none( + lambda s: s.replace(old, new)) + values = [replace_fn(x) for x in values.values] + return context.Column(tq_types.STRING, tq_modes.NULLABLE, + values=values) + + class JSONExtractFunction(ScalarFunction): """Extract from a JSON string based on a JSONPath expression. From a67289bb89c7e9f60741609eda3175a4a4e8e798 Mon Sep 17 00:00:00 2001 From: Sam Millar Date: Tue, 29 May 2018 11:28:40 +0100 Subject: [PATCH 2/4] Add to replace to dict --- tinyquery/runtime.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tinyquery/runtime.py b/tinyquery/runtime.py index 76860b7..dabcff6 100644 --- a/tinyquery/runtime.py +++ b/tinyquery/runtime.py @@ -1334,6 +1334,7 @@ def _evaluate(self, num_rows, json_expressions, json_paths): lambda dt: dt.year, return_type=tq_types.INT), TimestampFunction()), + 'replace': ReplaceFunction(), 'json_extract': JSONExtractFunction(), 'json_extract_scalar': JSONExtractFunction(scalar=True), } From b58a3d9b24edf858ecb024d5f30383da2d807706 Mon Sep 17 00:00:00 2001 From: Sam Millar Date: Tue, 29 May 2018 11:57:05 +0100 Subject: [PATCH 3/4] Fix --- tinyquery/runtime.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tinyquery/runtime.py b/tinyquery/runtime.py index 88c817a..6d7fa8c 100644 --- a/tinyquery/runtime.py +++ b/tinyquery/runtime.py @@ -1018,9 +1018,10 @@ def check_types(self, *arg_types): return tq_types.STRING def _evaluate(self, num_rows, values, old, new): - replace_fn = pass_through_none( - lambda s: s.replace(old, new)) - values = [replace_fn(x) for x in values.values] + values = [value.replace(old, new) if value is not None else None + for value, old, new in zip(values.values, + old.values, + new.values)] return context.Column(tq_types.STRING, tq_modes.NULLABLE, values=values) From 64a848fc088a20a17f9f37234862ca67ae4eb196 Mon Sep 17 00:00:00 2001 From: Sam Millar Date: Thu, 14 Mar 2019 12:42:44 +0000 Subject: [PATCH 4/4] Fix test --- tinyquery/evaluator_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinyquery/evaluator_test.py b/tinyquery/evaluator_test.py index 02a86fa..bf21293 100644 --- a/tinyquery/evaluator_test.py +++ b/tinyquery/evaluator_test.py @@ -1342,7 +1342,7 @@ def test_other_timestamp_functions(self): def test_replace(self): self.assert_query_result( "SELECT REPLACE(str, 'o', 'e') FROM string_table_with_null", - self.make_context([('f0_', tq_types.STRING, ["helle", "werld", null])])) + self.make_context([('f0_', tq_types.STRING, ["helle", "werld", None])])) def test_first(self): # Test over the equivalent of a GROUP BY