sql_fusion 1.1.0__tar.gz → 1.2.0__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.
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/PKG-INFO +6 -2
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/README.md +5 -1
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/pyproject.toml +1 -1
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/__init__.py +4 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/composite_table.py +2 -1
- sql_fusion-1.2.0/src/sql_fusion/query/__init__.py +15 -0
- sql_fusion-1.2.0/src/sql_fusion/query/sets.py +107 -0
- sql_fusion-1.1.0/src/sql_fusion/query/__init__.py +0 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/operators.py +0 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/query/delete.py +0 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/query/insert.py +0 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/query/select.py +0 -0
- {sql_fusion-1.1.0 → sql_fusion-1.2.0}/src/sql_fusion/query/update.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: sql_fusion
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Python query builder with a focus on composability and reusability.
|
|
5
5
|
Author: Mastermind-U
|
|
6
6
|
Author-email: Mastermind-U <rex49513@gmail.com>
|
|
@@ -77,6 +77,7 @@ In short, the goal is to keep the ergonomics of a lightweight builder while stil
|
|
|
77
77
|
- automatic table aliases
|
|
78
78
|
- composable conditions with `AND`, `OR`, and `NOT`
|
|
79
79
|
- joins, subqueries, and CTEs
|
|
80
|
+
- set operations with `UNION`, `INTERSECT`, and `EXCEPT`
|
|
80
81
|
- ordering and grouping with `GROUP BY`, `ROLLUP`, `CUBE`, and `GROUPING SETS`
|
|
81
82
|
- aggregate and custom SQL functions through `func`
|
|
82
83
|
- backend-specific SQL rewrites through compile expressions
|
|
@@ -113,10 +114,13 @@ from sql_fusion import (
|
|
|
113
114
|
Column,
|
|
114
115
|
Table,
|
|
115
116
|
delete,
|
|
117
|
+
except_,
|
|
116
118
|
func,
|
|
117
119
|
insert,
|
|
120
|
+
intersect,
|
|
118
121
|
select,
|
|
119
|
-
|
|
122
|
+
union,
|
|
123
|
+
text_op,
|
|
120
124
|
update,
|
|
121
125
|
)
|
|
122
126
|
```
|
|
@@ -63,6 +63,7 @@ In short, the goal is to keep the ergonomics of a lightweight builder while stil
|
|
|
63
63
|
- automatic table aliases
|
|
64
64
|
- composable conditions with `AND`, `OR`, and `NOT`
|
|
65
65
|
- joins, subqueries, and CTEs
|
|
66
|
+
- set operations with `UNION`, `INTERSECT`, and `EXCEPT`
|
|
66
67
|
- ordering and grouping with `GROUP BY`, `ROLLUP`, `CUBE`, and `GROUPING SETS`
|
|
67
68
|
- aggregate and custom SQL functions through `func`
|
|
68
69
|
- backend-specific SQL rewrites through compile expressions
|
|
@@ -99,10 +100,13 @@ from sql_fusion import (
|
|
|
99
100
|
Column,
|
|
100
101
|
Table,
|
|
101
102
|
delete,
|
|
103
|
+
except_,
|
|
102
104
|
func,
|
|
103
105
|
insert,
|
|
106
|
+
intersect,
|
|
104
107
|
select,
|
|
105
|
-
|
|
108
|
+
union,
|
|
109
|
+
text_op,
|
|
106
110
|
update,
|
|
107
111
|
)
|
|
108
112
|
```
|
|
@@ -2,6 +2,7 @@ from .composite_table import Alias, Column, Table, func, text_op
|
|
|
2
2
|
from .query.delete import delete
|
|
3
3
|
from .query.insert import insert
|
|
4
4
|
from .query.select import select
|
|
5
|
+
from .query.sets import except_, intersect, union
|
|
5
6
|
from .query.update import update
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
@@ -9,9 +10,12 @@ __all__ = [
|
|
|
9
10
|
"Column",
|
|
10
11
|
"Table",
|
|
11
12
|
"delete",
|
|
13
|
+
"except_",
|
|
12
14
|
"func",
|
|
13
15
|
"insert",
|
|
16
|
+
"intersect",
|
|
14
17
|
"select",
|
|
15
18
|
"text_op",
|
|
19
|
+
"union",
|
|
16
20
|
"update",
|
|
17
21
|
]
|
|
@@ -511,7 +511,8 @@ class Condition:
|
|
|
511
511
|
)
|
|
512
512
|
sql, op_params = operator.to_sql_ref(subquery_sql)
|
|
513
513
|
return apply_negation(
|
|
514
|
-
sql,
|
|
514
|
+
sql,
|
|
515
|
+
col_params + subquery_params + op_params,
|
|
515
516
|
)
|
|
516
517
|
|
|
517
518
|
sql, op_params = operator.to_sql(self.value)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .delete import delete
|
|
2
|
+
from .insert import insert
|
|
3
|
+
from .select import select
|
|
4
|
+
from .sets import except_, intersect, union
|
|
5
|
+
from .update import update
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"delete",
|
|
9
|
+
"except_",
|
|
10
|
+
"insert",
|
|
11
|
+
"intersect",
|
|
12
|
+
"select",
|
|
13
|
+
"union",
|
|
14
|
+
"update",
|
|
15
|
+
]
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from sql_fusion.composite_table import AbstractQuery, AliasRegistry
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class _set_operation(AbstractQuery):
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
query1: AbstractQuery,
|
|
10
|
+
query2: AbstractQuery,
|
|
11
|
+
) -> None:
|
|
12
|
+
super().__init__(table=None, columns=())
|
|
13
|
+
self._query1 = query1
|
|
14
|
+
self._query2 = query2
|
|
15
|
+
|
|
16
|
+
def _operator_sql(self) -> str:
|
|
17
|
+
raise NotImplementedError()
|
|
18
|
+
|
|
19
|
+
def _render_query(
|
|
20
|
+
self,
|
|
21
|
+
query: AbstractQuery,
|
|
22
|
+
alias_registry: AliasRegistry,
|
|
23
|
+
) -> tuple[str, tuple[Any, ...]]:
|
|
24
|
+
return query.build_query(alias_registry)
|
|
25
|
+
|
|
26
|
+
def build_query(
|
|
27
|
+
self,
|
|
28
|
+
alias_registry: AliasRegistry | None = None,
|
|
29
|
+
) -> tuple[str, tuple[Any, ...]]:
|
|
30
|
+
registry = alias_registry or self._alias_registry
|
|
31
|
+
params: list[Any] = []
|
|
32
|
+
|
|
33
|
+
with_sql, with_params = self._build_with_clause(registry)
|
|
34
|
+
params.extend(with_params)
|
|
35
|
+
|
|
36
|
+
left_sql, left_params = self._render_query(self._query1, registry)
|
|
37
|
+
right_sql, right_params = self._render_query(self._query2, registry)
|
|
38
|
+
|
|
39
|
+
query_parts: list[str] = []
|
|
40
|
+
if with_sql:
|
|
41
|
+
query_parts.append(with_sql)
|
|
42
|
+
query_parts.append(
|
|
43
|
+
f"{left_sql} {self._operator_sql()} {right_sql}",
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
params.extend(left_params)
|
|
47
|
+
params.extend(right_params)
|
|
48
|
+
|
|
49
|
+
return self._apply_compile_expressions(
|
|
50
|
+
" ".join(query_parts),
|
|
51
|
+
tuple(params),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class union(_set_operation):
|
|
56
|
+
def __init__(
|
|
57
|
+
self,
|
|
58
|
+
query1: AbstractQuery,
|
|
59
|
+
query2: AbstractQuery,
|
|
60
|
+
all: bool = False, # noqa: A002
|
|
61
|
+
by_name: bool = False,
|
|
62
|
+
) -> None:
|
|
63
|
+
super().__init__(query1, query2)
|
|
64
|
+
self._all = all
|
|
65
|
+
self._by_name = by_name
|
|
66
|
+
|
|
67
|
+
def _operator_sql(self) -> str:
|
|
68
|
+
operator = "UNION"
|
|
69
|
+
if self._all:
|
|
70
|
+
operator += " ALL"
|
|
71
|
+
if self._by_name:
|
|
72
|
+
operator += " BY NAME"
|
|
73
|
+
return operator
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class intersect(_set_operation):
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
query1: AbstractQuery,
|
|
80
|
+
query2: AbstractQuery,
|
|
81
|
+
all_: bool = False,
|
|
82
|
+
) -> None:
|
|
83
|
+
super().__init__(query1, query2)
|
|
84
|
+
self._all = all_
|
|
85
|
+
|
|
86
|
+
def _operator_sql(self) -> str:
|
|
87
|
+
operator = "INTERSECT"
|
|
88
|
+
if self._all:
|
|
89
|
+
operator += " ALL"
|
|
90
|
+
return operator
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class except_(_set_operation):
|
|
94
|
+
def __init__(
|
|
95
|
+
self,
|
|
96
|
+
query1: AbstractQuery,
|
|
97
|
+
query2: AbstractQuery,
|
|
98
|
+
all_: bool = False,
|
|
99
|
+
) -> None:
|
|
100
|
+
super().__init__(query1, query2)
|
|
101
|
+
self._all = all_
|
|
102
|
+
|
|
103
|
+
def _operator_sql(self) -> str:
|
|
104
|
+
operator = "EXCEPT"
|
|
105
|
+
if self._all:
|
|
106
|
+
operator += " ALL"
|
|
107
|
+
return operator
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|