ransacklib 1.1.0.dev12__tar.gz → 1.1.0.dev14__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.
- {ransacklib-1.1.0.dev12/ransacklib.egg-info → ransacklib-1.1.0.dev14}/PKG-INFO +2 -1
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/pyproject.toml +2 -1
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/function.py +4 -1
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/operator.py +23 -10
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/transformer.py +20 -7
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14/ransacklib.egg-info}/PKG-INFO +2 -1
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransacklib.egg-info/SOURCES.txt +1 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransacklib.egg-info/requires.txt +1 -0
- ransacklib-1.1.0.dev14/tests/test_postgres.py +1178 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/tests/test_transformer.py +4 -204
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/LICENSE +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/README.rst +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/__init__.py +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/exceptions.py +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/parser.py +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/py.typed +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransack/types.py +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransacklib.egg-info/dependency_links.txt +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/ransacklib.egg-info/top_level.txt +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/setup.cfg +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/tests/test_operator.py +0 -0
- {ransacklib-1.1.0.dev12 → ransacklib-1.1.0.dev14}/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.
|
|
3
|
+
Version: 1.1.0.dev14
|
|
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
|
|
@@ -26,6 +26,7 @@ Requires-Dist: mypy<2.0,>=1.18; extra == "dev"
|
|
|
26
26
|
Requires-Dist: ruff<0.15,>=0.14; extra == "dev"
|
|
27
27
|
Requires-Dist: build<1.4,>=1.3; extra == "dev"
|
|
28
28
|
Requires-Dist: twine<7.0,>=6.2; extra == "dev"
|
|
29
|
+
Requires-Dist: psycopg[binary]; extra == "dev"
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
|
|
31
32
|
Welcome to ransack
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ransacklib"
|
|
7
|
-
version = "1.1.0.
|
|
7
|
+
version = "1.1.0.dev14"
|
|
8
8
|
description = "A modern, extensible language for manipulation with structured data"
|
|
9
9
|
license = "MIT"
|
|
10
10
|
readme = "README.rst"
|
|
@@ -33,6 +33,7 @@ dev = [
|
|
|
33
33
|
"ruff>=0.14,<0.15",
|
|
34
34
|
"build>=1.3,<1.4",
|
|
35
35
|
"twine>=6.2,<7.0",
|
|
36
|
+
"psycopg[binary]",
|
|
36
37
|
]
|
|
37
38
|
|
|
38
39
|
[project.urls]
|
|
@@ -17,12 +17,15 @@ Example usage in query:
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
import datetime
|
|
20
|
+
from collections.abc import MutableSequence
|
|
20
21
|
|
|
21
22
|
from ipranges import IP4, IP6, IP4Net, IP4Range, IP6Net, IP6Range
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
def length(x):
|
|
25
|
-
if isinstance(
|
|
26
|
+
if isinstance(
|
|
27
|
+
x, (MutableSequence, str, IP4, IP4Net, IP4Range, IP6, IP6Net, IP6Range)
|
|
28
|
+
):
|
|
26
29
|
return len(x)
|
|
27
30
|
raise TypeError(f"Function length is not defined for value {x}")
|
|
28
31
|
|
|
@@ -607,20 +607,16 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, typing.Any, bool]:
|
|
|
607
607
|
(Number, Number): (f"{l_sql} {op} {r_sql}", False),
|
|
608
608
|
(Number, List(Number)): (f"{l_sql} {op} ANY({r_sql})", False),
|
|
609
609
|
(Number, Range(Number)): (f"{l_sql} {op} {tuple_repr_f}({r_sql})", False),
|
|
610
|
-
(List(Number), Number): (f"ANY({l_sql}) {op} {r_sql}", False),
|
|
611
610
|
(Datetime, Datetime): (f"{l_sql} {op} {r_sql}", False),
|
|
612
611
|
(Datetime, List(Datetime)): (f"{l_sql} {op} ANY({r_sql})", False),
|
|
613
612
|
(Datetime, Range(Datetime)): (
|
|
614
613
|
f"{r_sql} {op} {tuple_repr_f}({l_sql})",
|
|
615
614
|
True,
|
|
616
615
|
),
|
|
617
|
-
(List(Datetime), Datetime): (f"ANY({l_sql}) {op} {r_sql}", False),
|
|
618
616
|
(Timedelta, Timedelta): (f"{l_sql} {op} {r_sql}", False),
|
|
619
617
|
(Timedelta, List(Timedelta)): (f"{l_sql} {op} ANY({r_sql})", False),
|
|
620
|
-
(List(Timedelta), Timedelta): (f"ANY({l_sql}) {op} {r_sql}", False),
|
|
621
618
|
(IP, IP): (f"{l_sql} {op} {r_sql}", False),
|
|
622
619
|
(IP, List(IP)): (f"{l_sql} {op} ANY({r_sql})", False),
|
|
623
|
-
(List(IP), IP): (f"ANY({l_sql}) {op} {r_sql}", False),
|
|
624
620
|
}
|
|
625
621
|
|
|
626
622
|
# Comparison and logical operators (result is always boolean).
|
|
@@ -639,6 +635,7 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, typing.Any, bool]:
|
|
|
639
635
|
(String, List(String)): (f"{l_sql} = ANY({r_sql})", False),
|
|
640
636
|
(IP, IP): (f"{l_sql} && {r_sql}", False),
|
|
641
637
|
(IP, List(IP)): (f"{l_sql} && ANY({r_sql})", False),
|
|
638
|
+
(List(IP), IP): (f"{r_sql} && ANY({l_sql})", True),
|
|
642
639
|
(List(Any), List(Any)): (f"{l_sql} && {r_sql}", False),
|
|
643
640
|
(Range(Any), Range(Any)): (f"{l_sql} && {r_sql}", False),
|
|
644
641
|
},
|
|
@@ -647,24 +644,40 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, typing.Any, bool]:
|
|
|
647
644
|
(Range(Any), Range(Any)): (f"upper({l_sql}) > lower({r_sql})", False),
|
|
648
645
|
(Range(Number), Number): (f"upper({l_sql}) > {r_sql}", False),
|
|
649
646
|
(Range(Datetime), Datetime): (f"upper({l_sql}) > {r_sql}", False),
|
|
647
|
+
(List(Number), Number): (f"{r_sql} < ANY({l_sql})", True),
|
|
648
|
+
(List(Datetime), Datetime): (f"{r_sql} < ANY({l_sql})", True),
|
|
649
|
+
(List(Timedelta), Timedelta): (f"{r_sql} < ANY({l_sql})", True),
|
|
650
|
+
(List(IP), IP): (f"{r_sql} < ANY({l_sql})", True),
|
|
650
651
|
},
|
|
651
652
|
">=": _get_comp_dict_sql(">=", "lower")
|
|
652
653
|
| {
|
|
653
654
|
(Range(Any), Range(Any)): (f"upper({l_sql}) >= lower({r_sql})", False),
|
|
654
655
|
(Range(Number), Number): (f"upper({l_sql}) >= {r_sql}", False),
|
|
655
656
|
(Range(Datetime), Datetime): (f"upper({l_sql}) >= {r_sql}", False),
|
|
657
|
+
(List(Number), Number): (f"{r_sql} <= ANY({l_sql})", True),
|
|
658
|
+
(List(Datetime), Datetime): (f"{r_sql} <= ANY({l_sql})", True),
|
|
659
|
+
(List(Timedelta), Timedelta): (f"{r_sql} <= ANY({l_sql})", True),
|
|
660
|
+
(List(IP), IP): (f"{r_sql} <= ANY({l_sql})", True),
|
|
656
661
|
},
|
|
657
662
|
"<": _get_comp_dict_sql("<", "upper")
|
|
658
663
|
| {
|
|
659
664
|
(Range(Any), Range(Any)): (f"lower({l_sql}) < upper({r_sql})", False),
|
|
660
665
|
(Range(Number), Number): (f"lower({l_sql}) < {r_sql}", False),
|
|
661
666
|
(Range(Datetime), Datetime): (f"lower({l_sql}) < {r_sql}", False),
|
|
667
|
+
(List(Number), Number): (f"{r_sql} > ANY({l_sql})", True),
|
|
668
|
+
(List(Datetime), Datetime): (f"{r_sql} > ANY({l_sql})", True),
|
|
669
|
+
(List(Timedelta), Timedelta): (f"{r_sql} > ANY({l_sql})", True),
|
|
670
|
+
(List(IP), IP): (f"{r_sql} > ANY({l_sql})", True),
|
|
662
671
|
},
|
|
663
672
|
"<=": _get_comp_dict_sql("<=", "upper")
|
|
664
673
|
| {
|
|
665
674
|
(Range(Any), Range(Any)): (f"lower({l_sql}) <= upper({r_sql})", False),
|
|
666
675
|
(Range(Number), Number): (f"lower({l_sql}) <= {r_sql}", False),
|
|
667
676
|
(Range(Datetime), Datetime): (f"lower({l_sql}) <= {r_sql}", False),
|
|
677
|
+
(List(Number), Number): (f"{r_sql} >= ANY({l_sql})", True),
|
|
678
|
+
(List(Datetime), Datetime): (f"{r_sql} >= ANY({l_sql})", True),
|
|
679
|
+
(List(Timedelta), Timedelta): (f"{r_sql} >= ANY({l_sql})", True),
|
|
680
|
+
(List(IP), IP): (f"{r_sql} >= ANY({l_sql})", True),
|
|
668
681
|
},
|
|
669
682
|
"and": {(Bool, Bool): (f"{l_sql} AND {r_sql}", False)},
|
|
670
683
|
"or": {(Bool, Bool): (f"({l_sql} OR {r_sql})", False)},
|
|
@@ -743,28 +756,28 @@ def _operator_map_sql(op, l_sql, r_sql, t1, t2) -> tuple[str, typing.Any, bool]:
|
|
|
743
756
|
),
|
|
744
757
|
},
|
|
745
758
|
"*": {
|
|
746
|
-
(Timedelta, Number): (f"{l_sql} * {r_sql}", Timedelta),
|
|
759
|
+
(Timedelta, Number): (f"({l_sql} * {r_sql})", Timedelta),
|
|
747
760
|
(Timedelta, List(Number)): (
|
|
748
761
|
f"array(select {l_sql} * unnest({r_sql}))",
|
|
749
762
|
List(Timedelta),
|
|
750
763
|
),
|
|
751
|
-
(Number, Number): (f"{l_sql} * {r_sql}", Number),
|
|
764
|
+
(Number, Number): (f"({l_sql} * {r_sql})", Number),
|
|
752
765
|
(Number, List(Number)): (
|
|
753
766
|
f"array(select {l_sql} * unnest({r_sql}))",
|
|
754
767
|
List(Number),
|
|
755
768
|
),
|
|
756
769
|
},
|
|
757
770
|
"/": {
|
|
758
|
-
(Timedelta,
|
|
759
|
-
(Timedelta, List(
|
|
771
|
+
(Timedelta, Number): (f"({l_sql} / {r_sql})", Timedelta),
|
|
772
|
+
(Timedelta, List(Number)): (
|
|
760
773
|
f"array(select {l_sql} / unnest({r_sql}))",
|
|
761
774
|
List(Timedelta),
|
|
762
775
|
),
|
|
763
|
-
(List(Timedelta),
|
|
776
|
+
(List(Timedelta), Number): (
|
|
764
777
|
f"array(select unnest({l_sql}) / {r_sql})",
|
|
765
778
|
List(Timedelta),
|
|
766
779
|
),
|
|
767
|
-
(Number, Number): (f"{l_sql} / {r_sql}", Number),
|
|
780
|
+
(Number, Number): (f"({l_sql} / {r_sql})", Number),
|
|
768
781
|
(Number, List(Number)): (
|
|
769
782
|
f"array(select {l_sql} / unnest({r_sql}))",
|
|
770
783
|
List(Number),
|
|
@@ -853,8 +853,9 @@ class SQLInterpreter(Interpreter):
|
|
|
853
853
|
return result, params, type_
|
|
854
854
|
|
|
855
855
|
def number(self, token: TokenWrapper) -> tuple[str, list, types.RansackType]:
|
|
856
|
-
|
|
857
|
-
|
|
856
|
+
if isinstance(token.real_value, int):
|
|
857
|
+
return ("%s::int", [token.real_value], types.Integer)
|
|
858
|
+
return ("%s", [token.real_value], types.Float)
|
|
858
859
|
|
|
859
860
|
def datetime(self, token: TokenWrapper) -> tuple[str, list, types.RansackType]:
|
|
860
861
|
if token.real_value.tzinfo is not None:
|
|
@@ -893,6 +894,8 @@ class SQLInterpreter(Interpreter):
|
|
|
893
894
|
elif l_type is types.Float and r_type is types.Float:
|
|
894
895
|
range_type = "numrange"
|
|
895
896
|
l_type = types.Number
|
|
897
|
+
l_sql = l_sql + "::numeric"
|
|
898
|
+
r_sql = r_sql + "::numeric"
|
|
896
899
|
elif l_type is types.Datetime and r_type is types.Datetime:
|
|
897
900
|
if "WITH TIME ZONE" in l_sql and "WITH TIME ZONE" in r_sql:
|
|
898
901
|
range_type = "tstzrange"
|
|
@@ -950,20 +953,30 @@ class SQLInterpreter(Interpreter):
|
|
|
950
953
|
|
|
951
954
|
return sql, params, type_
|
|
952
955
|
|
|
956
|
+
def _arithmetic_operation(self, operator, l_tree, r_tree) -> tuple[str, list, Any]:
|
|
957
|
+
l_sql, l_params, l_type = self.visit(l_tree)
|
|
958
|
+
r_sql, r_params, r_type = self.visit(r_tree)
|
|
959
|
+
|
|
960
|
+
if l_type == types.List(types.Empty):
|
|
961
|
+
return l_sql, l_params, l_type
|
|
962
|
+
if r_type == types.List(types.Empty):
|
|
963
|
+
return r_sql, r_params, r_type
|
|
964
|
+
return self._binary_operation(operator, l_tree, r_tree)
|
|
965
|
+
|
|
953
966
|
def add(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
|
|
954
|
-
return self.
|
|
967
|
+
return self._arithmetic_operation("+", l_tree, r_tree)
|
|
955
968
|
|
|
956
969
|
def sub(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
|
|
957
|
-
return self.
|
|
970
|
+
return self._arithmetic_operation("-", l_tree, r_tree)
|
|
958
971
|
|
|
959
972
|
def mul(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
|
|
960
|
-
return self.
|
|
973
|
+
return self._arithmetic_operation("*", l_tree, r_tree)
|
|
961
974
|
|
|
962
975
|
def div(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
|
|
963
|
-
return self.
|
|
976
|
+
return self._arithmetic_operation("/", l_tree, r_tree)
|
|
964
977
|
|
|
965
978
|
def mod(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, Any]:
|
|
966
|
-
return self.
|
|
979
|
+
return self._arithmetic_operation("%", l_tree, r_tree)
|
|
967
980
|
|
|
968
981
|
def eq(self, l_tree: Tree, r_tree: Tree) -> tuple[str, list, type[bool]]:
|
|
969
982
|
return self._binary_operation("==", l_tree, r_tree)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ransacklib
|
|
3
|
-
Version: 1.1.0.
|
|
3
|
+
Version: 1.1.0.dev14
|
|
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
|
|
@@ -26,6 +26,7 @@ Requires-Dist: mypy<2.0,>=1.18; extra == "dev"
|
|
|
26
26
|
Requires-Dist: ruff<0.15,>=0.14; extra == "dev"
|
|
27
27
|
Requires-Dist: build<1.4,>=1.3; extra == "dev"
|
|
28
28
|
Requires-Dist: twine<7.0,>=6.2; extra == "dev"
|
|
29
|
+
Requires-Dist: psycopg[binary]; extra == "dev"
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
|
|
31
32
|
Welcome to ransack
|