sql-blocks 1.25.37022003__py3-none-any.whl → 1.25.312022057__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
@@ -196,17 +196,35 @@ class Dialect(Enum):
196
196
  POSTGRESQL = 3
197
197
  MYSQL = 4
198
198
 
199
+ SQL_TYPES = 'CHAR INT DATE FLOAT ANY'.split()
200
+ CHAR, INT, DATE, FLOAT, ANY = SQL_TYPES
201
+
199
202
  class Function:
200
203
  dialect = Dialect.ANSI
201
- need_params = True
204
+ inputs = None
205
+ output = None
202
206
  separator = ', '
207
+ auto_convert = True
208
+ append_param = False
203
209
 
204
210
  def __init__(self, *params: list):
211
+ def set_func_types(param):
212
+ if self.auto_convert and isinstance(param, Function):
213
+ func = param
214
+ main_param = self.inputs[0]
215
+ unfriendly = all([
216
+ func.output != main_param,
217
+ func.output != ANY,
218
+ main_param != ANY
219
+ ])
220
+ if unfriendly:
221
+ return Cast(func, main_param)
222
+ return param
205
223
  # --- Replace class methods by instance methods: ------
206
224
  self.add = self.__add
207
225
  self.format = self.__format
208
226
  # -----------------------------------------------------
209
- self.params = list(params)
227
+ self.params = [set_func_types(p) for p in params]
210
228
  self.field_class = Field
211
229
  self.pattern = self.get_pattern()
212
230
  self.extra = {}
@@ -226,17 +244,28 @@ class Function:
226
244
  params=self.separator.join(str(p) for p in self.params)
227
245
  )
228
246
 
247
+ @classmethod
248
+ def help(cls) -> str:
249
+ descr = ' '.join(B.__name__ for B in cls.__bases__)
250
+ params = cls.inputs or ''
251
+ return cls().get_pattern().format(
252
+ func_name=f'{descr} {cls.__name__}',
253
+ params=cls.separator.join(str(p) for p in params)
254
+ ) + f' Return {cls.output}'
255
+
229
256
  def set_main_param(self, name: str, main: SQLObject) -> bool:
230
257
  nested_functions = [
231
258
  param for param in self.params if isinstance(param, Function)
232
259
  ]
233
260
  for func in nested_functions:
234
- if func.need_params:
261
+ if func.inputs:
235
262
  func.set_main_param(name, main)
236
263
  return
237
- self.params = [
238
- Field.format(name, main)
239
- ] + self.params
264
+ new_params = [Field.format(name, main)]
265
+ if self.append_param:
266
+ self.params += new_params
267
+ else:
268
+ self.params = new_params + self.params
240
269
 
241
270
  def __format(self, name: str, main: SQLObject) -> str:
242
271
  if name not in '*_':
@@ -260,6 +289,9 @@ class Function:
260
289
 
261
290
  # ---- String Functions: ---------------------------------
262
291
  class SubString(Function):
292
+ inputs = [CHAR, INT, INT]
293
+ output = CHAR
294
+
263
295
  def get_pattern(self) -> str:
264
296
  if self.dialect in (Dialect.ORACLE, Dialect.MYSQL):
265
297
  return 'Substr({params})'
@@ -267,33 +299,54 @@ class SubString(Function):
267
299
 
268
300
  # ---- Numeric Functions: --------------------------------
269
301
  class Round(Function):
270
- ...
302
+ inputs = [FLOAT]
303
+ output = FLOAT
271
304
 
272
305
  # --- Date Functions: ------------------------------------
273
306
  class DateDiff(Function):
274
- def get_pattern(self) -> str:
307
+ inputs = [DATE]
308
+ output = DATE
309
+ append_param = True
310
+
311
+ def __str__(self) -> str:
275
312
  def is_field_or_func(name: str) -> bool:
276
- return re.sub('[()]', '', name).isidentifier()
277
- params = [str(p) for p in self.params]
313
+ candidate = re.sub(
314
+ '[()]', '', name.split('.')[-1]
315
+ )
316
+ return candidate.isidentifier()
278
317
  if self.dialect != Dialect.SQL_SERVER:
