sql-blocks 0.1.4__py3-none-any.whl → 0.2.0__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 +52 -24
- {sql_blocks-0.1.4.dist-info → sql_blocks-0.2.0.dist-info}/METADATA +32 -13
- sql_blocks-0.2.0.dist-info/RECORD +7 -0
- sql_blocks-0.1.4.dist-info/RECORD +0 -7
- {sql_blocks-0.1.4.dist-info → sql_blocks-0.2.0.dist-info}/LICENSE +0 -0
- {sql_blocks-0.1.4.dist-info → sql_blocks-0.2.0.dist-info}/WHEEL +0 -0
- {sql_blocks-0.1.4.dist-info → sql_blocks-0.2.0.dist-info}/top_level.txt +0 -0
sql_blocks/sql_blocks.py
CHANGED
@@ -176,17 +176,27 @@ class ExpressionField:
|
|
176
176
|
a=main.alias, f=name, t=main.table_name
|
177
177
|
)
|
178
178
|
|
179
|
+
class FieldList:
|
180
|
+
separator = ','
|
179
181
|
|
180
|
-
|
181
|
-
def __init__(self, fields: list=[]):
|
182
|
+
def __init__(self, fields: list=[], class_types = [Field]):
|
182
183
|
if isinstance(fields, str):
|
183
|
-
fields = [
|
184
|
+
fields = [
|
185
|
+
f.strip() for f in fields.split(self.separator)
|
186
|
+
]
|
184
187
|
self.fields = fields
|
188
|
+
self.class_types = class_types
|
185
189
|
|
186
190
|
def add(self, name: str, main: SQLObject):
|
187
|
-
main.set_table(name)
|
188
191
|
for field in self.fields:
|
189
|
-
|
192
|
+
for class_type in self.class_types:
|
193
|
+
class_type.add(field, main)
|
194
|
+
|
195
|
+
|
196
|
+
class Table(FieldList):
|
197
|
+
def add(self, name: str, main: SQLObject):
|
198
|
+
main.set_table(name)
|
199
|
+
super().add(name, main)
|
190
200
|
|
191
201
|
|
192
202
|
class PrimaryKey:
|
@@ -261,7 +271,7 @@ class Where:
|
|
261
271
|
return cls('IS NULL')
|
262
272
|
|
263
273
|
@classmethod
|
264
|
-
def
|
274
|
+
def contains(cls, values):
|
265
275
|
if isinstance(values, list):
|
266
276
|
values = ','.join(quoted(v) for v in values)
|
267
277
|
return cls(f'IN ({values})')
|
@@ -272,6 +282,12 @@ class Where:
|
|
272
282
|
))
|
273
283
|
|
274
284
|
|
285
|
+
eq, like, gt, gte, lt, lte, is_null, contains = (
|
286
|
+
getattr(Where, method) for method in
|
287
|
+
('eq', 'like', 'gt', 'gte', 'lt', 'lte', 'is_null', 'contains')
|
288
|
+
)
|
289
|
+
|
290
|
+
|
275
291
|
class Not(Where):
|
276
292
|
prefix = 'NOT '
|
277
293
|
|
@@ -346,9 +362,12 @@ class OrderBy:
|
|
346
362
|
sort: SortType = SortType.ASC
|
347
363
|
@classmethod
|
348
364
|
def add(cls, name: str, main: SQLObject):
|
349
|
-
|
365
|
+
found = re.findall(r'^_\d', name)
|
366
|
+
if found:
|
367
|
+
name = found[0].replace('_', '')
|
368
|
+
elif main.alias:
|
350
369
|
name = f'{main.alias}.{name}'
|
351
|
-
main.values.setdefault(ORDER_BY, []).append(name
|
370
|
+
main.values.setdefault(ORDER_BY, []).append(name+cls.sort.value)
|
352
371
|
|
353
372
|
|
354
373
|
class GroupBy:
|
@@ -414,17 +433,16 @@ class Select(SQLObject):
|
|
414
433
|
self.values.setdefault(key, []).append(value)
|
415
434
|
|
416
435
|
def add(self, name: str, main: SQLObject):
|
417
|
-
|
436
|
+
old_tables = main.values.get(FROM, [])
|
437
|
+
new_tables = set([
|
418
438
|
'{jt}JOIN {tb} {a2} ON ({a1}.{f1} = {a2}.{f2})'.format(
|
419
439
|
jt=self.join_type.value,
|
420
440
|
tb=self.table_name,
|
421
441
|
a1=main.alias, f1=name,
|
422
442
|
a2=self.alias, f2=self.key_field
|
423
443
|
)
|
424
|
-
]
|
425
|
-
|
426
|
-
new_tables += self.values[FROM][1:]
|
427
|
-
main.values.setdefault(FROM, []).extend(new_tables)
|
444
|
+
] + old_tables[1:])
|
445
|
+
main.values[FROM] = old_tables[:1] + list(new_tables)
|
428
446
|
for key in USUAL_KEYS:
|
429
447
|
main.update_values(key, self.values.get(key, []))
|
430
448
|
|
@@ -557,13 +575,22 @@ class Select(SQLObject):
|
|
557
575
|
for rule in rules:
|
558
576
|
rule.apply(self)
|
559
577
|
|
578
|
+
def add_fields(self, fields: list, order_by: bool=False, group_by:bool=False):
|
579
|
+
class_types = [Field]
|
580
|
+
if order_by:
|
581
|
+
class_types += [OrderBy]
|
582
|
+
if group_by:
|
583
|
+
class_types += [GroupBy]
|
584
|
+
FieldList(fields, class_types).add('', self)
|
585
|
+
|
586
|
+
|
560
587
|
|
561
588
|
class SelectIN(Select):
|
562
589
|
condition_class = Where
|
563
590
|
|
564
591
|
def add(self, name: str, main: SQLObject):
|
565
592
|
self.break_lines = False
|
566
|
-
self.condition_class.
|
593
|
+
self.condition_class.contains(self).add(name, main)
|
567
594
|
|
568
595
|
SubSelect = SelectIN
|
569
596
|
|
@@ -578,6 +605,7 @@ class RulePutLimit(Rule):
|
|
578
605
|
if need_limit:
|
579
606
|
target.limit()
|
580
607
|
|
608
|
+
|
581
609
|
class RuleSelectIN(Rule):
|
582
610
|
@classmethod
|
583
611
|
def apply(cls, target: Select):
|
@@ -592,6 +620,7 @@ class RuleSelectIN(Rule):
|
|
592
620
|
','.join(t.split('=')[-1].strip() for t in tokens)
|
593
621
|
)
|
594
622
|
|
623
|
+
|
595
624
|
class RuleAutoField(Rule):
|
596
625
|
@classmethod
|
597
626
|
def apply(cls, target: Select):
|
@@ -603,13 +632,11 @@ class RuleAutoField(Rule):
|
|
603
632
|
s2 = set(target.values[ORDER_BY])
|
604
633
|
target.values.setdefault(SELECT, []).extend( list(s2-s1) )
|
605
634
|
|
635
|
+
|
606
636
|
class RuleLogicalOp(Rule):
|
607
|
-
REVERSE = {
|
608
|
-
|
609
|
-
|
610
|
-
"<>": "=",
|
611
|
-
"=": "<>"
|
612
|
-
}
|
637
|
+
REVERSE = {">=": "<", "<=": ">", "=": "<>"}
|
638
|
+
REVERSE |= {v: k for k, v in REVERSE.items()}
|
639
|
+
|
613
640
|
@classmethod
|
614
641
|
def apply(cls, target: Select):
|
615
642
|
REGEX = re.compile('({})'.format(
|
@@ -617,13 +644,14 @@ class RuleLogicalOp(Rule):
|
|
617
644
|
))
|
618
645
|
for i, condition in enumerate(target.values.get(WHERE, [])):
|
619
646
|
expr = re.sub('\n|\t', ' ', condition)
|
620
|
-
|
621
|
-
if len(tokens) < 2 or not REGEX.findall(tokens[-1]):
|
647
|
+
if not re.search(r'\b(NOT|not)\b', expr):
|
622
648
|
continue
|
623
|
-
tokens =
|
624
|
-
|
649
|
+
tokens = [t.strip() for t in re.split(r'NOT\b|not\b|(<|>|=)', expr) if t]
|
650
|
+
op = ''.join(tokens[1: len(tokens)-1])
|
651
|
+
tokens = [tokens[0], cls.REVERSE[op], tokens[-1]]
|
625
652
|
target.values[WHERE][i] = ' '.join(tokens)
|
626
653
|
|
654
|
+
|
627
655
|
class RuleDateFuncReplace(Rule):
|
628
656
|
"""
|
629
657
|
SQL algorithm by Ralff Matias
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
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
|
@@ -55,12 +55,12 @@ You can specify your own alias: `a = Select('Actor a')`
|
|
55
55
|
---
|
56
56
|
|
57
57
|
### 3 - To set conditions, use **Where**:
|
58
|
-
* For example, `a = Select(... age=
|
58
|
+
* For example, `a = Select(... age=gt(45) )`
|
59
59
|
|
60
60
|
Some possible conditions:
|
61
|
-
* field=
|
62
|
-
* field=
|
63
|
-
* field=
|
61
|
+
* field=eq(value) - ...the field is EQUAL to the value;
|
62
|
+
* field=gt(value) - ...the field is GREATER than the value;
|
63
|
+
* field=lt(value) - ...the field is LESS than the value;
|
64
64
|
|
65
65
|
3.1 -- If you want to filter the field on a range of values:
|
66
66
|
|
@@ -71,7 +71,7 @@ You can specify your own alias: `a = Select('Actor a')`
|
|
71
71
|
query = Select('Movie m', title=Field,
|
72
72
|
id=SelectIN(
|
73
73
|
'Review r',
|
74
|
-
rate=
|
74
|
+
rate=gt(4.5),
|
75
75
|
movie_id=Distinct
|
76
76
|
)
|
77
77
|
)
|
@@ -92,8 +92,8 @@ query = Select('Movie m', title=Field,
|
|
92
92
|
3.3 -- Optional conditions:
|
93
93
|
```
|
94
94
|
OR=Options(
|
95
|
-
genre=
|
96
|
-
awards=
|
95
|
+
genre=eq("Sci-Fi"),
|
96
|
+
awards=like("Oscar")
|
97
97
|
)
|
98
98
|
```
|
99
99
|
> Could be AND=Options(...)
|
@@ -105,7 +105,7 @@ based_on_book=Not.is_null()
|
|
105
105
|
|
106
106
|
3.5 -- List of values
|
107
107
|
```
|
108
|
-
hash_tag=
|
108
|
+
hash_tag=contains(['space', 'monster', 'gore'])
|
109
109
|
```
|
110
110
|
|
111
111
|
---
|
@@ -117,7 +117,7 @@ hash_tag=Where.list(['space', 'monster', 'gore'])
|
|
117
117
|
```
|
118
118
|
SelectIN(
|
119
119
|
'Review r', movie=[GroupBy, Distinct],
|
120
|
-
rate=Having.avg(
|
120
|
+
rate=Having.avg(gt(4.5))
|
121
121
|
)
|
122
122
|
```
|
123
123
|
---
|
@@ -299,7 +299,7 @@ m = Select...
|
|
299
299
|
```
|
300
300
|
best_movies = SelectIN(
|
301
301
|
Review=Table('role'),
|
302
|
-
rate=[GroupBy, Having.avg(
|
302
|
+
rate=[GroupBy, Having.avg(gt(4.5))]
|
303
303
|
)
|
304
304
|
m1 = Select(
|
305
305
|
Movie=Table('title,release_date'),
|
@@ -320,9 +320,9 @@ m2 = Select(
|
|
320
320
|
Select(
|
321
321
|
'Product',
|
322
322
|
label=Case('price').when(
|
323
|
-
|
323
|
+
lt(50), 'cheap'
|
324
324
|
).when(
|
325
|
-
|
325
|
+
gt(100), 'expensive'
|
326
326
|
).else_value(
|
327
327
|
'normal'
|
328
328
|
)
|
@@ -360,3 +360,22 @@ m2 = Select(
|
|
360
360
|
* Replace `YEAR` function with date range comparison.
|
361
361
|
|
362
362
|
> The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
|
363
|
+
|
364
|
+
---
|
365
|
+
|
366
|
+
### 12 - Adding multiple fields at once
|
367
|
+
```
|
368
|
+
query = Select('post p')
|
369
|
+
query.add_fields(
|
370
|
+
'user_id, created_at',
|
371
|
+
order_by=True, group_by=True
|
372
|
+
)
|
373
|
+
```
|
374
|
+
...is the same as...
|
375
|
+
```
|
376
|
+
query = Select(
|
377
|
+
'post p',
|
378
|
+
user_id=[Field, GroupBy, OrderBy],
|
379
|
+
created_at=[Field, GroupBy, OrderBy]
|
380
|
+
)
|
381
|
+
```
|
@@ -0,0 +1,7 @@
|
|
1
|
+
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
+
sql_blocks/sql_blocks.py,sha256=Fg7yPeASygx7c7Nct5yKurxRrnjVGsvp4RnR93Wwems,21519
|
3
|
+
sql_blocks-0.2.0.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
+
sql_blocks-0.2.0.dist-info/METADATA,sha256=CU4oSLqoycnvhkPROx_SSbj9zJjCwwz4JoePIgk4wSE,8794
|
5
|
+
sql_blocks-0.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
sql_blocks-0.2.0.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
+
sql_blocks-0.2.0.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
-
sql_blocks/sql_blocks.py,sha256=wj54KGT9Bnbo9Jtyn_jA6lbHhgkmGirRUp6ZHq9ilZ8,20654
|
3
|
-
sql_blocks-0.1.4.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
-
sql_blocks-0.1.4.dist-info/METADATA,sha256=DWqKIgeFG_wjr8u4qusK-bcb_cgbxHXZ3DNFUXmMwKo,8503
|
5
|
-
sql_blocks-0.1.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
sql_blocks-0.1.4.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
-
sql_blocks-0.1.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|