From 767b1e3a337292cefc2fbadd11ca73bbfa368295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rajmund=20Hru=C5=A1ka?= <rajmund.hruska@cesnet.cz> Date: Fri, 9 May 2025 10:41:32 +0200 Subject: [PATCH] Remove SQLTransformer --- ransack/transformer.py | 241 +------------------------------------- tests/test_transformer.py | 114 +----------------- 2 files changed, 5 insertions(+), 350 deletions(-) diff --git a/ransack/transformer.py b/ransack/transformer.py index 1b148dc..74bf996 100644 --- a/ransack/transformer.py +++ b/ransack/transformer.py @@ -2,13 +2,12 @@ transformer.py - Provides transformers for converting Lark's AST into more usable Python objects. -This module contains the `ExpressionTransformer` and `SQLTransformer` -classes, which extend Lark's `Transformer` to convert the parse tree -generated by the Lark parser into more useful Python and SQL objects. +This module contains the `ExpressionTransformer` class, +which extend Lark's `Transformer` to convert the parse tree +generated by the Lark parser into more useful Python objects. `ExpressionTransformer` handles the interpretation of parsed structures like IP addresses, ranges, datetime objects, and arithmetic expressions, -transforming them into Python data structures. `SQLTransformer` -translates these expressions into SQL syntax for database queries. +transforming them into Python data structures. Classes: - TokenWrapper: A wrapper for Lark Token to provide a `real_value` @@ -17,9 +16,6 @@ Classes: into Python objects (e.g., IP addresses, datetime objects, timedelta, lists, strings). - - SQLTransformer: Converts parse tree nodes into SQL expressions - suitable for SQL query generation, supporting - logical and arithmetic operations. """ import re @@ -848,232 +844,3 @@ class Filter(Interpreter): end_column=name.end_column, end_pos=name.end_pos, ) - - -@v_args(inline=True) -class SQLTransformer(Transformer): - """ - A transformer that converts nodes from the Lark parse tree into SQL expressions. - - The SQLTransformer class supports logical, comparison, and arithmetic - operations, translating them into valid SQL syntax. It enables the - creation of SQL expressions from parsed data, including IP addresses, - timestamps, intervals, and strings. - """ - - def or_op(self, left: str, right: str) -> str: - """ - Transforms an OR operation into SQL syntax. - - Parameters: - left: The left operand in the OR operation. - right: The right operand in the OR operation. - - Returns: - The SQL OR operation as a string. - """ - return f"{left} OR {right}" - - def and_op(self, left: str, right: str) -> str: - """ - Transforms an AND operation into SQL syntax. - - Parameters: - left: The left operand in the AND operation. - right: The right operand in the AND operation. - - Returns: - The SQL AND operation as a string. - """ - return f"{left} AND {right}" - - def not_op(self, cond: str) -> str: - """ - Transforms a NOT operation into SQL syntax. - - Parameters: - cond: The condition to negate in the NOT operation. - - Returns: - The SQL NOT operation as a string. - """ - return f"NOT {cond}" - - def gt(self, left: str, right: str) -> str: - """Greater than comparison in SQL.""" - return f"{left} > {right}" - - def gte(self, left: str, right: str) -> str: - """Greater than or equal to comparison in SQL.""" - return f"{left} >= {right}" - - def lt(self, left: str, right: str) -> str: - """Less than comparison in SQL.""" - return f"{left} < {right}" - - def lte(self, left: str, right: str) -> str: - """Less than or equal to comparison in SQL.""" - return f"{left} <= {right}" - - def eq(self, left: str, right: str) -> str: - """Equality comparison in SQL.""" - return f"{left} = {right}" - - def like_op(self, column: str, pattern: str) -> str: - """ - Transforms a LIKE operation into SQL syntax. - - Parameters: - column: The column name to search. - pattern: The pattern to match in the LIKE operation. - - Returns: - The SQL LIKE operation as a string. - """ - return f"{column} LIKE {pattern}" - - def in_op(self, values, data) -> str: - """ - Transforms an IN or BETWEEN operation into SQL syntax. - - Parameters: - values: The value or expression to check. - data: The list of values for IN or the range for BETWEEN. - - Returns: - The SQL IN or BETWEEN operation as a string. - """ - if isinstance(data, str) and "BETWEEN" in data: - return f"{values} {data}" - return f"{values} IN {data}" - - def add(self, left: str, right: str) -> str: - """Addition in SQL.""" - return f"{left} + {right}" - - def sub(self, left: str, right: str) -> str: - """Subtraction in SQL.""" - return f"{left} - {right}" - - def mul(self, left: str, right: str) -> str: - """Multiplication in SQL.""" - return f"{left} * {right}" - - def div(self, left: str, right: str) -> str: - """Division in SQL.""" - return f"{left} / {right}" - - def mod(self, left: str, right: str) -> str: - """Modulus operation in SQL.""" - return f"{left} % {right}" - - def ip(self, data: TokenWrapper) -> str: - """ - Transforms an IP address node into SQL syntax. - - Parameters: - data: The IP address data. - - Returns: - The SQL representation of the IP address. - """ - return f"'{data.real_value}'" - - def datetime(self, dtime: TokenWrapper) -> str: - """ - Transforms a datetime object into SQL syntax. - - Parameters: - dtime: The datetime object to convert. - - Returns: - The SQL representation of the datetime with timestamp format. - """ - return f"'{dtime.real_value}'::timestamp with time zone" - - def timedelta_(self, timedelta: TokenWrapper) -> str: - """ - Transforms a timedelta object into SQL interval syntax. - - Parameters: - timedelta: The timedelta object to convert. - - Returns: - The SQL interval representation of the timedelta. - """ - return f"'{timedelta.real_value}'::interval" - - def string_(self, data: TokenWrapper) -> str: - """ - Transforms a string node into SQL syntax. - - Parameters: - data: The string value. - - Returns: - The SQL representation of the string. - """ - return f"'{data.real_value}'" - - def number(self, number: TokenWrapper) -> str: - """ - Transforms a datetime object into SQL syntax. - - Parameters: - dtime: The datetime object to convert. - - Returns: - The SQL representation of the datetime with timestamp format. - """ - return f"{number.real_value}" - - def var_from_data(self, var): - """ - Transforms a data variable node into SQL syntax. - - Parameters: - var: The variable name sourced from data. - - Returns: - The SQL representation of the data variable. - """ - return str(var.real_value) - - def var_from_context(self, var): - """ - Transforms a context variable node into SQL syntax. - - Parameters: - var: The variable name sourced from context. - - Returns: - The SQL representation of the context variable. - """ - return f"'{var}'" - - @v_args(tree=True) - def list(self, data: Tree) -> str: - """ - Transforms a list node into SQL syntax. - - Parameters: - data: A tree node containing the list elements. - - Returns: - The SQL representation of the list. - """ - elems = [str(x) for x in data.children if x is not None] - elems_str = ",".join(elems) - return f"({elems_str})" - - def range_op(self, start, end) -> str: - """ - Transforms a range into SQL BETWEEN syntax. - - Parameters: - range_: A tuple representing the start and end of the range. - - Returns: - The SQL BETWEEN representation of the range. - """ - return f"BETWEEN {start} AND {end}" diff --git a/tests/test_transformer.py b/tests/test_transformer.py index ad200d5..cac959f 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -6,13 +6,7 @@ from lark import Token from ransack.exceptions import EvaluationError, ShapeError from ransack.parser import Parser -from ransack.transformer import ( - ExpressionTransformer, - Filter, - SQLTransformer, - TokenWrapper, - get_values, -) +from ransack.transformer import ExpressionTransformer, Filter, TokenWrapper, get_values @pytest.fixture @@ -30,11 +24,6 @@ def expr_transformer(): return ExpressionTransformer() -@pytest.fixture -def sql_transformer(): - return SQLTransformer() - - sample_data = { "Category": ["Intrusion.UserCompromise"], "ConnCount": 1, @@ -498,104 +487,3 @@ class TestFilter: exp_tree = expr_transformer.transform(parser.parse_only("my_var == 14")) res = filter_.transform(exp_tree) assert res - - -class TestSQLTransformer: - - def parse_transform_sql( - self, parser, expr_transformer, sql_transformer, expression - ): - """Helper to parse, transform to Python object, then transform to SQL.""" - tree = parser.parse(expression) - sql_tree = sql_transformer.transform(tree) - return sql_tree - - @pytest.mark.parametrize( - ("expression", "expected_sql"), - [ - # Test IP4 - ("192.168.0.1", "'192.168.0.1'"), - ("192.168.0.0/24", "'192.168.0.0/24'"), - # Test IP6 - ("2001:db8::1", "'2001:db8::1'"), - ("2001:db8::/32", "'2001:db8::/32'"), - # Test Date and Time - ( - "2024-01-01T12:00:00Z", - "'2024-01-01 12:00:00+00:00'::timestamp with time zone", - ), - ( - "2024-01-01 12:00:00-02:00", - "'2024-01-01 12:00:00-02:00'::timestamp with time zone", - ), - ("01:00:00", "'1:00:00'::interval"), - ("1d01:00:00", "'1 day, 1:00:00'::interval"), - # Test datetime interval - ( - "2024-10-01..2024-10-31", - ( - "BETWEEN '2024-10-01 00:00:00+00:00'::timestamp with time zone " - "AND '2024-10-31 00:00:00+00:00'::timestamp with time zone" - ), - ), - # Test Strings - ("'constant1'", "'constant1'"), - ('"constant2"', "'constant2'"), - # Test Comparisons - ("1 > 2", "1 > 2"), - ("a >= b", "a >= b"), - ("5 < 10", "5 < 10"), - ("x <= y", "x <= y"), - ("name == 'Alice'", "name = 'Alice'"), - # Test Logical Operations - ("a or b", "a OR b"), - ("a and b", "a AND b"), - ("not x", "NOT x"), - # Test Arithmetic Operations - ("a + b", "a + b"), - ("5 - 3", "5 - 3"), - ("x * y", "x * y"), - ("10 / 2", "10 / 2"), - ("7 % 2", "7 % 2"), - ], - ) - def test_sql_transformations( - self, parser, expr_transformer, sql_transformer, expression, expected_sql - ): - sql_result = self.parse_transform_sql( - parser, expr_transformer, sql_transformer, expression - ) - assert sql_result == expected_sql - - def test_sql_list(self, parser, expr_transformer, sql_transformer): - """Test SQL list transformation with explicit list format.""" - expr = "[1, 2, 3]" - sql_result = self.parse_transform_sql( - parser, expr_transformer, sql_transformer, expr - ) - assert sql_result == "(1,2,3)" - - def test_sql_in_op(self, parser, expr_transformer, sql_transformer): - """Test SQL 'IN' operation for multiple values.""" - expr = "value IN [1, 2, 3]" - sql_result = self.parse_transform_sql( - parser, expr_transformer, sql_transformer, expr - ) - assert sql_result == "value IN (1,2,3)" - - def test_sql_like_op(self, parser, expr_transformer, sql_transformer): - """Test SQL 'LIKE' operation.""" - parser = Parser(context={"description": "%login%"}) - expr = ".description like description" - sql_result = self.parse_transform_sql( - parser, expr_transformer, sql_transformer, expr - ) - assert sql_result == "description LIKE '%login%'" - - def test_sql_between_numbers(self, parser, expr_transformer, sql_transformer): - """Test SQL 'BETWEEN' operation for datetime ranges.""" - expr = "port in 1..1024" - sql_result = self.parse_transform_sql( - parser, expr_transformer, sql_transformer, expr - ) - assert sql_result == "port BETWEEN 1 AND 1024" -- GitLab