sql-blocks 0.2.4__py3-none-any.whl → 0.2.9__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 +341 -68
- {sql_blocks-0.2.4.dist-info → sql_blocks-0.2.9.dist-info}/METADATA +1 -1
- sql_blocks-0.2.9.dist-info/RECORD +7 -0
- sql_blocks-0.2.4.dist-info/RECORD +0 -7
- {sql_blocks-0.2.4.dist-info → sql_blocks-0.2.9.dist-info}/LICENSE +0 -0
- {sql_blocks-0.2.4.dist-info → sql_blocks-0.2.9.dist-info}/WHEEL +0 -0
- {sql_blocks-0.2.4.dist-info → sql_blocks-0.2.9.dist-info}/top_level.txt +0 -0
sql_blocks/sql_blocks.py
CHANGED
@@ -7,20 +7,18 @@ PATTERN_SUFFIX = '( [A-Za-z_]+)'
|
|
7
7
|
DISTINCT_PREFX = '(DISTINCT|distinct)'
|
8
8
|
|
9
9
|
KEYWORD = {
|
10
|
-
'SELECT':
|
11
|
-
'FROM':
|
12
|
-
'WHERE':
|
13
|
-
'GROUP BY': (',{}',
|
14
|
-
'ORDER BY': (',{}',
|
15
|
-
'LIMIT':
|
16
|
-
}
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# |
|
23
|
-
# +-------- separator
|
10
|
+
'SELECT': (',{}', DISTINCT_PREFX),
|
11
|
+
'FROM': ('{}', PATTERN_SUFFIX),
|
12
|
+
'WHERE': ('{}AND ', ''),
|
13
|
+
'GROUP BY': (',{}', PATTERN_SUFFIX),
|
14
|
+
'ORDER BY': (',{}', PATTERN_SUFFIX),
|
15
|
+
'LIMIT': (' ', ''),
|
16
|
+
}
|
17
|
+
# ^ ^
|
18
|
+
# | |
|
19
|
+
# | +----- pattern to compare fields
|
20
|
+
# |
|
21
|
+
# +-------- separator
|
24
22
|
|
25
23
|
SELECT, FROM, WHERE, GROUP_BY, ORDER_BY, LIMIT = KEYWORD.keys()
|
26
24
|
USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY, LIMIT]
|
@@ -69,27 +67,34 @@ class SQLObject:
|
|
69
67
|
return KEYWORD[key][0].format(appendix.get(key, ''))
|
70
68
|
|
71
69
|
def diff(self, key: str, search_list: list, exact: bool=False) -> set:
|
70
|
+
def disassemble(source: list) -> list:
|
71
|
+
if not exact:
|
72
|
+
return source
|
73
|
+
result = []
|
74
|
+
for fld in source:
|
75
|
+
result += re.split(r'([=()]|<>|\s+ON\s+|\s+on\s+)', fld)
|
76
|
+
return result
|
72
77
|
def cleanup(fld: str) -> str:
|
73
78
|
if exact:
|
74
79
|
fld = fld.lower()
|
75
80
|
return fld.strip()
|
76
81
|
def is_named_field(fld: str) -> bool:
|
77
82
|
return key == SELECT and re.search(' as | AS ', fld)
|
78
|
-
pattern = KEYWORD[key][2]
|
79
|
-
if exact:
|
80
|
-
if key == WHERE:
|
81
|
-
pattern = ' '
|
82
|
-
pattern += f'|{PATTERN_PREFIX}'
|
83
|
-
separator = self.get_separator(key)
|
84
83
|
def field_set(source: list) -> set:
|
85
84
|
return set(
|
86
85
|
(
|
87
86
|
fld if is_named_field(fld) else
|
88
87
|
re.sub(pattern, '', cleanup(fld))
|
89
88
|
)
|
90
|
-
for string in source
|
89
|
+
for string in disassemble(source)
|
91
90
|
for fld in re.split(separator, string)
|
92
91
|
)
|
92
|
+
pattern = KEYWORD[key][1]
|
93
|
+
if exact:
|
94
|
+
if key == WHERE:
|
95
|
+
pattern = r'["\']| '
|
96
|
+
pattern += f'|{PATTERN_PREFIX}'
|
97
|
+
separator = self.get_separator(key)
|
93
98
|
s1 = field_set(search_list)
|
94
99
|
s2 = field_set(self.values.get(key, []))
|
95
100
|
if exact:
|
@@ -413,6 +418,222 @@ class Rule:
|
|
413
418
|
def apply(cls, target: 'Select'):
|
414
419
|
...
|
415
420
|
|
421
|
+
class QueryLanguage:
|
422
|
+
pattern = '{select}{_from}{where}{group_by}{order_by}'
|
423
|
+
has_default = {key: bool(key == SELECT) for key in KEYWORD}
|
424
|
+
|
425
|
+
@staticmethod
|
426
|
+
def remove_alias(fld: str) -> str:
|
427
|
+
return ''.join(re.split(r'\w+[.]', fld))
|
428
|
+
|
429
|
+
def join_with_tabs(self, values: list, sep: str='') -> str:
|
430
|
+
sep = sep + self.TABULATION
|
431
|
+
return sep.join(v for v in values if v)
|
432
|
+
|
433
|
+
def add_field(self, values: list) -> str:
|
434
|
+
if not values:
|
435
|
+
return '*'
|
436
|
+
return self.join_with_tabs(values, ',')
|
437
|
+
|
438
|
+
def get_tables(self, values: list) -> str:
|
439
|
+
return self.join_with_tabs(values)
|
440
|
+
|
441
|
+
def extract_conditions(self, values: list) -> str:
|
442
|
+
return self.join_with_tabs(values, ' AND ')
|
443
|
+
|
444
|
+
def sort_by(self, values: list) -> str:
|
445
|
+
return self.join_with_tabs(values)
|
446
|
+
|
447
|
+
def set_group(self, values: list) -> str:
|
448
|
+
return self.join_with_tabs(values, ',')
|
449
|
+
|
450
|
+
def __init__(self, target: 'Select'):
|
451
|
+
self.KEYWORDS = [SELECT, FROM, WHERE, GROUP_BY, ORDER_BY]
|
452
|
+
self.TABULATION = '\n\t' if target.break_lines else ' '
|
453
|
+
self.LINE_BREAK = '\n' if target.break_lines else ' '
|
454
|
+
self.TOKEN_METHODS = {
|
455
|
+
SELECT: self.add_field, FROM: self.get_tables,
|
456
|
+
WHERE: self.extract_conditions,
|
457
|
+
ORDER_BY: self.sort_by, GROUP_BY: self.set_group,
|
458
|
+
}
|
459
|
+
self.result = {}
|
460
|
+
self.target = target
|
461
|
+
|
462
|
+
def pair(self, key: str) -> str:
|
463
|
+
if key == FROM:
|
464
|
+
return '_from'
|
465
|
+
return key.lower().replace(' ', '_')
|
466
|
+
|
467
|
+
def prefix(self, key: str) -> str:
|
468
|
+
return self.LINE_BREAK + key + self.TABULATION
|
469
|
+
|
470
|
+
def convert(self) -> str:
|
471
|
+
for key in self.KEYWORDS:
|
472
|
+
method = self.TOKEN_METHODS.get(key)
|
473
|
+
ref = self.pair(key)
|
474
|
+
values = self.target.values.get(key, [])
|
475
|
+
if not method or (not values and not self.has_default[key]):
|
476
|
+
self.result[ref] = ''
|
477
|
+
continue
|
478
|
+
text = self.prefix(key) + method(values)
|
479
|
+
self.result[ref] = text
|
480
|
+
return self.pattern.format(**self.result).strip()
|
481
|
+
|
482
|
+
class MongoDBLanguage(QueryLanguage):
|
483
|
+
pattern = '{_from}.{function}({where}{select}{group_by}){order_by}'
|
484
|
+
has_default = {key: False for key in KEYWORD}
|
485
|
+
LOGICAL_OP_TO_MONGO_FUNC = {
|
486
|
+
'>': '$gt', '>=': '$gte',
|
487
|
+
'<': '$lt', '<=': '$lte',
|
488
|
+
'=': '$eq', '<>': '$ne',
|
489
|
+
}
|
490
|
+
OPERATORS = '|'.join(op for op in LOGICAL_OP_TO_MONGO_FUNC)
|
491
|
+
REGEX = {
|
492
|
+
'options': re.compile(r'\s+or\s+|\s+OR\s+'),
|
493
|
+
'condition': re.compile(fr'({OPERATORS})')
|
494
|
+
}
|
495
|
+
|
496
|
+
def join_with_tabs(self, values: list, sep: str=',') -> str:
|
497
|
+
def format_field(fld):
|
498
|
+
return '{indent}{fld}'.format(
|
499
|
+
fld=self.remove_alias(fld),
|
500
|
+
indent=self.TABULATION
|
501
|
+
)
|
502
|
+
return '{begin}{content}{line_break}{end}'.format(
|
503
|
+
begin='{',
|
504
|
+
content= sep.join(
|
505
|
+
format_field(fld) for fld in values if fld
|
506
|
+
),
|
507
|
+
end='}', line_break=self.LINE_BREAK,
|
508
|
+
)
|
509
|
+
|
510
|
+
def add_field(self, values: list) -> str:
|
511
|
+
if self.result['function'] == 'aggregate':
|
512
|
+
return ''
|
513
|
+
return ',{content}'.format(
|
514
|
+
content=self.join_with_tabs([f'{fld}: 1' for fld in values]),
|
515
|
+
)
|
516
|
+
|
517
|
+
def get_tables(self, values: list) -> str:
|
518
|
+
return values[0].split()[0].lower()
|
519
|
+
|
520
|
+
@classmethod
|
521
|
+
def mongo_where_list(cls, values: list) -> list:
|
522
|
+
OR_REGEX = cls.REGEX['options']
|
523
|
+
where_list = []
|
524
|
+
for condition in values:
|
525
|
+
if OR_REGEX.findall(condition):
|
526
|
+
condition = re.sub('[()]', '', condition)
|
527
|
+
expr = '{begin}$or: [{content}]{end}'.format(
|
528
|
+
content=','.join(
|
529
|
+
cls.mongo_where_list( OR_REGEX.split(condition) )
|
530
|
+
), begin='{', end='}',
|
531
|
+
)
|
532
|
+
where_list.append(expr)
|
533
|
+
continue
|
534
|
+
tokens = cls.REGEX['condition'].split(
|
535
|
+
cls.remove_alias(condition)
|
536
|
+
)
|
537
|
+
tokens = [t.strip() for t in tokens if t]
|
538
|
+
field, *op, const = tokens
|
539
|
+
op = ''.join(op)
|
540
|
+
expr = '{begin}{op}:{const}{end}'.format(
|
541
|
+
begin='{', const=const, end='}',
|
542
|
+
op=cls.LOGICAL_OP_TO_MONGO_FUNC[op],
|
543
|
+
)
|
544
|
+
where_list.append(f'{field}:{expr}')
|
545
|
+
return where_list
|
546
|
+
|
547
|
+
def extract_conditions(self, values: list) -> str:
|
548
|
+
return self.join_with_tabs(
|
549
|
+
self.mongo_where_list(values)
|
550
|
+
)
|
551
|
+
|
552
|
+
def sort_by(self, values: list) -> str:
|
553
|
+
return ".sort({begin}{indent}{field}:{flag}{line_break}{end})".format(
|
554
|
+
begin='{', field=self.remove_alias(values[0].split()[0]),
|
555
|
+
flag=-1 if OrderBy.sort == SortType.DESC else 1,
|
556
|
+
end='}', indent=self.TABULATION, line_break=self.LINE_BREAK,
|
557
|
+
)
|
558
|
+
|
559
|
+
def set_group(self, values: list) -> str:
|
560
|
+
self.result['function'] = 'aggregate'
|
561
|
+
return '{"$group" : {_id:"$%%", count:{$sum:1}}}'.replace(
|
562
|
+
'%%', self.remove_alias( values[0] )
|
563
|
+
)
|
564
|
+
|
565
|
+
def __init__(self, target: 'Select'):
|
566
|
+
super().__init__(target)
|
567
|
+
self.result['function'] = 'find'
|
568
|
+
self.KEYWORDS = [GROUP_BY, SELECT, FROM, WHERE, ORDER_BY]
|
569
|
+
|
570
|
+
def prefix(self, key: str):
|
571
|
+
return ''
|
572
|
+
|
573
|
+
|
574
|
+
class Neo4JLanguage(QueryLanguage):
|
575
|
+
pattern = 'MATCH {_from} RETURN {aliases}'
|
576
|
+
has_default = {key: False for key in KEYWORD}
|
577
|
+
|
578
|
+
def add_field(self, values: list) -> str:
|
579
|
+
return ''
|
580
|
+
|
581
|
+
def get_tables(self, values: list) -> str:
|
582
|
+
NODE_FORMAT = dict(
|
583
|
+
left='({}:{}{})<-',
|
584
|
+
core='[{}:{}{}]',
|
585
|
+
right='->({}:{}{})'
|
586
|
+
)
|
587
|
+
nodes = {k: '' for k in NODE_FORMAT}
|
588
|
+
for txt in values:
|
589
|
+
found = re.search(
|
590
|
+
r'^(left|right)\s+', txt, re.IGNORECASE
|
591
|
+
)
|
592
|
+
pos = 'core'
|
593
|
+
if found:
|
594
|
+
start, end = found.span()
|
595
|
+
pos = txt[start:end-1].lower()
|
596
|
+
tokens = re.split(r'JOIN\s+|ON\s+', txt[end:])
|
597
|
+
txt = tokens[1].strip()
|
598
|
+
table_name, *alias = txt.split()
|
599
|
+
if alias:
|
600
|
+
alias = alias[0]
|
601
|
+
else:
|
602
|
+
alias = SQLObject.ALIAS_FUNC(table_name)
|
603
|
+
condition = self.aliases.get(alias, '')
|
604
|
+
if not condition:
|
605
|
+
self.aliases[alias] = ''
|
606
|
+
nodes[pos] = NODE_FORMAT[pos].format(alias, table_name, condition)
|
607
|
+
self.result['aliases'] = ','.join(self.aliases.keys())
|
608
|
+
return '{left}{core}{right}'.format(**nodes)
|
609
|
+
|
610
|
+
def extract_conditions(self, values: list) -> str:
|
611
|
+
for condition in values:
|
612
|
+
other_comparisions = any(
|
613
|
+
char in condition for char in '<>%'
|
614
|
+
)
|
615
|
+
if '=' not in condition or other_comparisions:
|
616
|
+
raise NotImplementedError('Only comparisons with equality are available for now.')
|
617
|
+
alias, field, const = re.split(r'[.=]', condition)
|
618
|
+
begin, end = '{', '}'
|
619
|
+
self.aliases[alias] = f'{begin}{field}:{const}{end}'
|
620
|
+
return '' # --- WHERE [*other_comparisions*] ...
|
621
|
+
|
622
|
+
def sort_by(self, values: list) -> str:
|
623
|
+
return ''
|
624
|
+
|
625
|
+
def set_group(self, values: list) -> str:
|
626
|
+
return ''
|
627
|
+
|
628
|
+
def __init__(self, target: 'Select'):
|
629
|
+
super().__init__(target)
|
630
|
+
self.aliases = {}
|
631
|
+
self.KEYWORDS = [WHERE, FROM]
|
632
|
+
|
633
|
+
def prefix(self, key: str):
|
634
|
+
return ''
|
635
|
+
|
636
|
+
|
416
637
|
class Parser:
|
417
638
|
REGEX = {}
|
418
639
|
|
@@ -421,14 +642,37 @@ class Parser:
|
|
421
642
|
|
422
643
|
def __init__(self, txt: str, class_type):
|
423
644
|
self.queries = []
|
424
|
-
|
425
|
-
self.prepare()
|
645
|
+
self.prepare()
|
426
646
|
self.class_type = class_type
|
427
647
|
self.eval(txt)
|
428
648
|
|
429
649
|
def eval(self, txt: str):
|
430
650
|
...
|
431
651
|
|
652
|
+
@staticmethod
|
653
|
+
def remove_spaces(script: str) -> str:
|
654
|
+
is_string = False
|
655
|
+
result = []
|
656
|
+
for token in re.split(r'(")', script):
|
657
|
+
if token == '"':
|
658
|
+
is_string = not is_string
|
659
|
+
if not is_string:
|
660
|
+
token = re.sub(r'\s+', '', token)
|
661
|
+
result.append(token)
|
662
|
+
return ''.join(result)
|
663
|
+
|
664
|
+
def get_tokens(self, txt: str) -> list:
|
665
|
+
return self.REGEX['separator'].split(
|
666
|
+
self.remove_spaces(txt)
|
667
|
+
)
|
668
|
+
|
669
|
+
|
670
|
+
class JoinType(Enum):
|
671
|
+
INNER = ''
|
672
|
+
LEFT = 'LEFT '
|
673
|
+
RIGHT = 'RIGHT '
|
674
|
+
FULL = 'FULL '
|
675
|
+
|
432
676
|
|
433
677
|
class SQLParser(Parser):
|
434
678
|
REGEX = {}
|
@@ -506,21 +750,24 @@ class SQLParser(Parser):
|
|
506
750
|
|
507
751
|
class Cypher(Parser):
|
508
752
|
REGEX = {}
|
509
|
-
TOKEN_METHODS = {}
|
510
753
|
|
511
754
|
def prepare(self):
|
512
|
-
self.REGEX['separator'] = re.compile(r'([(,?)^]|->|<-)')
|
755
|
+
self.REGEX['separator'] = re.compile(r'([(,?)^{}[\]]|->|<-)')
|
513
756
|
self.REGEX['condition'] = re.compile(r'(^\w+)|([<>=])')
|
757
|
+
self.join_type = JoinType.INNER
|
514
758
|
self.TOKEN_METHODS = {
|
515
759
|
'(': self.add_field, '?': self.add_where,
|
516
760
|
',': self.add_field, '^': self.add_order,
|
517
|
-
')': self.new_query, '
|
518
|
-
'
|
761
|
+
')': self.new_query, '<-': self.left_ftable,
|
762
|
+
'->': self.right_ftable,
|
519
763
|
}
|
764
|
+
self.method = self.new_query
|
520
765
|
|
521
|
-
def new_query(self, token: str):
|
766
|
+
def new_query(self, token: str, join_type = JoinType.INNER):
|
522
767
|
if token.isidentifier():
|
523
|
-
|
768
|
+
query = self.class_type(token)
|
769
|
+
self.queries.append(query)
|
770
|
+
query.join_type = join_type
|
524
771
|
|
525
772
|
def add_where(self, token: str):
|
526
773
|
field, *condition = [
|
@@ -535,37 +782,76 @@ class Cypher(Parser):
|
|
535
782
|
FieldList(token, [Field]).add('', self.queries[-1])
|
536
783
|
|
537
784
|
def left_ftable(self, token: str):
|
785
|
+
if self.queries:
|
786
|
+
self.queries[-1].join_type = JoinType.LEFT
|
538
787
|
self.new_query(token)
|
539
|
-
self.join_type = JoinType.LEFT
|
540
788
|
|
541
789
|
def right_ftable(self, token: str):
|
542
|
-
self.new_query(token)
|
543
|
-
self.join_type = JoinType.RIGHT
|
790
|
+
self.new_query(token, JoinType.RIGHT)
|
544
791
|
|
545
|
-
def add_foreign_key(self, token: str):
|
792
|
+
def add_foreign_key(self, token: str, pk_field: str=''):
|
546
793
|
curr, last = [self.queries[i] for i in (-1, -2)]
|
547
|
-
|
548
|
-
|
549
|
-
|
794
|
+
if not pk_field:
|
795
|
+
if not last.values.get(SELECT):
|
796
|
+
raise IndexError(f'Primary Key not found for {last.table_name}.')
|
797
|
+
pk_field = last.values[SELECT][-1].split('.')[-1]
|
798
|
+
last.delete(pk_field, [SELECT])
|
799
|
+
if '{}' in token:
|
800
|
+
foreign_fld = token.format(
|
801
|
+
last.table_name.lower()
|
802
|
+
if last.join_type == JoinType.LEFT else
|
803
|
+
curr.table_name.lower()
|
804
|
+
)
|
805
|
+
else:
|
806
|
+
if not curr.values.get(SELECT):
|
807
|
+
raise IndexError(f'Foreign Key not found for {curr.table_name}.')
|
808
|
+
foreign_fld = curr.values[SELECT][0].split('.')[-1]
|
809
|
+
curr.delete(foreign_fld, [SELECT])
|
810
|
+
if curr.join_type == JoinType.RIGHT:
|
550
811
|
curr, last = last, curr
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
812
|
+
k = ForeignKey.get_key(curr, last)
|
813
|
+
ForeignKey.references[k] = (foreign_fld, pk_field)
|
814
|
+
|
815
|
+
def fk_charset(self) -> str:
|
816
|
+
return '(['
|
556
817
|
|
557
818
|
def eval(self, txt: str):
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
819
|
+
# ====================================
|
820
|
+
def has_side_table() -> bool:
|
821
|
+
count = 0 if len(self.queries) < 2 else sum(
|
822
|
+
q.join_type != JoinType.INNER
|
823
|
+
for q in self.queries[-2:]
|
824
|
+
)
|
825
|
+
return count > 0
|
826
|
+
# -----------------------------------
|
827
|
+
for token in self.get_tokens(txt):
|
828
|
+
if not token or (token in '([' and self.method):
|
562
829
|
continue
|
563
830
|
if self.method:
|
564
831
|
self.method(token)
|
565
|
-
if token
|
566
|
-
self.
|
567
|
-
|
568
|
-
|
832
|
+
if token in ')]' and has_side_table():
|
833
|
+
self.add_foreign_key('')
|
834
|
+
self.method = self.TOKEN_METHODS.get(token)
|
835
|
+
# ====================================
|
836
|
+
|
837
|
+
class Neo4JParser(Cypher):
|
838
|
+
def prepare(self):
|
839
|
+
super().prepare()
|
840
|
+
self.TOKEN_METHODS = {
|
841
|
+
'(': self.new_query, '{': self.add_where,
|
842
|
+
'<-': self.left_ftable, '->': self.right_ftable,
|
843
|
+
'[': self.new_query
|
844
|
+
}
|
845
|
+
self.method = None
|
846
|
+
|
847
|
+
def new_query(self, token: str, join_type = JoinType.INNER):
|
848
|
+
super().new_query(token.split(':')[-1], join_type)
|
849
|
+
|
850
|
+
def add_where(self, token: str):
|
851
|
+
super().add_where(token.replace(':', '='))
|
852
|
+
|
853
|
+
def add_foreign_key(self, token: str, pk_field: str='') -> tuple:
|
854
|
+
return super().add_foreign_key('{}_id', 'id')
|
569
855
|
|
570
856
|
# ----------------------------
|
571
857
|
class MongoParser(Parser):
|
@@ -669,7 +955,7 @@ class MongoParser(Parser):
|
|
669
955
|
self.TOKEN_METHODS = {
|
670
956
|
'{': self.get_param, ',': self.next_param, ')': self.new_query,
|
671
957
|
}
|
672
|
-
for token in self.
|
958
|
+
for token in self.get_tokens(txt):
|
673
959
|
if not token:
|
674
960
|
continue
|
675
961
|
if self.method:
|
@@ -684,12 +970,6 @@ class MongoParser(Parser):
|
|
684
970
|
# ----------------------------
|
685
971
|
|
686
972
|
|
687
|
-
class JoinType(Enum):
|
688
|
-
INNER = ''
|
689
|
-
LEFT = 'LEFT '
|
690
|
-
RIGHT = 'RIGHT '
|
691
|
-
FULL = 'FULL '
|
692
|
-
|
693
973
|
class Select(SQLObject):
|
694
974
|
join_type: JoinType = JoinType.INNER
|
695
975
|
REGEX = {}
|
@@ -739,16 +1019,7 @@ class Select(SQLObject):
|
|
739
1019
|
return query
|
740
1020
|
|
741
1021
|
def __str__(self) -> str:
|
742
|
-
|
743
|
-
LINE_BREAK = '\n' if self.break_lines else ' '
|
744
|
-
DEFAULT = lambda key: KEYWORD[key][1]
|
745
|
-
FMT_SEP = lambda key: KEYWORD[key][0].format(TABULATION)
|
746
|
-
select, _from, where, groupBy, orderBy, limit = [
|
747
|
-
DEFAULT(key) if not self.values.get(key) else "{}{}{}{}".format(
|
748
|
-
LINE_BREAK, key, TABULATION, FMT_SEP(key).join(self.values[key])
|
749
|
-
) for key in KEYWORD
|
750
|
-
]
|
751
|
-
return f'{select}{_from}{where}{groupBy}{orderBy}{limit}'.strip()
|
1022
|
+
return self.translate_to(QueryLanguage)
|
752
1023
|
|
753
1024
|
def __call__(self, **values):
|
754
1025
|
to_list = lambda x: x if isinstance(x, list) else [x]
|
@@ -791,6 +1062,8 @@ class Select(SQLObject):
|
|
791
1062
|
class_types += [GroupBy]
|
792
1063
|
FieldList(fields, class_types).add('', self)
|
793
1064
|
|
1065
|
+
def translate_to(self, language: QueryLanguage) -> str:
|
1066
|
+
return language(self).convert()
|
794
1067
|
|
795
1068
|
|
796
1069
|
class SelectIN(Select):
|
@@ -818,7 +1091,7 @@ class RuleSelectIN(Rule):
|
|
818
1091
|
@classmethod
|
819
1092
|
def apply(cls, target: Select):
|
820
1093
|
for i, condition in enumerate(target.values[WHERE]):
|
821
|
-
tokens = re.split('
|
1094
|
+
tokens = re.split(r'\s+or\s+|\s+OR\s+', re.sub('\n|\t|[()]', ' ', condition))
|
822
1095
|
if len(tokens) < 2:
|
823
1096
|
continue
|
824
1097
|
fields = [t.split('=')[0].split('.')[-1].lower().strip() for t in tokens]
|
@@ -864,7 +1137,7 @@ class RuleDateFuncReplace(Rule):
|
|
864
1137
|
"""
|
865
1138
|
SQL algorithm by Ralff Matias
|
866
1139
|
"""
|
867
|
-
REGEX = re.compile(r'(
|
1140
|
+
REGEX = re.compile(r'(YEAR[(]|year[(]|=|[)])')
|
868
1141
|
|
869
1142
|
@classmethod
|
870
1143
|
def apply(cls, target: Select):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sql_blocks
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.9
|
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=CLkYCavcOlIieQkbersjZ30P_UvjFvrjXKxMdNURDVU,38486
|
3
|
+
sql_blocks-0.2.9.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
+
sql_blocks-0.2.9.dist-info/METADATA,sha256=XeK2YuLwhnYlQVq8My7GZfBJQ_gysd7pHGJTBFzwDEI,9675
|
5
|
+
sql_blocks-0.2.9.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
sql_blocks-0.2.9.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
+
sql_blocks-0.2.9.dist-info/RECORD,,
|
@@ -1,7 +0,0 @@
|
|
1
|
-
sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
|
2
|
-
sql_blocks/sql_blocks.py,sha256=DJN_xFMXH9apG4304PtLyVSep7Kz32nyTD5-lSWs6ts,28659
|
3
|
-
sql_blocks-0.2.4.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
|
4
|
-
sql_blocks-0.2.4.dist-info/METADATA,sha256=kNLOaXxpoPXmHiq9uRpWnVgEAxPnQH3tlmiJ1f3cYP8,9675
|
5
|
-
sql_blocks-0.2.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
-
sql_blocks-0.2.4.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
|
7
|
-
sql_blocks-0.2.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|