DefPixel-PostgreSQL 0.1.6__91-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.
- DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/Array.py +16 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/JavaScriptObjectNotation.py +74 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Adapters/__init__.py +51 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Column.py +34 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Compiler.py +161 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Configuration.py +116 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Connection.py +138 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraint.py +18 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Check.py +23 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Columns.py +24 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/ForeignKey.py +56 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/PrimaryKey.py +21 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/Unique.py +25 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Constraints/__init__.py +13 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Context.py +48 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Cursor.py +123 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Create.py +181 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Delete.py +31 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Drop.py +53 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Get.py +24 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Insert.py +98 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Query.py +37 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Select.py +122 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/Update.py +57 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Executors/__init__.py +19 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Expr.py +11 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Common.py +180 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Compare.py +87 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Condition.py +155 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/JavaScriptObjectNotation.py +53 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/Operator.py +42 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/String.py +48 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Exprs/__init__.py +75 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Function.py +11 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/Common.py +142 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/DateTime.py +219 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/JavaScriptObjectNotation.py +100 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/Sequence.py +55 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Functions/__init__.py +91 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Index.py +135 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/FullOuter.py +15 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/Inner.py +15 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/Join.py +41 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/LeftOuter.py +15 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/RightOuter.py +15 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Joins/__init__.py +15 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Mapping.py +359 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Orders.py +59 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Pool.py +84 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Schema.py +28 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Sequence.py +55 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Session.py +84 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Type.py +113 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Array.py +61 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Binary.py +34 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Bool.py +29 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/DateTime.py +120 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/JavaScriptObjectNotation.py +52 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Numeric.py +151 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/Size.py +13 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/String.py +80 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/Types/__init__.py +76 -0
- DefPixel/DataAccessObject/Implements/PostgreSQL/__init__.py +85 -0
- defpixel_postgresql-0.1.6.dist-info/METADATA +184 -0
- defpixel_postgresql-0.1.6.dist-info/RECORD +68 -0
- defpixel_postgresql-0.1.6.dist-info/WHEEL +6 -0
- defpixel_postgresql-0.1.6.dist-info/licenses/LICENSE +674 -0
- defpixel_postgresql-0.1.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
Dict,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from ..Compiler import (
|
|
10
|
+
Compilable,
|
|
11
|
+
Compiler,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
'Query',
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Query(Compilable):
|
|
20
|
+
"""Executor base whose query and args come from one deterministic compilation."""
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def compile(self, compiler: Compiler) -> str:
|
|
24
|
+
raise NotImplementedError('{} must be implemented compile'.format(self.__class__.__name__))
|
|
25
|
+
|
|
26
|
+
def statement(self):
|
|
27
|
+
compiler = Compiler()
|
|
28
|
+
query = self.compile(compiler)
|
|
29
|
+
return query, compiler.args
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def query(self) -> str:
|
|
33
|
+
return self.statement()[0]
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def args(self) -> Dict[str, Any]:
|
|
37
|
+
return self.statement()[1]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import (
|
|
4
|
+
Executor,
|
|
5
|
+
Fetch,
|
|
6
|
+
)
|
|
7
|
+
from ..Column import Column
|
|
8
|
+
from ..Compiler import (
|
|
9
|
+
Compilable,
|
|
10
|
+
Compiler,
|
|
11
|
+
)
|
|
12
|
+
from ..Exprs.Operator import conditions
|
|
13
|
+
from ..Joins import Join
|
|
14
|
+
from ..Mapping import inspect_model
|
|
15
|
+
from .Query import Query
|
|
16
|
+
|
|
17
|
+
__all__ = (
|
|
18
|
+
'Select',
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def expressions(args, name: str) -> tuple:
|
|
23
|
+
result = []
|
|
24
|
+
for arg in args:
|
|
25
|
+
if isinstance(arg, str):
|
|
26
|
+
arg = Column(arg)
|
|
27
|
+
if not isinstance(arg, Compilable):
|
|
28
|
+
raise TypeError('{} must be column names or SQL expressions'.format(name))
|
|
29
|
+
result.append(arg)
|
|
30
|
+
return tuple(result)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Select(Query, Executor, Fetch):
|
|
34
|
+
"""SELECT query for a mapped table or view."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, o):
|
|
37
|
+
self.mapping = inspect_model(o)
|
|
38
|
+
self.joins = ()
|
|
39
|
+
self.conds = ()
|
|
40
|
+
self.grps = ()
|
|
41
|
+
self.havs = ()
|
|
42
|
+
self.ords = ()
|
|
43
|
+
self.vals = ()
|
|
44
|
+
self.offset = 0
|
|
45
|
+
self.size = None
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
def join(self, *args):
|
|
49
|
+
for arg in args:
|
|
50
|
+
if not isinstance(arg, Join):
|
|
51
|
+
raise TypeError('join requires Join objects')
|
|
52
|
+
self.joins = args
|
|
53
|
+
return self
|
|
54
|
+
|
|
55
|
+
def where(self, *args):
|
|
56
|
+
self.conds = conditions(args)
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
def group(self, *args):
|
|
60
|
+
self.grps = expressions(args, 'Groups')
|
|
61
|
+
return self
|
|
62
|
+
|
|
63
|
+
def having(self, *args):
|
|
64
|
+
self.havs = conditions(args)
|
|
65
|
+
return self
|
|
66
|
+
|
|
67
|
+
def order(self, *args):
|
|
68
|
+
self.ords = expressions(args, 'Orders')
|
|
69
|
+
return self
|
|
70
|
+
|
|
71
|
+
def limit(
|
|
72
|
+
self,
|
|
73
|
+
size=None,
|
|
74
|
+
offset=0,
|
|
75
|
+
):
|
|
76
|
+
if size is not None and (type(size) is not int or size < 0):
|
|
77
|
+
raise ValueError('size must be a nonnegative integer')
|
|
78
|
+
if type(offset) is not int or offset < 0:
|
|
79
|
+
raise ValueError('offset must be a nonnegative integer')
|
|
80
|
+
self.size = size
|
|
81
|
+
self.offset = offset
|
|
82
|
+
return self
|
|
83
|
+
|
|
84
|
+
def values(self, *args):
|
|
85
|
+
self.vals = expressions(args, 'Values')
|
|
86
|
+
return self
|
|
87
|
+
|
|
88
|
+
def compile(self, compiler: Compiler) -> str:
|
|
89
|
+
columns = self.vals or tuple(self.mapping.columns.values())
|
|
90
|
+
sql = 'SELECT {} FROM {}'.format(
|
|
91
|
+
', '.join(compiler.compile(value) for value in columns),
|
|
92
|
+
self.mapping.target,
|
|
93
|
+
)
|
|
94
|
+
for join in self.joins:
|
|
95
|
+
sql += ' ' + compiler.compile(join)
|
|
96
|
+
for keyword, values, separator in (
|
|
97
|
+
('WHERE', self.conds, ' AND '),
|
|
98
|
+
('GROUP BY', self.grps, ', '),
|
|
99
|
+
('HAVING', self.havs, ' AND '),
|
|
100
|
+
('ORDER BY', self.ords, ', '),
|
|
101
|
+
):
|
|
102
|
+
if values:
|
|
103
|
+
sql += ' {} {}'.format(keyword, separator.join(compiler.compile(value) for value in values))
|
|
104
|
+
if self.size is not None:
|
|
105
|
+
sql += ' LIMIT {}'.format(self.size)
|
|
106
|
+
if self.offset:
|
|
107
|
+
sql += ' OFFSET {}'.format(self.offset)
|
|
108
|
+
return sql
|
|
109
|
+
|
|
110
|
+
def fetch(
|
|
111
|
+
self,
|
|
112
|
+
cursor,
|
|
113
|
+
filter=None,
|
|
114
|
+
fetch=None,
|
|
115
|
+
):
|
|
116
|
+
mapping = inspect_model(fetch) if fetch is not None else None
|
|
117
|
+
result = []
|
|
118
|
+
for row in cursor.rows():
|
|
119
|
+
if filter is not None:
|
|
120
|
+
row = filter(row)
|
|
121
|
+
result.append(mapping.restore(row) if mapping is not None else row)
|
|
122
|
+
return result if result else None
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from DefPixel.DataAccessObject.Properties.Database import (
|
|
4
|
+
Executor,
|
|
5
|
+
Fetch,
|
|
6
|
+
)
|
|
7
|
+
from ..Compiler import (
|
|
8
|
+
Compiler,
|
|
9
|
+
identifier,
|
|
10
|
+
valuetype,
|
|
11
|
+
)
|
|
12
|
+
from ..Exprs.Operator import conditions
|
|
13
|
+
from ..Mapping import inspect_model
|
|
14
|
+
from .Insert import first
|
|
15
|
+
from .Query import Query
|
|
16
|
+
|
|
17
|
+
__all__ = (
|
|
18
|
+
'Update',
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Update(Query, Executor, Fetch):
|
|
23
|
+
"""UPDATE ... SET ... [WHERE ...] RETURNING *; fetch returns the first updated row."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, o):
|
|
26
|
+
self.mapping = inspect_model(o, 'table')
|
|
27
|
+
self.kwargs = {}
|
|
28
|
+
self.conds = ()
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
def set(self, **kwargs):
|
|
32
|
+
self.kwargs.update(self.mapping.values(kwargs))
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
def where(self, *args):
|
|
36
|
+
self.conds = conditions(args)
|
|
37
|
+
return self
|
|
38
|
+
|
|
39
|
+
def compile(self, compiler: Compiler) -> str:
|
|
40
|
+
if not self.kwargs:
|
|
41
|
+
raise ValueError('No columns are specified for update')
|
|
42
|
+
return 'UPDATE {} SET {}{} RETURNING *'.format(
|
|
43
|
+
self.mapping.target,
|
|
44
|
+
', '.join(
|
|
45
|
+
'{}={}'.format(identifier(key), compiler.bind(value, valuetype(spec)))
|
|
46
|
+
for key, (spec, value) in self.kwargs.items()
|
|
47
|
+
),
|
|
48
|
+
' WHERE {}'.format(' AND '.join(compiler.compile(cond) for cond in self.conds)) if self.conds else '',
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def fetch(
|
|
52
|
+
self,
|
|
53
|
+
cursor,
|
|
54
|
+
filter=None,
|
|
55
|
+
fetch=None,
|
|
56
|
+
):
|
|
57
|
+
return first(cursor, filter, fetch)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from .Create import Create
|
|
4
|
+
from .Drop import Drop
|
|
5
|
+
from .Insert import Insert
|
|
6
|
+
from .Update import Update
|
|
7
|
+
from .Delete import Delete
|
|
8
|
+
from .Select import Select
|
|
9
|
+
from .Get import Get
|
|
10
|
+
|
|
11
|
+
__all__ = (
|
|
12
|
+
'Create',
|
|
13
|
+
'Drop',
|
|
14
|
+
'Insert',
|
|
15
|
+
'Update',
|
|
16
|
+
'Delete',
|
|
17
|
+
'Select',
|
|
18
|
+
'Get',
|
|
19
|
+
)
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from dataclasses import MISSING
|
|
4
|
+
|
|
5
|
+
from ..Compiler import (
|
|
6
|
+
Compilable,
|
|
7
|
+
Compiler,
|
|
8
|
+
identifier,
|
|
9
|
+
typename,
|
|
10
|
+
)
|
|
11
|
+
from ..Expr import Expr
|
|
12
|
+
|
|
13
|
+
__all__ = (
|
|
14
|
+
'Alias',
|
|
15
|
+
'TypeTo',
|
|
16
|
+
'If',
|
|
17
|
+
'IfNull',
|
|
18
|
+
'IfNotNull',
|
|
19
|
+
'Switch',
|
|
20
|
+
'Query',
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def term(compiler: Compiler, value) -> str:
|
|
25
|
+
"""Compile a value, rendering None as the NULL keyword."""
|
|
26
|
+
if value is None:
|
|
27
|
+
return 'NULL'
|
|
28
|
+
return compiler.compile(value)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Alias(Expr):
|
|
32
|
+
"""expr AS "name"."""
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
col,
|
|
37
|
+
name: str,
|
|
38
|
+
):
|
|
39
|
+
identifier(name)
|
|
40
|
+
self.col = col
|
|
41
|
+
self.name = name
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
def compile(self, compiler: Compiler) -> str:
|
|
45
|
+
return '{} AS {}'.format(term(compiler, self.col), identifier(self.name))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TypeTo(Expr):
|
|
49
|
+
"""expr::type."""
|
|
50
|
+
|
|
51
|
+
def __init__(
|
|
52
|
+
self,
|
|
53
|
+
col,
|
|
54
|
+
type,
|
|
55
|
+
):
|
|
56
|
+
typename(type)
|
|
57
|
+
self.col = col
|
|
58
|
+
self.type = type
|
|
59
|
+
return
|
|
60
|
+
|
|
61
|
+
def compile(self, compiler: Compiler) -> str:
|
|
62
|
+
if isinstance(self.col, Compilable):
|
|
63
|
+
return '({})::{}'.format(compiler.compile(self.col), typename(self.type))
|
|
64
|
+
if self.col is None:
|
|
65
|
+
return 'NULL::{}'.format(typename(self.type))
|
|
66
|
+
return compiler.bind(self.col, self.type)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class Conditional(Expr):
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
cond,
|
|
73
|
+
thenexpr=None,
|
|
74
|
+
elseexpr=MISSING,
|
|
75
|
+
):
|
|
76
|
+
self.cond = cond
|
|
77
|
+
self.thenexpr = thenexpr
|
|
78
|
+
self.elseexpr = elseexpr
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
def then_(self, expr):
|
|
82
|
+
self.thenexpr = expr
|
|
83
|
+
return self
|
|
84
|
+
|
|
85
|
+
def else_(self, expr):
|
|
86
|
+
self.elseexpr = expr
|
|
87
|
+
return self
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class If(Conditional):
|
|
91
|
+
"""CASE WHEN cond THEN then [ELSE else] END."""
|
|
92
|
+
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
cond,
|
|
96
|
+
thenexpr=None,
|
|
97
|
+
elseexpr=MISSING,
|
|
98
|
+
):
|
|
99
|
+
if not isinstance(cond, Compilable):
|
|
100
|
+
raise TypeError('If requires a SQL condition')
|
|
101
|
+
super().__init__(cond, thenexpr, elseexpr)
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
def compile(self, compiler: Compiler) -> str:
|
|
105
|
+
return 'CASE WHEN {} THEN {}{} END'.format(
|
|
106
|
+
compiler.compile(self.cond),
|
|
107
|
+
term(compiler, self.thenexpr),
|
|
108
|
+
'' if self.elseexpr is MISSING else ' ELSE {}'.format(term(compiler, self.elseexpr)),
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class IfNull(Conditional):
|
|
113
|
+
"""CASE WHEN expr IS NULL THEN then ELSE else-or-expr END."""
|
|
114
|
+
|
|
115
|
+
predicate = 'IS NULL'
|
|
116
|
+
|
|
117
|
+
def compile(self, compiler: Compiler) -> str:
|
|
118
|
+
return 'CASE WHEN {} {} THEN {} ELSE {} END'.format(
|
|
119
|
+
compiler.compile(self.cond),
|
|
120
|
+
self.predicate,
|
|
121
|
+
term(compiler, self.thenexpr),
|
|
122
|
+
compiler.compile(self.cond) if self.elseexpr is MISSING else term(compiler, self.elseexpr),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class IfNotNull(IfNull):
|
|
127
|
+
"""CASE WHEN expr IS NOT NULL THEN then ELSE else-or-expr END."""
|
|
128
|
+
|
|
129
|
+
predicate = 'IS NOT NULL'
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class Switch(Expr):
|
|
133
|
+
"""CASE WHEN cond THEN value ... [ELSE other] END built from (cond, value) pairs."""
|
|
134
|
+
|
|
135
|
+
def __init__(self, *args):
|
|
136
|
+
self.args = []
|
|
137
|
+
self.elseexpr = MISSING
|
|
138
|
+
for arg in args:
|
|
139
|
+
if not isinstance(arg, (tuple, list)) or len(arg) != 2:
|
|
140
|
+
raise TypeError('Switch arguments must be (condition, value) pairs')
|
|
141
|
+
self.case(*arg)
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
def case(
|
|
145
|
+
self,
|
|
146
|
+
cond,
|
|
147
|
+
thenexpr=None,
|
|
148
|
+
):
|
|
149
|
+
if not isinstance(cond, Compilable):
|
|
150
|
+
raise TypeError('Switch cases require SQL conditions')
|
|
151
|
+
self.args.append((cond, thenexpr))
|
|
152
|
+
return self
|
|
153
|
+
|
|
154
|
+
def other(self, elseexpr=None):
|
|
155
|
+
self.elseexpr = elseexpr
|
|
156
|
+
return self
|
|
157
|
+
|
|
158
|
+
def compile(self, compiler: Compiler) -> str:
|
|
159
|
+
if not self.args:
|
|
160
|
+
return 'NULL'
|
|
161
|
+
return 'CASE {}{} END'.format(
|
|
162
|
+
' '.join(
|
|
163
|
+
'WHEN {} THEN {}'.format(compiler.compile(cond), term(compiler, value))
|
|
164
|
+
for cond, value in self.args
|
|
165
|
+
),
|
|
166
|
+
'' if self.elseexpr is MISSING else ' ELSE {}'.format(term(compiler, self.elseexpr)),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class Query(Expr):
|
|
171
|
+
"""Parenthesized subquery whose parameters join the outer query."""
|
|
172
|
+
|
|
173
|
+
def __init__(self, executor):
|
|
174
|
+
if not isinstance(executor, Compilable):
|
|
175
|
+
raise TypeError('Query requires a PostgreSQL Select executor')
|
|
176
|
+
self.executor = executor
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
def compile(self, compiler: Compiler) -> str:
|
|
180
|
+
return '({})'.format(self.executor.compile(compiler))
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from ..Compiler import Compiler
|
|
4
|
+
from ..Expr import Expr
|
|
5
|
+
from ..Types.JavaScriptObjectNotation import JavaScriptObjectNotation
|
|
6
|
+
from .JavaScriptObjectNotation import Of
|
|
7
|
+
|
|
8
|
+
__all__ = (
|
|
9
|
+
'EqualTo',
|
|
10
|
+
'NotEqualTo',
|
|
11
|
+
'GreaterThan',
|
|
12
|
+
'GreaterEqualTo',
|
|
13
|
+
'LessThan',
|
|
14
|
+
'LessEqualTo',
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def is_json_type(expr):
|
|
19
|
+
if isinstance(expr, JavaScriptObjectNotation):
|
|
20
|
+
return expr
|
|
21
|
+
if isinstance(expr, Of) and expr.type is None:
|
|
22
|
+
return is_json_type(expr.col)
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Compare(Expr):
|
|
27
|
+
operator = ''
|
|
28
|
+
null = None
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
col,
|
|
33
|
+
other,
|
|
34
|
+
):
|
|
35
|
+
self.col = col
|
|
36
|
+
self.other = other
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
def compile(self, compiler: Compiler) -> str:
|
|
40
|
+
json_type = is_json_type(self.col) or is_json_type(self.other)
|
|
41
|
+
if json_type is not None and isinstance(self.col, list):
|
|
42
|
+
col = compiler.bind(json_type.adapt(self.col))
|
|
43
|
+
else:
|
|
44
|
+
col = compiler.compile(self.col)
|
|
45
|
+
if isinstance(self.col, Expr):
|
|
46
|
+
col = '({})'.format(col)
|
|
47
|
+
if self.other is None and self.null is not None:
|
|
48
|
+
return '{} {}'.format(col, self.null)
|
|
49
|
+
if json_type is not None and isinstance(self.other, list):
|
|
50
|
+
other = compiler.bind(json_type.adapt(self.other))
|
|
51
|
+
else:
|
|
52
|
+
other = compiler.compile(self.other)
|
|
53
|
+
if isinstance(self.other, Expr):
|
|
54
|
+
other = '({})'.format(other)
|
|
55
|
+
return '{} {} {}'.format(
|
|
56
|
+
col,
|
|
57
|
+
self.operator,
|
|
58
|
+
other,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class EqualTo(Compare):
|
|
63
|
+
"""col = other; None compiles to IS NULL."""
|
|
64
|
+
operator = '='
|
|
65
|
+
null = 'IS NULL'
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class NotEqualTo(Compare):
|
|
69
|
+
"""col != other; None compiles to IS NOT NULL."""
|
|
70
|
+
operator = '!='
|
|
71
|
+
null = 'IS NOT NULL'
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class GreaterThan(Compare):
|
|
75
|
+
operator = '>'
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class GreaterEqualTo(Compare):
|
|
79
|
+
operator = '>='
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class LessThan(Compare):
|
|
83
|
+
operator = '<'
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class LessEqualTo(Compare):
|
|
87
|
+
operator = '<='
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
from ..Compiler import (
|
|
6
|
+
Compilable,
|
|
7
|
+
Compiler,
|
|
8
|
+
typename,
|
|
9
|
+
valuetype,
|
|
10
|
+
)
|
|
11
|
+
from ..Expr import Expr
|
|
12
|
+
from ..Type import Type
|
|
13
|
+
|
|
14
|
+
__all__ = (
|
|
15
|
+
'In',
|
|
16
|
+
'NotIn',
|
|
17
|
+
'Is',
|
|
18
|
+
'IsNull',
|
|
19
|
+
'IsNotNull',
|
|
20
|
+
'IsTrue',
|
|
21
|
+
'IsNotTrue',
|
|
22
|
+
'IsFalse',
|
|
23
|
+
'IsNotFalse',
|
|
24
|
+
'IsUnknown',
|
|
25
|
+
'IsNotUnknown',
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Membership(Expr):
|
|
30
|
+
operator = ''
|
|
31
|
+
array = ''
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
col,
|
|
36
|
+
args=None,
|
|
37
|
+
):
|
|
38
|
+
self.col = col
|
|
39
|
+
if args is None:
|
|
40
|
+
self.args = []
|
|
41
|
+
elif isinstance(args, Sequence) and not isinstance(args, (str, bytes, bytearray)):
|
|
42
|
+
self.args = list(args)
|
|
43
|
+
else:
|
|
44
|
+
self.args = [args]
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
def where(self, arg):
|
|
48
|
+
self.args.append(arg)
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def compile(self, compiler: Compiler) -> str:
|
|
52
|
+
col = compiler.compile(self.col)
|
|
53
|
+
if isinstance(self.col, Expr):
|
|
54
|
+
col = '({})'.format(col)
|
|
55
|
+
from .Common import Query
|
|
56
|
+
if len(self.args) == 1 and isinstance(self.args[0], Query):
|
|
57
|
+
return '{} {} {}'.format(col, self.operator, compiler.compile(self.args[0]))
|
|
58
|
+
if any(isinstance(arg, Compilable) for arg in self.args):
|
|
59
|
+
return '{} {} ({})'.format(
|
|
60
|
+
col,
|
|
61
|
+
self.operator,
|
|
62
|
+
', '.join(compiler.compile(arg) for arg in self.args),
|
|
63
|
+
)
|
|
64
|
+
cast = None
|
|
65
|
+
if isinstance(self.col, Type):
|
|
66
|
+
if typename(self.col, escape=False).endswith(']'):
|
|
67
|
+
if not self.args:
|
|
68
|
+
return 'FALSE' if self.operator == 'IN' else 'TRUE'
|
|
69
|
+
return '{} {} ({})'.format(
|
|
70
|
+
col,
|
|
71
|
+
self.operator,
|
|
72
|
+
', '.join(compiler.bind(arg, valuetype(self.col)) for arg in self.args),
|
|
73
|
+
)
|
|
74
|
+
cast = '{}[]'.format(valuetype(self.col))
|
|
75
|
+
return '{} {}({})'.format(col, self.array, compiler.bind(list(self.args), cast))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class In(Membership):
|
|
79
|
+
"""col IN values; plain values are bound as one array parameter (= ANY)."""
|
|
80
|
+
operator = 'IN'
|
|
81
|
+
array = '= ANY'
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class NotIn(Membership):
|
|
85
|
+
"""col NOT IN values; plain values are bound as one array parameter (<> ALL)."""
|
|
86
|
+
operator = 'NOT IN'
|
|
87
|
+
array = '<> ALL'
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
KEYWORDS = {
|
|
91
|
+
None: 'NULL',
|
|
92
|
+
True: 'TRUE',
|
|
93
|
+
False: 'FALSE',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Is(Expr):
|
|
98
|
+
"""col IS other, where other is None, True, or False."""
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
col,
|
|
103
|
+
other,
|
|
104
|
+
):
|
|
105
|
+
if not any(other is key for key in KEYWORDS):
|
|
106
|
+
raise TypeError('Is requires None, True, or False')
|
|
107
|
+
self.col = col
|
|
108
|
+
self.other = other
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
def compile(self, compiler: Compiler) -> str:
|
|
112
|
+
return '{} IS {}'.format(compiler.compile(self.col), KEYWORDS[self.other])
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class Predicate(Expr):
|
|
116
|
+
predicate = ''
|
|
117
|
+
|
|
118
|
+
def __init__(self, col):
|
|
119
|
+
self.col = col
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
def compile(self, compiler: Compiler) -> str:
|
|
123
|
+
return '{} {}'.format(compiler.compile(self.col), self.predicate)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class IsNull(Predicate):
|
|
127
|
+
predicate = 'IS NULL'
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class IsNotNull(Predicate):
|
|
131
|
+
predicate = 'IS NOT NULL'
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class IsTrue(Predicate):
|
|
135
|
+
predicate = 'IS TRUE'
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class IsNotTrue(Predicate):
|
|
139
|
+
predicate = 'IS NOT TRUE'
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class IsFalse(Predicate):
|
|
143
|
+
predicate = 'IS FALSE'
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class IsNotFalse(Predicate):
|
|
147
|
+
predicate = 'IS NOT FALSE'
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class IsUnknown(Predicate):
|
|
151
|
+
predicate = 'IS UNKNOWN'
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class IsNotUnknown(Predicate):
|
|
155
|
+
predicate = 'IS NOT UNKNOWN'
|