ransacklib 1.1.0.dev7__tar.gz → 1.1.0.dev9__tar.gz

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.
Files changed (20) hide show
  1. {ransacklib-1.1.0.dev7/ransacklib.egg-info → ransacklib-1.1.0.dev9}/PKG-INFO +1 -1
  2. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/pyproject.toml +1 -1
  3. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/operator.py +8 -4
  4. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/transformer.py +10 -5
  5. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9/ransacklib.egg-info}/PKG-INFO +1 -1
  6. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/tests/test_transformer.py +9 -5
  7. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/LICENSE +0 -0
  8. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/README.rst +0 -0
  9. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/__init__.py +0 -0
  10. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/exceptions.py +0 -0
  11. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/function.py +0 -0
  12. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/parser.py +0 -0
  13. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransack/py.typed +0 -0
  14. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransacklib.egg-info/SOURCES.txt +0 -0
  15. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransacklib.egg-info/dependency_links.txt +0 -0
  16. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransacklib.egg-info/requires.txt +0 -0
  17. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/ransacklib.egg-info/top_level.txt +0 -0
  18. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/setup.cfg +0 -0
  19. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/tests/test_operator.py +0 -0
  20. {ransacklib-1.1.0.dev7 → ransacklib-1.1.0.dev9}/tests/test_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ransacklib
3
- Version: 1.1.0.dev7
3
+ Version: 1.1.0.dev9
4
4
  Summary: A modern, extensible language for manipulation with structured data
5
5
  Author-email: "Rajmund H. Hruška" <rajmund.hruska@cesnet.cz>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ransacklib"
7
- version = "1.1.0.dev7"
7
+ version = "1.1.0.dev9"
8
8
  description = "A modern, extensible language for manipulation with structured data"
9
9
  license = "MIT"
10
10
  readme = "README.rst"
@@ -578,10 +578,10 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, Any, bool]:
578
578
  "and": {(bool, bool): (f"{l_sql} AND {r_sql}", False)},
579
579
  "or": {(bool, bool): (f"({l_sql} OR {r_sql})", False)},
580
580
  "contains": {
581
- (str, str): (f"position({r_sql} in {l_sql})>0", True),
581
+ (str, str): (f"{l_sql} like '%' || {r_sql} || '%'", False),
582
582
  (list, str): (
583
- f"position({r_sql} in array_to_string({l_sql}, ','))>0",
584
- True,
583
+ f"array_to_string({l_sql}, ',') like '%' || {r_sql} || '%'",
584
+ False,
585
585
  ),
586
586
  },
587
587
  }
@@ -610,6 +610,10 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, Any, bool]:
610
610
  "%": {
611
611
  (Number, Number): (f"({l_sql} % {r_sql})", Number),
612
612
  },
613
+ ".": {
614
+ (str, str): (f"{l_sql} || {r_sql}", str),
615
+ (list, list): (f"array_cat({l_sql}, {r_sql})", list),
616
+ },
613
617
  }
614
618
 
615
619
  if op == "==" and t1 == t2:
