python-sql 1.5.1__py3-none-any.whl → 1.6.0__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.
- {python_sql-1.5.1.dist-info → python_sql-1.6.0.dist-info}/METADATA +23 -11
- python_sql-1.6.0.dist-info/RECORD +41 -0
- {python_sql-1.5.1.dist-info → python_sql-1.6.0.dist-info}/WHEEL +1 -1
- sql/__init__.py +178 -105
- sql/aggregate.py +21 -6
- sql/functions.py +9 -8
- sql/operators.py +6 -3
- sql/tests/__init__.py +1 -1
- sql/tests/test_aggregate.py +25 -1
- sql/tests/test_alias.py +15 -0
- sql/tests/test_collate.py +0 -5
- sql/tests/test_combining_query.py +5 -1
- sql/tests/test_delete.py +21 -1
- sql/tests/test_excluded.py +15 -0
- sql/tests/test_expression.py +17 -0
- sql/tests/test_flavor.py +46 -0
- sql/tests/test_for.py +4 -0
- sql/tests/test_from.py +25 -0
- sql/tests/test_from_item.py +46 -0
- sql/tests/test_functions.py +17 -1
- sql/tests/test_grouping.py +13 -0
- sql/tests/test_insert.py +57 -1
- sql/tests/test_join.py +23 -0
- sql/tests/test_lateral.py +1 -1
- sql/tests/test_merge.py +43 -5
- sql/tests/test_operators.py +20 -1
- sql/tests/test_order.py +16 -7
- sql/tests/test_rollup.py +13 -0
- sql/tests/test_select.py +69 -3
- sql/tests/test_update.py +8 -0
- sql/tests/test_window.py +24 -0
- sql/tests/test_with.py +4 -0
- python_sql-1.5.1.dist-info/RECORD +0 -34
- {python_sql-1.5.1.dist-info → python_sql-1.6.0.dist-info}/top_level.txt +0 -0
sql/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ from collections import defaultdict
|
|
|
7
7
|
from itertools import chain
|
|
8
8
|
from threading import current_thread, local
|
|
9
9
|
|
|
10
|
-
__version__ = '1.
|
|
10
|
+
__version__ = '1.6.0'
|
|
11
11
|
__all__ = [
|
|
12
12
|
'Flavor', 'Table', 'Values', 'Literal', 'Column', 'Grouping', 'Conflict',
|
|
13
13
|
'Matched', 'MatchedUpdate', 'MatchedDelete',
|
|
@@ -62,17 +62,23 @@ class Flavor(object):
|
|
|
62
62
|
def __init__(self, limitstyle='limit', max_limit=None, paramstyle='format',
|
|
63
63
|
ilike=False, no_as=False, no_boolean=False, null_ordering=True,
|
|
64
64
|
function_mapping=None, filter_=False, escape_empty=False):
|
|
65
|
-
|
|
65
|
+
if limitstyle not in {'fetch', 'limit', 'rownum'}:
|
|
66
|
+
raise ValueError("unsupported limitstyle: %r" % limitstyle)
|
|
66
67
|
self.limitstyle = limitstyle
|
|
68
|
+
if (max_limit is not None
|
|
69
|
+
and not isinstance(max_limit, numbers.Integral)):
|
|
70
|
+
raise ValueError("unsupported max_limit: %r" % max_limit)
|
|
67
71
|
self.max_limit = max_limit
|
|
72
|
+
if paramstyle not in {'format', 'qmark'}:
|
|
73
|
+
raise ValueError("unsupported paramstyle: %r" % paramstyle)
|
|
68
74
|
self.paramstyle = paramstyle
|
|
69
|
-
self.ilike = ilike
|
|
70
|
-
self.no_as = no_as
|
|
71
|
-
self.no_boolean = no_boolean
|
|
72
|
-
self.null_ordering = null_ordering
|
|
73
|
-
self.function_mapping = function_mapping or {}
|
|
74
|
-
self.filter_ = filter_
|
|
75
|
-
self.escape_empty = escape_empty
|
|
75
|
+
self.ilike = bool(ilike)
|
|
76
|
+
self.no_as = bool(no_as)
|
|
77
|
+
self.no_boolean = bool(no_boolean)
|
|
78
|
+
self.null_ordering = bool(null_ordering)
|
|
79
|
+
self.function_mapping = dict(function_mapping or {})
|
|
80
|
+
self.filter_ = bool(filter_)
|
|
81
|
+
self.escape_empty = bool(escape_empty)
|
|
76
82
|
|
|
77
83
|
@property
|
|
78
84
|
def param(self):
|
|
@@ -176,7 +182,7 @@ def format2numeric(query, params):
|
|
|
176
182
|
|
|
177
183
|
|
|
178
184
|
class Query(object):
|
|
179
|
-
__slots__ = ()
|
|
185
|
+
__slots__ = ('__weakref__',)
|
|
180
186
|
|
|
181
187
|
@property
|
|
182
188
|
def params(self):
|
|
@@ -213,7 +219,8 @@ class WithQuery(Query):
|
|
|
213
219
|
if value is not None:
|
|
214
220
|
if isinstance(value, With):
|
|
215
221
|
value = [value]
|
|
216
|
-
|
|
222
|
+
if any(not isinstance(w, With) for w in value):
|
|
223
|
+
raise ValueError("invalid with: %r" % value)
|
|
217
224
|
self._with = value
|
|
218
225
|
|
|
219
226
|
def _with_str(self):
|
|
@@ -236,7 +243,7 @@ class WithQuery(Query):
|
|
|
236
243
|
|
|
237
244
|
|
|
238
245
|
class FromItem(object):
|
|
239
|
-
__slots__ = ()
|
|
246
|
+
__slots__ = ('__weakref__',)
|
|
240
247
|
|
|
241
248
|
@property
|
|
242
249
|
def alias(self):
|
|
@@ -252,7 +259,8 @@ class FromItem(object):
|
|
|
252
259
|
return Column(self, name)
|
|
253
260
|
|
|
254
261
|
def __add__(self, other):
|
|
255
|
-
|
|
262
|
+
if not isinstance(other, FromItem):
|
|
263
|
+
return NotImplemented
|
|
256
264
|
return From((self, other))
|
|
257
265
|
|
|
258
266
|
def select(self, *args, **kwargs):
|
|
@@ -348,7 +356,8 @@ class SelectQuery(WithQuery):
|
|
|
348
356
|
if value is not None:
|
|
349
357
|
if isinstance(value, Expression):
|
|
350
358
|
value = [value]
|
|
351
|
-
|
|
359
|
+
if any(not isinstance(col, Expression) for col in value):
|
|
360
|
+
raise ValueError("invalid order by: %r" % value)
|
|
352
361
|
self._order_by = value
|
|
353
362
|
|
|
354
363
|
@property
|
|
@@ -365,7 +374,8 @@ class SelectQuery(WithQuery):
|
|
|
365
374
|
@limit.setter
|
|
366
375
|
def limit(self, value):
|
|
367
376
|
if value is not None:
|
|
368
|
-
|
|
377
|
+
if not isinstance(value, numbers.Integral):
|
|
378
|
+
raise ValueError("invalid limit: %r" % value)
|
|
369
379
|
self._limit = value
|
|
370
380
|
|
|
371
381
|
@property
|
|
@@ -375,7 +385,8 @@ class SelectQuery(WithQuery):
|
|
|
375
385
|
@offset.setter
|
|
376
386
|
def offset(self, value):
|
|
377
387
|
if value is not None:
|
|
378
|
-
|
|
388
|
+
if not isinstance(value, numbers.Integral):
|
|
389
|
+
raise ValueError("invalid offset: %r" % value)
|
|
379
390
|
self._offset = value
|
|
380
391
|
|
|
381
392
|
@property
|
|
@@ -464,7 +475,8 @@ class Select(FromItem, SelectQuery):
|
|
|
464
475
|
if value is not None:
|
|
465
476
|
if isinstance(value, Expression):
|
|
466
477
|
value = [value]
|
|
467
|
-
|
|
478
|
+
if any(not isinstance(col, Expression) for col in value):
|
|
479
|
+
raise ValueError("invalid distinct on: %r" % value)
|
|
468
480
|
self._distinct_on = value
|
|
469
481
|
|
|
470
482
|
@property
|
|
@@ -473,7 +485,10 @@ class Select(FromItem, SelectQuery):
|
|
|
473
485
|
|
|
474
486
|
@columns.setter
|
|
475
487
|
def columns(self, value):
|
|
476
|
-
|
|
488
|
+
if any(
|
|
489
|
+
not isinstance(col, (Expression, SelectQuery))
|
|
490
|
+
for col in value):
|
|
491
|
+
raise ValueError("invalid columns: %r" % value)
|
|
477
492
|
self._columns = tuple(value)
|
|
478
493
|
|
|
479
494
|
@property
|
|
@@ -484,7 +499,8 @@ class Select(FromItem, SelectQuery):
|
|
|
484
499
|
def where(self, value):
|
|
485
500
|
from sql.operators import And, Or
|
|
486
501
|
if value is not None:
|
|
487
|
-
|
|
502
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
503
|
+
raise ValueError("invalid where: %r" % value)
|
|
488
504
|
self._where = value
|
|
489
505
|
|
|
490
506
|
@property
|
|
@@ -496,7 +512,8 @@ class Select(FromItem, SelectQuery):
|
|
|
496
512
|
if value is not None:
|
|
497
513
|
if isinstance(value, Expression):
|
|
498
514
|
value = [value]
|
|
499
|
-
|
|
515
|
+
if any(not isinstance(col, Expression) for col in value):
|
|
516
|
+
raise ValueError("invalid group by: %r" % value)
|
|
500
517
|
self._group_by = value
|
|
501
518
|
|
|
502
519
|
@property
|
|
@@ -507,7 +524,8 @@ class Select(FromItem, SelectQuery):
|
|
|
507
524
|
def having(self, value):
|
|
508
525
|
from sql.operators import And, Or
|
|
509
526
|
if value is not None:
|
|
510
|
-
|
|
527
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
528
|
+
raise ValueError("invalid having: %r" % value)
|
|
511
529
|
self._having = value
|
|
512
530
|
|
|
513
531
|
@property
|
|
@@ -519,7 +537,8 @@ class Select(FromItem, SelectQuery):
|
|
|
519
537
|
if value is not None:
|
|
520
538
|
if isinstance(value, For):
|
|
521
539
|
value = [value]
|
|
522
|
-
|
|
540
|
+
if any(not isinstance(f, For) for f in value):
|
|
541
|
+
raise ValueError("invalid for: %r" % value)
|
|
523
542
|
self._for_ = value
|
|
524
543
|
|
|
525
544
|
@property
|
|
@@ -547,7 +566,8 @@ class Select(FromItem, SelectQuery):
|
|
|
547
566
|
@windows.setter
|
|
548
567
|
def windows(self, value):
|
|
549
568
|
if value is not None:
|
|
550
|
-
|
|
569
|
+
if any(not isinstance(w, Window) for w in value):
|
|
570
|
+
raise ValueError("invalid windows: %r" % value)
|
|
551
571
|
self._windows = value
|
|
552
572
|
|
|
553
573
|
@staticmethod
|
|
@@ -672,13 +692,13 @@ class Select(FromItem, SelectQuery):
|
|
|
672
692
|
if self.group_by:
|
|
673
693
|
for expression in self.group_by:
|
|
674
694
|
p.extend(expression.params)
|
|
675
|
-
if self.order_by:
|
|
676
|
-
for expression in self.order_by:
|
|
677
|
-
p.extend(expression.params)
|
|
678
695
|
if self.having:
|
|
679
696
|
p.extend(self.having.params)
|
|
680
697
|
for window in self.windows:
|
|
681
698
|
p.extend(window.params)
|
|
699
|
+
if self.order_by:
|
|
700
|
+
for expression in self.order_by:
|
|
701
|
+
p.extend(expression.params)
|
|
682
702
|
p.extend(self._limit_offset_params)
|
|
683
703
|
return tuple(p)
|
|
684
704
|
|
|
@@ -707,7 +727,8 @@ class Insert(WithQuery):
|
|
|
707
727
|
|
|
708
728
|
@table.setter
|
|
709
729
|
def table(self, value):
|
|
710
|
-
|
|
730
|
+
if not isinstance(value, Table):
|
|
731
|
+
raise ValueError("invalid table: %r" % value)
|
|
711
732
|
self._table = value
|
|
712
733
|
|
|
713
734
|
@property
|
|
@@ -717,8 +738,10 @@ class Insert(WithQuery):
|
|
|
717
738
|
@columns.setter
|
|
718
739
|
def columns(self, value):
|
|
719
740
|
if value is not None:
|
|
720
|
-
|
|
721
|
-
|
|
741
|
+
if any(
|
|
742
|
+
not isinstance(col, Column) or col.table != self.table
|
|
743
|
+
for col in value):
|
|
744
|
+
raise ValueError("invalid columns: %r" % value)
|
|
722
745
|
self._columns = value
|
|
723
746
|
|
|
724
747
|
@property
|
|
@@ -728,7 +751,8 @@ class Insert(WithQuery):
|
|
|
728
751
|
@values.setter
|
|
729
752
|
def values(self, value):
|
|
730
753
|
if value is not None:
|
|
731
|
-
|
|
754
|
+
if not isinstance(value, (list, Select)):
|
|
755
|
+
raise ValueError("invalid values: %r" % value)
|
|
732
756
|
if isinstance(value, list):
|
|
733
757
|
value = Values(value)
|
|
734
758
|
self._values = value
|
|
@@ -740,8 +764,8 @@ class Insert(WithQuery):
|
|
|
740
764
|
@on_conflict.setter
|
|
741
765
|
def on_conflict(self, value):
|
|
742
766
|
if value is not None:
|
|
743
|
-
|
|
744
|
-
|
|
767
|
+
if not isinstance(value, Conflict) or value.table != self.table:
|
|
768
|
+
raise ValueError("invalid on conflict: %r" % value)
|
|
745
769
|
self._on_conflict = value
|
|
746
770
|
|
|
747
771
|
@property
|
|
@@ -751,7 +775,8 @@ class Insert(WithQuery):
|
|
|
751
775
|
@returning.setter
|
|
752
776
|
def returning(self, value):
|
|
753
777
|
if value is not None:
|
|
754
|
-
|
|
778
|
+
if not isinstance(value, list):
|
|
779
|
+
raise ValueError("invalid returning: %r" % value)
|
|
755
780
|
self._returning = value
|
|
756
781
|
|
|
757
782
|
@staticmethod
|
|
@@ -834,7 +859,8 @@ class Conflict(object):
|
|
|
834
859
|
|
|
835
860
|
@table.setter
|
|
836
861
|
def table(self, value):
|
|
837
|
-
|
|
862
|
+
if not isinstance(value, Table):
|
|
863
|
+
raise ValueError("invalid table: %r" % value)
|
|
838
864
|
self._table = value
|
|
839
865
|
|
|
840
866
|
@property
|
|
@@ -844,8 +870,10 @@ class Conflict(object):
|
|
|
844
870
|
@indexed_columns.setter
|
|
845
871
|
def indexed_columns(self, value):
|
|
846
872
|
if value is not None:
|
|
847
|
-
|
|
848
|
-
|
|
873
|
+
if any(
|
|
874
|
+
not isinstance(col, Column) or col.table != self.table
|
|
875
|
+
for col in value):
|
|
876
|
+
raise ValueError("invalid indexed columns: %r" % value)
|
|
849
877
|
self._indexed_columns = value
|
|
850
878
|
|
|
851
879
|
@property
|
|
@@ -856,7 +884,8 @@ class Conflict(object):
|
|
|
856
884
|
def index_where(self, value):
|
|
857
885
|
from sql.operators import And, Or
|
|
858
886
|
if value is not None:
|
|
859
|
-
|
|
887
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
888
|
+
raise ValueError("invalid index where: %r" % value)
|
|
860
889
|
self._index_where = value
|
|
861
890
|
|
|
862
891
|
@property
|
|
@@ -866,8 +895,10 @@ class Conflict(object):
|
|
|
866
895
|
@columns.setter
|
|
867
896
|
def columns(self, value):
|
|
868
897
|
if value is not None:
|
|
869
|
-
|
|
870
|
-
|
|
898
|
+
if any(
|
|
899
|
+
not isinstance(col, Column) or col.table != self.table
|
|
900
|
+
for col in value):
|
|
901
|
+
raise ValueError("invalid columns: %r" % value)
|
|
871
902
|
self._columns = value
|
|
872
903
|
|
|
873
904
|
@property
|
|
@@ -877,7 +908,8 @@ class Conflict(object):
|
|
|
877
908
|
@values.setter
|
|
878
909
|
def values(self, value):
|
|
879
910
|
if value is not None:
|
|
880
|
-
|
|
911
|
+
if not isinstance(value, (list, Select)):
|
|
912
|
+
raise ValueError("invalid values: %r" % value)
|
|
881
913
|
if isinstance(value, list):
|
|
882
914
|
value = Values([value])
|
|
883
915
|
self._values = value
|
|
@@ -890,7 +922,8 @@ class Conflict(object):
|
|
|
890
922
|
def where(self, value):
|
|
891
923
|
from sql.operators import And, Or
|
|
892
924
|
if value is not None:
|
|
893
|
-
|
|
925
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
926
|
+
raise ValueError("invalid where: %r" % value)
|
|
894
927
|
self._where = value
|
|
895
928
|
|
|
896
929
|
def __str__(self):
|
|
@@ -961,7 +994,8 @@ class Update(Insert):
|
|
|
961
994
|
def values(self, value):
|
|
962
995
|
if isinstance(value, Select):
|
|
963
996
|
value = [value]
|
|
964
|
-
|
|
997
|
+
if not isinstance(value, list):
|
|
998
|
+
raise ValueError("invalid values: %r" % value)
|
|
965
999
|
self._values = value
|
|
966
1000
|
|
|
967
1001
|
@property
|
|
@@ -972,9 +1006,14 @@ class Update(Insert):
|
|
|
972
1006
|
def where(self, value):
|
|
973
1007
|
from sql.operators import And, Or
|
|
974
1008
|
if value is not None:
|
|
975
|
-
|
|
1009
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
1010
|
+
raise ValueError("invalid where: %r" % value)
|
|
976
1011
|
self._where = value
|
|
977
1012
|
|
|
1013
|
+
@staticmethod
|
|
1014
|
+
def _format_column(value):
|
|
1015
|
+
return Select._format_column(value)
|
|
1016
|
+
|
|
978
1017
|
def __str__(self):
|
|
979
1018
|
assert all(col.table == self.table for col in self.columns)
|
|
980
1019
|
# Get columns without alias
|
|
@@ -992,7 +1031,7 @@ class Update(Insert):
|
|
|
992
1031
|
returning = ''
|
|
993
1032
|
if self.returning:
|
|
994
1033
|
returning = ' RETURNING ' + ', '.join(
|
|
995
|
-
map(self.
|
|
1034
|
+
map(self._format_column, self.returning))
|
|
996
1035
|
return (self._with_str()
|
|
997
1036
|
+ 'UPDATE %s AS "%s" SET ' % (self.table, self.table.alias)
|
|
998
1037
|
+ values + from_ + where + returning)
|
|
@@ -1037,7 +1076,8 @@ class Delete(WithQuery):
|
|
|
1037
1076
|
|
|
1038
1077
|
@table.setter
|
|
1039
1078
|
def table(self, value):
|
|
1040
|
-
|
|
1079
|
+
if not isinstance(value, Table):
|
|
1080
|
+
raise ValueError("invalid table: %r" % value)
|
|
1041
1081
|
self._table = value
|
|
1042
1082
|
|
|
1043
1083
|
@property
|
|
@@ -1048,7 +1088,8 @@ class Delete(WithQuery):
|
|
|
1048
1088
|
def where(self, value):
|
|
1049
1089
|
from sql.operators import And, Or
|
|
1050
1090
|
if value is not None:
|
|
1051
|
-
|
|
1091
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
1092
|
+
raise ValueError("invalid where: %r" % value)
|
|
1052
1093
|
self._where = value
|
|
1053
1094
|
|
|
1054
1095
|
@property
|
|
@@ -1058,19 +1099,15 @@ class Delete(WithQuery):
|
|
|
1058
1099
|
@returning.setter
|
|
1059
1100
|
def returning(self, value):
|
|
1060
1101
|
if value is not None:
|
|
1061
|
-
|
|
1102
|
+
if any(
|
|
1103
|
+
not isinstance(col, (Expression, SelectQuery))
|
|
1104
|
+
for col in value):
|
|
1105
|
+
raise ValueError("invalid returning: %r" % value)
|
|
1062
1106
|
self._returning = value
|
|
1063
1107
|
|
|
1064
1108
|
@staticmethod
|
|
1065
|
-
def _format(value
|
|
1066
|
-
|
|
1067
|
-
param = Flavor.get().param
|
|
1068
|
-
if isinstance(value, Expression):
|
|
1069
|
-
return str(value)
|
|
1070
|
-
elif isinstance(value, Select):
|
|
1071
|
-
return '(%s)' % value
|
|
1072
|
-
else:
|
|
1073
|
-
return param
|
|
1109
|
+
def _format(value):
|
|
1110
|
+
return Select._format_column(value)
|
|
1074
1111
|
|
|
1075
1112
|
def __str__(self):
|
|
1076
1113
|
with AliasManager(exclude=[self.table]):
|
|
@@ -1118,7 +1155,8 @@ class Merge(WithQuery):
|
|
|
1118
1155
|
|
|
1119
1156
|
@target.setter
|
|
1120
1157
|
def target(self, value):
|
|
1121
|
-
|
|
1158
|
+
if not isinstance(value, Table):
|
|
1159
|
+
raise ValueError("invalid target: %r" % value)
|
|
1122
1160
|
self._target = value
|
|
1123
1161
|
|
|
1124
1162
|
@property
|
|
@@ -1127,7 +1165,8 @@ class Merge(WithQuery):
|
|
|
1127
1165
|
|
|
1128
1166
|
@source.setter
|
|
1129
1167
|
def source(self, value):
|
|
1130
|
-
|
|
1168
|
+
if not isinstance(value, (Table, SelectQuery, Values)):
|
|
1169
|
+
raise ValueError("invalid source: %r" % value)
|
|
1131
1170
|
self._source = value
|
|
1132
1171
|
|
|
1133
1172
|
@property
|
|
@@ -1136,7 +1175,8 @@ class Merge(WithQuery):
|
|
|
1136
1175
|
|
|
1137
1176
|
@condition.setter
|
|
1138
1177
|
def condition(self, value):
|
|
1139
|
-
|
|
1178
|
+
if not isinstance(value, Expression):
|
|
1179
|
+
raise ValueError("invalid condition: %r" % value)
|
|
1140
1180
|
self._condition = value
|
|
1141
1181
|
|
|
1142
1182
|
@property
|
|
@@ -1145,7 +1185,8 @@ class Merge(WithQuery):
|
|
|
1145
1185
|
|
|
1146
1186
|
@whens.setter
|
|
1147
1187
|
def whens(self, value):
|
|
1148
|
-
|
|
1188
|
+
if any(not isinstance(w, Matched) for w in value):
|
|
1189
|
+
raise ValueError("invalid whens: %r" % value)
|
|
1149
1190
|
self._whens = tuple(value)
|
|
1150
1191
|
|
|
1151
1192
|
def __str__(self):
|
|
@@ -1154,10 +1195,7 @@ class Merge(WithQuery):
|
|
|
1154
1195
|
source = '(%s)' % self.source
|
|
1155
1196
|
else:
|
|
1156
1197
|
source = self.source
|
|
1157
|
-
|
|
1158
|
-
condition = 'ON %s' % self.condition
|
|
1159
|
-
else:
|
|
1160
|
-
condition = ''
|
|
1198
|
+
condition = 'ON %s' % self.condition
|
|
1161
1199
|
return (self._with_str()
|
|
1162
1200
|
+ 'MERGE INTO %s AS "%s" ' % (self.target, self.target.alias)
|
|
1163
1201
|
+ 'USING %s AS "%s" ' % (source, self.source.alias)
|
|
@@ -1191,7 +1229,8 @@ class Matched(object):
|
|
|
1191
1229
|
@condition.setter
|
|
1192
1230
|
def condition(self, value):
|
|
1193
1231
|
if value is not None:
|
|
1194
|
-
|
|
1232
|
+
if not isinstance(value, Expression):
|
|
1233
|
+
raise ValueError("invalid condition: %r" % value)
|
|
1195
1234
|
self._condition = value
|
|
1196
1235
|
|
|
1197
1236
|
def _then_str(self):
|
|
@@ -1228,7 +1267,8 @@ class _MatchedValues(Matched):
|
|
|
1228
1267
|
|
|
1229
1268
|
@columns.setter
|
|
1230
1269
|
def columns(self, value):
|
|
1231
|
-
|
|
1270
|
+
if any(not isinstance(col, Column) for col in value):
|
|
1271
|
+
raise ValueError("invalid columns: %r" % value)
|
|
1232
1272
|
self._columns = value
|
|
1233
1273
|
|
|
1234
1274
|
|
|
@@ -1281,13 +1321,15 @@ class NotMatchedInsert(_MatchedValues, NotMatched):
|
|
|
1281
1321
|
|
|
1282
1322
|
@values.setter
|
|
1283
1323
|
def values(self, value):
|
|
1284
|
-
|
|
1324
|
+
if value is not None:
|
|
1325
|
+
value = Values([value])
|
|
1326
|
+
self._values = value
|
|
1285
1327
|
|
|
1286
1328
|
def _then_str(self):
|
|
1287
1329
|
columns = ', '.join(c.column_name for c in self.columns)
|
|
1288
1330
|
columns = '(' + columns + ')'
|
|
1289
1331
|
if self.values is None:
|
|
1290
|
-
values = ' DEFAULT VALUES
|
|
1332
|
+
values = ' DEFAULT VALUES'
|
|
1291
1333
|
else:
|
|
1292
1334
|
values = ' ' + str(self.values)
|
|
1293
1335
|
return 'INSERT ' + columns + values
|
|
@@ -1295,7 +1337,8 @@ class NotMatchedInsert(_MatchedValues, NotMatched):
|
|
|
1295
1337
|
@property
|
|
1296
1338
|
def params(self):
|
|
1297
1339
|
p = list(super().params)
|
|
1298
|
-
|
|
1340
|
+
if self.values:
|
|
1341
|
+
p.extend(self.values.params)
|
|
1299
1342
|
return tuple(p)
|
|
1300
1343
|
|
|
1301
1344
|
|
|
@@ -1304,7 +1347,8 @@ class CombiningQuery(FromItem, SelectQuery):
|
|
|
1304
1347
|
_operator = ''
|
|
1305
1348
|
|
|
1306
1349
|
def __init__(self, *queries, **kwargs):
|
|
1307
|
-
|
|
1350
|
+
if any(not isinstance(q, Query) for q in queries):
|
|
1351
|
+
raise ValueError("invalid queries: %r" % (queries,))
|
|
1308
1352
|
self.queries = queries
|
|
1309
1353
|
self.all_ = kwargs.pop('all_', False)
|
|
1310
1354
|
super(CombiningQuery, self).__init__(**kwargs)
|
|
@@ -1424,7 +1468,8 @@ class Join(FromItem):
|
|
|
1424
1468
|
|
|
1425
1469
|
@left.setter
|
|
1426
1470
|
def left(self, value):
|
|
1427
|
-
|
|
1471
|
+
if not isinstance(value, FromItem):
|
|
1472
|
+
raise ValueError("invalid left: %r" % value)
|
|
1428
1473
|
self._left = value
|
|
1429
1474
|
|
|
1430
1475
|
@property
|
|
@@ -1433,7 +1478,8 @@ class Join(FromItem):
|
|
|
1433
1478
|
|
|
1434
1479
|
@right.setter
|
|
1435
1480
|
def right(self, value):
|
|
1436
|
-
|
|
1481
|
+
if not isinstance(value, FromItem):
|
|
1482
|
+
raise ValueError("invalid right: %r" % value)
|
|
1437
1483
|
self._right = value
|
|
1438
1484
|
|
|
1439
1485
|
@property
|
|
@@ -1444,7 +1490,8 @@ class Join(FromItem):
|
|
|
1444
1490
|
def condition(self, value):
|
|
1445
1491
|
from sql.operators import And, Or
|
|
1446
1492
|
if value is not None:
|
|
1447
|
-
|
|
1493
|
+
if not isinstance(value, (Expression, And, Or)):
|
|
1494
|
+
raise ValueError("invalid condition: %r" % value)
|
|
1448
1495
|
self._condition = value
|
|
1449
1496
|
|
|
1450
1497
|
@property
|
|
@@ -1454,8 +1501,10 @@ class Join(FromItem):
|
|
|
1454
1501
|
@type_.setter
|
|
1455
1502
|
def type_(self, value):
|
|
1456
1503
|
value = value.upper()
|
|
1457
|
-
|
|
1458
|
-
|
|
1504
|
+
if value not in {
|
|
1505
|
+
'INNER', 'LEFT', 'LEFT OUTER', 'RIGHT', 'RIGHT OUTER', 'FULL',
|
|
1506
|
+
'FULL OUTER', 'CROSS'}:
|
|
1507
|
+
raise ValueError("invalid type: %r" % value)
|
|
1459
1508
|
self._type_ = value
|
|
1460
1509
|
|
|
1461
1510
|
def __str__(self):
|
|
@@ -1471,14 +1520,9 @@ class Join(FromItem):
|
|
|
1471
1520
|
def params(self):
|
|
1472
1521
|
p = []
|
|
1473
1522
|
for item in (self.left, self.right):
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
except AttributeError:
|
|
1477
|
-
pass
|
|
1478
|
-
try:
|
|
1523
|
+
p.extend(item.params)
|
|
1524
|
+
if self.condition:
|
|
1479
1525
|
p.extend(self.condition.params)
|
|
1480
|
-
except AttributeError:
|
|
1481
|
-
pass
|
|
1482
1526
|
return tuple(p)
|
|
1483
1527
|
|
|
1484
1528
|
@property
|
|
@@ -1534,8 +1578,10 @@ class From(list):
|
|
|
1534
1578
|
return tuple(p)
|
|
1535
1579
|
|
|
1536
1580
|
def __add__(self, other):
|
|
1537
|
-
|
|
1538
|
-
|
|
1581
|
+
if not isinstance(other, FromItem):
|
|
1582
|
+
return NotImplemented
|
|
1583
|
+
elif isinstance(other, CombiningQuery):
|
|
1584
|
+
return NotImplemented
|
|
1539
1585
|
return From(super(From, self).__add__([other]))
|
|
1540
1586
|
|
|
1541
1587
|
|
|
@@ -1558,7 +1604,7 @@ class Values(list, Query, FromItem):
|
|
|
1558
1604
|
|
|
1559
1605
|
@property
|
|
1560
1606
|
def params(self):
|
|
1561
|
-
p =
|
|
1607
|
+
p = list(super().params)
|
|
1562
1608
|
for values in self:
|
|
1563
1609
|
for value in values:
|
|
1564
1610
|
if isinstance(value, Expression):
|
|
@@ -1569,7 +1615,7 @@ class Values(list, Query, FromItem):
|
|
|
1569
1615
|
|
|
1570
1616
|
|
|
1571
1617
|
class Expression(object):
|
|
1572
|
-
__slots__ = ()
|
|
1618
|
+
__slots__ = ('__weakref__',)
|
|
1573
1619
|
|
|
1574
1620
|
def __str__(self):
|
|
1575
1621
|
raise NotImplementedError
|
|
@@ -1823,21 +1869,35 @@ class Cast(Expression):
|
|
|
1823
1869
|
|
|
1824
1870
|
|
|
1825
1871
|
class Collate(Expression):
|
|
1826
|
-
__slots__ = ('
|
|
1872
|
+
__slots__ = ('_expression', '_collation')
|
|
1827
1873
|
|
|
1828
1874
|
def __init__(self, expression, collation):
|
|
1829
1875
|
super(Collate, self).__init__()
|
|
1830
1876
|
self.expression = expression
|
|
1831
1877
|
self.collation = collation
|
|
1832
1878
|
|
|
1879
|
+
@property
|
|
1880
|
+
def expression(self):
|
|
1881
|
+
return self._expression
|
|
1882
|
+
|
|
1883
|
+
@expression.setter
|
|
1884
|
+
def expression(self, value):
|
|
1885
|
+
self._expression = value
|
|
1886
|
+
|
|
1887
|
+
@property
|
|
1888
|
+
def collation(self):
|
|
1889
|
+
return self._collation
|
|
1890
|
+
|
|
1891
|
+
@collation.setter
|
|
1892
|
+
def collation(self, value):
|
|
1893
|
+
self._collation = value
|
|
1894
|
+
|
|
1833
1895
|
def __str__(self):
|
|
1834
1896
|
if isinstance(self.expression, Expression):
|
|
1835
1897
|
value = self.expression
|
|
1836
1898
|
else:
|
|
1837
1899
|
value = Flavor.get().param
|
|
1838
|
-
|
|
1839
|
-
raise ValueError("Wrong collation %s" % self.collation)
|
|
1840
|
-
return '%s COLLATE "%s"' % (value, self.collation)
|
|
1900
|
+
return '%s COLLATE %s' % (value, _escape_identifier(self.collation))
|
|
1841
1901
|
|
|
1842
1902
|
@property
|
|
1843
1903
|
def params(self):
|
|
@@ -1860,8 +1920,11 @@ class Grouping(Expression):
|
|
|
1860
1920
|
|
|
1861
1921
|
@sets.setter
|
|
1862
1922
|
def sets(self, value):
|
|
1863
|
-
|
|
1864
|
-
|
|
1923
|
+
if any(
|
|
1924
|
+
not isinstance(col, Expression)
|
|
1925
|
+
for cols in value
|
|
1926
|
+
for col in cols):
|
|
1927
|
+
raise ValueError("invalid sets: %r" % value)
|
|
1865
1928
|
self._sets = tuple(tuple(cols) for cols in value)
|
|
1866
1929
|
|
|
1867
1930
|
def __str__(self):
|
|
@@ -1888,10 +1951,11 @@ class Rollup(Expression):
|
|
|
1888
1951
|
|
|
1889
1952
|
@expressions.setter
|
|
1890
1953
|
def expressions(self, value):
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1954
|
+
if not all(
|
|
1955
|
+
isinstance(col, Expression)
|
|
1956
|
+
or all(isinstance(c, Expression) for c in col)
|
|
1957
|
+
for col in value):
|
|
1958
|
+
raise ValueError("invalid expressions: %r" % value)
|
|
1895
1959
|
self._expressions = tuple(value)
|
|
1896
1960
|
|
|
1897
1961
|
def __str__(self):
|
|
@@ -1922,7 +1986,8 @@ class Cube(Rollup):
|
|
|
1922
1986
|
|
|
1923
1987
|
class Window(object):
|
|
1924
1988
|
__slots__ = (
|
|
1925
|
-
'_partition', '_order_by', '_frame', '_start', '_end', '_exclude'
|
|
1989
|
+
'_partition', '_order_by', '_frame', '_start', '_end', '_exclude',
|
|
1990
|
+
'__weakref__')
|
|
1926
1991
|
|
|
1927
1992
|
def __init__(self, partition, order_by=None,
|
|
1928
1993
|
frame=None, start=None, end=0, exclude=None):
|
|
@@ -1945,7 +2010,8 @@ class Window(object):
|
|
|
1945
2010
|
|
|
1946
2011
|
@partition.setter
|
|
1947
2012
|
def partition(self, value):
|
|
1948
|
-
|
|
2013
|
+
if any(not isinstance(e, Expression) for e in value):
|
|
2014
|
+
raise ValueError("invalid partition: %r" % value)
|
|
1949
2015
|
self._partition = value
|
|
1950
2016
|
|
|
1951
2017
|
@property
|
|
@@ -1957,7 +2023,8 @@ class Window(object):
|
|
|
1957
2023
|
if value is not None:
|
|
1958
2024
|
if isinstance(value, Expression):
|
|
1959
2025
|
value = [value]
|
|
1960
|
-
|
|
2026
|
+
if any(not isinstance(col, Expression) for col in value):
|
|
2027
|
+
raise ValueError("invalid order by: %r" % value)
|
|
1961
2028
|
self._order_by = value
|
|
1962
2029
|
|
|
1963
2030
|
@property
|
|
@@ -1967,7 +2034,8 @@ class Window(object):
|
|
|
1967
2034
|
@frame.setter
|
|
1968
2035
|
def frame(self, value):
|
|
1969
2036
|
if value:
|
|
1970
|
-
|
|
2037
|
+
if value not in {'RANGE', 'ROWS', 'GROUPS'}:
|
|
2038
|
+
raise ValueError("invalid frame: %r" % value)
|
|
1971
2039
|
self._frame = value
|
|
1972
2040
|
|
|
1973
2041
|
@property
|
|
@@ -1977,7 +2045,8 @@ class Window(object):
|
|
|
1977
2045
|
@start.setter
|
|
1978
2046
|
def start(self, value):
|
|
1979
2047
|
if value:
|
|
1980
|
-
|
|
2048
|
+
if not isinstance(value, numbers.Integral):
|
|
2049
|
+
raise ValueError("invalid start: %r" % value)
|
|
1981
2050
|
self._start = value
|
|
1982
2051
|
|
|
1983
2052
|
@property
|
|
@@ -1987,7 +2056,8 @@ class Window(object):
|
|
|
1987
2056
|
@end.setter
|
|
1988
2057
|
def end(self, value):
|
|
1989
2058
|
if value:
|
|
1990
|
-
|
|
2059
|
+
if not isinstance(value, numbers.Integral):
|
|
2060
|
+
raise ValueError("invalid end: %r" % value)
|
|
1991
2061
|
self._end = value
|
|
1992
2062
|
|
|
1993
2063
|
@property
|
|
@@ -1997,7 +2067,8 @@ class Window(object):
|
|
|
1997
2067
|
@exclude.setter
|
|
1998
2068
|
def exclude(self, value):
|
|
1999
2069
|
if value:
|
|
2000
|
-
|
|
2070
|
+
if value not in {'CURRENT ROW', 'GROUP', 'TIES'}:
|
|
2071
|
+
raise ValueError("invalid exclude: %r" % value)
|
|
2001
2072
|
self._exclude = value
|
|
2002
2073
|
|
|
2003
2074
|
@property
|
|
@@ -2070,7 +2141,8 @@ class Order(Expression):
|
|
|
2070
2141
|
|
|
2071
2142
|
@expression.setter
|
|
2072
2143
|
def expression(self, value):
|
|
2073
|
-
|
|
2144
|
+
if not isinstance(value, (Expression, SelectQuery)):
|
|
2145
|
+
raise ValueError("invalid expression: %r" % value)
|
|
2074
2146
|
self._expression = value
|
|
2075
2147
|
|
|
2076
2148
|
def __str__(self):
|
|
@@ -2173,7 +2245,8 @@ class For(object):
|
|
|
2173
2245
|
@type_.setter
|
|
2174
2246
|
def type_(self, value):
|
|
2175
2247
|
value = value.upper()
|
|
2176
|
-
|
|
2248
|
+
if value not in {'UPDATE', 'SHARE'}:
|
|
2249
|
+
raise ValueError("invalid type: %r" % value)
|
|
2177
2250
|
self._type_ = value
|
|
2178
2251
|
|
|
2179
2252
|
def __str__(self):
|