sql-blocks 1.25.26011923__py3-none-any.whl → 1.25.30011644__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
@@ -42,17 +42,23 @@ class SQLObject:
42
42
  if not table_name:
43
43
  return
44
44
  cls = SQLObject
45
+ is_file_name = any([
46
+ '/' in table_name, '.' in table_name
47
+ ])
48
+ ref = table_name
49
+ if is_file_name:
50
+ ref = table_name.split('/')[-1].split('.')[0]
45
51
  if cls.ALIAS_FUNC:
46
- self.__alias = cls.ALIAS_FUNC(table_name)
52
+ self.__alias = cls.ALIAS_FUNC(ref)
47
53
  elif ' ' in table_name.strip():
48
54
  table_name, self.__alias = table_name.split()
49
- elif '_' in table_name:
55
+ elif '_' in ref:
50
56
  self.__alias = ''.join(
51
57
  word[0].lower()
52
- for word in table_name.split('_')
58
+ for word in ref.split('_')
53
59
  )
54
60
  else:
55
- self.__alias = table_name.lower()[:3]
61
+ self.__alias = ref.lower()[:3]
56
62
  self.values.setdefault(FROM, []).append(f'{table_name} {self.alias}')
57
63
 
58
64
  @property
@@ -423,23 +429,23 @@ class Position(Enum):
423
429
  class Where:
424
430
  prefix = ''
425
431
 
426
- def __init__(self, expr: str):
427
- self.expr = expr
432
+ def __init__(self, content: str):
433
+ self.content = content
428
434
 
429
435
  @classmethod
430
436
  def __constructor(cls, operator: str, value):
431
- return cls(expr=f'{operator} {quoted(value)}')
437
+ return cls(f'{operator} {quoted(value)}')
432
438
 
433
439
  @classmethod
434
440
  def eq(cls, value):
435
441
  return cls.__constructor('=', value)
436
442
 
437
443
  @classmethod
438
- def contains(cls, content: str, pos: Position = Position.Middle):
444
+ def contains(cls, text: str, pos: Position = Position.Middle):
439
445
  return cls(
440
446
  "LIKE '{}{}{}'".format(
441
447
  '%' if pos != Position.StartsWith else '',
442
- content,
448
+ text,
443
449
  '%' if pos != Position.EndsWith else ''
444
450
  )
445
451
  )
@@ -472,15 +478,33 @@ class Where:
472
478
 
473
479
  @classmethod
474
480
  def formula(cls, formula: str):
475
- return cls( ExpressionField(formula) )
481
+ where = cls( ExpressionField(formula) )
482
+ where.add = where.add_expression
483
+ return where
484
+
485
+ def add_expression(self, name: str, main: SQLObject):
486
+ self.content = self.content.format(name, main)
487
+ main.values.setdefault(WHERE, []).append('{} {}'.format(
488
+ self.prefix, self.content
489
+ ))
490
+
491
+ @classmethod
492
+ def join(cls, query: SQLObject):
493
+ where = cls(query)
494
+ where.add = where.add_join
495
+ return where
496
+
497
+ def add_join(self, name: str, main: SQLObject):
498
+ query = self.content
499
+ main.values[FROM].append(f',{query.table_name} {query.alias}')
500
+ for key in USUAL_KEYS:
501
+ main.update_values(key, query.values.get(key, []))
502
+ main.values.setdefault(WHERE, []).append('({a1}.{f1} = {a2}.{f2})'.format(
503
+ a1=main.alias, f1=name,
504
+ a2=query.alias, f2=query.key_field
505
+ ))
476
506
 
477
507
  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
484
508
  func_type = FUNCTION_CLASS.get(name.lower())