@@ -676,4 +680,4 @@ def binary_operation_sql(
676
680
  return sql, type_, not switch
677
681
  except KeyError:
678
682
  pass
679
- raise OperatorNotFoundError(operator, (l_type, r_type), (left, right)) from None
683
+ raise OperatorNotFoundError(operator, (l_type, r_type)) from None
@@ -830,7 +830,9 @@ class SQLInterpreter(Interpreter):
830
830
  A class providing a method for translating the query from 'ransack' language to SQL.
831
831
  """
832
832
 
833
- def to_sql(self, tree: Tree, data: dict | None = None) -> tuple[str, list[Any]]:
833
+ def to_sql(
834
+ self, tree: Tree, data: dict | None = None
835
+ ) -> tuple[str, list[Any], Any]:
834
836
  """
835
837
  Translates the given tree to PostgreSQL query using the provided data.
836
838
 
@@ -839,15 +841,15 @@ class SQLInterpreter(Interpreter):
839
841
  data: Optional dictionary containing the definition of queried columns.
840
842
 
841
843
  Returns:
842
- A part of the SQL query (the part after 'SELECT' or 'WHERE') and its
843
- parameters.
844
+ A part of the SQL query (the part after 'SELECT' or 'WHERE'), its
845
+ parameters and a resulting type.
844
846
  """
845
847
  self.data = data if data is not None else {}
846
848
 
847
- result, params, _ = self.visit(tree)
849
+ result, params, type_ = self.visit(tree)
848
850
 
849
851
  self.data = {}
850
- return result, params
852
+ return result, params, type_
851
853
 
852
854
  def number(self, token: TokenWrapper) -> tuple[str, list, type[int | float]]:
853
855
  return ("%s", [token.real_value], type(token.real_value))
@@ -993,6 +995,9 @@ class SQLInterpreter(Interpreter):
993
995
  def contains_op(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, type[bool]]:
994
996
  return self._binary_operation("contains", l_tree, r_tree)
995
997
 
998
+ def concat_op(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
999
+ return self._binary_operation(".", l_tree, r_tree)
1000
+
996
1001
  def exists_op(self, path: Token) -> tuple[str, list, type[bool]]:
997
1002
  var_sql, _, _ = self.var_from_data(TokenWrapper(path, path))
998
1003
  return f"{var_sql} IS NOT NULL", [], bool
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ransacklib
3
- Version: 1.1.0.dev7
3
+ Version: 1.1.0.dev9
4
4
  Summary: A modern, extensible language for manipulation with structured data
5
5
  Author-email: "Rajmund H. Hruška" <rajmund.hruska@cesnet.cz>
6
6
  License-Expression: MIT
@@ -738,16 +738,16 @@ class TestSQLInterpreter:
738
738
  ("a_int??", '"a" IS NOT NULL', []),
739
739
  ("a_int??14", 'COALESCE("a", %s)', [14]),
740
740
  # Test contains operator.
741
- ("'abcdfg' contains 'bcd'", "position(%s in %s)>0", ["bcd", "abcdfg"]),
741
+ ("'abcdf' contains 'bcd'", "%s like '%' || %s || '%'", ["abcdf", "bcd"]),
742
742
  (
743
743
  "Category contains 'Attempt'",
744
- "position(%s in array_to_string(\"category\", ','))>0",
744
+ "array_to_string(\"category\", ',') like '%' || %s || '%'",
745
745
  ["Attempt"],
746
746
  ),
747
747
  (
748
748
  "['abcdfg', 'qwerty', 'azerty'] contains 'bcd'",
749
- "position(%s in array_to_string(ARRAY[%s, %s, %s], ','))>0",
750
- ["bcd", "abcdfg", "qwerty", "azerty"],
749
+ "array_to_string(ARRAY[%s, %s, %s], ',') like '%' || %s || '%'",
750
+ ["abcdfg", "qwerty", "azerty", "bcd"],
751
751
  ),
752
752
  # Test = operator.
753
753
  ("1 = 1", "%s = %s", [1, 1]),
@@ -835,6 +835,10 @@ class TestSQLInterpreter:
835
835
  from_str("192.168.0.0/16"),
836
836
  ],
837
837
  ),
838
+ # Test concatenation.
839
+ ("[1, 2] . [3]", "array_cat(ARRAY[%s, %s], ARRAY[%s])", [1, 2, 3]),
840
+ ("Category . Category", 'array_cat("category", "category")', []),
841
+ ("'abc'.'def'", "%s || %s", ["abc", "def"]),
838
842
  # Test functions.
839
843
  (
840
844
  "now() > 2025-12-12T12:34:56Z",
@@ -852,7 +856,7 @@ class TestSQLInterpreter:
852
856
  ],
853
857
  )
854
858
  def test_parse_sql(self, parser, sql, expr, expected_sql, expected_params):
855
- sql_str, params = self.parse(parser, sql, expr)
859
+ sql_str, params, _ = self.parse(parser, sql, expr)
856
860
 
857
861
  assert sql_str == expected_sql
858
862
  assert params == expected_params
File without changes