sql-blocks 0.0.4__tar.gz → 0.0.6__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-0.0.4/sql_blocks.egg-info → sql_blocks-0.0.6}/PKG-INFO +5 -5
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/README.md +4 -4
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/pyproject.toml +1 -1
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/setup.py +1 -1
- sql_blocks-0.0.6/sql_blocks/__init__.py +1 -0
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/sql_blocks/sql_blocks.py +55 -53
- {sql_blocks-0.0.4 → sql_blocks-0.0.6/sql_blocks.egg-info}/PKG-INFO +5 -5
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/tests/tests.py +33 -6
- sql_blocks-0.0.4/sql_blocks/__init__.py +0 -1
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/LICENSE +0 -0
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/setup.cfg +0 -0
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/sql_blocks.egg-info/SOURCES.txt +0 -0
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/sql_blocks.egg-info/dependency_links.txt +0 -0
- {sql_blocks-0.0.4 → sql_blocks-0.0.6}/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: 0.0.
|
3
|
+
Version: 0.0.6
|
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
|
@@ -249,13 +249,13 @@ m = Select...
|
|
249
249
|
9.1
|
250
250
|
```
|
251
251
|
a1 = Select.parse('''
|
252
|
-
SELECT gender,
|
252
|
+
SELECT gender, Max(act.age) FROM Actor act
|
253
253
|
WHERE act.age <= 69 AND act.age >= 45
|
254
254
|
GROUP BY gender
|
255
255
|
''')[0]
|
256
256
|
|
257
257
|
a2 = Select('Actor',
|
258
|
-
age=Between(45, 69),
|
258
|
+
age=[ Between(45, 69), Max ],
|
259
259
|
gender=[GroupBy, Field]
|
260
260
|
)
|
261
261
|
```
|
@@ -306,9 +306,9 @@ m2 = Select(
|
|
306
306
|
Select(
|
307
307
|
'Product',
|
308
308
|
label=Case('price').when(
|
309
|
-
lt(50), 'cheap'
|
309
|
+
Where.lt(50), 'cheap'
|
310
310
|
).when(
|
311
|
-
gt(100), 'expensive'
|
311
|
+
Where.gt(100), 'expensive'
|
312
312
|
).else_value(
|
313
313
|
'normal'
|
314
314
|
)
|
@@ -234,13 +234,13 @@ m = Select...
|
|
234
234
|
9.1
|
235
235
|
```
|
236
236
|
a1 = Select.parse('''
|
237
|
-
SELECT gender,
|
237
|
+
SELECT gender, Max(act.age) FROM Actor act
|
238
238
|
WHERE act.age <= 69 AND act.age >= 45
|
239
239
|
GROUP BY gender
|
240
240
|
''')[0]
|
241
241
|
|
242
242
|
a2 = Select('Actor',
|
243
|
-
age=Between(45, 69),
|
243
|
+
age=[ Between(45, 69), Max ],
|
244
244
|
gender=[GroupBy, Field]
|
245
245
|
)
|
246
246
|
```
|
@@ -291,9 +291,9 @@ m2 = Select(
|
|
291
291
|
Select(
|
292
292
|
'Product',
|
293
293
|
label=Case('price').when(
|
294
|
-
lt(50), 'cheap'
|
294
|
+
Where.lt(50), 'cheap'
|
295
295
|
).when(
|
296
|
-
gt(100), 'expensive'
|
296
|
+
Where.gt(100), 'expensive'
|
297
297
|
).else_value(
|
298
298
|
'normal'
|
299
299
|
)
|
@@ -0,0 +1 @@
|
|
1
|
+
from sql_blocks.sql_blocks import *
|
@@ -2,14 +2,27 @@ from enum import Enum
|
|
2
2
|
import re
|
3
3
|
|
4
4
|
|
5
|
+
PATTERN_PREFIX = '([^0-9 ]+[.])'
|
6
|
+
PATTERN_SUFFIX = '( [A-Za-z_]+)'
|
7
|
+
SUFFIX_AND_PRE = f'{PATTERN_SUFFIX}|{PATTERN_PREFIX}'
|
8
|
+
DISTINCT_SF_PR = f'(DISTINCT|distinct)|{SUFFIX_AND_PRE}'
|
9
|
+
|
5
10
|
KEYWORD = {
|
6
|
-
'SELECT': (',{}', 'SELECT *'),
|
7
|
-
'FROM': ('{}', ''),
|
8
|
-
'WHERE': ('{}AND ', ''),
|
9
|
-
'GROUP BY': (',{}', ''),
|
10
|
-
'ORDER BY': (',{}', ''),
|
11
|
-
'LIMIT': (' ', ''),
|
11
|
+
'SELECT': (',{}', 'SELECT *', DISTINCT_SF_PR),
|
12
|
+
'FROM': ('{}', '', PATTERN_SUFFIX),
|
13
|
+
'WHERE': ('{}AND ', '', PATTERN_PREFIX),
|
14
|
+
'GROUP BY': (',{}', '', SUFFIX_AND_PRE),
|
15
|
+
'ORDER BY': (',{}', '', SUFFIX_AND_PRE),
|
16
|
+
'LIMIT': (' ', '', ''),
|
12
17
|
}
|
18
|
+
# ^ ^ ^
|
19
|
+
# | | |
|
20
|
+
# | | +----- pattern to compare fields
|
21
|
+
# | |
|
22
|
+
# | +----- default when empty (SELECT * ...)
|
23
|
+
# |
|
24
|
+
# +-------- separator
|
25
|
+
|
13
26
|
SELECT, FROM, WHERE, GROUP_BY, ORDER_BY, LIMIT = KEYWORD.keys()
|
14
27
|
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY]
|
15
28
|
|
@@ -39,6 +52,26 @@ class SQLObject:
|
|
39
52
|
def table_name(self) -> str:
|
40
53
|
return self.values[FROM][0].split()[0]
|
41
54
|
|
55
|
+
@staticmethod
|
56
|
+
def get_separator(key: str) -> str:
|
57
|
+
appendix = {WHERE: 'and|', FROM: 'join|JOIN'}
|
58
|
+
return KEYWORD[key][0].format(appendix.get(key, ''))
|
59
|
+
|
60
|
+
def diff(self, key: str, search_list: list, symmetrical: bool=False) -> set:
|
61
|
+
pattern = KEYWORD[key][2]
|
62
|
+
separator = self.get_separator(key)
|
63
|
+
def field_set(source: list) -> set:
|
64
|
+
return set(
|
65
|
+
re.sub(pattern, '', fld.strip()).lower()
|
66
|
+
for string in source
|
67
|
+
for fld in re.split(separator, string)
|
68
|
+
)
|
69
|
+
s1 = field_set(search_list)
|
70
|
+
s2 = field_set(self.values.get(key, []))
|
71
|
+
if symmetrical:
|
72
|
+
return s1.symmetric_difference(s2)
|
73
|
+
return s1 - s2
|
74
|
+
|
42
75
|
def delete(self, search: str, keys: list=USUAL_KEYS):
|
43
76
|
for key in keys:
|
44
77
|
result = []
|
@@ -329,13 +362,12 @@ class Select(SQLObject):
|
|
329
362
|
self.__call__(**values)
|
330
363
|
self.break_lines = True
|
331
364
|
|
365
|
+
def update_values(self, key: str, new_values: list):
|
366
|
+
for value in self.diff(key, new_values):
|
367
|
+
self.values.setdefault(key, []).append(value)
|
368
|
+
|
332
369
|
def add(self, name: str, main: SQLObject):
|
333
|
-
|
334
|
-
for value in new_values:
|
335
|
-
old_values = main.values.get(key, [])
|
336
|
-
if value not in old_values:
|
337
|
-
main.values[key] = old_values + [value]
|
338
|
-
update_values(
|
370
|
+
main.update_values(
|
339
371
|
FROM, [
|
340
372
|
'{jt}JOIN {tb} {a2} ON ({a1}.{f1} = {a2}.{f2})'.format(
|
341
373
|
jt=self.join_type.value,
|
@@ -346,9 +378,13 @@ class Select(SQLObject):
|
|
346
378
|
] + self.values[FROM][1:]
|
347
379
|
)
|
348
380
|
for key in USUAL_KEYS:
|
349
|
-
update_values(key, self.values.get(key, []))
|
381
|
+
main.update_values(key, self.values.get(key, []))
|
350
382
|
|
351
383
|
def __add__(self, other: SQLObject):
|
384
|
+
if self.table_name.lower() == other.table_name.lower():
|
385
|
+
for key in USUAL_KEYS:
|
386
|
+
self.update_values(key, other.values.get(key, []))
|
387
|
+
return self
|
352
388
|
foreign_field, primary_key = ForeignKey.find(self, other)
|
353
389
|
if not foreign_field:
|
354
390
|
foreign_field, primary_key = ForeignKey.find(other, self)
|
@@ -383,10 +419,8 @@ class Select(SQLObject):
|
|
383
419
|
return self
|
384
420
|
|
385
421
|
def __eq__(self, other: SQLObject) -> bool:
|
386
|
-
def sorted_values(obj: SQLObject, key: str) -> list:
|
387
|
-
return sorted(obj.values.get(key, []))
|
388
422
|
for key in KEYWORD:
|
389
|
-
if
|
423
|
+
if self.diff(key, other.values.get(key, []), True):
|
390
424
|
return False
|
391
425
|
return True
|
392
426
|
|
@@ -427,7 +461,7 @@ class Select(SQLObject):
|
|
427
461
|
inner = txt[start: end]
|
428
462
|
if inner.count('(') > inner.count(')'):
|
429
463
|
end = find_parenthesis(end)
|
430
|
-
inner = txt[start: end]
|
464
|
+
inner = txt[start: end-1]
|
431
465
|
fld, *inner = re.split(r' IN | in', inner, maxsplit=1)
|
432
466
|
if fld.upper() == 'NOT':
|
433
467
|
pos = find_last_word(start)
|
@@ -457,15 +491,12 @@ class Select(SQLObject):
|
|
457
491
|
for key in USUAL_KEYS:
|
458
492
|
if not key in values:
|
459
493
|
continue
|
460
|
-
separator =
|
461
|
-
|
494
|
+
separator = cls.get_separator(key)
|
495
|
+
obj.values[key] = [
|
462
496
|
Field.format(fld, obj)
|
463
|
-
for fld in re.split(
|
464
|
-
|
465
|
-
) if len(tables) == 1
|
466
|
-
or re.findall(f'\b*{obj.alias}[.]', fld)
|
497
|
+
for fld in re.split(separator, values[key])
|
498
|
+
if len(tables) == 1 or re.findall(f'\b*{obj.alias}[.]', fld)
|
467
499
|
]
|
468
|
-
obj.values[key] = [ f for f in fields if f.strip() ]
|
469
500
|
result[obj.alias] = obj
|
470
501
|
return list( result.values() )
|
471
502
|
|
@@ -480,32 +511,3 @@ SubSelect = SelectIN
|
|
480
511
|
|
481
512
|
class NotSelectIN(SelectIN):
|
482
513
|
condition_class = Not
|
483
|
-
|
484
|
-
|
485
|
-
if __name__ == "__main__":
|
486
|
-
query_list = Select.parse("""
|
487
|
-
SELECT
|
488
|
-
cas.role,
|
489
|
-
m.title,
|
490
|
-
m.release_date,
|
491
|
-
a.name as actors_name
|
492
|
-
FROM
|
493
|
-
Actor a
|
494
|
-
LEFT JOIN Cast cas ON (a.cast = cas.id)
|
495
|
-
LEFT JOIN Movie m ON (cas.movie = m.id)
|
496
|
-
WHERE
|
497
|
-
m.genre NOT in (SELECT g.id from Genres g where g.name in ('sci-fi', 'horror', 'distopia'))
|
498
|
-
AND (m.hashtag = '#cult' OR m.awards LIKE '%Oscar%')
|
499
|
-
AND m.id IN (select DISTINCT r.movie FROM Review r GROUP BY r.movie HAVING Avg(r.rate) > 4.5)
|
500
|
-
AND a.age <= 69 AND a.age >= 45
|
501
|
-
ORDER BY
|
502
|
-
m.release_date
|
503
|
-
""")
|
504
|
-
for query in query_list:
|
505
|
-
descr = ' {} ({}) '.format(
|
506
|
-
query.table_name,
|
507
|
-
query.__class__.__name__
|
508
|
-
)
|
509
|
-
print(descr.center(50, '-'))
|
510
|
-
print(query)
|
511
|
-
print('='*50)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
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
|
@@ -249,13 +249,13 @@ m = Select...
|
|
249
249
|
9.1
|
250
250
|
```
|
251
251
|
a1 = Select.parse('''
|
252
|
-
SELECT gender,
|
252
|
+
SELECT gender, Max(act.age) FROM Actor act
|
253
253
|
WHERE act.age <= 69 AND act.age >= 45
|
254
254
|
GROUP BY gender
|
255
255
|
''')[0]
|
256
256
|
|
257
257
|
a2 = Select('Actor',
|
258
|
-
age=Between(45, 69),
|
258
|
+
age=[ Between(45, 69), Max ],
|
259
259
|
gender=[GroupBy, Field]
|
260
260
|
)
|
261
261
|
```
|
@@ -306,9 +306,9 @@ m2 = Select(
|
|
306
306
|
Select(
|
307
307
|
'Product',
|
308
308
|
label=Case('price').when(
|
309
|
-
lt(50), 'cheap'
|
309
|
+
Where.lt(50), 'cheap'
|
310
310
|
).when(
|
311
|
-
gt(100), 'expensive'
|
311
|
+
Where.gt(100), 'expensive'
|
312
312
|
).else_value(
|
313
313
|
'normal'
|
314
314
|
)
|
@@ -4,8 +4,8 @@ from sql_blocks.sql_blocks import *
|
|
4
4
|
Select.join_type = JoinType.LEFT
|
5
5
|
OrderBy.sort = SortType.DESC
|
6
6
|
|
7
|
-
def best_movies() ->
|
8
|
-
return
|
7
|
+
def best_movies() -> SelectIN:
|
8
|
+
return SelectIN(
|
9
9
|
'Review r', movie=[GroupBy, Distinct], rate=Having.avg(Where.gt(4.5))
|
10
10
|
)
|
11
11
|
|
@@ -35,7 +35,7 @@ def query_reference() -> Select:
|
|
35
35
|
'Movie m', title=Field,
|
36
36
|
release_date=[OrderBy, Field],
|
37
37
|
id=[
|
38
|
-
|
38
|
+
SelectIN(
|
39
39
|
'Review r', movie=[GroupBy, Distinct],
|
40
40
|
rate=Having.avg(Where.gt(4.5))
|
41
41
|
),
|
@@ -48,8 +48,15 @@ def query_reference() -> Select:
|
|
48
48
|
name=NamedField('actors_name'),
|
49
49
|
) # ----------- Actor
|
50
50
|
|
51
|
-
|
52
|
-
|
51
|
+
SINGLE_CONDITION_GENRE = "( m.genre = 'Sci-Fi' OR m.awards LIKE '%Oscar%' )"
|
52
|
+
SUB_QUERIES_CONDITIONS = """
|
53
|
+
m.genre NOT in (SELECT g.id from Genres g where g.name in ('sci-fi', 'horror', 'distopia'))
|
54
|
+
AND (m.hashtag = '#cult' OR m.awards LIKE '%Oscar%')
|
55
|
+
AND m.id IN (select DISTINCT r.movie FROM Review r GROUP BY r.movie HAVING Avg(r.rate) > 4.5)
|
56
|
+
"""
|
57
|
+
|
58
|
+
def single_text_to_objects(conditions: str=SINGLE_CONDITION_GENRE):
|
59
|
+
return Select.parse(f'''
|
53
60
|
SELECT
|
54
61
|
cas.role,
|
55
62
|
m.title,
|
@@ -60,7 +67,7 @@ def single_text_to_objects():
|
|
60
67
|
LEFT JOIN Cast cas ON (a.cast = cas.id)
|
61
68
|
LEFT JOIN Movie m ON (cas.movie = m.id)
|
62
69
|
WHERE
|
63
|
-
|
70
|
+
{conditions}
|
64
71
|
AND a.age <= 69 AND a.age >= 45
|
65
72
|
ORDER BY
|
66
73
|
m.release_date DESC
|
@@ -81,3 +88,23 @@ def many_texts_to_objects():
|
|
81
88
|
WHERE ( m.genre = 'Sci-Fi' OR m.awards LIKE '%Oscar%' ) GROUP BY director
|
82
89
|
""")[0]
|
83
90
|
return actor, cast, movie
|
91
|
+
|
92
|
+
def two_queries_same_table() -> Select:
|
93
|
+
txt1 = """SELECT p.name, p.category
|
94
|
+
,p.price,p.promotional FROM product p
|
95
|
+
where p.category in (6,14,29,35,78)
|
96
|
+
AND p.Status = p.last_st ORDER BY p.EAN"""
|
97
|
+
txt2 = """select stock_amount, EAN,Name ,expiration_date
|
98
|
+
from PRODUCT where price < 357.46 and status = Last_ST order by ean"""
|
99
|
+
return Select.parse(txt1)[0] + Select.parse(txt2)[0]
|
100
|
+
|
101
|
+
def select_product() -> Select:
|
102
|
+
return Select(
|
103
|
+
Product=Table('name,promotional,stock_amount,expiration_date'),
|
104
|
+
category=[Where.list([6,14,29,35,78]),Field], EAN=[Field, OrderBy],
|
105
|
+
price=[Where.lt(357.46),Field], status=Where('= Last_st')
|
106
|
+
)
|
107
|
+
|
108
|
+
def extract_subqueries() -> dict:
|
109
|
+
query_list = single_text_to_objects(SUB_QUERIES_CONDITIONS)
|
110
|
+
return {query.table_name: query for query in query_list}
|
@@ -1 +0,0 @@
|
|
1
|
-
from sql_blocks import *
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|