sql-blocks 1.25.19011745__py3-none-any.whl → 1.25.26011923__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
@@ -470,7 +470,17 @@ class Where:
470
470
  values = ','.join(quoted(v) for v in values)
471
471
  return cls(f'IN ({values})')
472
472
 
473
+ @classmethod
474
+ def formula(cls, formula: str):
475
+ return cls( ExpressionField(formula) )
476
+
473
477
  def add(self, name: str, main: SQLObject):
478
+ if isinstance(self.expr, ExpressionField):
479
+ self.expr = self.expr.format(name, main)
480
+ main.values.setdefault(WHERE, []).append('{} {}'.format(
481
+ self.prefix, self.expr
482
+ ))
483
+ return
474
484
  func_type = FUNCTION_CLASS.get(name.lower())
475
485
  exists = any(
476
486
  main.is_named_field(fld, SELECT)
@@ -566,7 +576,7 @@ class Clause:
566
576
  found = re.findall(r'^_\d', name)
567
577
  if found:
568
578
  name = found[0].replace('_', '')
569
- elif main.alias and not is_function():
579
+ elif '.' not in name and main.alias and not is_function():
570
580
  name = f'{main.alias}.{name}'
571
581
  return name
572
582
 
@@ -1008,8 +1018,11 @@ class SQLParser(Parser):
1008
1018
  if not key in values:
1009
1019
  continue
1010
1020
  separator = self.class_type.get_separator(key)
1021
+ cls = {
1022
+ ORDER_BY: OrderBy, GROUP_BY: GroupBy
1023
+ }.get(key, Field)
1011
1024
  obj.values[key] = [
1012
- Field.format(fld, obj)
1025
+ cls.format(fld, obj)
1013
1026
  for fld in re.split(separator, values[key])
1014
1027
  if (fld != '*' and len(tables) == 1) or obj.match(fld, key)
1015
1028
  ]
@@ -1416,6 +1429,47 @@ class NotSelectIN(SelectIN):
1416
1429
  condition_class = Not
1417
1430
 
1418
1431
 
1432
+ class CTE:
1433
+ prefix = ''
1434
+
1435
+ def __init__(self, name: str, query_list: list[Select]):
1436
+ self.name = name
1437
+ for query in query_list:
1438
+ query.break_lines = False
1439
+ self.query_list = query_list
1440
+
1441
+ def format(self, query: Select) -> str:
1442
+ LINE_MAX_SIZE = 50
1443
+ result, line = [], ''
1444
+ for word in str(query).split(' '):
1445
+ if len(line) >= LINE_MAX_SIZE and word in KEYWORD:
1446
+ result.append(line)
1447
+ line = ''
1448
+ line += word + ' '
1449
+ if line:
1450
+ result.append(line)
1451
+ return '\n\t'.join(result)
1452
+
1453
+ def __str__(self) -> str:
1454
+ return 'WITH {}{} AS (\n\t{}\n)SELECT * FROM {}'.format(
1455
+ self.prefix, self.name,
1456
+ '\nUNION ALL\n\t'.join(
1457
+ self.format(q) for q in self.query_list
1458
+ ), self.name
1459
+ )
1460
+
1461
+ class Recursive(CTE):
1462
+ prefix = 'RECURSIVE '
1463
+
1464
+ def __str__(self) -> str:
1465
+ if len(self.query_list) > 1:
1466
+ alias = self.name[0].lower()
1467
+ self.query_list[-1].values[FROM].append(f', {self.name} {alias}')
1468
+ return super().__str__()
1469
+
1470
+
1471
+ # ----- Rules -----
1472
+
1419
1473
  class RulePutLimit(Rule):
1420
1474
  @classmethod
1421
1475
  def apply(cls, target: Select):
@@ -1554,13 +1608,14 @@ def detect(text: str, join_queries: bool = True) -> Select:
1554
1608
  return result
1555
1609
 
1556
1610
 
1557
- if __name__ == '__main__':
1558
- query = Select(
1559
- 'Tips t',
1560
- tip=[Field, Lag().over(day=OrderBy).As('last')],
1561
- diff=[
1562
- ExpressionField('Round(tip-last, 2) as {f}'),
1563
- Not.is_null()
1564
- ]
1611
+ if __name__ == "__main__":
1612
+ MY_NAME = 'Júlio Cascalles'
1613
+ # query = Select('SocialMedia s', post=Count, reaction=Sum, user=GroupBy)
1614
+ # print( CTE('Metrics', [query]) )
1615
+ q1 = Select(
1616
+ 'SocialMedia me', name=[ eq(MY_NAME), Field ]
1617
+ )
1618
+ q2 = Select(
1619
+ 'SocialMedia you', name=Field, id=Where.formula('{af} = n.friend')
1565
1620
  )
1566
- print(query)
1621
+ print( Recursive('Network', [q1, q2]) )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.25.19011745
3
+ Version: 1.25.26011923
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
@@ -115,6 +115,16 @@ based_on_book=Not.is_null()
115
115
  hash_tag=inside(['space', 'monster', 'gore'])
116
116
  ```
117
117
 
118
+ 3.6 -- Combining ExpressionField with Where condition:
119
+ * The **formula** method allows you to write an expression as a condition:
120
+ ```
121
+ query=Select(
122
+ 'Folks f2',
123
+ id=Where.formula('({af} = a.father OR {af} = a.mother)')
124
+ )
125
+ ```
126
+ > Results: `WHERE...f2.id = a.father OR f2.id = a.mother`
127
+
118
128
  ---
119
129
  ### 4 - A field can be two things at the same time:
120
130
 
@@ -631,3 +641,39 @@ For example, if your query is going to run on Oracle, do the following:
631
641
 
632
642
  `Function.dialect = Dialect.ORACLE`
633
643
 
644
+ ---
645
+
646
+ ### 17 - CTE and Recursive classes
647
+
648
+ * **_CTE class_**
649
+ ```
650
+ query = Select(
651
+ 'SocialMedia s', post=Count, reaction=Sum, user=GroupBy
652
+ )
653
+ print( CTE('Metrics', [query]) )
654
+ ```
655
+ The result is...
656
+ ```
657
+ WITH Metrics AS (
658
+ SELECT Count(s.post), Sum(s.reaction) FROM SocialMedia s GROUP BY user
659
+ )SELECT * FROM Metrics
660
+ ```
661
+
662
+ * **_Recursive class_**
663
+ ```
664
+ q1 = Select(
665
+ 'SocialMedia me', name=[ eq(MY_NAME), Field ]
666
+ )
667
+ q2 = Select(
668
+ 'SocialMedia you' name=Field, id=Where.formula('{af} = n.friend')
669
+ )
670
+ print( Recursive('Network', [q1, q2]) )
671
+ ```
672
+ The result is...
673
+ ```
674
+ WITH RECURSIVE Network AS (
675
+ SELECT me.name FROM SocialMedia me WHERE me.name = 'Júlio Cascalles'
676
+ UNION ALL
677
+ SELECT you.name FROM SocialMedia you , Network n WHERE you.id = n.friend
678
+ )SELECT * FROM Network
679
+ ```
@@ -0,0 +1,7 @@
1
+ sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
+ sql_blocks/sql_blocks.py,sha256=lVV1Z09JVmwvV0vzKqZVBHpGWpZefD1RsMZy-aIJZSk,53868
3
+ sql_blocks-1.25.26011923.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.26011923.dist-info/METADATA,sha256=qvFr99uB0b95uv7MqpvpZaMrH7VrE557bmW4YWFQgnA,16187
5
+ sql_blocks-1.25.26011923.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.26011923.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.26011923.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=lPUpYOLHjvx84EVjlydJK03rm7qG1DWotRtqyldKqvo,52020
3
- sql_blocks-1.25.19011745.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-1.25.19011745.dist-info/METADATA,sha256=KPw30aPiITpjBHpfWU9yAuTtr8aQ5cW5cdIdzM4iD0k,15031
5
- sql_blocks-1.25.19011745.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-1.25.19011745.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-1.25.19011745.dist-info/RECORD,,