sql-blocks 0.31.89__py3-none-any.whl → 1.25.1__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
@@ -22,6 +22,7 @@ KEYWORD = {
22
22
 
23
23
  SELECT, FROM, WHERE, GROUP_BY, ORDER_BY, LIMIT = KEYWORD.keys()
24
24
  USUAL_KEYS = [SELECT, WHERE, GROUP_BY, ORDER_BY, LIMIT]
25
+ TO_LIST = lambda x: x if isinstance(x, list) else [x]
25
26
 
26
27
 
27
28
  class SQLObject:
@@ -110,9 +111,6 @@ class SQLObject:
110
111
  self.values[key] = result
111
112
 
112
113
 
113
- class Function:
114
- ...
115
-
116
114
  class Field:
117
115
  prefix = ''
118
116
 
@@ -134,17 +132,6 @@ class Field:
134
132
  )
135
133
 
136
134
 
137
- class Avg(Function, Field):
138
- ...
139
- class Min(Function, Field):
140
- ...
141
- class Max(Function, Field):
142
- ...
143
- class Sum(Function, Field):
144
- ...
145
- class Count(Function, Field):
146
- ...
147
-
148
135
  class Distinct(Field):
149
136
  prefix = 'DISTINCT '
150
137
 
@@ -163,6 +150,106 @@ class NamedField:
163
150
  )
164
151
 
165
152
 
153
+ class Function:
154
+ instance: dict = {}
155
+
156
+ def __init__(self, *params: list):
157
+ func_name = self.__class__.__name__
158
+ Function.instance[func_name] = self
159
+ self.params = [str(p) for p in params]
160
+ self.class_type = Field
161
+ self.pattern = '{}({})'
162
+ self.extra = {}
163
+
164
+ def As(self, field_alias: str, modifiers=None):
165
+ if modifiers:
166
+ self.extra[field_alias] = TO_LIST(modifiers)
167
+ self.class_type = NamedField(field_alias)
168
+ return self
169
+
170
+ @classmethod
171
+ def format(cls, name: str, main: SQLObject) -> str:
172
+ obj = cls.get_instance()
173
+ params = [
174
+ Field.format(name, main)
175
+ ] + obj.params
176
+ return obj.pattern.format(
177
+ cls.__name__,
178
+ ', '.join(params)
179
+ )
180
+
181
+ def __add(self, name: str, main: SQLObject):
182
+ name = self.format(name, main)
183
+ self.class_type.add(name, main)
184
+ if self.extra:
185
+ main.__call__(**self.extra)
186
+
187
+ @classmethod
188
+ def get_instance(cls):
189
+ obj = Function.instance.get(cls.__name__)
190
+ if not obj:
191
+ obj = cls()
192
+ return obj
193
+
194
+ @classmethod
195
+ def add(cls, name: str, main: SQLObject):
196
+ cls.get_instance().__add(name, main)
197
+
198
+
199
+ # ---- String Functions: ---------------------------------
200
+ class SubString(Function):
201
+ ...
202
+
203
+ # ---- Numeric Functions: --------------------------------
204
+ class Round(Function):
205
+ ...
206
+
207
+ # --- Date Functions: ------------------------------------
208
+ class DateDiff(Function):
209
+ ...
210
+ class Extract(Function):
211
+ ...
212
+ class DatePart(Function):
213
+ ...
214
+ class Current_Date(Function):
215
+ ...
216
+
217
+ class Aggregate:
218
+ break_lines: bool = True
219
+
220
+ def over(self, **args):
221
+ keywords = ' '.join(
222
+ '{}{} BY {}'.format(
223
+ '\n\t\t' if self.break_lines else '',
224
+ key.upper(), args[key]
225
+ ) for key in ('partition', 'order')
226
+ if key in args
227
+ )
228
+ if keywords and self.break_lines:
229
+ keywords += '\n\t'
230
+ self.pattern = '{}({})' + f' OVER({keywords})'
231
+ return self
232
+
233
+
234
+ # ---- Aggregate Functions: -------------------------------
235
+ class Avg(Aggregate, Function):
236
+ ...
237
+ class Min(Aggregate, Function):
238
+ ...
239
+ class Max(Aggregate, Function):
240
+ ...
241
+ class Sum(Aggregate, Function):
242
+ ...
243
+ class Count(Aggregate, Function):
244
+ ...
245
+
246
+ # ---- Conversions and other Functions: ---------------------
247
+ class Coalesce(Function):
248
+ ...
249
+ class Cast(Function):
250
+ ...
251
+
252
+
166
253
  class ExpressionField:
