sql-blocks 0.0.6__tar.gz → 0.0.7__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.6/sql_blocks.egg-info → sql_blocks-0.0.7}/PKG-INFO +36 -3
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/README.md +35 -2
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/pyproject.toml +1 -1
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/setup.py +1 -1
- sql_blocks-0.0.7/sql_blocks/__init__.py +1 -0
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/sql_blocks/sql_blocks.py +124 -23
- {sql_blocks-0.0.6 → sql_blocks-0.0.7/sql_blocks.egg-info}/PKG-INFO +36 -3
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/sql_blocks.egg-info/SOURCES.txt +1 -2
- sql_blocks-0.0.6/sql_blocks/__init__.py +0 -1
- sql_blocks-0.0.6/tests/tests.py +0 -110
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/LICENSE +0 -0
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/setup.cfg +0 -0
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/sql_blocks.egg-info/dependency_links.txt +0 -0
- {sql_blocks-0.0.6 → sql_blocks-0.0.7}/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.7
|
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
|
@@ -306,10 +306,43 @@ m2 = Select(
|
|
306
306
|
Select(
|
307
307
|
'Product',
|
308
308
|
label=Case('price').when(
|
309
|
-
|
309
|
+
lt(50), 'cheap'
|
310
310
|
).when(
|
311
|
-
|
311
|
+
gt(100), 'expensive'
|
312
312
|
).else_value(
|
313
313
|
'normal'
|
314
314
|
)
|
315
315
|
)
|
316
|
+
|
317
|
+
---
|
318
|
+
|
319
|
+
### 11 - optimize method
|
320
|
+
p1 = Select.parse("""
|
321
|
+
SELECT * FROM Product p
|
322
|
+
WHERE (p.category = 'Gizmo'
|
323
|
+
OR p.category = 'Gadget'
|
324
|
+
OR p.category = 'Doohickey')
|
325
|
+
AND NOT price <= 387.64
|
326
|
+
AND YEAR(last_sale) = 2024
|
327
|
+
ORDER BY
|
328
|
+
category
|
329
|
+
""")[0]
|
330
|
+
p1.optimize() # <<===============
|
331
|
+
p2 = Select.parse("""
|
332
|
+
SELECT category FROM Product p
|
333
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
334
|
+
and p.price > 387.64
|
335
|
+
and p.last_sale >= '2024-01-01'
|
336
|
+
and p.last_sale <= '2024-12-31'
|
337
|
+
ORDER BY p.category LIMIT 100
|
338
|
+
""")[0]
|
339
|
+
p1 == p2 # --- True!
|
340
|
+
|
341
|
+
This will...
|
342
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
343
|
+
* Put `LIMIT` if no fields or conditions defined;
|
344
|
+
* Normalizes inverted conditions;
|
345
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
346
|
+
* Replace `YEAR` function with date range comparison.
|
347
|
+
|
348
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
@@ -291,10 +291,43 @@ m2 = Select(
|
|
291
291
|
Select(
|
292
292
|
'Product',
|
293
293
|
label=Case('price').when(
|
294
|
-
|
294
|
+
lt(50), 'cheap'
|
295
295
|
).when(
|
296
|
-
|
296
|
+
gt(100), 'expensive'
|
297
297
|
).else_value(
|
298
298
|
'normal'
|
299
299
|
)
|
300
300
|
)
|
301
|
+
|
302
|
+
---
|
303
|
+
|
304
|
+
### 11 - optimize method
|
305
|
+
p1 = Select.parse("""
|
306
|
+
SELECT * FROM Product p
|
307
|
+
WHERE (p.category = 'Gizmo'
|
308
|
+
OR p.category = 'Gadget'
|
309
|
+
OR p.category = 'Doohickey')
|
310
|
+
AND NOT price <= 387.64
|
311
|
+
AND YEAR(last_sale) = 2024
|
312
|
+
ORDER BY
|
313
|
+
category
|
314
|
+
""")[0]
|
315
|
+
p1.optimize() # <<===============
|
316
|
+
p2 = Select.parse("""
|
317
|
+
SELECT category FROM Product p
|
318
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
319
|
+
and p.price > 387.64
|
320
|
+
and p.last_sale >= '2024-01-01'
|
321
|
+
and p.last_sale <= '2024-12-31'
|
322
|
+
ORDER BY p.category LIMIT 100
|
323
|
+
""")[0]
|
324
|
+
p1 == p2 # --- True!
|
325
|
+
|
326
|
+
This will...
|
327
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
328
|
+
* Put `LIMIT` if no fields or conditions defined;
|
329
|
+
* Normalizes inverted conditions;
|
330
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
331
|
+
* Replace `YEAR` function with date range comparison.
|
332
|
+
|
333
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
@@ -0,0 +1 @@
|
|
1
|
+
from sql_blocks import *
|
@@ -10,26 +10,32 @@ DISTINCT_SF_PR = f'(DISTINCT|distinct)|{SUFFIX_AND_PRE}'
|
|
10
10
|
KEYWORD = {
|
11
11
|
'SELECT': (',{}', 'SELECT *', DISTINCT_SF_PR),
|
12
12
|
'FROM': ('{}', '', PATTERN_SUFFIX),
|
13
|
-
'WHERE': ('{}AND ', '', PATTERN_PREFIX),
|
13
|
+
'WHERE': ('{}AND ', '', f'{PATTERN_PREFIX}| '),
|
14
14
|
'GROUP BY': (',{}', '', SUFFIX_AND_PRE),
|
15
15
|
'ORDER BY': (',{}', '', SUFFIX_AND_PRE),
|
16
16
|
'LIMIT': (' ', '', ''),
|
17
17
|
}
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
18
|
+
# ^ ^ ^
|
19
|
+
# | | |
|
20
|
+
# | | +----- pattern to compare fields
|
21
|
+
# | |
|
22
|
+
# | +----- default when empty (SELECT * ...)
|
23
|
+
# |
|
24
|
+
# +-------- separator
|
25
25
|
|
26
26
|
SELECT, FROM, WHERE, GROUP_BY, ORDER_BY, LIMIT = KEYWORD.keys()
|
27
|
-
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY]
|
27
|
+
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY, LIMIT]
|
28
28
|
|
29
29
|
|
30
30
|
class SQLObject:
|
31
|
+
ALIAS_FUNC = lambda t: t.lower()[:3]
|
32
|
+
""" ^^^^^^^^^^^^^^^^^^^^^^^^
|
33
|
+
You can change the behavior by assigning
|
34
|
+
a user function to SQLObject.ALIAS_FUNC
|
35
|
+
"""
|
36
|
+
|
31
37
|
def __init__(self, table_name: str=''):
|
32
|
-
self.
|
38
|
+
self.__alias = ''
|
33
39
|
self.values = {}
|
34
40
|
self.key_field = ''
|
35
41
|
self.set_table(table_name)
|
@@ -37,20 +43,26 @@ class SQLObject:
|
|
37
43
|
def set_table(self, table_name: str):
|
38
44
|
if not table_name:
|
39
45
|
return
|
40
|
-
if ' ' in table_name:
|
41
|
-
table_name, self.
|
46
|
+
if ' ' in table_name.strip():
|
47
|
+
table_name, self.__alias = table_name.split()
|
42
48
|
elif '_' in table_name:
|
43
|
-
self.
|
49
|
+
self.__alias = ''.join(
|
44
50
|
word[0].lower()
|
45
51
|
for word in table_name.split('_')
|
46
52
|
)
|
47
53
|
else:
|
48
|
-
self.
|
54
|
+
self.__alias = SQLObject.ALIAS_FUNC(table_name)
|
49
55
|
self.values.setdefault(FROM, []).append(f'{table_name} {self.alias}')
|
50
56
|
|
51
57
|
@property
|
52
58
|
def table_name(self) -> str:
|
53
59
|
return self.values[FROM][0].split()[0]
|
60
|
+
|
61
|
+
@property
|
62
|
+
def alias(self) -> str:
|
63
|
+
if self.__alias:
|
64
|
+
return self.__alias
|
65
|
+
return self.table_name
|
54
66
|
|
55
67
|
@staticmethod
|
56
68
|
def get_separator(key: str) -> str:
|
@@ -90,9 +102,9 @@ class Field:
|
|
90
102
|
@classmethod
|
91
103
|
def format(cls, name: str, main: SQLObject) -> str:
|
92
104
|
name = name.strip()
|
93
|
-
if name
|
105
|
+
if name in ('_', '*'):
|
94
106
|
name = '*'
|
95
|
-
elif '.'
|
107
|
+
elif not re.findall('[.()0-9]', name):
|
96
108
|
name = f'{main.alias}.{name}'
|
97
109
|
if Function in cls.__bases__:
|
98
110
|
name = f'{cls.__name__}({name})'
|
@@ -185,7 +197,7 @@ class Where:
|
|
185
197
|
prefix = ''
|
186
198
|
|
187
199
|
def __init__(self, expr: str):
|
188
|
-
self.expr =
|
200
|
+
self.expr = expr
|
189
201
|
|
190
202
|
@classmethod
|
191
203
|
def __constructor(cls, operator: str, value):
|
@@ -226,8 +238,8 @@ class Where:
|
|
226
238
|
return cls(f'IN ({values})')
|
227
239
|
|
228
240
|
def add(self, name: str, main: SQLObject):
|
229
|
-
main.values.setdefault(WHERE, []).append('{} {}'.format(
|
230
|
-
Field.format(name, main), self.expr
|
241
|
+
main.values.setdefault(WHERE, []).append('{}{} {}'.format(
|
242
|
+
self.prefix, Field.format(name, main), self.expr
|
231
243
|
))
|
232
244
|
|
233
245
|
|
@@ -347,6 +359,12 @@ class Having:
|
|
347
359
|
return cls(Count, condition)
|
348
360
|
|
349
361
|
|
362
|
+
class Rule:
|
363
|
+
@classmethod
|
364
|
+
def apply(cls, target: 'Select'):
|
365
|
+
...
|
366
|
+
|
367
|
+
|
350
368
|
class JoinType(Enum):
|
351
369
|
INNER = ''
|
352
370
|
LEFT = 'LEFT '
|
@@ -424,13 +442,16 @@ class Select(SQLObject):
|
|
424
442
|
return False
|
425
443
|
return True
|
426
444
|
|
427
|
-
def limit(self, row_count: int, offset: int=0):
|
445
|
+
def limit(self, row_count: int=100, offset: int=0):
|
428
446
|
result = [str(row_count)]
|
429
447
|
if offset > 0:
|
430
448
|
result.append(f'OFFSET {offset}')
|
431
449
|
self.values.setdefault(LIMIT, result)
|
432
450
|
return self
|
433
451
|
|
452
|
+
def match(self, expr: str) -> bool:
|
453
|
+
return re.findall(f'\b*{self.alias}[.]', expr) != []
|
454
|
+
|
434
455
|
@classmethod
|
435
456
|
def parse(cls, txt: str) -> list[SQLObject]:
|
436
457
|
def find_last_word(pos: int) -> int:
|
@@ -452,7 +473,7 @@ class Select(SQLObject):
|
|
452
473
|
if not cls.REGEX:
|
453
474
|
keywords = '|'.join(k + r'\b' for k in KEYWORD)
|
454
475
|
flags = re.IGNORECASE + re.MULTILINE
|
455
|
-
cls.REGEX['keywords'] = re.compile(f'({keywords})', flags)
|
476
|
+
cls.REGEX['keywords'] = re.compile(f'({keywords}|[*])', flags)
|
456
477
|
cls.REGEX['subquery'] = re.compile(r'(\w\.)*\w+ +in +\(SELECT.*?\)', flags)
|
457
478
|
result = {}
|
458
479
|
found = cls.REGEX['subquery'].search(txt)
|
@@ -476,7 +497,7 @@ class Select(SQLObject):
|
|
476
497
|
result[obj.alias] = obj
|
477
498
|
txt = txt[:start-1] + txt[end+1:]
|
478
499
|
found = cls.REGEX['subquery'].search(txt)
|
479
|
-
tokens = [t.strip() for t in cls.REGEX['keywords'].split(txt) if
|
500
|
+
tokens = [t.strip() for t in cls.REGEX['keywords'].split(txt) if t.strip()]
|
480
501
|
values = {k.upper(): v for k, v in zip(tokens[::2], tokens[1::2])}
|
481
502
|
tables = [t.strip() for t in re.split('JOIN|LEFT|RIGHT|ON', values[FROM]) if t.strip()]
|
482
503
|
for item in tables:
|
@@ -495,11 +516,18 @@ class Select(SQLObject):
|
|
495
516
|
obj.values[key] = [
|
496
517
|
Field.format(fld, obj)
|
497
518
|
for fld in re.split(separator, values[key])
|
498
|
-
if len(tables) == 1 or
|
519
|
+
if (fld != '*' and len(tables) == 1) or obj.match(fld)
|
499
520
|
]
|
500
521
|
result[obj.alias] = obj
|
501
522
|
return list( result.values() )
|
502
523
|
|
524
|
+
def optimize(self, rules: list[Rule]=None):
|
525
|
+
if not rules:
|
526
|
+
rules = Rule.__subclasses__()
|
527
|
+
for rule in rules:
|
528
|
+
rule.apply(self)
|
529
|
+
|
530
|
+
|
503
531
|
class SelectIN(Select):
|
504
532
|
condition_class = Where
|
505
533
|
|
@@ -511,3 +539,76 @@ SubSelect = SelectIN
|
|
511
539
|
|
512
540
|
class NotSelectIN(SelectIN):
|
513
541
|
condition_class = Not
|
542
|
+
|
543
|
+
|
544
|
+
class RulePutLimit(Rule):
|
545
|
+
@classmethod
|
546
|
+
def apply(cls, target: Select):
|
547
|
+
need_limit = any(not target.values.get(key) for key in (WHERE, SELECT))
|
548
|
+
if need_limit:
|
549
|
+
target.limit()
|
550
|
+
|
551
|
+
class RuleSelectIN(Rule):
|
552
|
+
@classmethod
|
553
|
+
def apply(cls, target: Select):
|
554
|
+
for i, condition in enumerate(target.values[WHERE]):
|
555
|
+
tokens = re.split(' or | OR ', re.sub('\n|\t|[()]', ' ', condition))
|
556
|
+
if len(tokens) < 2:
|
557
|
+
continue
|
558
|
+
fields = [t.split('=')[0].split('.')[-1].lower().strip() for t in tokens]
|
559
|
+
if len(set(fields)) == 1:
|
560
|
+
target.values[WHERE][i] = '{} IN ({})'.format(
|
561
|
+
Field.format(fields[0], target),
|
562
|
+
','.join(t.split('=')[-1].strip() for t in tokens)
|
563
|
+
)
|
564
|
+
|
565
|
+
class RuleAutoField(Rule):
|
566
|
+
@classmethod
|
567
|
+
def apply(cls, target: Select):
|
568
|
+
if target.values.get(GROUP_BY):
|
569
|
+
target.values[SELECT] = target.values[GROUP_BY]
|
570
|
+
target.values[ORDER_BY] = []
|
571
|
+
elif target.values.get(ORDER_BY):
|
572
|
+
s1 = set(target.values.get(SELECT, []))
|
573
|
+
s2 = set(target.values[ORDER_BY])
|
574
|
+
target.values.setdefault(SELECT, []).extend( list(s2-s1) )
|
575
|
+
|
576
|
+
class RuleLogicalOp(Rule):
|
577
|
+
REVERSE = {
|
578
|
+
">=": "<",
|
579
|
+
"<=": ">",
|
580
|
+
"<>": "=",
|
581
|
+
"=": "<>"
|
582
|
+
}
|
583
|
+
@classmethod
|
584
|
+
def apply(cls, target: Select):
|
585
|
+
REGEX = re.compile('({})'.format(
|
586
|
+
'|'.join(cls.REVERSE)
|
587
|
+
))
|
588
|
+
for i, condition in enumerate(target.values.get(WHERE, [])):
|
589
|
+
expr = re.sub('\n|\t', ' ', condition)
|
590
|
+
tokens = [t for t in re.split(r'(NOT\b|not\b)',expr) if t.strip()]
|
591
|
+
if len(tokens) < 2 or not REGEX.findall(tokens[-1]):
|
592
|
+
continue
|
593
|
+
tokens = REGEX.split(tokens[-1])
|
594
|
+
tokens[1] = cls.REVERSE[tokens[1]]
|
595
|
+
target.values[WHERE][i] = ' '.join(tokens)
|
596
|
+
|
597
|
+
class RuleDateFuncReplace(Rule):
|
598
|
+
"""
|
599
|
+
SQL algorithm by Ralff Matias
|
600
|
+
"""
|
601
|
+
REGEX = re.compile(r'(\bYEAR[(]|\byear[(]|=|[)])')
|
602
|
+
|
603
|
+
@classmethod
|
604
|
+
def apply(cls, target: Select):
|
605
|
+
for i, condition in enumerate(target.values.get(WHERE, [])):
|
606
|
+
tokens = [
|
607
|
+
t.strip() for t in cls.REGEX.split(condition) if t.strip()
|
608
|
+
]
|
609
|
+
if len(tokens) < 3:
|
610
|
+
continue
|
611
|
+
func, field, *rest, year = tokens
|
612
|
+
temp = Select(f'{target.table_name} {target.alias}')
|
613
|
+
Between(f'{year}-01-01', f'{year}-12-31').add(field, temp)
|
614
|
+
target.values[WHERE][i] = ' AND '.join(temp.values[WHERE])
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
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
|
@@ -306,10 +306,43 @@ m2 = Select(
|
|
306
306
|
Select(
|
307
307
|
'Product',
|
308
308
|
label=Case('price').when(
|
309
|
-
|
309
|
+
lt(50), 'cheap'
|
310
310
|
).when(
|
311
|
-
|
311
|
+
gt(100), 'expensive'
|
312
312
|
).else_value(
|
313
313
|
'normal'
|
314
314
|
)
|
315
315
|
)
|
316
|
+
|
317
|
+
---
|
318
|
+
|
319
|
+
### 11 - optimize method
|
320
|
+
p1 = Select.parse("""
|
321
|
+
SELECT * FROM Product p
|
322
|
+
WHERE (p.category = 'Gizmo'
|
323
|
+
OR p.category = 'Gadget'
|
324
|
+
OR p.category = 'Doohickey')
|
325
|
+
AND NOT price <= 387.64
|
326
|
+
AND YEAR(last_sale) = 2024
|
327
|
+
ORDER BY
|
328
|
+
category
|
329
|
+
""")[0]
|
330
|
+
p1.optimize() # <<===============
|
331
|
+
p2 = Select.parse("""
|
332
|
+
SELECT category FROM Product p
|
333
|
+
WHERE category IN ('Gizmo','Gadget','Doohickey')
|
334
|
+
and p.price > 387.64
|
335
|
+
and p.last_sale >= '2024-01-01'
|
336
|
+
and p.last_sale <= '2024-12-31'
|
337
|
+
ORDER BY p.category LIMIT 100
|
338
|
+
""")[0]
|
339
|
+
p1 == p2 # --- True!
|
340
|
+
|
341
|
+
This will...
|
342
|
+
* Replace `OR` conditions to `SELECT IN ...`
|
343
|
+
* Put `LIMIT` if no fields or conditions defined;
|
344
|
+
* Normalizes inverted conditions;
|
345
|
+
* Auto includes fields present in `ORDER/GROUP BY`;
|
346
|
+
* Replace `YEAR` function with date range comparison.
|
347
|
+
|
348
|
+
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
@@ -1 +0,0 @@
|
|
1
|
-
from sql_blocks.sql_blocks import *
|
sql_blocks-0.0.6/tests/tests.py
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
from sql_blocks.sql_blocks import *
|
2
|
-
|
3
|
-
|
4
|
-
Select.join_type = JoinType.LEFT
|
5
|
-
OrderBy.sort = SortType.DESC
|
6
|
-
|
7
|
-
def best_movies() -> SelectIN:
|
8
|
-
return SelectIN(
|
9
|
-
'Review r', movie=[GroupBy, Distinct], rate=Having.avg(Where.gt(4.5))
|
10
|
-
)
|
11
|
-
|
12
|
-
def detached_objects() -> tuple:
|
13
|
-
def select_actor() -> Select:
|
14
|
-
return Select('Actor a', cast=ForeignKey('Cast'),
|
15
|
-
name=NamedField('actors_name'), age=Between(45, 69)
|
16
|
-
)
|
17
|
-
def select_cast() -> Select:
|
18
|
-
return Select(
|
19
|
-
Cast=Table('role'), id=PrimaryKey, movie=ForeignKey('Movie'),
|
20
|
-
)
|
21
|
-
def select_movie() -> Select:
|
22
|
-
return Select('Movie m', title=Field,
|
23
|
-
release_date=[OrderBy, Field], id=PrimaryKey,
|
24
|
-
OR=Options(
|
25
|
-
genre=Where.eq('Sci-Fi'), awards=Where.like('Oscar')
|
26
|
-
), director=[Where.like('Coppola'), Field, OrderBy]
|
27
|
-
)
|
28
|
-
return select_actor(), select_cast(), select_movie()
|
29
|
-
|
30
|
-
def query_reference() -> Select:
|
31
|
-
return Select('Actor a', age=Between(45, 69),
|
32
|
-
cast=Select(
|
33
|
-
Cast=Table('role'), id=PrimaryKey,
|
34
|
-
movie=Select(
|
35
|
-
'Movie m', title=Field,
|
36
|
-
release_date=[OrderBy, Field],
|
37
|
-
id=[
|
38
|
-
SelectIN(
|
39
|
-
'Review r', movie=[GroupBy, Distinct],
|
40
|
-
rate=Having.avg(Where.gt(4.5))
|
41
|
-
),
|
42
|
-
PrimaryKey
|
43
|
-
], OR=Options(
|
44
|
-
genre=Where.eq('Sci-Fi'), awards=Where.like('Oscar')
|
45
|
-
)
|
46
|
-
) # --- Movie
|
47
|
-
), # ------- Cast
|
48
|
-
name=NamedField('actors_name'),
|
49
|
-
) # ----------- Actor
|
50
|
-
|
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'''
|
60
|
-
SELECT
|
61
|
-
cas.role,
|
62
|
-
m.title,
|
63
|
-
m.release_date,
|
64
|
-
a.name as actors_name
|
65
|
-
FROM
|
66
|
-
Actor a
|
67
|
-
LEFT JOIN Cast cas ON (a.cast = cas.id)
|
68
|
-
LEFT JOIN Movie m ON (cas.movie = m.id)
|
69
|
-
WHERE
|
70
|
-
{conditions}
|
71
|
-
AND a.age <= 69 AND a.age >= 45
|
72
|
-
ORDER BY
|
73
|
-
m.release_date DESC
|
74
|
-
''')
|
75
|
-
|
76
|
-
def many_texts_to_objects():
|
77
|
-
ForeignKey.references = {
|
78
|
-
('Actor', 'Cast'): ('cast', 'id'),
|
79
|
-
('Cast', 'Movie'): ('movie', 'id'),
|
80
|
-
}
|
81
|
-
actor = Select.parse('''
|
82
|
-
SELECT name as actors_name FROM Actor a
|
83
|
-
WHERE a.age >= 45 AND a.age <= 69
|
84
|
-
''')[0]
|
85
|
-
cast = Select.parse('SELECT role FROM Cast')[0]
|
86
|
-
movie = Select.parse("""
|
87
|
-
SELECT title, release_date FROM Movie m ORDER BY release_date DESC
|
88
|
-
WHERE ( m.genre = 'Sci-Fi' OR m.awards LIKE '%Oscar%' ) GROUP BY director
|
89
|
-
""")[0]
|
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}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|