sql-blocks 1.25.528999999999__py3-none-any.whl → 1.25.6109999999999__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 CHANGED
@@ -84,6 +84,17 @@ class SQLObject:
84
84
  appendix = {WHERE: r'\s+and\s+|', FROM: r'\s+join\s+|\s+JOIN\s+'}
85
85
  return KEYWORD[key][0].format(appendix.get(key, ''))
86
86
 
87
+ @staticmethod
88
+ def contains_CASE_statement(text: str) -> bool:
89
+ return re.search(r'\bCASE\b', text, re.IGNORECASE)
90
+
91
+ @classmethod
92
+ def split_fields(cls, text: str, key: str) -> list:
93
+ if key == SELECT and cls.contains_CASE_statement(text):
94
+ return Case.parse(text)
95
+ separator = cls.get_separator(key)
96
+ return re.split(separator, text)
97
+
87
98
  @staticmethod
88
99
  def is_named_field(fld: str, name: str='') -> bool:
89
100
  return re.search(fr'(\s+as\s+|\s+AS\s+){name}', fld)
@@ -103,6 +114,9 @@ class SQLObject:
103
114
  result += re.split(r'([=()]|<>|\s+ON\s+|\s+on\s+)', fld)
104
115
  return result
105
116
  def cleanup(text: str) -> str:
117
+ # if re.search(r'^CASE\b', text):
118
+ if self.contains_CASE_statement(text):
119
+ return text
106
120
  text = re.sub(r'[\n\t]', ' ', text)
107
121
  if exact:
108
122
  text = text.lower()
@@ -116,14 +130,13 @@ class SQLObject:
116
130
  re.sub(pattern, '', cleanup(fld))
117
131
  )
118
132
  for string in disassemble(source)
119
- for fld in re.split(separator, string)
133
+ for fld in self.split_fields(string, key)
120
134
  )
121
135
  pattern = KEYWORD[key][1]
122
136
  if exact:
123
137
  if key == WHERE:
124
138
  pattern = r'["\']| '
125
139
  pattern += f'|{PATTERN_PREFIX}'
126
- separator = self.get_separator(key)
127
140
  s1 = field_set(search_list)
128
141
  s2 = field_set(self.values.get(key, []))
129
142
  if exact:
@@ -642,11 +655,19 @@ class Case:
642
655
  self.__conditions = {}
643
656
  self.default = None
644
657
  self.field = field
658
+ self.current_condition = None
659
+ self.fields = []
645
660
 
646
- def when(self, condition: Where, result):
661
+ def when(self, condition: Where, result=None):
662
+ self.current_condition = condition
663
+ if result is None:
664
+ return self
665
+ return self.then(result)
666
+
667
+ def then(self, result):
647
668
  if isinstance(result, str):
648
669
  result = quoted(result)
649
- self.__conditions[result] = condition
670
+ self.__conditions[result] = self.current_condition
650
671
  return self
651
672
 
652
673
  def else_value(self, default):
@@ -655,17 +676,67 @@ class Case:
655
676
  self.default = default
656
677
  return self
657
678
 
658
- def add(self, name: str, main: SQLObject):
659
- field = Field.format(self.field, main)
679
+ def format(self, name: str, field: str='') -> str:
660
680
  default = self.default
661
- name = 'CASE \n{}\n\tEND AS {}'.format(
681
+ if not field:
682
+ field = self.field
683
+ return 'CASE \n{}\n\tEND AS {}'.format(
662
684
  '\n'.join(
663
685
  f'\t\tWHEN {field} {cond.content} THEN {res}'
664
686
  for res, cond in self.__conditions.items()
665
687
  ) + (f'\n\t\tELSE {default}' if default else ''),
666
688
  name
667
689
  )
668
- main.values.setdefault(SELECT, []).append(name)
690
+
691
+ def add(self, name: str, main: SQLObject):
692
+ main.values.setdefault(SELECT, []).append(
693
+ self.format(
694
+ name, Field.format(self.field, main)
695
+ )
696
+ )
697
+
698
+ @classmethod
699
+ def parse(cls, expr: str) -> list:
700
+ result = []
701
+ block: 'Case' = None
702
+ # ---- functions of keywords: -----------------
703
+ def _when(word: str):
704
+ field, condition = word.split(' ', maxsplit=1)
705
+ condition = Where(condition)
706
+ if not block:
707
+ return cls(field).when(condition)
708
+ return block.when(condition)
709
+ def _then(word: str):
710
+ return block.then( eval(word) )
711
+ def _else(word: str):
712
+ return block.else_value( eval(word) )
713
+ def _end(word: str):
714
+ name, *rest = [t.strip() for t in re.split(r'\s+AS\s+|[,]', word) if t]
715
+ block.fields.append(
716
+ block.format(name)
717
+ )
718
+ block.fields += rest
719
+ return block
720
+ # -------------------------------------------------
721
+ KEYWORDS = {
722
+ 'WHEN': _when, 'THEN': _then,
723
+ 'ELSE': _else, 'END': _end,
724
+ }
725
+ RESERVED_WORDS = ['CASE'] + list(KEYWORDS)
726
+ REGEX = '|'.join(fr'\b{word}\b' for word in RESERVED_WORDS)
727
+ expr = re.sub(r'\s+', ' ', expr)
728
+ tokens = [t for t in re.split(f'({REGEX})', expr) if t.strip()]
729
+ last_word = ''
730
+ while tokens:
731
+ word = tokens.pop(0)
732
+ if last_word in KEYWORDS:
733
+ block = KEYWORDS[last_word](word)
734
+ result += block.fields
735
+ block.fields = []
736
+ elif word not in RESERVED_WORDS:
737
+ result.append(word.replace(',', ''))
738
+ last_word = word
739
+ return result
669
740
 
670
741
 
671
742
  class Options:
@@ -1353,13 +1424,12 @@ class SQLParser(Parser):
1353
1424
  for key in USUAL_KEYS:
1354
1425
  if not key in values:
1355
1426
  continue
1356
- separator = self.class_type.get_separator(key)
1357
1427
  cls = {
1358
1428
  ORDER_BY: OrderBy, GROUP_BY: GroupBy
1359
1429
  }.get(key, Field)
1360
1430
  obj.values[key] = [
1361
1431
  cls.format(fld, obj)
1362
- for fld in re.split(separator, values[key])
1432
+ for fld in self.class_type.split_fields(values[key], key)
1363
1433
  if (fld != '*' and len(tables) == 1) or obj.match(fld, key)
1364
1434
  ]
1365
1435
  result[obj.alias] = obj
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.25.528999999999
3
+ Version: 1.25.6109999999999
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=09o87wu2xc82AMMyV-OBiYmv0d_kfL_DIH6G--3-DIA,71615
3
+ sql_blocks-1.25.6109999999999.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.6109999999999.dist-info/METADATA,sha256=KpFEm1tvvHvoURZ3kV1VjvBvSIEGGAWuskacBXg0Xp4,22236
5
+ sql_blocks-1.25.6109999999999.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.6109999999999.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.6109999999999.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=qhzO4tlxBE3dSqDZ-ow1b08H90xDytWXrFMrf6Y-5Og,69096
3
- sql_blocks-1.25.528999999999.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-1.25.528999999999.dist-info/METADATA,sha256=GNAFIVbNrBrijE1PbjoHaaPRIwrC_NbSLEd-VF0WWyc,22235
5
- sql_blocks-1.25.528999999999.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-1.25.528999999999.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-1.25.528999999999.dist-info/RECORD,,