sql-blocks 1.25.6139999999999__py3-none-any.whl → 1.2025.627__py3-none-any.whl
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_blocks/sql_blocks.py +83 -6
- {sql_blocks-1.25.6139999999999.dist-info → sql_blocks-1.2025.627.dist-info}/METADATA +47 -1
- sql_blocks-1.2025.627.dist-info/RECORD +7 -0
- sql_blocks-1.25.6139999999999.dist-info/RECORD +0 -7
- {sql_blocks-1.25.6139999999999.dist-info → sql_blocks-1.2025.627.dist-info}/LICENSE +0 -0
- {sql_blocks-1.25.6139999999999.dist-info → sql_blocks-1.2025.627.dist-info}/WHEEL +0 -0
- {sql_blocks-1.25.6139999999999.dist-info → sql_blocks-1.2025.627.dist-info}/top_level.txt +0 -0
sql_blocks/sql_blocks.py
CHANGED
@@ -847,8 +847,15 @@ class Rows:
|
|
847
847
|
)
|
848
848
|
|
849
849
|
|
850
|
+
class DescOrderBy:
|
851
|
+
@classmethod
|
852
|
+
def add(cls, name: str, main: SQLObject):
|
853
|
+
name = Clause.format(name, main)
|
854
|
+
main.values.setdefault(ORDER_BY, []).append(name + SortType.DESC.value)
|
855
|
+
|
850
856
|
class OrderBy(Clause):
|
851
857
|
sort: SortType = SortType.ASC
|
858
|
+
DESC = DescOrderBy
|
852
859
|
|
853
860
|
@classmethod
|
854
861
|
def add(cls, name: str, main: SQLObject):
|
@@ -1973,13 +1980,12 @@ class NotSelectIN(SelectIN):
|
|
1973
1980
|
|
1974
1981
|
class CTE(Select):
|
1975
1982
|
prefix = ''
|
1983
|
+
show_query = True
|
1976
1984
|
|
1977
|
-
def __init__(self, table_name: str, query_list: list[Select]):
|
1985
|
+
def __init__(self, table_name: str, query_list: list[Select]=[]):
|
1978
1986
|
super().__init__(table_name)
|
1979
|
-
for query in query_list:
|
1980
|
-
query.break_lines = False
|
1981
1987
|
self.query_list = query_list
|
1982
|
-
self.break_lines = False
|
1988
|
+
self.break_lines = False
|
1983
1989
|
|
1984
1990
|
def __str__(self) -> str:
|
1985
1991
|
size = 0
|
@@ -1989,6 +1995,7 @@ class CTE(Select):
|
|
1989
1995
|
self.break_lines = True
|
1990
1996
|
# ---------------------------------------------------------
|
1991
1997
|
def justify(query: Select) -> str:
|
1998
|
+
query.break_lines = False
|
1992
1999
|
result, line = [], ''
|
1993
2000
|
keywords = '|'.join(KEYWORD)
|
1994
2001
|
for word in re.split(fr'({keywords}|AND|OR|,)', str(query)):
|
@@ -2002,9 +2009,9 @@ class CTE(Select):
|
|
2002
2009
|
# ---------------------------------------------------------
|
2003
2010
|
return 'WITH {}{} AS (\n {}\n){}'.format(
|
2004
2011
|
self.prefix, self.table_name,
|
2005
|
-
'\
|
2012
|
+
'\n\tUNION ALL\n '.join(
|
2006
2013
|
justify(q) for q in self.query_list
|
2007
|
-
), super().__str__()
|
2014
|
+
), super().__str__() if self.show_query else ''
|
2008
2015
|
)
|
2009
2016
|
|
2010
2017
|
def join(self, pattern: str, fields: list | str, format: str=''):
|
@@ -2058,6 +2065,76 @@ class Recursive(CTE):
|
|
2058
2065
|
return self
|
2059
2066
|
|
2060
2067
|
|
2068
|
+
MAIN_TAG = '__main__'
|
2069
|
+
|
2070
|
+
class CTEFactory:
|
2071
|
+
def __init__(self, txt: str):
|
2072
|
+
"""
|
2073
|
+
Syntax:
|
2074
|
+
---
|
2075
|
+
**SELECT ...
|
2076
|
+
FROM** ( `sub_query1` ) **AS** `alias_1`
|
2077
|
+
JOIN ( `sub_query2` ) **AS** `alias_2` **ON** `__join__`
|
2078
|
+
"""
|
2079
|
+
summary = self.extract_subqueries(txt)
|
2080
|
+
self.main = detect( summary.pop(MAIN_TAG) )
|
2081
|
+
self.cte_list = [
|
2082
|
+
CTE(alias, [
|
2083
|
+
Select.parse(query)[0]
|
2084
|
+
for query in elements
|
2085
|
+
])
|
2086
|
+
for alias, elements in summary.items()
|
2087
|
+
]
|
2088
|
+
|
2089
|
+
def __str__(self):
|
2090
|
+
CTE.show_query = False
|
2091
|
+
lines = [str(cte) for cte in self.cte_list]
|
2092
|
+
return ',\n'.join(lines) + '\n' + str(self.main)
|
2093
|
+
|
2094
|
+
@staticmethod
|
2095
|
+
def extract_subqueries(txt: str) -> dict:
|
2096
|
+
result = {}
|
2097
|
+
# ---------------------------------------------------
|
2098
|
+
def clean_subquery(source: list) -> str:
|
2099
|
+
while source:
|
2100
|
+
if source[0].upper() == 'SELECT':
|
2101
|
+
break
|
2102
|
+
word = source.pop(0)
|
2103
|
+
if word.upper() in ('FROM', 'JOIN'):
|
2104
|
+
result[MAIN_TAG] += f' {word}'
|
2105
|
+
return ' '.join(source)
|
2106
|
+
def balanced_parentheses(expr: str) -> bool:
|
2107
|
+
return expr.count('(') == expr.count(')')
|
2108
|
+
# ---------------------------------------------------
|
2109
|
+
for found in re.finditer(r'(FROM|JOIN)\s*[(]\s*SELECT', txt, re.IGNORECASE):
|
2110
|
+
start = found.start()
|
2111
|
+
alias = ''
|
2112
|
+
pos = start
|
2113
|
+
while not alias:
|
2114
|
+
found = re.search(r'[)]\s*AS\s+\w+', txt[pos:], re.IGNORECASE)
|
2115
|
+
if not found:
|
2116
|
+
break
|
2117
|
+
end = found.end() + pos
|
2118
|
+
last = end
|
2119
|
+
if balanced_parentheses(txt[start: end]):
|
2120
|
+
pos += found.start()
|
2121
|
+
alias = re.findall(r'\s*(\w+)$', txt[pos: end])[0]
|
2122
|
+
end = pos
|
2123
|
+
pos = end
|
2124
|
+
if not result:
|
2125
|
+
result[MAIN_TAG] = txt[:start]
|
2126
|
+
query_list = [
|
2127
|
+
clean_subquery( expr.split() )
|
2128
|
+
for expr in re.split(
|
2129
|
+
r'\bUNION\b', txt[start: end], re.IGNORECASE
|
2130
|
+
)
|
2131
|
+
]
|
2132
|
+
result[MAIN_TAG] += f' {alias} {alias}'
|
2133
|
+
result[alias] = query_list
|
2134
|
+
result[MAIN_TAG] += txt[last:]
|
2135
|
+
return result
|
2136
|
+
|
2137
|
+
|
2061
2138
|
# ----- Rules -----
|
2062
2139
|
|
2063
2140
|
class RulePutLimit(Rule):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.2025.627
|
4
4
|
Summary: Allows you to create objects for parts of SQL query commands. Also to combine these objects by joining them, adding or removing parts...
|
5
5
|
Home-page: https://github.com/julio-cascalles/sql_blocks
|
6
6
|
Author: Júlio Cascalles
|
@@ -888,3 +888,49 @@ R2 = Recursive.create(
|
|
888
888
|
|
889
889
|
>> Note: Comments added later.
|
890
890
|
---
|
891
|
+
|
892
|
+
### CTEFactory class
|
893
|
+
CTEFactory exchanges subqueries for CTEs, simply by passing the text of the "dirty" query:
|
894
|
+
|
895
|
+
*Example*:
|
896
|
+
```
|
897
|
+
print(
|
898
|
+
CTEFactory("""
|
899
|
+
SELECT u001.name, agg_sales.total
|
900
|
+
FROM (
|
901
|
+
SELECT * FROM Users u
|
902
|
+
WHERE u.status = 'active'
|
903
|
+
) AS u001
|
904
|
+
JOIN (
|
905
|
+
SELECT s.user_id, Sum(s.value) as total
|
906
|
+
FROM Sales s
|
907
|
+
GROUP BY s.user_id
|
908
|
+
)
|
909
|
+
As agg_sales
|
910
|
+
ON u001.id = agg_sales.user_id
|
911
|
+
ORDER BY u001.name
|
912
|
+
""")
|
913
|
+
)
|
914
|
+
```
|
915
|
+
results...
|
916
|
+
```
|
917
|
+
WITH u001 AS (
|
918
|
+
SELECT * FROM Users u
|
919
|
+
WHERE u.status = 'active'
|
920
|
+
),
|
921
|
+
WITH agg_sales AS (
|
922
|
+
SELECT s.user_id, Sum(s.value) as total
|
923
|
+
FROM Sales s
|
924
|
+
GROUP BY s.user_id
|
925
|
+
)
|
926
|
+
SELECT
|
927
|
+
u001.name,
|
928
|
+
agg_sales.total
|
929
|
+
FROM
|
930
|
+
u001 u001
|
931
|
+
JOIN agg_sales agg_sales ON
|
932
|
+
(u001.id = agg_sales.user_id)
|
933
|
+
ORDER BY
|
934
|
+
u001.name
|
935
|
+
```
|
936
|
+
---
|
@@ -0,0 +1,7 @@
|
|
1
|
+
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
+
sql_blocks/sql_blocks.py,sha256=Eq2EMaVALy1IBGcjyjh7SaE1WZBPNvXCi748iCi6AtM,77469
|
3
|
+
sql_blocks-1.2025.627.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
+
sql_blocks-1.2025.627.dist-info/METADATA,sha256=n1Ju94eliblEldBRpj-VzmXg4_09K_vgT5hszgqqVS0,23328
|
5
|
+
sql_blocks-1.2025.627.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
sql_blocks-1.2025.627.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
+
sql_blocks-1.2025.627.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
-
sql_blocks/sql_blocks.py,sha256=qDwpII5rYY8tqpp93bKKHW9udOqI3SRb-0wfxjAsYD4,74694
|
3
|
-
sql_blocks-1.25.6139999999999.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
-
sql_blocks-1.25.6139999999999.dist-info/METADATA,sha256=Pmk2nqJ3hV7PZVGE8V0bqw8TnSa1_rVIiylJad-nDCk,22236
|
5
|
-
sql_blocks-1.25.6139999999999.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
sql_blocks-1.25.6139999999999.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
-
sql_blocks-1.25.6139999999999.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|