sql-blocks 1.20250710__py3-none-any.whl → 1.20250711__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
@@ -221,11 +221,12 @@ class Code:
221
221
  def As(self, field_alias: str, modifiers=None):
222
222
  if modifiers:
223
223
  self.extra[field_alias] = TO_LIST(modifiers)
224
- self.field_class = NamedField(field_alias)
224
+ if field_alias:
225
+ self.field_class = NamedField(field_alias)
225
226
  return self
226
227
 
227
228
  def format(self, name: str, main: SQLObject) -> str:
228
- raise NotImplementedError('Use child classes instead of this one')
229
+ return Field.format(name, main)
229
230
 
230
231
  def __add(self, name: str, main: SQLObject):
231
232
  name = self.format(name, main)
@@ -1674,38 +1675,51 @@ class CypherParser(Parser):
1674
1675
  Where(' '.join(condition)).add(field, query)
1675
1676
 
1676
1677
  def add_order(self, token: str):
1677
- self.add_field(token, [OrderBy])
1678
+ self.add_field(token, sorted=True)
1678
1679
 
1679
- def add_field(self, token: str, extra_classes: list['type']=[]):
1680
+ def add_field(self, token: str, sorted: bool = False):
1680
1681
  if token in self.TOKEN_METHODS:
1681
1682
  return
1682
- class_list = [Field]
1683
1683
  if '*' in token:
1684
1684
  token = token.replace('*', '')
1685
1685
  self.queries[-1].key_field = token
1686
1686
  return
1687
- elif '$' in token:
1688
- func_name, token = token.split('$')
1689
- if func_name == 'count':
1690
- if not token:
1691
- token = 'count_1'
1692
- pk_field = self.queries[-1].key_field or 'id'
1693
- Count().As(token, extra_classes).add(pk_field, self.queries[-1])
1694
- return
1695
- else:
1696
- class_type = FUNCTION_CLASS.get(func_name)
1687
+ # -------------------------------------------------------
1688
+ def field_params() -> dict:
1689
+ ROLE_OF_SEPARATOR = {
1690
+ '$': 'function',
1691
+ ':': 'alias',
1692
+ '@': 'group',
1693
+ '!': 'field',
1694
+ }
1695
+ REGEX_FIELD = r'([{}])'.format(''.join(ROLE_OF_SEPARATOR))
1696
+ elements = re.split(REGEX_FIELD, token+'!')
1697
+ return {
1698
+ ROLE_OF_SEPARATOR[k]: v
1699
+ for k, v in zip(elements[1::2], elements[::2])
1700
+ }
1701
+ def run(function: str='', alias: str='', group: str='', field: str=''):
1702
+ is_count = function == 'count'
1703
+ if alias or is_count:
1704
+ field, alias = alias, field
1705
+ extra_classes = [OrderBy] if sorted else []
1706
+ if group:
1707
+ if not field:
1708
+ field = group
1709
+ extra_classes += [GroupBy]
1710
+ if function:
1711
+ if is_count and not field:
1712
+ field = self.queries[-1].key_field or 'id'
1713
+ class_type = FUNCTION_CLASS.get(function)
1697
1714
  if not class_type:
1698
- raise ValueError(f'Unknown function `{func_name}`.')
1699
- if ':' in token:
1700
- token, field_alias = token.split(':')
1701
- if extra_classes == [OrderBy]:
1702
- class_type = class_type().As(field_alias, OrderBy)
1703
- extra_classes = []
1704
- else:
1705
- class_type = class_type().As(field_alias)
1706
- class_list = [class_type]
1707
- class_list += extra_classes
1708
- FieldList(token, class_list).add('', self.queries[-1])
1715
+ raise ValueError(f'Unknown function `{function}`.')
1716
+ class_list = [ class_type().As(alias or group, extra_classes) ]
1717
+ else:
1718
+ class_list = [Field] + extra_classes
1719
+ FieldList(field, class_list).add('', self.queries[-1])
1720
+ # -------------------------------------------------------
1721
+ run( **field_params() )
1722
+ # -------------------------------------------------------
1709
1723
 
1710
1724
  def left_ftable(self, token: str):
1711
1725
  if self.queries:
@@ -2117,7 +2131,7 @@ class CTE(Select):
2117
2131
  else:
2118
2132
  count = len(fields)
2119
2133
  queries = detect(
2120
- pattern*count, join_queries=False, format=format
2134
+ pattern*count, join_method=None, format=format
2121
2135
  )
2122
2136
  FieldList(fields, queries, ziped=True).add('', self)
2123
2137
  self.break_lines = True
@@ -2138,7 +2152,7 @@ class Recursive(CTE):
2138
2152
  def get_field(obj: SQLObject, pos: int) -> str:
2139
2153
  return obj.values[SELECT][pos].split('.')[-1]
2140
2154
  t1, t2 = detect(
2141
- pattern*2, join_queries=False, format=format
2155
+ pattern*2, join_method=None, format=format
2142
2156
  )
