sql-blocks 1.25.6139999999999__py3-none-any.whl → 1.2025.625__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 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)):
@@ -2004,7 +2011,7 @@ class CTE(Select):
2004
2011
  self.prefix, self.table_name,
2005
2012
  '\nUNION 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,56 @@ 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
+ ])
2085
+ for alias, query in summary.items()
2086
+ ]
2087
+
2088
+ def __str__(self):
2089
+ CTE.show_query = False
2090
+ lines = [str(cte) for cte in self.cte_list]
2091
+ return ',\n'.join(lines) + '\n' + str(self.main)
2092
+
2093
+ @staticmethod
2094
+ def extract_subqueries(txt: str) -> dict:
2095
+ result = {}
2096
+ for found in re.finditer(r'(FROM|JOIN)\s*[(]\s*SELECT', txt, re.IGNORECASE):
2097
+ start = found.start()
2098
+ alias = ''
2099
+ pos = start
2100
+ while not alias:
2101
+ found = re.search(r'[)]\s*AS\s+\w+', txt[pos:], re.IGNORECASE)
2102
+ if not found:
2103
+ break
2104
+ end = found.end() + pos
2105
+ elements = txt[start: end].split()
2106
+ if '(' not in elements[-3]:
2107
+ _, alias = elements[-2:]
2108
+ pos = end
2109
+ first_word = elements.pop(0)
2110
+ if not result:
2111
+ result[MAIN_TAG] = txt[:start]
2112
+ result[MAIN_TAG] += f' {first_word} {alias} {alias}'
2113
+ result[alias] = ' '.join(elements[1: -3])
2114
+ result[MAIN_TAG] += txt[end:]
2115
+ return result
2116
+
2117
+
2061
2118
  # ----- Rules -----
2062
2119
 
2063
2120
  class RulePutLimit(Rule):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.25.6139999999999
3
+ Version: 1.2025.625
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=J7zEJ5JNRxI3F-7TIypb0myb5OgdE5Stv4boZCTVBLM,76610
3
+ sql_blocks-1.2025.625.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.2025.625.dist-info/METADATA,sha256=I6KTi5S_usvCjJEQl6lm8LG4DaxHhX0NlGRwhHpKBT8,23328
5
+ sql_blocks-1.2025.625.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.2025.625.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.2025.625.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,,