167
254
  def __init__(self, expr: str):
168
255
  self.expr = expr
@@ -361,14 +448,9 @@ class Between:
361
448
  Where.lte(self.end).add(name, main)
362
449
 
363
450
 
364
- class SortType(Enum):
365
- ASC = ''
366
- DESC = ' DESC'
367
-
368
- class OrderBy:
369
- sort: SortType = SortType.ASC
451
+ class Clause:
370
452
  @classmethod
371
- def add(cls, name: str, main: SQLObject):
453
+ def format(cls, name: str, main: SQLObject) -> str:
372
454
  def is_function() -> bool:
373
455
  diff = main.diff(SELECT, [name.lower()], True)
374
456
  FUNCTION_CLASS = {f.__name__.lower(): f for f in Function.__subclasses__()}
@@ -378,13 +460,28 @@ class OrderBy:
378
460
  name = found[0].replace('_', '')
379
461
  elif main.alias and not is_function():
380
462
  name = f'{main.alias}.{name}'
463
+ return name
464
+
465
+
466
+ class SortType(Enum):
467
+ ASC = ''
468
+ DESC = ' DESC'
469
+
470
+
471
+ class OrderBy(Clause):
472
+ sort: SortType = SortType.ASC
473
+
474
+ @classmethod
475
+ def add(cls, name: str, main: SQLObject):
476
+ name = cls.format(name, main)
381
477
  main.values.setdefault(ORDER_BY, []).append(name+cls.sort.value)
382
478
 
383
479
 
384
- class GroupBy:
385
- @staticmethod
386
- def add(name: str, main: SQLObject):
387
- main.values.setdefault(GROUP_BY, []).append(f'{main.alias}.{name}')
480
+ class GroupBy(Clause):
481
+ @classmethod
482
+ def add(cls, name: str, main: SQLObject):
483
+ name = cls.format(name, main)
484
+ main.values.setdefault(GROUP_BY, []).append(name)
388
485
 
389
486
 
390
487
  class Having:
@@ -1095,9 +1192,8 @@ class Select(SQLObject):
1095
1192
  return self.translate_to(QueryLanguage)
1096
1193
 
1097
1194
  def __call__(self, **values):
1098
- to_list = lambda x: x if isinstance(x, list) else [x]
1099
1195
  for name, params in values.items():
1100
- for obj in to_list(params):
1196
+ for obj in TO_LIST(params):
1101
1197
  obj.add(name, self)
1102
1198
  return self
1103
1199
 
@@ -1260,22 +1356,3 @@ def detect(text: str) -> Select:
1260
1356
  for query in query_list[1:]:
1261
1357
  result += query
1262
1358
  return result
1263
-
1264
-
1265
- if __name__ == "__main__":
1266
- print('░▒▓▒░'*20)
1267
- p, c, a = Select.parse(
1268
- '''
1269
- Professor(?nome="Júlio Cascalles", id)
1270
- <- Curso@disciplina(professor, aluno) ->
1271
- Aluno(id ^count$qtd_alunos)
1272
- ''', CypherParser
1273
- )
1274
- print(p)
1275
- print('-'*50)
1276
- print(c)
1277
- print('-'*50)
1278
- print(a)
1279
- print('='*50)
1280
- print(a + c + p)
1281
- print('░▒▓▒░'*20)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 0.31.89
3
+ Version: 1.25.1
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
@@ -427,7 +427,7 @@ ORDER BY
427
427
  It is useful to write a query in a few lines, without specifying the script type (cypher, mongoDB, SQL, Neo4J...)
428
428
  ### Examples:
429
429
 