485
509
  exists = any(
486
510
  main.is_named_field(fld, SELECT)
@@ -492,7 +516,7 @@ class Where:
492
516
  elif not exists:
493
517
  name = Field.format(name, main)
494
518
  main.values.setdefault(WHERE, []).append('{}{} {}'.format(
495
- self.prefix, name, self.expr
519
+ self.prefix, name, self.content
496
520
  ))
497
521
 
498
522
 
@@ -500,6 +524,10 @@ eq, contains, gt, gte, lt, lte, is_null, inside = (
500
524
  getattr(Where, method) for method in
501
525
  ('eq', 'contains', 'gt', 'gte', 'lt', 'lte', 'is_null', 'inside')
502
526
  )
527
+ startswith, endswith = [
528
+ lambda x: contains(x, Position.StartsWith),
529
+ lambda x: contains(x, Position.EndsWith)
530
+ ]
503
531
 
504
532
 
505
533
  class Not(Where):
@@ -507,7 +535,7 @@ class Not(Where):
507
535
 
508
536
  @classmethod
509
537
  def eq(cls, value):
510
- return Where(expr=f'<> {quoted(value)}')
538
+ return Where(f'<> {quoted(value)}')
511
539
 
512
540
 
513
541
  class Case:
@@ -548,7 +576,7 @@ class Options:
548
576
  child: Where
549
577
  for field, child in self.__children.items():
550
578
  conditions.append(' {} {} '.format(
551
- Field.format(field, main), child.expr
579
+ Field.format(field, main), child.content
552
580
  ))
553
581
  main.values.setdefault(WHERE, []).append(
554
582
  '(' + logical_separator.join(conditions) + ')'
@@ -647,7 +675,7 @@ class Having:
647
675
 
648
676
  def add(self, name: str, main:SQLObject):
649
677
  main.values[GROUP_BY][-1] += ' HAVING {} {}'.format(
650
- self.function.format(name, main), self.condition.expr
678
+ self.function.format(name, main), self.condition.content
651
679
  )
652
680
 
653
681
  @classmethod
@@ -1451,11 +1479,11 @@ class CTE:
1451
1479
  return '\n\t'.join(result)
1452
1480
 
1453
1481
  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(
1482
+ return 'WITH {prefix}{name} AS (\n\t{queries}\n)SELECT * FROM {name}'.format(
1483
+ prefix=self.prefix, name=self.name,
1484
+ queries='\nUNION ALL\n\t'.join(
1457
1485
  self.format(q) for q in self.query_list
1458
- ), self.name
1486
+ )
1459
1487
  )
1460
1488
 
1461
1489
  class Recursive(CTE):
@@ -1584,7 +1612,7 @@ def parser_class(text: str) -> Parser:
1584
1612
  return None
1585
1613
 
1586
1614
 
1587
- def detect(text: str, join_queries: bool = True) -> Select:
1615
+ def detect(text: str, join_queries: bool = True) -> Select | list[Select]:
1588
1616
  from collections import Counter
1589
1617
  parser = parser_class(text)
1590
1618
  if not parser:
@@ -1607,15 +1635,3 @@ def detect(text: str, join_queries: bool = True) -> Select:
1607
1635
  result += query
1608
1636
  return result
1609
1637
 
1610
-
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')
1620
- )
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.26011923
3
+ Version: 1.25.30011644
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
@@ -153,6 +153,35 @@ FROM
153
153
  JOIN Cast c ON (a.cast = c.id)
154
154
  ```
155
155
 
156
+ ---
157
+ **5.1 Multiple tables without JOIN**
158
+ > Warning: This is **NOT** recommended! ⛔
159
+
160
+
161
+ #### Example:
162
+ singer = Select(
163
+ "Singer artist", id=PrimaryKey,
164
+ name=NamedField('artist_name')
165
+ )
166
+ album = Select (
167
+ "Album album",
168
+ name=NamedField('album_name'),
169
+ artist_id=Where.join(singer), # <===== 👀
170
+ )
171
+ **>> print(query)**
172
+
173
+ SELECT
174
+ album.name as album_name,
175
+ artist.name as artist_name,
176
+ album.year_recorded
177
+ FROM
178
+ 'sql_blocks/music/data/Album.csv' album
179
+ ,'sql_blocks/music/data/Singer.csv' artist
180
+ WHERE
181
+ (album.artist_id = artist.id)
182
+
183
+
184
+
156
185
  ---
157
186
  ### 6 - The reverse process (parse):
158
187
  ```
@@ -0,0 +1,7 @@
1
+ sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
+ sql_blocks/sql_blocks.py,sha256=2R4VoSZUHTb1gSZwKjtNfkjxeH8G1dKYuDpuKv-UP7E,54430
3
+ sql_blocks-1.25.30011644.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.30011644.dist-info/METADATA,sha256=2Q1naQygxXqw87DTc70LyLjs8uWK95v0CWu5B9qHLlQ,16884
5
+ sql_blocks-1.25.30011644.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.30011644.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.30011644.dist-info/RECORD,,
@@ -1,7 +0,0 @@
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,,