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 +118 -27
- {sql_blocks-1.25.37022003.dist-info → sql_blocks-1.25.312022057.dist-info}/METADATA +17 -1
- sql_blocks-1.25.312022057.dist-info/RECORD +7 -0
- sql_blocks-1.25.37022003.dist-info/RECORD +0 -7
- {sql_blocks-1.25.37022003.dist-info → sql_blocks-1.25.312022057.dist-info}/LICENSE +0 -0
- {sql_blocks-1.25.37022003.dist-info → sql_blocks-1.25.312022057.dist-info}/WHEEL +0 -0
- {sql_blocks-1.25.37022003.dist-info → sql_blocks-1.25.312022057.dist-info}/top_level.txt +0 -0
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
|
-
|
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 =
|
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.
|
261
|
+
if func.inputs:
|
235
262
|
func.set_main_param(name, main)
|
236
263
|
return
|
237
|
-
|
238
|
-
|
239
|
-
|
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
|
-
|
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
|
-
|
277
|
-
|
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().
|
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(
|
289
|
-
Dialect.POSTGRESQL: "Date_Part('
|
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
|
-
|
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
|
-
|
1397
|
-
|
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
|
-
|
1404
|
-
|
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) >=
|
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.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|