sql-blocks 1.20250715__tar.gz → 1.20250718__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_blocks-1.20250715/sql_blocks.egg-info → sql_blocks-1.20250718}/PKG-INFO +15 -11
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/README.md +14 -10
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/pyproject.toml +1 -1
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/setup.py +1 -1
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/sql_blocks/sql_blocks.py +100 -67
- {sql_blocks-1.20250715 → sql_blocks-1.20250718/sql_blocks.egg-info}/PKG-INFO +15 -11
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/LICENSE +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/setup.cfg +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/sql_blocks/__init__.py +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/sql_blocks.egg-info/SOURCES.txt +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/sql_blocks.egg-info/dependency_links.txt +0 -0
- {sql_blocks-1.20250715 → sql_blocks-1.20250718}/sql_blocks.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.20250718
|
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
|
@@ -995,26 +995,30 @@ results...
|
|
995
995
|
|
996
996
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
997
997
|
|
998
|
-
cte = CTEFactory(
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
998
|
+
cte = CTEFactory("""
|
999
|
+
Annual_Sales_per_Vendor[
|
1000
|
+
Sales(
|
1001
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
1002
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
1003
|
+
]
|
1004
1004
|
|
1005
|
-
|
1005
|
+
[-1](**, ref_year) -> Goal(year, target)
|
1006
|
+
""")
|
1007
|
+
print(cte)
|
1006
1008
|
|
1007
1009
|
results...
|
1008
1010
|
```
|
1009
1011
|
WITH Annual_Sales_per_Vendor AS (
|
1010
|
-
SELECT ven.name as vendors_name
|
1011
|
-
,
|
1012
|
+
SELECT ven.name as vendors_name
|
1013
|
+
, Year(sal.ref_date) as ref_year
|
1014
|
+
, Sum(sal.quantity) as qty_sold
|
1015
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
1012
1016
|
GROUP BY ven.name, ref_year
|
1013
1017
|
)
|
1014
1018
|
SELECT
|
1019
|
+
aspv.vendors_name,
|
1015
1020
|
aspv.ref_year,
|
1016
1021
|
aspv.qty_sold,
|
1017
|
-
aspv.vendors_name,
|
1018
1022
|
goa.target
|
1019
1023
|
FROM
|
1020
1024
|
Annual_Sales_per_Vendor aspv
|
@@ -980,26 +980,30 @@ results...
|
|
980
980
|
|
981
981
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
982
982
|
|
983
|
-
cte = CTEFactory(
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
983
|
+
cte = CTEFactory("""
|
984
|
+
Annual_Sales_per_Vendor[
|
985
|
+
Sales(
|
986
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
987
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
988
|
+
]
|
989
989
|
|
990
|
-
|
990
|
+
[-1](**, ref_year) -> Goal(year, target)
|
991
|
+
""")
|
992
|
+
print(cte)
|
991
993
|
|
992
994
|
results...
|
993
995
|
```
|
994
996
|
WITH Annual_Sales_per_Vendor AS (
|
995
|
-
SELECT ven.name as vendors_name
|
996
|
-
,
|
997
|
+
SELECT ven.name as vendors_name
|
998
|
+
, Year(sal.ref_date) as ref_year
|
999
|
+
, Sum(sal.quantity) as qty_sold
|
1000
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
997
1001
|
GROUP BY ven.name, ref_year
|
998
1002
|
)
|
999
1003
|
SELECT
|
1004
|
+
aspv.vendors_name,
|
1000
1005
|
aspv.ref_year,
|
1001
1006
|
aspv.qty_sold,
|
1002
|
-
aspv.vendors_name,
|
1003
1007
|
goa.target
|
1004
1008
|
FROM
|
1005
1009
|
Annual_Sales_per_Vendor aspv
|
@@ -1994,7 +1994,7 @@ class Select(SQLObject):
|
|
1994
1994
|
from copy import deepcopy
|
1995
1995
|
return deepcopy(self)
|
1996
1996
|
|
1997
|
-
def
|
1997
|
+
def relation_error(self, other: SQLObject):
|
1998
1998
|
raise ValueError(f'No relationship found between {self.table_name} and {other.table_name}.')
|
1999
1999
|
|
2000
2000
|
def __add__(self, other: SQLObject):
|
@@ -2011,7 +2011,7 @@ class Select(SQLObject):
|
|
2011
2011
|
PrimaryKey.add(primary_key, query)
|
2012
2012
|
query.add(foreign_field, other)
|
2013
2013
|
return other
|
2014
|
-
self.
|
2014
|
+
self.relation_error(other) # === raise ERROR ... ===
|
2015
2015
|
elif primary_key:
|
2016
2016
|
PrimaryKey.add(primary_key, other)
|
2017
2017
|
other.add(foreign_field, query)
|
@@ -2040,7 +2040,7 @@ class Select(SQLObject):
|
|
2040
2040
|
else:
|
2041
2041
|
fk_field, primary_k = ForeignKey.find(other, self)
|
2042
2042
|
if not fk_field:
|
2043
|
-
self.
|
2043
|
+
self.relation_error(other) # === raise ERROR ... ===
|
2044
2044
|
query = other.copy()
|
2045
2045
|
other = self.copy()
|
2046
2046
|
query.__class__ = NotSelectIN
|
@@ -2127,8 +2127,8 @@ class CTE(Select):
|
|
2127
2127
|
query.break_lines = False
|
2128
2128
|
result, line = [], ''
|
2129
2129
|
keywords = '|'.join(KEYWORD)
|
2130
|
-
for word in re.split(fr'({keywords}|AND|OR|,)', str(query)):
|
2131
|
-
if len(line) >=
|
2130
|
+
for word in re.split(fr'({keywords}|AND|OR|JOIN|,)', str(query)):
|
2131
|
+
if len(line) >= 30:
|
2132
2132
|
result.append(line)
|
2133
2133
|
line = ''
|
2134
2134
|
line += word
|
@@ -2197,7 +2197,8 @@ class Recursive(CTE):
|
|
2197
2197
|
MAIN_TAG = '__main__'
|
2198
2198
|
|
2199
2199
|
class CTEFactory:
|
2200
|
-
|
2200
|
+
TEMPLATE_FIELD_FUNC = lambda t: t.lower()[:3] + '_id'
|
2201
|
+
|
2201
2202
|
def __init__(self, txt: str, template: str = ''):
|
2202
2203
|
"""
|
2203
2204
|
SQL syntax:
|
@@ -2208,35 +2209,61 @@ class CTEFactory:
|
|
2208
2209
|
|
2209
2210
|
Cypher syntax:
|
2210
2211
|
---
|
2211
|
-
|
2212
|
-
|
2212
|
+
`cte_name`[
|
2213
|
+
Table1(field, `function$`field`:alias`, `group@`) <- Table2(field)
|
2214
|
+
]
|
2213
2215
|
"""
|
2216
|
+
def put_parentheses():
|
2217
|
+
result = txt
|
2218
|
+
for found in re.findall(r'\[\d+\][^(]', result):
|
2219
|
+
item = found.strip()[:3]
|
2220
|
+
result = result.replace(item, f'{item}()')
|
2221
|
+
return result
|
2222
|
+
txt, *negative = re.split(r'(\[-\d+\])', txt)
|
2223
|
+
txt = put_parentheses()
|
2224
|
+
txt, *suffix = re.split(r'(\[\d+\])', txt, maxsplit=1)
|
2214
2225
|
if template:
|
2215
2226
|
for table in re.findall(r'[#](\w+)', txt):
|
2216
|
-
txt = txt.replace(f'#{table}', template.format(
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
)
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
+
txt = txt.replace( f'#{table}', template.format(
|
2228
|
+
t=table, f=CTEFactory.TEMPLATE_FIELD_FUNC(table)
|
2229
|
+
) )
|
2230
|
+
self.cte_list = []
|
2231
|
+
self.main = None
|
2232
|
+
for script in txt.split(']'):
|
2233
|
+
if '(' not in script:
|
2234
|
+
script += self.replace_wildcards(''.join(suffix))
|
2235
|
+
suffix = []
|
2236
|
+
self.build_ctes(script)
|
2237
|
+
if not self.cte_list:
|
2238
|
+
return
|
2239
|
+
if not suffix and negative:
|
2240
|
+
suffix = negative
|
2241
|
+
if suffix:
|
2242
|
+
self.main = detect( self.replace_wildcards(''.join(suffix)) )
|
2243
|
+
elif not self.main:
|
2244
|
+
self.main = Select(self.cte_list[0].table_name)
|
2245
|
+
self.main.break_lines = False
|
2246
|
+
|
2247
|
+
def build_ctes(self, script: str):
|
2248
|
+
alias, *body = script.split('[')
|
2249
|
+
if body:
|
2250
|
+
script = ''.join(body)
|
2251
|
+
if not re.sub( r'\s+', '', script):
|
2252
|
+
return
|
2253
|
+
if parser_class(script) == CypherParser:
|
2254
|
+
query_list = Select.parse(script, CypherParser)
|
2255
|
+
if not body:
|
2227
2256
|
alias = '_'.join(query.table_name for query in query_list)
|
2228
|
-
self.main = Select(alias)
|
2229
|
-
self.main.break_lines = False
|
2230
2257
|
related_tables = any([
|
2231
2258
|
query.join_type.value for query in query_list
|
2232
2259
|
])
|
2233
2260
|
if related_tables:
|
2234
2261
|
query_list = [ join_queries(query_list) ]
|
2235
|
-
self.cte_list
|
2262
|
+
self.cte_list += [CTE(alias, query_list)]
|
2236
2263
|
return
|
2237
|
-
summary = self.extract_subqueries(
|
2264
|
+
summary = self.extract_subqueries(script)
|
2238
2265
|
self.main = detect( summary.pop(MAIN_TAG) )
|
2239
|
-
self.cte_list
|
2266
|
+
self.cte_list += [
|
2240
2267
|
CTE(alias, [
|
2241
2268
|
Select.parse(query)[0]
|
2242
2269
|
for query in elements
|
@@ -2245,24 +2272,43 @@ class CTEFactory:
|
|
2245
2272
|
]
|
2246
2273
|
|
2247
2274
|
def __str__(self):
|
2275
|
+
if not self.main:
|
2276
|
+
return ''
|
2248
2277
|
CTE.show_query = False
|
2249
2278
|
lines = [str(cte) for cte in self.cte_list]
|
2250
2279
|
result = ',\n'.join(lines) + '\n' + str(self.main)
|
2251
2280
|
CTE.show_query = True
|
2252
2281
|
return result
|
2253
2282
|
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2283
|
+
def replace_wildcards(self, txt: str) -> str:
|
2284
|
+
ALL_FIELDS_WILDCARD = '**'
|
2285
|
+
result = ''
|
2286
|
+
names = []
|
2287
|
+
query_list = []
|
2288
|
+
cte: CTE
|
2289
|
+
for cte in self.cte_list:
|
2290
|
+
names.append(cte.table_name)
|
2291
|
+
query_list += cte.query_list
|
2292
|
+
last = 0
|
2293
|
+
for found in re.finditer(r'\[[-]*\d+\]', txt):
|
2294
|
+
pos = int(re.sub(r'\[|\]', '', found.group()))
|
2295
|
+
if pos > 0:
|
2296
|
+
pos -= 1
|
2297
|
+
start = found.start()
|
2298
|
+
result += txt[last:start] + names[pos]
|
2299
|
+
last = found.end()
|
2300
|
+
txt = result + txt[last:]
|
2301
|
+
if ALL_FIELDS_WILDCARD in txt:
|
2302
|
+
field_list = []
|
2303
|
+
for query in query_list:
|
2304
|
+
for field in query.values.get(SELECT, []):
|
2305
|
+
new_item = re.split(
|
2306
|
+
r'\bas\b|\bAS\b|[.]', field
|
2307
|
+
)[-1].strip()
|
2308
|
+
if new_item not in field_list:
|
2309
|
+
field_list.append(new_item)
|
2310
|
+
return txt.replace(ALL_FIELDS_WILDCARD, '{}'.format(
|
2311
|
+
','.join(field_list)
|
2266
2312
|
))
|
2267
2313
|
return txt
|
2268
2314
|
|
@@ -2459,37 +2505,24 @@ def detect(text: str, join_method = join_queries, format: str='') -> Select | li
|
|
2459
2505
|
|
2460
2506
|
|
2461
2507
|
if __name__ == "__main__":
|
2462
|
-
|
2508
|
+
# cte = CTEFactory("""
|
2509
|
+
# Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name:vendors_name@)
|
2510
|
+
# """)
|
2463
2511
|
cte = CTEFactory(
|
2464
|
-
|
2465
|
-
|
2466
|
-
|
2467
|
-
|
2468
|
-
|
2469
|
-
|
2470
|
-
|
2471
|
-
)
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
2479
|
-
ORDER BY u001.name
|
2480
|
-
"""
|
2481
|
-
# "Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name:vendors_name@)"
|
2482
|
-
# ^^^ ^^^ ^^^
|
2483
|
-
# | | | ^^^ ^^^
|
2484
|
-
# | | | | |
|
2485
|
-
# | | | Relate Sales to Vendor --------+ |
|
2486
|
-
# | | | |
|
2487
|
-
# | | +---- Call it `ref_year` and group it |
|
2488
|
-
# | | |
|
2489
|
-
# | +-- Extracts the year from the `ref_date` field |
|
2490
|
-
# | |
|
2491
|
-
# +--- The Sales table |
|
2492
|
-
# Also groups by vendor´s name ------------------+
|
2493
|
-
# "...Annual_Sales_per_Vendor(*) -> Goal(^year, target)"
|
2512
|
+
txt='''
|
2513
|
+
#Empregado #Cliente #Fornecedor
|
2514
|
+
|
2515
|
+
Todas_as_pessoas[
|
2516
|
+
[1] [2] [3]
|
2517
|
+
]
|
2518
|
+
|
2519
|
+
[-1](**, ano*) <- Meta(ano, qt_ideal)
|
2520
|
+
''',
|
2521
|
+
template='''
|
2522
|
+
Vendas_por_{t}[
|
2523
|
+
Vendas(year$data:ano@, sum$quantidade:qt_vendida,
|
2524
|
+
{f}) -> {t}(id, nome:nome_pessoa@)
|
2525
|
+
]
|
2526
|
+
'''
|
2494
2527
|
)
|
2495
2528
|
print(cte)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.20250718
|
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
|
@@ -995,26 +995,30 @@ results...
|
|
995
995
|
|
996
996
|
#### 17.3.1 - You can also pass a Cypher script like in the example below:
|
997
997
|
|
998
|
-
cte = CTEFactory(
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
998
|
+
cte = CTEFactory("""
|
999
|
+
Annual_Sales_per_Vendor[
|
1000
|
+
Sales(
|
1001
|
+
year$ref_date:ref_year@, sum$quantity:qty_sold,
|
1002
|
+
vendor) <- Vendor(id, name:vendors_name@)
|
1003
|
+
]
|
1004
1004
|
|
1005
|
-
|
1005
|
+
[-1](**, ref_year) -> Goal(year, target)
|
1006
|
+
""")
|
1007
|
+
print(cte)
|
1006
1008
|
|
1007
1009
|
results...
|
1008
1010
|
```
|
1009
1011
|
WITH Annual_Sales_per_Vendor AS (
|
1010
|
-
SELECT ven.name as vendors_name
|
1011
|
-
,
|
1012
|
+
SELECT ven.name as vendors_name
|
1013
|
+
, Year(sal.ref_date) as ref_year
|
1014
|
+
, Sum(sal.quantity) as qty_sold
|
1015
|
+
FROM Vendor ven LEFT JOIN Sales sal ON (ven.id = sal.vendor
|
1012
1016
|
GROUP BY ven.name, ref_year
|
1013
1017
|
)
|
1014
1018
|
SELECT
|
1019
|
+
aspv.vendors_name,
|
1015
1020
|
aspv.ref_year,
|
1016
1021
|
aspv.qty_sold,
|
1017
|
-
aspv.vendors_name,
|
1018
1022
|
goa.target
|
1019
1023
|
FROM
|
1020
1024
|
Annual_Sales_per_Vendor aspv
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|