430
- > **1 - Relationship**
430
+ > **13.1 - Relationship**
431
431
  ```
432
432
  query = detect(
433
433
  'MATCH(c:Customer)<-[:Order]->(p:Product)RETURN c, p'
@@ -439,7 +439,7 @@ print(query)
439
439
  Order ord
440
440
  LEFT JOIN Customer cus ON (ord.customer_id = cus.id)
441
441
  RIGHT JOIN Product pro ON (ord.product_id = pro.id)
442
- > **2 - Grouping**
442
+ > **13.2 - Grouping**
443
443
  ```
444
444
  query = detect(
445
445
  'People@gender(avg$age?region="SOUTH"^count$qtde)'
@@ -460,7 +460,7 @@ print(query)
460
460
  ORDER BY
461
461
  peo.qtde
462
462
 
463
- > **3 - Many conditions...**
463
+ > **13.3 - Many conditions...**
464
464
  ```
465
465
  print( detect('''
466
466
  db.people.find({
@@ -491,7 +491,7 @@ print(query)
491
491
  ORDER BY
492
492
  peo.user_id DESC
493
493
 
494
- > **4 - Relations with same table twice (or more)**
494
+ > **13.4 - Relations with same table twice (or more)**
495
495
 
496
496
  Automatically assigns aliases to each side of the relationship (In this example, one user invites another to add to their contact list)
497
497
  ```
@@ -516,3 +516,54 @@ It consists of the inverse process of parsing: From a Select object, it returns
516
516
  * QueryLanguage - default
517
517
  * MongoDBLanguage
518
518
  * Neo4JLanguage
519
+
520
+ ---
521
+ ### 14 - Window Function
522
+
523
+ Aggregation functions (Avg, Min, Max, Sum, Count) have the **over** method...
524
+
525
+ query=Select(
526
+ 'Enrollment e',
527
+ payment=Sum().over(
528
+ partition='student_id', order='due_date'
529
+ ).As('sum_per_student')
530
+ )
531
+
532
+ ...that generates the following query:
533
+
534
+ ```
535
+ SELECT
536
+ Sum(e.payment) OVER(
537
+ PARTITION BY student_id
538
+ ORDER BY due_date
539
+ ) as sum_per_student
540
+ FROM
541
+ Enrollment e
542
+ ```
543
+ ---
544
+ ### 15 - The `As` method:
545
+ query=Select(
546
+ 'Customers c',
547
+ phone=[
548
+ Not.is_null(),
549
+ SubString(1, 4).As('area_code', GroupBy)
550
+ ],
551
+ customer_id=[
552
+ Count().As('customer_count', OrderBy),
553
+ Having.count(gt(5))
554
+ ]
555
+ )
556
+ You can use the result of a function as a new field -- and optionally use it in ORDER BY and/or GROUP BY clause(s):
557
+ ```
558
+ SELECT
559
+ SubString(c.phone, 1, 4) as area_code,
560
+ Count(c.customer_id) as customer_count
561
+ FROM
562
+ Customers c
563
+ WHERE
564
+ NOT c.phone IS NULL
565
+ GROUP BY
566
+ area_code HAVING Count(c.customer_id) > 5
567
+ ORDER BY
568
+ customer_count
569
+ ```
@@ -0,0 +1,7 @@
1
+ sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
+ sql_blocks/sql_blocks.py,sha256=JYATgw-J3SzAVCYZpdNGyc7rK700jHJtOWbK9gxywu4,45466
3
+ sql_blocks-1.25.1.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.1.dist-info/METADATA,sha256=k6Xd3FtNhl3KHAOzVA0zkx5TvQdcb2P5st6-fEm7r4M,13423
5
+ sql_blocks-1.25.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.1.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.1.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=nsIT8JEeYHw3KIkzAUHUdzUAR_i2asJmdytsvW0hYKc,43342
3
- sql_blocks-0.31.89.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-0.31.89.dist-info/METADATA,sha256=xKHVfM76nzvZBr-TYC5_PN4bAvYW9oWoi5ChPIPdbDE,12202
5
- sql_blocks-0.31.89.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-0.31.89.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-0.31.89.dist-info/RECORD,,