318
+ params = [str(p) for p in self.params]
279
319
  return ' - '.join(
280
320
  p if is_field_or_func(p) else f"'{p}'"
281
321
  for p in params
282
322
  ) # <==== Date subtract
283
- return super().get_pattern()
323
+ return super().__str__()
324
+
325
+
326
+ class DatePart(Function):
327
+ inputs = [DATE]
328
+ output = INT
284
329
 
285
- class Year(Function):
286
330
  def get_pattern(self) -> str:
331
+ interval = self.__class__.__name__
287
332
  database_type = {
288
- Dialect.ORACLE: 'Extract(YEAR FROM {params})',
289
- Dialect.POSTGRESQL: "Date_Part('year', {params})",
333
+ Dialect.ORACLE: 'Extract('+interval+' FROM {params})',
334
+ Dialect.POSTGRESQL: "Date_Part('"+interval+"', {params})",
290
335
  }
291
336
  if self.dialect in database_type:
292
337
  return database_type[self.dialect]
293
338
  return super().get_pattern()
294
339
 
340
+ class Year(DatePart):
341
+ ...
342
+ class Month(DatePart):
343
+ ...
344
+ class Day(DatePart):
345
+ ...
346
+
347
+
295
348
  class Current_Date(Function):
296
- need_params = False
349
+ output = DATE
297
350
 
298
351
  def get_pattern(self) -> str:
299
352
  database_type = {
@@ -334,7 +387,8 @@ class Frame:
334
387
 
335
388
 
336
389
  class Aggregate(Frame):
337
- ...
390
+ inputs = [FLOAT]
391
+ output = FLOAT
338
392
 
339
393
  class Window(Frame):
340
394
  ...
@@ -353,19 +407,26 @@ class Count(Aggregate, Function):
353
407
 
354
408
  # ---- Window Functions: -----------------------------------
355
409
  class Row_Number(Window, Function):
356
- ...
410
+ output = INT
411
+
357
412
  class Rank(Window, Function):
358
- ...
413
+ output = INT
414
+
359
415
  class Lag(Window, Function):
360
- ...
416
+ output = ANY
417
+
361
418
  class Lead(Window, Function):
362
- ...
419
+ output = ANY
363
420
 
364
421
 
365
422
  # ---- Conversions and other Functions: ---------------------
366
423
  class Coalesce(Function):
367
- ...
424
+ inputs = [ANY]
425
+ output = ANY
426
+
368
427
  class Cast(Function):
428
+ inputs = [ANY]
429
+ output = ANY
369
430
  separator = ' As '
370
431
 
371
432
 
@@ -1393,15 +1454,18 @@ class Select(SQLObject):
1393
1454
 
1394
1455
  def add(self, name: str, main: SQLObject):
1395
1456
  old_tables = main.values.get(FROM, [])
1396
- new_tables = set([
1397
- '{jt}JOIN {tb} {a2} ON ({a1}.{f1} = {a2}.{f2})'.format(
1457
+ if len(self.values[FROM]) > 1:
1458
+ old_tables += self.values[FROM][1:]
1459
+ new_tables = []
1460
+ row = '{jt}JOIN {tb} {a2} ON ({a1}.{f1} = {a2}.{f2})'.format(
1398
1461
  jt=self.join_type.value,
1399
1462
  tb=self.aka(),
1400
1463
  a1=main.alias, f1=name,
1401
1464
  a2=self.alias, f2=self.key_field
1402
1465
  )
1403
- ] + old_tables[1:])
1404
- main.values[FROM] = old_tables[:1] + list(new_tables)
1466
+ if row not in old_tables[1:]:
1467
+ new_tables.append(row)
1468
+ main.values[FROM] = old_tables[:1] + new_tables + old_tables[1:]
1405
1469
  for key in USUAL_KEYS:
1406
1470
  main.update_values(key, self.values.get(key, []))
1407
1471
 
@@ -1521,7 +1585,7 @@ class CTE(Select):
1521
1585
  result, line = [], ''
1522
1586
  keywords = '|'.join(KEYWORD)
1523
1587
  for word in re.split(fr'({keywords}|AND|OR|,)', str(query)):
1524
- if len(line) >= 60:
1588
+ if len(line) >= 50:
1525
1589
  result.append(line)
1526
1590
  line = ''
1527
1591
  line += word
@@ -1728,4 +1792,31 @@ def detect(text: str, join_queries: bool = True, format: str='') -> Select | lis
1728
1792
  for query in query_list[1:]:
1729
1793
  result += query
1730
1794
  return result
1731
- # ===========================================================================================//
1795
+ # ===========================================================================================//
1796
+
1797
+ if __name__ == "__main__":
1798
+ print('='*50)
1799
+ visitante = Select(
1800
+ 'Pessoa p1',
1801
+ nome=NamedField('nome_visitante'),
1802
+ tipo=eq('V'), cpf=PrimaryKey
1803
+ )
1804
+ dono_do_apto = Select(
1805
+ 'Apartamento A',
1806
+ dono=Select(
1807
+ 'Pessoa p2',
1808
+ cpf=PrimaryKey,
1809
+ nome=NamedField('nome_morador')
1810
+ ),
1811
+ id=PrimaryKey
1812
+ )
1813
+ movimento = Select(
1814
+ 'Movimento M',
1815
+ entrada_saida=eq('E'),
1816
+ apartamento=dono_do_apto,
1817
+ pessoa=visitante
1818
+ )
1819
+ print(dono_do_apto)
1820
+ print('-'*50)
1821
+ print(movimento)
1822
+ print('='*50)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sql_blocks
3
- Version: 1.25.37022003
3
+ Version: 1.25.312022057
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
@@ -693,6 +693,22 @@ Results...
693
693
  SELECT ...
694
694
  SubString(Cast(event_date As char), 12, 19) as time
695
695
  ```
696
+
697
+ >> `Function.auto_convert` option (default: True)
698
+
699
+ - Put Cast(...) when there is a difference between the types of the parameter and the return of the nested function
700
+ ```
701
+ birth=Round( DateDiff(Current_Date()) ).As('age')
702
+ ```
703
+ ...Returns...
704
+ ```
705
+ SELECT
706
+ Round(
707
+ Cast(Current_Date() - p.birth As FLOAT)
708
+ /* ^^^ */
709
+ ) as age
710
+ ...
711
+ ```
696
712
  ---
697
713
 
698
714
  ### 17 - CTE and Recursive classes
@@ -0,0 +1,7 @@
1
+ sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
+ sql_blocks/sql_blocks.py,sha256=ICqvEtrB1xnCqquTyTgDX-O9hkeeysQLcLz9pdkFBYs,60671
3
+ sql_blocks-1.25.312022057.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
+ sql_blocks-1.25.312022057.dist-info/METADATA,sha256=VCXJmWhUPrpSd5dD_Jj5JeXnr2D5XLQNnXMYkWRsN0g,20512
5
+ sql_blocks-1.25.312022057.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
+ sql_blocks-1.25.312022057.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
+ sql_blocks-1.25.312022057.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- sql_blocks/__init__.py,sha256=5ItzGCyqqa6kwY8wvF9kapyHsAiWJ7KEXCcC-OtdXKg,37
2
- sql_blocks/sql_blocks.py,sha256=kaI6nCcq1X3CenGFP4HkKkk3rsDt_jts8xErg-ml7dk,58217
3
- sql_blocks-1.25.37022003.dist-info/LICENSE,sha256=6kbiFSfobTZ7beWiKnHpN902HgBx-Jzgcme0SvKqhKY,1091
4
- sql_blocks-1.25.37022003.dist-info/METADATA,sha256=AUa01HeqYtgwVObYWMTkqixy0RNoxwNQXurTMEWjjQ8,20146
5
- sql_blocks-1.25.37022003.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
6
- sql_blocks-1.25.37022003.dist-info/top_level.txt,sha256=57AbUvUjYNy4m1EqDaU3WHeP-uyIAfV0n8GAUp1a1YQ,11
7
- sql_blocks-1.25.37022003.dist-info/RECORD,,