sql-blocks 1.25.109__py3-none-any.whl → 1.25.111__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
@@ -379,10 +379,9 @@ def quoted(value) -> str:
379
379
 
380
380
 
381
381
  class Position(Enum):
382
- Middle = "LIKE '%{}%'"
383
- StartWith = "LIKE '{}%'"
384
- EndsWith = "LIKE '%{}'"
385
- RegEx = "REGEXP_LIKE('{}')"
382
+ Middle = 0
383
+ StartsWith = 1
384
+ EndsWith = 2
386
385
 
387
386
 
388
387
  class Where:
@@ -401,7 +400,13 @@ class Where:
401
400
 
402
401
  @classmethod
403
402
  def contains(cls, content: str, pos: Position = Position.Middle):
404
- return cls(pos.value.format(content))
403
+ return cls(
404
+ "LIKE '{}{}{}'".format(
405
+ '%' if pos != Position.StartsWith else '',
406
+ content,
407
+ '%' if pos != Position.EndsWith else ''
408
+ )
409
+ )
405
410
 
406
411
  @classmethod
407
412
  def gt(cls, value):
@@ -481,9 +486,8 @@ class Options:
481
486
  self.__children: dict = values
482
487
 
483
488
  def add(self, logical_separator: str, main: SQLObject):
484
- """
485
- `logical_separator` must be AND or OR
486
- """
489
+ if logical_separator not in ('AND', 'OR'):
490
+ raise ValueError('`logical_separator` must be AND or OR')
487
491
  conditions: list[str] = []
488
492
  child: Where
489
493
  for field, child in self.__children.items():
@@ -1381,6 +1385,31 @@ class RuleDateFuncReplace(Rule):
1381
1385
  target.values[WHERE][i] = ' AND '.join(temp.values[WHERE])
1382
1386
 
1383
1387
 
1388
+ class RuleReplaceJoinBySubselect(Rule):
1389
+ @classmethod
1390
+ def apply(cls, target: Select):
1391
+ main, *others = Select.parse( str(target) )
1392
+ modified = False
1393
+ for query in others:
1394
+ fk_field, primary_k = ForeignKey.find(main, query)
1395
+ more_relations = any([
1396
+ ref[0] == query.table_name for ref in ForeignKey.references
1397
+ ])
1398
+ invalid = any([
1399
+ len( query.values.get(SELECT, []) ) > 0,
1400
+ len( query.values.get(WHERE, []) ) == 0,
1401
+ not fk_field, more_relations
1402
+ ])
1403
+ if invalid:
1404
+ continue
1405
+ query.__class__ = SubSelect
1406
+ Field.add(primary_k, query)
1407
+ query.add(fk_field, main)
1408
+ modified = True
1409
+ if modified:
1410
+ target.values = main.values.copy()
1411
+
1412
+
1384
1413
  def parser_class(text: str) -> Parser:
1385
1414
  PARSER_REGEX = [
1386
1415
  (r'select.*from', SQLParser),
@@ -1415,3 +1444,16 @@ def detect(text: str) -> Select:
1415
1444
  for query in query_list[1:]:
1416
1445
  result += query
1417
1446
  return result
1447
+
1448
+
1449
+ if __name__ == "__main__":
1450
+ query = Select(
1451
+ 'Installments i', due_date=Field, customer=Select(
1452
+ 'Customer c', id=PrimaryKey,
1453
+ name=contains('Smith', Position.EndsWith)
1454
+ )
1455
+ )
1456
+ print(query)
1457
+ print('-----')
1458
+ query.optimize([RuleReplaceJoinBySubselect])
1459
+ print(query)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.25.109
3
+ Version: 1.25.111
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
@@ -97,8 +97,13 @@ query = Select('Movie m', title=Field,
97
97
  genre=eq("Sci-Fi"),
98
98
  awards=contains("Oscar")
99
99
  )
100
+ AND=Options(
101
+ ..., name=contains(
102
+ 'Chris',
103
+ Position.StartsWith
104
+ )
105
+ )
100
106
  ```
101
- > Could be AND=Options(...)
102
107
 
103
108
  3.4 -- Negative conditions use the _Not_ class instead of _Where_
104
109
  ```
@@ -363,6 +368,35 @@ m2 = Select(
363
368
 
364
369
  > The method allows you to select which rules you want to apply in the optimization...Or define your own rules!
365
370
 
371
+ >> NOTE: When a joined table is used only as a filter, it is possible that it can be changed to a sub-query:
372
+
373
+ query = Select(
374
+ 'Installments i', due_date=Field, customer=Select(
375
+ 'Customer c', id=PrimaryKey,
376
+ name=contains('Smith', Position.EndsWith)
377
+ )
378
+ )
379
+ print(query)
380
+ print('-----')
381
+ query.optimize([RuleReplaceJoinBySubselect])
382
+ print(query)
383
+ ```
384
+ SELECT
385
+ i.due_date
386
+ FROM
387
+ Installments i
388
+ JOIN Customer c ON (i.customer = c.id)
389
+ WHERE
390
+ c.name LIKE '%Smith'
391
+ -----
392
+ SELECT
393
+ i.due_date
394
+ FROM
395
+ Installments i
396
+ WHERE
397
+ i.customer IN (SELECT c.id FROM Customer c WHERE c.name LIKE '%Smith')
398
+ ```
399
+
366
400
  ---
367
401
 
368
402
  ### 12 - Adding multiple fields at once
@@ -567,3 +601,21 @@ GROUP BY
567
601
  ORDER BY
568
602
  customer_count
569
603
  ```
604
+ ---
605
+ ### 16 - Function classes
606
+ You may use this functions:
607
+ * SubString
608
+ * Round
609
+ * DateDiff
610
+ * Year
611
+ * Current_Date
612
+ * Avg
613
+ * Min
614
+ * Max
615
+ * Sum
616
+ * Count
617
+ > Some of these functions may vary in syntax depending on the database.
618
+ For example, if your query is going to run on Oracle, do the following:
619
+
620
+ `Function.dialect = Dialect.ORACLE`
621
+
@@ -0,0 +1,7 @@
1
+ sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
+ sql_blocks/sql_blocks.py,sha256=rARGbJxL3Di9mOXRBS4aEFvclO922-dzDOXPy1vSTGg,49018
3
+ sql_blocks-1.25.111.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.111.dist-info/METADATA,sha256=Lm7JKPIdZSJT5dkWUc2K7fpY4r0MQ-TeTyv0pbiMy24,14581
5
+ sql_blocks-1.25.111.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.111.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.111.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=OnIlTb03DTgK_U8QBnXQtQ-rKrkSuKNj1hjJiHogmYE,47639
3
- sql_blocks-1.25.109.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-1.25.109.dist-info/METADATA,sha256=TRybMQgmXhlz14FxEV6f4rg0-gTPpveyQi3xEYPdZ1w,13425
5
- sql_blocks-1.25.109.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-1.25.109.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-1.25.109.dist-info/RECORD,,