sql-blocks 1.20250709__py3-none-any.whl → 1.20250711__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 +93 -42
- {sql_blocks-1.20250709.dist-info → sql_blocks-1.20250711.dist-info}/METADATA +2 -1
- sql_blocks-1.20250711.dist-info/RECORD +7 -0
- sql_blocks-1.20250709.dist-info/RECORD +0 -7
- {sql_blocks-1.20250709.dist-info → sql_blocks-1.20250711.dist-info}/LICENSE +0 -0
- {sql_blocks-1.20250709.dist-info → sql_blocks-1.20250711.dist-info}/WHEEL +0 -0
- {sql_blocks-1.20250709.dist-info → sql_blocks-1.20250711.dist-info}/top_level.txt +0 -0
sql_blocks/sql_blocks.py
CHANGED
@@ -221,11 +221,12 @@ class Code:
|
|
221
221
|
def As(self, field_alias: str, modifiers=None):
|
222
222
|
if modifiers:
|
223
223
|
self.extra[field_alias] = TO_LIST(modifiers)
|
224
|
-
|
224
|
+
if field_alias:
|
225
|
+
self.field_class = NamedField(field_alias)
|
225
226
|
return self
|
226
227
|
|
227
228
|
def format(self, name: str, main: SQLObject) -> str:
|
228
|
-
|
229
|
+
return Field.format(name, main)
|
229
230
|
|
230
231
|
def __add(self, name: str, main: SQLObject):
|
231
232
|
name = self.format(name, main)
|
@@ -624,8 +625,9 @@ class Where:
|
|
624
625
|
))
|
625
626
|
|
626
627
|
@classmethod
|
627
|
-
def join(cls, query: SQLObject):
|
628
|
+
def join(cls, query: SQLObject, pairs: dict=None):
|
628
629
|
where = cls(query)
|
630
|
+
where.pairs = pairs
|
629
631
|
where.add = where.add_join
|
630
632
|
return where
|
631
633
|
|
@@ -634,11 +636,18 @@ class Where:
|
|
634
636
|
main.values[FROM].append(f',{query.table_name} {query.alias}')
|
635
637
|
for key in USUAL_KEYS:
|
636
638
|
main.update_values(key, query.values.get(key, []))
|
637
|
-
if
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
639
|
+
if not self.pairs:
|
640
|
+
if not query.key_field:
|
641
|
+
return
|
642
|
+
self.pairs = {name: query.key_field}
|
643
|
+
a1, a2 = main.alias, query.alias
|
644
|
+
main.has_named_field
|
645
|
+
for f1, f2 in self.pairs.items():
|
646
|
+
if main.has_named_field(f1):
|
647
|
+
expr = f'({a2}.{f2} = {f1})'
|
648
|
+
else:
|
649
|
+
expr = f'({a2}.{f2} = {a1}.{f1})'
|
650
|
+
main.values.setdefault(WHERE, []).append(expr)
|
642
651
|
|
643
652
|
def add(self, name: str, main: SQLObject):
|
644
653
|
func_type = FUNCTION_CLASS.get(name.lower())
|
@@ -970,6 +979,8 @@ class GroupBy(Clause):
|
|
970
979
|
query: Select = obj
|
971
980
|
fields += query.values.get(SELECT, [])
|
972
981
|
query.add(alias, main)
|
982
|
+
elif obj == Field:
|
983
|
+
fields += [alias]
|
973
984
|
if not func:
|
974
985
|
fields += [self.format(name, main)]
|
975
986
|
for field in fields:
|
@@ -1664,38 +1675,51 @@ class CypherParser(Parser):
|
|
1664
1675
|
Where(' '.join(condition)).add(field, query)
|
1665
1676
|
|
1666
1677
|
def add_order(self, token: str):
|
1667
|
-
self.add_field(token,
|
1678
|
+
self.add_field(token, sorted=True)
|
1668
1679
|
|
1669
|
-
def add_field(self, token: str,
|
1680
|
+
def add_field(self, token: str, sorted: bool = False):
|
1670
1681
|
if token in self.TOKEN_METHODS:
|
1671
1682
|
return
|
1672
|
-
class_list = [Field]
|
1673
1683
|
if '*' in token:
|
1674
1684
|
token = token.replace('*', '')
|
1675
1685
|
self.queries[-1].key_field = token
|
1676
1686
|
return
|
1677
|
-
|
1678
|
-
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
+
# -------------------------------------------------------
|
1688
|
+
def field_params() -> dict:
|
1689
|
+
ROLE_OF_SEPARATOR = {
|
1690
|
+
'$': 'function',
|
1691
|
+
':': 'alias',
|
1692
|
+
'@': 'group',
|
1693
|
+
'!': 'field',
|
1694
|
+
}
|
1695
|
+
REGEX_FIELD = r'([{}])'.format(''.join(ROLE_OF_SEPARATOR))
|
1696
|
+
elements = re.split(REGEX_FIELD, token+'!')
|
1697
|
+
return {
|
1698
|
+
ROLE_OF_SEPARATOR[k]: v
|
1699
|
+
for k, v in zip(elements[1::2], elements[::2])
|
1700
|
+
}
|
1701
|
+
def run(function: str='', alias: str='', group: str='', field: str=''):
|
1702
|
+
is_count = function == 'count'
|
1703
|
+
if alias or is_count:
|
1704
|
+
field, alias = alias, field
|
1705
|
+
extra_classes = [OrderBy] if sorted else []
|
1706
|
+
if group:
|
1707
|
+
if not field:
|
1708
|
+
field = group
|
1709
|
+
extra_classes += [GroupBy]
|
1710
|
+
if function:
|
1711
|
+
if is_count and not field:
|
1712
|
+
field = self.queries[-1].key_field or 'id'
|
1713
|
+
class_type = FUNCTION_CLASS.get(function)
|
1687
1714
|
if not class_type:
|
1688
|
-
raise ValueError(f'Unknown function `{
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
class_list = [class_type]
|
1697
|
-
class_list += extra_classes
|
1698
|
-
FieldList(token, class_list).add('', self.queries[-1])
|
1715
|
+
raise ValueError(f'Unknown function `{function}`.')
|
1716
|
+
class_list = [ class_type().As(alias or group, extra_classes) ]
|
1717
|
+
else:
|
1718
|
+
class_list = [Field] + extra_classes
|
1719
|
+
FieldList(field, class_list).add('', self.queries[-1])
|
1720
|
+
# -------------------------------------------------------
|
1721
|
+
run( **field_params() )
|
1722
|
+
# -------------------------------------------------------
|
1699
1723
|
|
1700
1724
|
def left_ftable(self, token: str):
|
1701
1725
|
if self.queries:
|
@@ -2107,7 +2131,7 @@ class CTE(Select):
|
|
2107
2131
|
else:
|
2108
2132
|
count = len(fields)
|
2109
2133
|
queries = detect(
|
2110
|
-
pattern*count,
|
2134
|
+
pattern*count, join_method=None, format=format
|
2111
2135
|
)
|
2112
2136
|
FieldList(fields, queries, ziped=True).add('', self)
|
2113
2137
|
self.break_lines = True
|
@@ -2128,7 +2152,7 @@ class Recursive(CTE):
|
|
2128
2152
|
def get_field(obj: SQLObject, pos: int) -> str:
|
2129
2153
|
return obj.values[SELECT][pos].split('.')[-1]
|
2130
2154
|
t1, t2 = detect(
|
2131
|
-
pattern*2,
|
2155
|
+
pattern*2, join_method=None, format=format
|
2132
2156
|
)
|
2133
2157
|
pk_field = get_field(t1, 0)
|
2134
2158
|
foreign_key = ''
|
@@ -2163,6 +2187,14 @@ class CTEFactory:
|
|
2163
2187
|
FROM** ( `sub_query1` ) **AS** `alias_1`
|
2164
2188
|
JOIN ( `sub_query2` ) **AS** `alias_2` **ON** `__join__`
|
2165
2189
|
"""
|
2190
|
+
if parser_class(txt) == CypherParser:
|
2191
|
+
query_list = Select.parse(txt, CypherParser)
|
2192
|
+
alias = '_'.join(query.table_name for query in query_list)
|
2193
|
+
self.main = Select(alias)
|
2194
|
+
self.main.break_lines = False
|
2195
|
+
query = join_queries(query_list)
|
2196
|
+
self.cte_list = [CTE(alias, [query])]
|
2197
|
+
return
|
2166
2198
|
summary = self.extract_subqueries(txt)
|
2167
2199
|
self.main = detect( summary.pop(MAIN_TAG) )
|
2168
2200
|
self.cte_list = [
|
@@ -2341,8 +2373,13 @@ def parser_class(text: str) -> Parser:
|
|
2341
2373
|
return class_type
|
2342
2374
|
return None
|
2343
2375
|
|
2376
|
+
def join_queries(query_list: list) -> Select:
|
2377
|
+
result = query_list[0]
|
2378
|
+
for query in query_list[1:]:
|
2379
|
+
result += query
|
2380
|
+
return result
|
2344
2381
|
|
2345
|
-
def detect(text: str,
|
2382
|
+
def detect(text: str, join_method = join_queries, format: str='') -> Select | list[Select]:
|
2346
2383
|
from collections import Counter
|
2347
2384
|
parser = parser_class(text)
|
2348
2385
|
if not parser:
|
@@ -2357,14 +2394,28 @@ def detect(text: str, join_queries: bool = True, format: str='') -> Select | lis
|
|
2357
2394
|
Select.EQUIVALENT_NAMES[new_name] = table
|
2358
2395
|
text = text[:begin] + new_name + '(' + text[end:]
|
2359
2396
|
count -= 1
|
2360
|
-
|
2397
|
+
result = Select.parse(text, parser)
|
2361
2398
|
if format:
|
2362
|
-
for query in
|
2399
|
+
for query in result:
|
2363
2400
|
query.set_file_format(format)
|
2364
|
-
if
|
2365
|
-
|
2366
|
-
result = query_list[0]
|
2367
|
-
for query in query_list[1:]:
|
2368
|
-
result += query
|
2401
|
+
if join_method:
|
2402
|
+
result = join_method(result)
|
2369
2403
|
return result
|
2370
2404
|
# ===========================================================================================//
|
2405
|
+
|
2406
|
+
if __name__ == "__main__":
|
2407
|
+
cte = CTEFactory(
|
2408
|
+
"Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name@)"
|
2409
|
+
# ^^^ ^^^ ^^^
|
2410
|
+
# | | | ^^^ ^^^
|
2411
|
+
# | | | | |
|
2412
|
+
# | | | Relaciona Sales com Vendor ----+ |
|
2413
|
+
# | | | |
|
2414
|
+
# | | +---- Chama de `ref_year` e agrupa |
|
2415
|
+
# | | |
|
2416
|
+
# | +-- Extrai o ano do campo `ref_date` |
|
2417
|
+
# | |
|
2418
|
+
# +--- Tabela de vendas |
|
2419
|
+
# Agrupa também pelo nome do vendedor -------------+
|
2420
|
+
)
|
2421
|
+
print(cte)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.20250711
|
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
|
@@ -197,6 +197,7 @@ FROM
|
|
197
197
|
WHERE
|
198
198
|
(album.artist_id = artist.id)
|
199
199
|
|
200
|
+
(*) --> For more than one relationship, use the **pairs** parameter.
|
200
201
|
|
201
202
|
|
202
203
|
---
|
@@ -0,0 +1,7 @@
|
|
1
|
+
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
+
sql_blocks/sql_blocks.py,sha256=JHQ0CzciUEodZoA0WjUYKDpC2VZWcFlDB9C2wrNc4rA,83004
|
3
|
+
sql_blocks-1.20250711.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
+
sql_blocks-1.20250711.dist-info/METADATA,sha256=fci6o5QrXStVrXylRQ7QaCpO9jid0P6eON6xMK4Rob0,24486
|
5
|
+
sql_blocks-1.20250711.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
sql_blocks-1.20250711.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
+
sql_blocks-1.20250711.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
-
sql_blocks/sql_blocks.py,sha256=xyJGWgUf0nG7Vxcfy0DIjrvuCMGLRU3PGeg4UsZrRnY,80533
|
3
|
-
sql_blocks-1.20250709.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
-
sql_blocks-1.20250709.dist-info/METADATA,sha256=QzoGQNftNY_wHmpm3EkMcMDqgrA1OMtN79-f8jS0XV4,24416
|
5
|
-
sql_blocks-1.20250709.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
sql_blocks-1.20250709.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
-
sql_blocks-1.20250709.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|