2143
2157
  pk_field = get_field(t1, 0)
2144
2158
  foreign_key = ''
@@ -2173,6 +2187,14 @@ class CTEFactory:
2173
2187
  FROM** ( `sub_query1` ) **AS** `alias_1`
2174
2188
  JOIN ( `sub_query2` ) **AS** `alias_2` **ON** `__join__`
2175
2189
  """
2190
+ if parser_class(txt) == CypherParser:
2191
+ query_list = Select.parse(txt, CypherParser)
2192
+ alias = '_'.join(query.table_name for query in query_list)
2193
+ self.main = Select(alias)
2194
+ self.main.break_lines = False
2195
+ query = join_queries(query_list)
2196
+ self.cte_list = [CTE(alias, [query])]
2197
+ return
2176
2198
  summary = self.extract_subqueries(txt)
2177
2199
  self.main = detect( summary.pop(MAIN_TAG) )
2178
2200
  self.cte_list = [
@@ -2351,8 +2373,13 @@ def parser_class(text: str) -> Parser:
2351
2373
  return class_type
2352
2374
  return None
2353
2375
 
2376
+ def join_queries(query_list: list) -> Select:
2377
+ result = query_list[0]
2378
+ for query in query_list[1:]:
2379
+ result += query
2380
+ return result
2354
2381
 
2355
- def detect(text: str, join_queries: bool = True, format: str='') -> Select | list[Select]:
2382
+ def detect(text: str, join_method = join_queries, format: str='') -> Select | list[Select]:
2356
2383
  from collections import Counter
2357
2384
  parser = parser_class(text)
2358
2385
  if not parser:
@@ -2367,34 +2394,28 @@ def detect(text: str, join_queries: bool = True, format: str='') -> Select | lis
2367
2394
  Select.EQUIVALENT_NAMES[new_name] = table
2368
2395
  text = text[:begin] + new_name + '(' + text[end:]
2369
2396
  count -= 1
2370
- query_list = Select.parse(text, parser)
2397
+ result = Select.parse(text, parser)
2371
2398
  if format:
2372
- for query in query_list:
2399
+ for query in result:
2373
2400
  query.set_file_format(format)
2374
- if not join_queries:
2375
- return query_list
2376
- result = query_list[0]
2377
- for query in query_list[1:]:
2378
- result += query
2401
+ if join_method:
2402
+ result = join_method(result)
2379
2403
  return result
2380
2404
  # ===========================================================================================//
2381
2405
 
2382
2406
  if __name__ == "__main__":
2383
- query = Select(
2384
- 'Sales s', #quantity=Sum().As('qty_sold'),
2385
- ref_date=GroupBy(
2386
- ref_year=Year, qty_sold=Sum('quantity'),
2387
- vendor=Select(
2388
- 'Vendor v', id=[PrimaryKey, NamedField('vendor_id')], name=Field
2389
- ),
2390
- prod_id=Field
2391
- )
2392
- )
2393
- cte = CTE('Sales_by_year', [query])(
2394
- _=Where.join(
2395
- Select('Goal G'), dict(
2396
- prod_id='product', ref_year='year', vendor_id='vendor'
2397
- )
2398
- )
2407
+ cte = CTEFactory(
2408
+ "Sales(year$ref_date:ref_year@, sum$quantity:qty_sold, vendor) <- Vendor(id, name@)"
2409
+ # ^^^ ^^^ ^^^
2410
+ # | | | ^^^ ^^^
2411
+ # | | | | |
2412
+ # | | | Relaciona Sales com Vendor ----+ |
2413
+ # | | | |
2414
+ # | | +---- Chama de `ref_year` e agrupa |
2415
+ # | | |
2416
+ # | +-- Extrai o ano do campo `ref_date` |
2417
+ # | |
2418
+ # +--- Tabela de vendas |
2419
+ # Agrupa também pelo nome do vendedor -------------+
2399
2420
  )
2400
- print(cte)
2421
+ print(cte)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.20250710
3
+ Version: 1.20250711
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=JHQ0CzciUEodZoA0WjUYKDpC2VZWcFlDB9C2wrNc4rA,83004
3
+ sql_blocks-1.20250711.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.20250711.dist-info/METADATA,sha256=fci6o5QrXStVrXylRQ7QaCpO9jid0P6eON6xMK4Rob0,24486
5
+ sql_blocks-1.20250711.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.20250711.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.20250711.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=FLjT_V60QyfqUvbdu2hKUcFh3KTJNP091p0q_pg43v4,81469
3
- sql_blocks-1.20250710.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-1.20250710.dist-info/METADATA,sha256=zuWxpPD-1LoJHSD7D4EywcpQaYi5buEjfuypOmwNdOE,24486
5
- sql_blocks-1.20250710.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-1.20250710.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-1.20250710.dist-info/RECORD,,