sql-blocks 1.20250713__py3-none-any.whl → 1.20250715__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 +67 -27
- {sql_blocks-1.20250713.dist-info → sql_blocks-1.20250715.dist-info}/METADATA +1 -1
- sql_blocks-1.20250715.dist-info/RECORD +7 -0
- sql_blocks-1.20250713.dist-info/RECORD +0 -7
- {sql_blocks-1.20250713.dist-info → sql_blocks-1.20250715.dist-info}/LICENSE +0 -0
- {sql_blocks-1.20250713.dist-info → sql_blocks-1.20250715.dist-info}/WHEEL +0 -0
- {sql_blocks-1.20250713.dist-info → sql_blocks-1.20250715.dist-info}/top_level.txt +0 -0
sql_blocks/sql_blocks.py
CHANGED
@@ -202,9 +202,14 @@ class NamedField:
|
|
202
202
|
self.class_type = class_type
|
203
203
|
|
204
204
|
def add(self, name: str, main: SQLObject):
|
205
|
+
def is_literal() -> bool:
|
206
|
+
if re.search(r'^[\'"].*', name):
|
207
|
+
return True
|
208
|
+
return False
|
205
209
|
main.values.setdefault(SELECT, []).append(
|
206
210
|
'{} as {}'.format(
|
207
|
-
|
211
|
+
name if is_literal()
|
212
|
+
else self.class_type.format(name, main),
|
208
213
|
self.alias # --- field alias
|
209
214
|
)
|
210
215
|
)
|
@@ -945,15 +950,16 @@ class OrderBy(Clause):
|
|
945
950
|
|
946
951
|
@classmethod
|
947
952
|
def format(cls, name: str, main: SQLObject) -> str:
|
948
|
-
if cls.ascending(name):
|
949
|
-
|
950
|
-
else:
|
953
|
+
# if cls.ascending(name):
|
954
|
+
# cls.sort = SortType.ASC
|
955
|
+
# else:
|
956
|
+
if not cls.ascending(name):
|
951
957
|
cls.sort = SortType.DESC
|
952
958
|
return super().format(name, main)
|
953
959
|
|
954
960
|
@classmethod
|
955
961
|
def cls_to_str(cls, field: str='') -> str:
|
956
|
-
return f"{ORDER_BY} {field}"
|
962
|
+
return f"{ORDER_BY} {field}{cls.sort.value}"
|
957
963
|
|
958
964
|
class Partition:
|
959
965
|
@classmethod
|
@@ -1064,7 +1070,8 @@ class QueryLanguage:
|
|
1064
1070
|
return self.join_with_tabs(values, ' AND ')
|
1065
1071
|
|
1066
1072
|
def sort_by(self, values: list) -> str:
|
1067
|
-
|
1073
|
+
is_ascending = OrderBy.ascending(values[-1]) if values else False
|
1074
|
+
if OrderBy.sort == SortType.DESC and is_ascending:
|
1068
1075
|
values[-1] += ' DESC'
|
1069
1076
|
return self.join_with_tabs(values, ',')
|
1070
1077
|
|
@@ -2190,7 +2197,8 @@ class Recursive(CTE):
|
|
2190
2197
|
MAIN_TAG = '__main__'
|
2191
2198
|
|
2192
2199
|
class CTEFactory:
|
2193
|
-
|
2200
|
+
|
2201
|
+
def __init__(self, txt: str, template: str = ''):
|
2194
2202
|
"""
|
2195
2203
|
SQL syntax:
|
2196
2204
|
---
|
@@ -2203,30 +2211,28 @@ class CTEFactory:
|
|
2203
2211
|
Table1(field, `function$`field`:alias`, `group@`) <- Table2(field)
|
2204
2212
|
`...`MainTable(field)
|
2205
2213
|
"""
|
2214
|
+
if template:
|
2215
|
+
for table in re.findall(r'[#](\w+)', txt):
|
2216
|
+
txt = txt.replace(f'#{table}', template.format(t=table))
|
2206
2217
|
if parser_class(txt) == CypherParser:
|
2207
|
-
txt, main_script = txt.split('...')
|
2218
|
+
txt, *main_script = txt.split('...')
|
2208
2219
|
query_list = Select.parse(txt, CypherParser)
|
2209
2220
|
if main_script:
|
2210
|
-
main_script =
|
2211
|
-
|
2212
|
-
|
2213
|
-
re.split(
|
2214
|
-
r'\bas\b|\bAS\b', field
|
2215
|
-
)[-1].strip()
|
2216
|
-
for query in query_list
|
2217
|
-
for field in query.values.get(SELECT, [])
|
2218
|
-
]
|
2219
|
-
main_script = main_script.replace('(*)', '({}, *)'.format(
|
2220
|
-
','.join(field_list)
|
2221
|
-
))
|
2221
|
+
main_script = self.replace_wildcards(
|
2222
|
+
''.join(main_script), query_list
|
2223
|
+
)
|
2222
2224
|
self.main = detect(main_script)
|
2223
2225
|
alias = self.main.table_name
|
2224
2226
|
else:
|
2225
2227
|
alias = '_'.join(query.table_name for query in query_list)
|
2226
2228
|
self.main = Select(alias)
|
2227
2229
|
self.main.break_lines = False
|
2228
|
-
|
2229
|
-
|
2230
|
+
related_tables = any([
|
2231
|
+
query.join_type.value for query in query_list
|
2232
|
+
])
|
2233
|
+
if related_tables:
|
2234
|
+
query_list = [ join_queries(query_list) ]
|
2235
|
+
self.cte_list = [CTE(alias, query_list)]
|
2230
2236
|
return
|
2231
2237
|
summary = self.extract_subqueries(txt)
|
2232
2238
|
self.main = detect( summary.pop(MAIN_TAG) )
|
@@ -2244,6 +2250,21 @@ class CTEFactory:
|
|
2244
2250
|
result = ',\n'.join(lines) + '\n' + str(self.main)
|
2245
2251
|
CTE.show_query = True
|
2246
2252
|
return result
|
2253
|
+
|
2254
|
+
@staticmethod
|
2255
|
+
def replace_wildcards(txt: str, query_list: list) -> str:
|
2256
|
+
if '(*)' in txt:
|
2257
|
+
field_list = [
|
2258
|
+
re.split(
|
2259
|
+
r'\bas\b|\bAS\b', field
|
2260
|
+
)[-1].strip()
|
2261
|
+
for query in query_list
|
2262
|
+
for field in query.values.get(SELECT, [])
|
2263
|
+
]
|
2264
|
+
return txt.replace('(*)', '({}, *)'.format(
|
2265
|
+
','.join( set(field_list) )
|
2266
|
+
))
|
2267
|
+
return txt
|
2247
2268
|
|
2248
2269
|
@staticmethod
|
2249
2270
|
def extract_subqueries(txt: str) -> dict:
|
@@ -2280,7 +2301,7 @@ class CTEFactory:
|
|
2280
2301
|
query_list = [
|
2281
2302
|
clean_subquery( expr.split() )
|
2282
2303
|
for expr in re.split(
|
2283
|
-
r'\bUNION\b', txt[start: end], re.IGNORECASE
|
2304
|
+
r'\bUNION\b', txt[start: end], flags=re.IGNORECASE
|
2284
2305
|
)
|
2285
2306
|
]
|
2286
2307
|
result[MAIN_TAG] += f' {alias} {alias}'
|
@@ -2397,8 +2418,8 @@ def parser_class(text: str) -> Parser:
|
|
2397
2418
|
PARSER_REGEX = [
|
2398
2419
|
(r'select.*from', SQLParser),
|
2399
2420
|
(r'[.](find|aggregate)[(]', MongoParser),
|
2400
|
-
(r'
|
2401
|
-
(r'^\w+[
|
2421
|
+
(r'\bmatch\b\s*[(]', Neo4JParser),
|
2422
|
+
(r'^\w+\S+[(]', CypherParser),
|
2402
2423
|
]
|
2403
2424
|
text = Parser.remove_spaces(text)
|
2404
2425
|
for regex, class_type in PARSER_REGEX:
|
@@ -2436,9 +2457,28 @@ def detect(text: str, join_method = join_queries, format: str='') -> Select | li
|
|
2436
2457
|
return result
|
2437
2458
|
# ===========================================================================================//
|
2438
2459
|
|
2460
|
+
|
2439
2461
|
if __name__ == "__main__":
|
2462
|
+
OrderBy.sort = SortType.DESC
|
2440
2463
|
cte = CTEFactory(
|
2441
|
-
"
|
2464
|
+
# "#Customer#Employee#Supplier...People_by_Type(*)",
|
2465
|
+
# template = '{t}("{t[0]}":ptype, nome:person_name)'
|
2466
|
+
"""
|
2467
|
+
SELECT u001.name, agg_sales.total
|
2468
|
+
FROM (
|
2469
|
+
SELECT * FROM Users u
|
2470
|
+
WHERE u.status = 'active'
|
2471
|
+
) AS u001
|
2472
|
+
JOIN (
|
2473
|
+
SELECT s.user_id, Sum(s.value) as total
|
2474
|
+
FROM Sales s
|
2475
|
+
GROUP BY s.user_id
|
2476
|
+
)
|
2477
|
+
As agg_sales
|
2478
|
+
ON u001.id = agg_sales.user_id
|
2479
|
+
ORDER BY u001.name
|
2480
|
+
"""
|
2481
|
+
# "Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name:vendors_name@)"
|
2442
2482
|
# ^^^ ^^^ ^^^
|
2443
2483
|
# | | | ^^^ ^^^
|
2444
2484
|
# | | | | |
|
@@ -2450,6 +2490,6 @@ if __name__ == "__main__":
|
|
2450
2490
|
# | |
|
2451
2491
|
# +--- The Sales table |
|
2452
2492
|
# Also groups by vendor´s name ------------------+
|
2453
|
-
"...Annual_Sales_per_Vendor(*) -> Goal(year, target)"
|
2493
|
+
# "...Annual_Sales_per_Vendor(*) -> Goal(^year, target)"
|
2454
2494
|
)
|
2455
2495
|
print(cte)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.20250715
|
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
|
@@ -0,0 +1,7 @@
|
|
1
|
+
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
+
sql_blocks/sql_blocks.py,sha256=LNdU9qK7eROrpCzggnPxOOlTSKkuU-mVYJLNsZNjvdY,85746
|
3
|
+
sql_blocks-1.20250715.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
+
sql_blocks-1.20250715.dist-info/METADATA,sha256=pVsle1pwP1elpLwRZtpcXjL5uIi2iTiysunYaBj4N3I,25388
|
5
|
+
sql_blocks-1.20250715.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
sql_blocks-1.20250715.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
+
sql_blocks-1.20250715.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
-
sql_blocks/sql_blocks.py,sha256=h5toXPu_0Nw9VaifIXAVlLBOKAv1Oz2Iw2kQSVEbk4Y,84392
|
3
|
-
sql_blocks-1.20250713.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
-
sql_blocks-1.20250713.dist-info/METADATA,sha256=OnjjmdmJU39ADp7D1IS6FmC020iIqguDP1MbkKCdJtg,25388
|
5
|
-
sql_blocks-1.20250713.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
sql_blocks-1.20250713.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
-
sql_blocks-1.20250713.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|