plain.models 0.49.1__py3-none-any.whl → 0.50.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.
- plain/models/CHANGELOG.md +23 -0
- plain/models/aggregates.py +42 -19
- plain/models/backends/base/base.py +125 -105
- plain/models/backends/base/client.py +11 -3
- plain/models/backends/base/creation.py +22 -12
- plain/models/backends/base/features.py +10 -4
- plain/models/backends/base/introspection.py +29 -16
- plain/models/backends/base/operations.py +187 -91
- plain/models/backends/base/schema.py +267 -165
- plain/models/backends/base/validation.py +12 -3
- plain/models/backends/ddl_references.py +85 -43
- plain/models/backends/mysql/base.py +29 -26
- plain/models/backends/mysql/client.py +7 -2
- plain/models/backends/mysql/compiler.py +12 -3
- plain/models/backends/mysql/creation.py +5 -2
- plain/models/backends/mysql/features.py +24 -22
- plain/models/backends/mysql/introspection.py +22 -13
- plain/models/backends/mysql/operations.py +106 -39
- plain/models/backends/mysql/schema.py +48 -24
- plain/models/backends/mysql/validation.py +13 -6
- plain/models/backends/postgresql/base.py +41 -34
- plain/models/backends/postgresql/client.py +7 -2
- plain/models/backends/postgresql/creation.py +10 -5
- plain/models/backends/postgresql/introspection.py +15 -8
- plain/models/backends/postgresql/operations.py +109 -42
- plain/models/backends/postgresql/schema.py +85 -46
- plain/models/backends/sqlite3/_functions.py +151 -115
- plain/models/backends/sqlite3/base.py +37 -23
- plain/models/backends/sqlite3/client.py +7 -1
- plain/models/backends/sqlite3/creation.py +9 -5
- plain/models/backends/sqlite3/features.py +5 -3
- plain/models/backends/sqlite3/introspection.py +32 -16
- plain/models/backends/sqlite3/operations.py +125 -42
- plain/models/backends/sqlite3/schema.py +82 -58
- plain/models/backends/utils.py +52 -29
- plain/models/backups/cli.py +8 -6
- plain/models/backups/clients.py +16 -7
- plain/models/backups/core.py +24 -13
- plain/models/base.py +113 -74
- plain/models/cli.py +94 -63
- plain/models/config.py +1 -1
- plain/models/connections.py +23 -7
- plain/models/constraints.py +65 -47
- plain/models/database_url.py +1 -1
- plain/models/db.py +6 -2
- plain/models/deletion.py +66 -43
- plain/models/entrypoints.py +1 -1
- plain/models/enums.py +22 -11
- plain/models/exceptions.py +23 -8
- plain/models/expressions.py +440 -257
- plain/models/fields/__init__.py +253 -202
- plain/models/fields/json.py +120 -54
- plain/models/fields/mixins.py +12 -8
- plain/models/fields/related.py +284 -252
- plain/models/fields/related_descriptors.py +34 -25
- plain/models/fields/related_lookups.py +23 -11
- plain/models/fields/related_managers.py +81 -47
- plain/models/fields/reverse_related.py +58 -55
- plain/models/forms.py +89 -63
- plain/models/functions/comparison.py +71 -18
- plain/models/functions/datetime.py +79 -29
- plain/models/functions/math.py +43 -10
- plain/models/functions/mixins.py +24 -7
- plain/models/functions/text.py +104 -25
- plain/models/functions/window.py +12 -6
- plain/models/indexes.py +52 -28
- plain/models/lookups.py +228 -153
- plain/models/migrations/autodetector.py +86 -43
- plain/models/migrations/exceptions.py +7 -3
- plain/models/migrations/executor.py +33 -7
- plain/models/migrations/graph.py +79 -50
- plain/models/migrations/loader.py +45 -22
- plain/models/migrations/migration.py +23 -18
- plain/models/migrations/operations/base.py +37 -19
- plain/models/migrations/operations/fields.py +89 -42
- plain/models/migrations/operations/models.py +245 -143
- plain/models/migrations/operations/special.py +82 -25
- plain/models/migrations/optimizer.py +7 -2
- plain/models/migrations/questioner.py +58 -31
- plain/models/migrations/recorder.py +18 -11
- plain/models/migrations/serializer.py +50 -39
- plain/models/migrations/state.py +220 -133
- plain/models/migrations/utils.py +29 -13
- plain/models/migrations/writer.py +17 -14
- plain/models/options.py +63 -56
- plain/models/otel.py +16 -6
- plain/models/preflight.py +35 -12
- plain/models/query.py +323 -228
- plain/models/query_utils.py +93 -58
- plain/models/registry.py +34 -16
- plain/models/sql/compiler.py +146 -97
- plain/models/sql/datastructures.py +38 -25
- plain/models/sql/query.py +255 -169
- plain/models/sql/subqueries.py +32 -21
- plain/models/sql/where.py +54 -29
- plain/models/test/pytest.py +15 -11
- plain/models/test/utils.py +4 -2
- plain/models/transaction.py +20 -7
- plain/models/utils.py +13 -5
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/METADATA +1 -1
- plain_models-0.50.0.dist-info/RECORD +122 -0
- plain_models-0.49.1.dist-info/RECORD +0 -122
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/licenses/LICENSE +0 -0
plain/models/lookups.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import itertools
|
2
4
|
import math
|
3
5
|
from functools import cached_property
|
6
|
+
from typing import TYPE_CHECKING, Any
|
4
7
|
|
5
8
|
from plain.models.exceptions import EmptyResultSet, FullResultSet
|
6
9
|
from plain.models.expressions import Expression, Func, Value
|
@@ -16,18 +19,22 @@ from plain.models.query_utils import RegisterLookupMixin
|
|
16
19
|
from plain.utils.datastructures import OrderedSet
|
17
20
|
from plain.utils.hashable import make_hashable
|
18
21
|
|
22
|
+
if TYPE_CHECKING:
|
23
|
+
from plain.models.backends.base.base import BaseDatabaseWrapper
|
24
|
+
from plain.models.sql.compiler import SQLCompiler
|
25
|
+
|
19
26
|
|
20
27
|
class Lookup(Expression):
|
21
|
-
lookup_name = None
|
22
|
-
prepare_rhs = True
|
23
|
-
can_use_none_as_rhs = False
|
28
|
+
lookup_name: str | None = None
|
29
|
+
prepare_rhs: bool = True
|
30
|
+
can_use_none_as_rhs: bool = False
|
24
31
|
|
25
|
-
def __init__(self, lhs, rhs):
|
32
|
+
def __init__(self, lhs: Any, rhs: Any):
|
26
33
|
self.lhs, self.rhs = lhs, rhs
|
27
34
|
self.rhs = self.get_prep_lookup()
|
28
35
|
self.lhs = self.get_prep_lhs()
|
29
36
|
if hasattr(self.lhs, "get_bilateral_transforms"):
|
30
|
-
bilateral_transforms = self.lhs.get_bilateral_transforms()
|
37
|
+
bilateral_transforms = self.lhs.get_bilateral_transforms() # type: ignore[attr-defined]
|
31
38
|
else:
|
32
39
|
bilateral_transforms = []
|
33
40
|
if bilateral_transforms:
|
@@ -41,23 +48,25 @@ class Lookup(Expression):
|
|
41
48
|
)
|
42
49
|
self.bilateral_transforms = bilateral_transforms
|
43
50
|
|
44
|
-
def apply_bilateral_transforms(self, value):
|
51
|
+
def apply_bilateral_transforms(self, value: Any) -> Any:
|
45
52
|
for transform in self.bilateral_transforms:
|
46
53
|
value = transform(value)
|
47
54
|
return value
|
48
55
|
|
49
|
-
def __repr__(self):
|
56
|
+
def __repr__(self) -> str:
|
50
57
|
return f"{self.__class__.__name__}({self.lhs!r}, {self.rhs!r})"
|
51
58
|
|
52
|
-
def batch_process_rhs(
|
59
|
+
def batch_process_rhs(
|
60
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper, rhs: Any = None
|
61
|
+
) -> tuple[list[str], list[Any]]:
|
53
62
|
if rhs is None:
|
54
63
|
rhs = self.rhs
|
55
64
|
if self.bilateral_transforms:
|
56
65
|
sqls, sqls_params = [], []
|
57
66
|
for p in rhs:
|
58
|
-
value = Value(p, output_field=self.lhs.output_field)
|
67
|
+
value = Value(p, output_field=self.lhs.output_field) # type: ignore[attr-defined]
|
59
68
|
value = self.apply_bilateral_transforms(value)
|
60
|
-
value = value.resolve_expression(compiler.query)
|
69
|
+
value = value.resolve_expression(compiler.query) # type: ignore[attr-defined]
|
61
70
|
sql, sql_params = compiler.compile(value)
|
62
71
|
sqls.append(sql)
|
63
72
|
sqls_params.extend(sql_params)
|
@@ -66,54 +75,60 @@ class Lookup(Expression):
|
|
66
75
|
sqls, sqls_params = ["%s"] * len(params), params
|
67
76
|
return sqls, sqls_params
|
68
77
|
|
69
|
-
def get_source_expressions(self):
|
78
|
+
def get_source_expressions(self) -> list[Any]:
|
70
79
|
if self.rhs_is_direct_value():
|
71
80
|
return [self.lhs]
|
72
81
|
return [self.lhs, self.rhs]
|
73
82
|
|
74
|
-
def set_source_expressions(self, new_exprs):
|
83
|
+
def set_source_expressions(self, new_exprs: list[Any]) -> None:
|
75
84
|
if len(new_exprs) == 1:
|
76
85
|
self.lhs = new_exprs[0]
|
77
86
|
else:
|
78
87
|
self.lhs, self.rhs = new_exprs
|
79
88
|
|
80
|
-
def get_prep_lookup(self):
|
89
|
+
def get_prep_lookup(self) -> Any:
|
81
90
|
if not self.prepare_rhs or hasattr(self.rhs, "resolve_expression"):
|
82
91
|
return self.rhs
|
83
92
|
if hasattr(self.lhs, "output_field"):
|
84
|
-
if hasattr(self.lhs.output_field, "get_prep_value"):
|
85
|
-
return self.lhs.output_field.get_prep_value(self.rhs)
|
93
|
+
if hasattr(self.lhs.output_field, "get_prep_value"): # type: ignore[attr-defined]
|
94
|
+
return self.lhs.output_field.get_prep_value(self.rhs) # type: ignore[attr-defined]
|
86
95
|
elif self.rhs_is_direct_value():
|
87
96
|
return Value(self.rhs)
|
88
97
|
return self.rhs
|
89
98
|
|
90
|
-
def get_prep_lhs(self):
|
99
|
+
def get_prep_lhs(self) -> Any:
|
91
100
|
if hasattr(self.lhs, "resolve_expression"):
|
92
101
|
return self.lhs
|
93
102
|
return Value(self.lhs)
|
94
103
|
|
95
|
-
def get_db_prep_lookup(
|
104
|
+
def get_db_prep_lookup(
|
105
|
+
self, value: Any, connection: BaseDatabaseWrapper
|
106
|
+
) -> tuple[str, list[Any]]:
|
96
107
|
return ("%s", [value])
|
97
108
|
|
98
|
-
def process_lhs(
|
109
|
+
def process_lhs(
|
110
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper, lhs: Any = None
|
111
|
+
) -> tuple[str, list[Any]]:
|
99
112
|
lhs = lhs or self.lhs
|
100
113
|
if hasattr(lhs, "resolve_expression"):
|
101
|
-
lhs = lhs.resolve_expression(compiler.query)
|
114
|
+
lhs = lhs.resolve_expression(compiler.query) # type: ignore[attr-defined]
|
102
115
|
sql, params = compiler.compile(lhs)
|
103
116
|
if isinstance(lhs, Lookup):
|
104
117
|
# Wrapped in parentheses to respect operator precedence.
|
105
118
|
sql = f"({sql})"
|
106
|
-
return sql, params
|
119
|
+
return sql, list(params)
|
107
120
|
|
108
|
-
def process_rhs(
|
121
|
+
def process_rhs(
|
122
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
123
|
+
) -> tuple[str, list[Any]]:
|
109
124
|
value = self.rhs
|
110
125
|
if self.bilateral_transforms:
|
111
126
|
if self.rhs_is_direct_value():
|
112
127
|
# Do not call get_db_prep_lookup here as the value will be
|
113
128
|
# transformed before being used for lookup
|
114
|
-
value = Value(value, output_field=self.lhs.output_field)
|
129
|
+
value = Value(value, output_field=self.lhs.output_field) # type: ignore[attr-defined]
|
115
130
|
value = self.apply_bilateral_transforms(value)
|
116
|
-
value = value.resolve_expression(compiler.query)
|
131
|
+
value = value.resolve_expression(compiler.query) # type: ignore[attr-defined]
|
117
132
|
if hasattr(value, "as_sql"):
|
118
133
|
sql, params = compiler.compile(value)
|
119
134
|
# Ensure expression is wrapped in parentheses to respect operator
|
@@ -121,50 +136,57 @@ class Lookup(Expression):
|
|
121
136
|
# on some backends (e.g. subqueries on SQLite).
|
122
137
|
if sql and sql[0] != "(":
|
123
138
|
sql = f"({sql})"
|
124
|
-
return sql, params
|
139
|
+
return sql, list(params)
|
125
140
|
else:
|
126
141
|
return self.get_db_prep_lookup(value, connection)
|
127
142
|
|
128
|
-
def rhs_is_direct_value(self):
|
143
|
+
def rhs_is_direct_value(self) -> bool:
|
129
144
|
return not hasattr(self.rhs, "as_sql")
|
130
145
|
|
131
|
-
def get_group_by_cols(self):
|
146
|
+
def get_group_by_cols(self) -> list[Any]:
|
132
147
|
cols = []
|
133
148
|
for source in self.get_source_expressions():
|
134
|
-
cols.extend(source.get_group_by_cols())
|
149
|
+
cols.extend(source.get_group_by_cols()) # type: ignore[attr-defined]
|
135
150
|
return cols
|
136
151
|
|
137
152
|
@cached_property
|
138
|
-
def output_field(self):
|
153
|
+
def output_field(self) -> BooleanField:
|
139
154
|
return BooleanField()
|
140
155
|
|
141
156
|
@property
|
142
|
-
def identity(self):
|
157
|
+
def identity(self) -> tuple[type[Lookup], Any, Any]:
|
143
158
|
return self.__class__, self.lhs, self.rhs
|
144
159
|
|
145
|
-
def __eq__(self, other):
|
160
|
+
def __eq__(self, other: object) -> bool:
|
146
161
|
if not isinstance(other, Lookup):
|
147
162
|
return NotImplemented
|
148
163
|
return self.identity == other.identity
|
149
164
|
|
150
|
-
def __hash__(self):
|
165
|
+
def __hash__(self) -> int:
|
151
166
|
return hash(make_hashable(self.identity))
|
152
167
|
|
153
168
|
def resolve_expression(
|
154
|
-
self,
|
155
|
-
|
156
|
-
|
169
|
+
self,
|
170
|
+
query: Any = None,
|
171
|
+
allow_joins: bool = True,
|
172
|
+
reuse: Any = None,
|
173
|
+
summarize: bool = False,
|
174
|
+
for_save: bool = False,
|
175
|
+
) -> Lookup:
|
176
|
+
c = self.copy() # type: ignore[attr-defined]
|
157
177
|
c.is_summary = summarize
|
158
|
-
c.lhs = self.lhs.resolve_expression(
|
178
|
+
c.lhs = self.lhs.resolve_expression( # type: ignore[attr-defined]
|
159
179
|
query, allow_joins, reuse, summarize, for_save
|
160
180
|
)
|
161
181
|
if hasattr(self.rhs, "resolve_expression"):
|
162
|
-
c.rhs = self.rhs.resolve_expression(
|
182
|
+
c.rhs = self.rhs.resolve_expression( # type: ignore[attr-defined]
|
163
183
|
query, allow_joins, reuse, summarize, for_save
|
164
184
|
)
|
165
185
|
return c
|
166
186
|
|
167
|
-
def select_format(
|
187
|
+
def select_format(
|
188
|
+
self, compiler: SQLCompiler, sql: str, params: list[Any]
|
189
|
+
) -> tuple[str, list[Any]]:
|
168
190
|
# Wrap filters with a CASE WHEN expression if a database backend
|
169
191
|
# (e.g. Oracle) doesn't support boolean expression in SELECT or GROUP
|
170
192
|
# BY list.
|
@@ -179,16 +201,16 @@ class Transform(RegisterLookupMixin, Func):
|
|
179
201
|
first examine self and then check output_field.
|
180
202
|
"""
|
181
203
|
|
182
|
-
bilateral = False
|
183
|
-
arity = 1
|
204
|
+
bilateral: bool = False
|
205
|
+
arity: int = 1
|
184
206
|
|
185
207
|
@property
|
186
|
-
def lhs(self):
|
208
|
+
def lhs(self) -> Any:
|
187
209
|
return self.get_source_expressions()[0]
|
188
210
|
|
189
|
-
def get_bilateral_transforms(self):
|
211
|
+
def get_bilateral_transforms(self) -> list[type[Transform]]:
|
190
212
|
if hasattr(self.lhs, "get_bilateral_transforms"):
|
191
|
-
bilateral_transforms = self.lhs.get_bilateral_transforms()
|
213
|
+
bilateral_transforms = self.lhs.get_bilateral_transforms() # type: ignore[attr-defined]
|
192
214
|
else:
|
193
215
|
bilateral_transforms = []
|
194
216
|
if self.bilateral:
|
@@ -197,25 +219,29 @@ class Transform(RegisterLookupMixin, Func):
|
|
197
219
|
|
198
220
|
|
199
221
|
class BuiltinLookup(Lookup):
|
200
|
-
def process_lhs(
|
201
|
-
|
202
|
-
|
203
|
-
|
222
|
+
def process_lhs(
|
223
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper, lhs: Any = None
|
224
|
+
) -> tuple[str, list[Any]]:
|
225
|
+
lhs_sql, params = super().process_lhs(compiler, connection, lhs) # type: ignore[misc]
|
226
|
+
field_internal_type = self.lhs.output_field.get_internal_type() # type: ignore[attr-defined]
|
227
|
+
db_type = self.lhs.output_field.db_type(connection=connection) # type: ignore[attr-defined]
|
204
228
|
lhs_sql = connection.ops.field_cast_sql(db_type, field_internal_type) % lhs_sql
|
205
229
|
lhs_sql = (
|
206
|
-
connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql
|
230
|
+
connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql # type: ignore[arg-type]
|
207
231
|
)
|
208
232
|
return lhs_sql, list(params)
|
209
233
|
|
210
|
-
def as_sql(
|
234
|
+
def as_sql(
|
235
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
236
|
+
) -> tuple[str, list[Any]]:
|
211
237
|
lhs_sql, params = self.process_lhs(compiler, connection)
|
212
238
|
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
|
213
239
|
params.extend(rhs_params)
|
214
240
|
rhs_sql = self.get_rhs_op(connection, rhs_sql)
|
215
241
|
return f"{lhs_sql} {rhs_sql}", params
|
216
242
|
|
217
|
-
def get_rhs_op(self, connection, rhs):
|
218
|
-
return connection.operators[self.lookup_name] % rhs
|
243
|
+
def get_rhs_op(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
244
|
+
return connection.operators[self.lookup_name] % rhs # type: ignore[index]
|
219
245
|
|
220
246
|
|
221
247
|
class FieldGetDbPrepValueMixin:
|
@@ -224,15 +250,19 @@ class FieldGetDbPrepValueMixin:
|
|
224
250
|
inputs.
|
225
251
|
"""
|
226
252
|
|
227
|
-
get_db_prep_lookup_value_is_iterable = False
|
253
|
+
get_db_prep_lookup_value_is_iterable: bool = False
|
254
|
+
lhs: Any
|
255
|
+
rhs: Any
|
228
256
|
|
229
|
-
def get_db_prep_lookup(
|
257
|
+
def get_db_prep_lookup(
|
258
|
+
self, value: Any, connection: BaseDatabaseWrapper
|
259
|
+
) -> tuple[str, list[Any]]:
|
230
260
|
# For relational fields, use the 'target_field' attribute of the
|
231
261
|
# output_field.
|
232
|
-
field = getattr(self.lhs.output_field, "target_field", None)
|
262
|
+
field = getattr(self.lhs.output_field, "target_field", None) # type: ignore[attr-defined]
|
233
263
|
get_db_prep_value = (
|
234
264
|
getattr(field, "get_db_prep_value", None)
|
235
|
-
or self.lhs.output_field.get_db_prep_value
|
265
|
+
or self.lhs.output_field.get_db_prep_value # type: ignore[attr-defined]
|
236
266
|
)
|
237
267
|
return (
|
238
268
|
"%s",
|
@@ -248,9 +278,10 @@ class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
|
|
248
278
|
in an iterable.
|
249
279
|
"""
|
250
280
|
|
251
|
-
get_db_prep_lookup_value_is_iterable = True
|
281
|
+
get_db_prep_lookup_value_is_iterable: bool = True
|
282
|
+
prepare_rhs: bool
|
252
283
|
|
253
|
-
def get_prep_lookup(self):
|
284
|
+
def get_prep_lookup(self) -> Any:
|
254
285
|
if hasattr(self.rhs, "resolve_expression"):
|
255
286
|
return self.rhs
|
256
287
|
prepared_values = []
|
@@ -259,29 +290,40 @@ class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
|
|
259
290
|
# An expression will be handled by the database but can coexist
|
260
291
|
# alongside real values.
|
261
292
|
pass
|
262
|
-
elif self.prepare_rhs and hasattr(self.lhs.output_field, "get_prep_value"):
|
263
|
-
rhs_value = self.lhs.output_field.get_prep_value(rhs_value)
|
293
|
+
elif self.prepare_rhs and hasattr(self.lhs.output_field, "get_prep_value"): # type: ignore[attr-defined]
|
294
|
+
rhs_value = self.lhs.output_field.get_prep_value(rhs_value) # type: ignore[attr-defined]
|
264
295
|
prepared_values.append(rhs_value)
|
265
296
|
return prepared_values
|
266
297
|
|
267
|
-
def process_rhs(
|
268
|
-
|
298
|
+
def process_rhs(
|
299
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
300
|
+
) -> tuple[str, list[Any]]:
|
301
|
+
if self.rhs_is_direct_value(): # type: ignore[attr-defined]
|
269
302
|
# rhs should be an iterable of values. Use batch_process_rhs()
|
270
303
|
# to prepare/transform those values.
|
271
|
-
return self.batch_process_rhs(compiler, connection)
|
304
|
+
return self.batch_process_rhs(compiler, connection) # type: ignore[attr-defined]
|
272
305
|
else:
|
273
|
-
return super().process_rhs(compiler, connection)
|
274
|
-
|
275
|
-
def resolve_expression_parameter(
|
276
|
-
|
306
|
+
return super().process_rhs(compiler, connection) # type: ignore[misc]
|
307
|
+
|
308
|
+
def resolve_expression_parameter(
|
309
|
+
self,
|
310
|
+
compiler: SQLCompiler,
|
311
|
+
connection: BaseDatabaseWrapper,
|
312
|
+
sql: str,
|
313
|
+
param: Any,
|
314
|
+
) -> tuple[str, list[Any]]:
|
315
|
+
params: list[Any] = [param]
|
277
316
|
if hasattr(param, "resolve_expression"):
|
278
|
-
param = param.resolve_expression(compiler.query)
|
317
|
+
param = param.resolve_expression(compiler.query) # type: ignore[attr-defined]
|
279
318
|
if hasattr(param, "as_sql"):
|
280
|
-
sql,
|
319
|
+
sql, compiled_params = compiler.compile(param)
|
320
|
+
params = list(compiled_params)
|
281
321
|
return sql, params
|
282
322
|
|
283
|
-
def batch_process_rhs(
|
284
|
-
|
323
|
+
def batch_process_rhs(
|
324
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper, rhs: Any = None
|
325
|
+
) -> tuple[tuple[str, ...], tuple[Any, ...]]:
|
326
|
+
pre_processed = super().batch_process_rhs(compiler, connection, rhs) # type: ignore[misc]
|
285
327
|
# The params list may contain expressions which compile to a
|
286
328
|
# sql/param pair. Zip them to get sql and param pairs that refer to the
|
287
329
|
# same argument and attempt to replace them with the result of
|
@@ -299,9 +341,11 @@ class FieldGetDbPrepValueIterableMixin(FieldGetDbPrepValueMixin):
|
|
299
341
|
class PostgresOperatorLookup(Lookup):
|
300
342
|
"""Lookup defined by operators on PostgreSQL."""
|
301
343
|
|
302
|
-
postgres_operator = None
|
344
|
+
postgres_operator: str | None = None
|
303
345
|
|
304
|
-
def as_postgresql(
|
346
|
+
def as_postgresql(
|
347
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
348
|
+
) -> tuple[str, tuple[Any, ...]]:
|
305
349
|
lhs, lhs_params = self.process_lhs(compiler, connection)
|
306
350
|
rhs, rhs_params = self.process_rhs(compiler, connection)
|
307
351
|
params = tuple(lhs_params) + tuple(rhs_params)
|
@@ -310,9 +354,9 @@ class PostgresOperatorLookup(Lookup):
|
|
310
354
|
|
311
355
|
@Field.register_lookup
|
312
356
|
class Exact(FieldGetDbPrepValueMixin, BuiltinLookup):
|
313
|
-
lookup_name = "exact"
|
357
|
+
lookup_name: str = "exact"
|
314
358
|
|
315
|
-
def get_prep_lookup(self):
|
359
|
+
def get_prep_lookup(self) -> Any:
|
316
360
|
from plain.models.sql.query import Query # avoid circular import
|
317
361
|
|
318
362
|
if isinstance(self.rhs, Query):
|
@@ -325,9 +369,11 @@ class Exact(FieldGetDbPrepValueMixin, BuiltinLookup):
|
|
325
369
|
"The QuerySet value for an exact lookup must be limited to "
|
326
370
|
"one result using slicing."
|
327
371
|
)
|
328
|
-
return super().get_prep_lookup()
|
372
|
+
return super().get_prep_lookup() # type: ignore[misc]
|
329
373
|
|
330
|
-
def as_sql(
|
374
|
+
def as_sql(
|
375
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
376
|
+
) -> tuple[str, list[Any]]:
|
331
377
|
# Avoid comparison against direct rhs if lhs is a boolean value. That
|
332
378
|
# turns "boolfield__exact=True" into "WHERE boolean_field" instead of
|
333
379
|
# "WHERE boolean_field = True" when allowed.
|
@@ -341,16 +387,18 @@ class Exact(FieldGetDbPrepValueMixin, BuiltinLookup):
|
|
341
387
|
lhs_sql, params = self.process_lhs(compiler, connection)
|
342
388
|
template = "%s" if self.rhs else "NOT %s"
|
343
389
|
return template % lhs_sql, params
|
344
|
-
return super().as_sql(compiler, connection)
|
390
|
+
return super().as_sql(compiler, connection) # type: ignore[misc]
|
345
391
|
|
346
392
|
|
347
393
|
@Field.register_lookup
|
348
394
|
class IExact(BuiltinLookup):
|
349
|
-
lookup_name = "iexact"
|
350
|
-
prepare_rhs = False
|
395
|
+
lookup_name: str = "iexact"
|
396
|
+
prepare_rhs: bool = False
|
351
397
|
|
352
|
-
def process_rhs(
|
353
|
-
|
398
|
+
def process_rhs(
|
399
|
+
self, qn: SQLCompiler, connection: BaseDatabaseWrapper
|
400
|
+
) -> tuple[str, list[Any]]:
|
401
|
+
rhs, params = super().process_rhs(qn, connection) # type: ignore[misc]
|
354
402
|
if params:
|
355
403
|
params[0] = connection.ops.prep_for_iexact_query(params[0])
|
356
404
|
return rhs, params
|
@@ -358,32 +406,36 @@ class IExact(BuiltinLookup):
|
|
358
406
|
|
359
407
|
@Field.register_lookup
|
360
408
|
class GreaterThan(FieldGetDbPrepValueMixin, BuiltinLookup):
|
361
|
-
lookup_name = "gt"
|
409
|
+
lookup_name: str = "gt"
|
362
410
|
|
363
411
|
|
364
412
|
@Field.register_lookup
|
365
413
|
class GreaterThanOrEqual(FieldGetDbPrepValueMixin, BuiltinLookup):
|
366
|
-
lookup_name = "gte"
|
414
|
+
lookup_name: str = "gte"
|
367
415
|
|
368
416
|
|
369
417
|
@Field.register_lookup
|
370
418
|
class LessThan(FieldGetDbPrepValueMixin, BuiltinLookup):
|
371
|
-
lookup_name = "lt"
|
419
|
+
lookup_name: str = "lt"
|
372
420
|
|
373
421
|
|
374
422
|
@Field.register_lookup
|
375
423
|
class LessThanOrEqual(FieldGetDbPrepValueMixin, BuiltinLookup):
|
376
|
-
lookup_name = "lte"
|
424
|
+
lookup_name: str = "lte"
|
377
425
|
|
378
426
|
|
379
427
|
class IntegerFieldOverflow:
|
380
|
-
underflow_exception = EmptyResultSet
|
381
|
-
overflow_exception = EmptyResultSet
|
382
|
-
|
383
|
-
|
428
|
+
underflow_exception: type[Exception] = EmptyResultSet
|
429
|
+
overflow_exception: type[Exception] = EmptyResultSet
|
430
|
+
lhs: Any
|
431
|
+
rhs: Any
|
432
|
+
|
433
|
+
def process_rhs(
|
434
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
435
|
+
) -> tuple[str, list[Any]]:
|
384
436
|
rhs = self.rhs
|
385
437
|
if isinstance(rhs, int):
|
386
|
-
field_internal_type = self.lhs.output_field.get_internal_type()
|
438
|
+
field_internal_type = self.lhs.output_field.get_internal_type() # type: ignore[attr-defined]
|
387
439
|
min_value, max_value = connection.ops.integer_field_range(
|
388
440
|
field_internal_type
|
389
441
|
)
|
@@ -391,7 +443,7 @@ class IntegerFieldOverflow:
|
|
391
443
|
raise self.underflow_exception
|
392
444
|
if max_value is not None and rhs > max_value:
|
393
445
|
raise self.overflow_exception
|
394
|
-
return super().process_rhs(compiler, connection)
|
446
|
+
return super().process_rhs(compiler, connection) # type: ignore[misc]
|
395
447
|
|
396
448
|
|
397
449
|
class IntegerFieldFloatRounding:
|
@@ -400,10 +452,12 @@ class IntegerFieldFloatRounding:
|
|
400
452
|
decimal portion of the float would always be discarded.
|
401
453
|
"""
|
402
454
|
|
403
|
-
|
455
|
+
rhs: Any
|
456
|
+
|
457
|
+
def get_prep_lookup(self) -> Any:
|
404
458
|
if isinstance(self.rhs, float):
|
405
459
|
self.rhs = math.ceil(self.rhs)
|
406
|
-
return super().get_prep_lookup()
|
460
|
+
return super().get_prep_lookup() # type: ignore[misc]
|
407
461
|
|
408
462
|
|
409
463
|
@IntegerField.register_lookup
|
@@ -435,9 +489,9 @@ class IntegerLessThanOrEqual(IntegerFieldOverflow, LessThanOrEqual):
|
|
435
489
|
|
436
490
|
@Field.register_lookup
|
437
491
|
class In(FieldGetDbPrepValueIterableMixin, BuiltinLookup):
|
438
|
-
lookup_name = "in"
|
492
|
+
lookup_name: str = "in"
|
439
493
|
|
440
|
-
def get_prep_lookup(self):
|
494
|
+
def get_prep_lookup(self) -> Any:
|
441
495
|
from plain.models.sql.query import Query # avoid circular import
|
442
496
|
|
443
497
|
if isinstance(self.rhs, Query):
|
@@ -445,10 +499,12 @@ class In(FieldGetDbPrepValueIterableMixin, BuiltinLookup):
|
|
445
499
|
if not self.rhs.has_select_fields:
|
446
500
|
self.rhs.clear_select_clause()
|
447
501
|
self.rhs.add_fields(["id"])
|
448
|
-
return super().get_prep_lookup()
|
502
|
+
return super().get_prep_lookup() # type: ignore[misc]
|
449
503
|
|
450
|
-
def process_rhs(
|
451
|
-
|
504
|
+
def process_rhs(
|
505
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
506
|
+
) -> tuple[str, list[Any]] | tuple[str, tuple[Any, ...]]:
|
507
|
+
if self.rhs_is_direct_value(): # type: ignore[attr-defined]
|
452
508
|
# Remove None from the list as NULL is never equal to anything.
|
453
509
|
try:
|
454
510
|
rhs = OrderedSet(self.rhs)
|
@@ -461,39 +517,43 @@ class In(FieldGetDbPrepValueIterableMixin, BuiltinLookup):
|
|
461
517
|
|
462
518
|
# rhs should be an iterable; use batch_process_rhs() to
|
463
519
|
# prepare/transform those values.
|
464
|
-
sqls, sqls_params = self.batch_process_rhs(compiler, connection, rhs)
|
520
|
+
sqls, sqls_params = self.batch_process_rhs(compiler, connection, rhs) # type: ignore[attr-defined]
|
465
521
|
placeholder = "(" + ", ".join(sqls) + ")"
|
466
522
|
return (placeholder, sqls_params)
|
467
|
-
return super().process_rhs(compiler, connection)
|
523
|
+
return super().process_rhs(compiler, connection) # type: ignore[misc]
|
468
524
|
|
469
|
-
def get_rhs_op(self, connection, rhs):
|
525
|
+
def get_rhs_op(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
470
526
|
return f"IN {rhs}"
|
471
527
|
|
472
|
-
def as_sql(
|
528
|
+
def as_sql(
|
529
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
530
|
+
) -> tuple[str, list[Any]]:
|
473
531
|
max_in_list_size = connection.ops.max_in_list_size()
|
474
532
|
if (
|
475
|
-
self.rhs_is_direct_value()
|
533
|
+
self.rhs_is_direct_value() # type: ignore[attr-defined]
|
476
534
|
and max_in_list_size
|
477
535
|
and len(self.rhs) > max_in_list_size
|
478
536
|
):
|
479
537
|
return self.split_parameter_list_as_sql(compiler, connection)
|
480
|
-
return super().as_sql(compiler, connection)
|
538
|
+
return super().as_sql(compiler, connection) # type: ignore[misc]
|
481
539
|
|
482
|
-
def split_parameter_list_as_sql(
|
540
|
+
def split_parameter_list_as_sql(
|
541
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
542
|
+
) -> tuple[str, list[Any]]:
|
483
543
|
# This is a special case for databases which limit the number of
|
484
544
|
# elements which can appear in an 'IN' clause.
|
485
545
|
max_in_list_size = connection.ops.max_in_list_size()
|
486
546
|
lhs, lhs_params = self.process_lhs(compiler, connection)
|
487
|
-
rhs, rhs_params = self.batch_process_rhs(compiler, connection)
|
547
|
+
rhs, rhs_params = self.batch_process_rhs(compiler, connection) # type: ignore[attr-defined]
|
488
548
|
in_clause_elements = ["("]
|
489
549
|
params = []
|
490
|
-
for offset in range(0, len(rhs_params), max_in_list_size):
|
550
|
+
for offset in range(0, len(rhs_params), max_in_list_size): # type: ignore[arg-type]
|
491
551
|
if offset > 0:
|
492
552
|
in_clause_elements.append(" OR ")
|
493
553
|
in_clause_elements.append(f"{lhs} IN (")
|
494
554
|
params.extend(lhs_params)
|
495
|
-
sqls = rhs[offset : offset + max_in_list_size]
|
496
|
-
sqls_params = rhs_params[offset : offset + max_in_list_size]
|
555
|
+
sqls = rhs[offset : offset + max_in_list_size] # type: ignore[operator]
|
556
|
+
sqls_params = rhs_params[offset : offset + max_in_list_size] # type: ignore[index,operator]
|
497
557
|
param_group = ", ".join(sqls)
|
498
558
|
in_clause_elements.append(param_group)
|
499
559
|
in_clause_elements.append(")")
|
@@ -503,10 +563,11 @@ class In(FieldGetDbPrepValueIterableMixin, BuiltinLookup):
|
|
503
563
|
|
504
564
|
|
505
565
|
class PatternLookup(BuiltinLookup):
|
506
|
-
param_pattern = "%%%s%%"
|
507
|
-
prepare_rhs = False
|
566
|
+
param_pattern: str = "%%%s%%"
|
567
|
+
prepare_rhs: bool = False
|
568
|
+
bilateral_transforms: list[Any]
|
508
569
|
|
509
|
-
def get_rhs_op(self, connection, rhs):
|
570
|
+
def get_rhs_op(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
510
571
|
# Assume we are in startswith. We need to produce SQL like:
|
511
572
|
# col LIKE %s, ['thevalue%']
|
512
573
|
# For python values we can (and should) do that directly in Python,
|
@@ -517,16 +578,18 @@ class PatternLookup(BuiltinLookup):
|
|
517
578
|
# SQL reference values or SQL transformations we need the correct
|
518
579
|
# pattern added.
|
519
580
|
if hasattr(self.rhs, "as_sql") or self.bilateral_transforms:
|
520
|
-
pattern = connection.pattern_ops[self.lookup_name].format(
|
521
|
-
connection.pattern_esc
|
581
|
+
pattern = connection.pattern_ops[self.lookup_name].format( # type: ignore[index]
|
582
|
+
connection.pattern_esc # type: ignore[attr-defined]
|
522
583
|
)
|
523
584
|
return pattern.format(rhs)
|
524
585
|
else:
|
525
586
|
return super().get_rhs_op(connection, rhs)
|
526
587
|
|
527
|
-
def process_rhs(
|
528
|
-
|
529
|
-
|
588
|
+
def process_rhs(
|
589
|
+
self, qn: SQLCompiler, connection: BaseDatabaseWrapper
|
590
|
+
) -> tuple[str, list[Any]]:
|
591
|
+
rhs, params = super().process_rhs(qn, connection) # type: ignore[misc]
|
592
|
+
if self.rhs_is_direct_value() and params and not self.bilateral_transforms: # type: ignore[attr-defined]
|
530
593
|
params[0] = self.param_pattern % connection.ops.prep_for_like_query(
|
531
594
|
params[0]
|
532
595
|
)
|
@@ -535,50 +598,52 @@ class PatternLookup(BuiltinLookup):
|
|
535
598
|
|
536
599
|
@Field.register_lookup
|
537
600
|
class Contains(PatternLookup):
|
538
|
-
lookup_name = "contains"
|
601
|
+
lookup_name: str = "contains"
|
539
602
|
|
540
603
|
|
541
604
|
@Field.register_lookup
|
542
605
|
class IContains(Contains):
|
543
|
-
lookup_name = "icontains"
|
606
|
+
lookup_name: str = "icontains"
|
544
607
|
|
545
608
|
|
546
609
|
@Field.register_lookup
|
547
610
|
class StartsWith(PatternLookup):
|
548
|
-
lookup_name = "startswith"
|
549
|
-
param_pattern = "%s%%"
|
611
|
+
lookup_name: str = "startswith"
|
612
|
+
param_pattern: str = "%s%%"
|
550
613
|
|
551
614
|
|
552
615
|
@Field.register_lookup
|
553
616
|
class IStartsWith(StartsWith):
|
554
|
-
lookup_name = "istartswith"
|
617
|
+
lookup_name: str = "istartswith"
|
555
618
|
|
556
619
|
|
557
620
|
@Field.register_lookup
|
558
621
|
class EndsWith(PatternLookup):
|
559
|
-
lookup_name = "endswith"
|
560
|
-
param_pattern = "%%%s"
|
622
|
+
lookup_name: str = "endswith"
|
623
|
+
param_pattern: str = "%%%s"
|
561
624
|
|
562
625
|
|
563
626
|
@Field.register_lookup
|
564
627
|
class IEndsWith(EndsWith):
|
565
|
-
lookup_name = "iendswith"
|
628
|
+
lookup_name: str = "iendswith"
|
566
629
|
|
567
630
|
|
568
631
|
@Field.register_lookup
|
569
632
|
class Range(FieldGetDbPrepValueIterableMixin, BuiltinLookup):
|
570
|
-
lookup_name = "range"
|
633
|
+
lookup_name: str = "range"
|
571
634
|
|
572
|
-
def get_rhs_op(self, connection, rhs):
|
635
|
+
def get_rhs_op(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
573
636
|
return f"BETWEEN {rhs[0]} AND {rhs[1]}"
|
574
637
|
|
575
638
|
|
576
639
|
@Field.register_lookup
|
577
640
|
class IsNull(BuiltinLookup):
|
578
|
-
lookup_name = "isnull"
|
579
|
-
prepare_rhs = False
|
641
|
+
lookup_name: str = "isnull"
|
642
|
+
prepare_rhs: bool = False
|
580
643
|
|
581
|
-
def as_sql(
|
644
|
+
def as_sql(
|
645
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
646
|
+
) -> tuple[str, list[Any]]:
|
582
647
|
if not isinstance(self.rhs, bool):
|
583
648
|
raise ValueError(
|
584
649
|
"The QuerySet value for an isnull lookup must be True or False."
|
@@ -592,12 +657,14 @@ class IsNull(BuiltinLookup):
|
|
592
657
|
|
593
658
|
@Field.register_lookup
|
594
659
|
class Regex(BuiltinLookup):
|
595
|
-
lookup_name = "regex"
|
596
|
-
prepare_rhs = False
|
597
|
-
|
598
|
-
def as_sql(
|
599
|
-
|
600
|
-
|
660
|
+
lookup_name: str = "regex"
|
661
|
+
prepare_rhs: bool = False
|
662
|
+
|
663
|
+
def as_sql(
|
664
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
665
|
+
) -> tuple[str, list[Any]]:
|
666
|
+
if self.lookup_name in connection.operators: # type: ignore[operator]
|
667
|
+
return super().as_sql(compiler, connection) # type: ignore[misc]
|
601
668
|
else:
|
602
669
|
lhs, lhs_params = self.process_lhs(compiler, connection)
|
603
670
|
rhs, rhs_params = self.process_rhs(compiler, connection)
|
@@ -607,15 +674,17 @@ class Regex(BuiltinLookup):
|
|
607
674
|
|
608
675
|
@Field.register_lookup
|
609
676
|
class IRegex(Regex):
|
610
|
-
lookup_name = "iregex"
|
677
|
+
lookup_name: str = "iregex"
|
611
678
|
|
612
679
|
|
613
680
|
class YearLookup(Lookup):
|
614
|
-
def year_lookup_bounds(
|
681
|
+
def year_lookup_bounds(
|
682
|
+
self, connection: BaseDatabaseWrapper, year: int
|
683
|
+
) -> list[str | Any | None]:
|
615
684
|
from plain.models.functions import ExtractIsoYear
|
616
685
|
|
617
686
|
iso_year = isinstance(self.lhs, ExtractIsoYear)
|
618
|
-
output_field = self.lhs.lhs.output_field
|
687
|
+
output_field = self.lhs.lhs.output_field # type: ignore[attr-defined]
|
619
688
|
if isinstance(output_field, DateTimeField):
|
620
689
|
bounds = connection.ops.year_lookup_bounds_for_datetime_field(
|
621
690
|
year,
|
@@ -628,54 +697,56 @@ class YearLookup(Lookup):
|
|
628
697
|
)
|
629
698
|
return bounds
|
630
699
|
|
631
|
-
def as_sql(
|
700
|
+
def as_sql(
|
701
|
+
self, compiler: SQLCompiler, connection: BaseDatabaseWrapper
|
702
|
+
) -> tuple[str, list[Any]]:
|
632
703
|
# Avoid the extract operation if the rhs is a direct value to allow
|
633
704
|
# indexes to be used.
|
634
705
|
if self.rhs_is_direct_value():
|
635
706
|
# Skip the extract part by directly using the originating field,
|
636
707
|
# that is self.lhs.lhs.
|
637
|
-
lhs_sql, params = self.process_lhs(compiler, connection, self.lhs.lhs)
|
708
|
+
lhs_sql, params = self.process_lhs(compiler, connection, self.lhs.lhs) # type: ignore[attr-defined]
|
638
709
|
rhs_sql, _ = self.process_rhs(compiler, connection)
|
639
710
|
rhs_sql = self.get_direct_rhs_sql(connection, rhs_sql)
|
640
711
|
start, finish = self.year_lookup_bounds(connection, self.rhs)
|
641
712
|
params.extend(self.get_bound_params(start, finish))
|
642
713
|
return f"{lhs_sql} {rhs_sql}", params
|
643
|
-
return super().as_sql(compiler, connection)
|
714
|
+
return super().as_sql(compiler, connection) # type: ignore[misc]
|
644
715
|
|
645
|
-
def get_direct_rhs_sql(self, connection, rhs):
|
646
|
-
return connection.operators[self.lookup_name] % rhs
|
716
|
+
def get_direct_rhs_sql(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
717
|
+
return connection.operators[self.lookup_name] % rhs # type: ignore[index]
|
647
718
|
|
648
|
-
def get_bound_params(self, start, finish):
|
719
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any, ...]:
|
649
720
|
raise NotImplementedError(
|
650
721
|
"subclasses of YearLookup must provide a get_bound_params() method"
|
651
722
|
)
|
652
723
|
|
653
724
|
|
654
725
|
class YearExact(YearLookup, Exact):
|
655
|
-
def get_direct_rhs_sql(self, connection, rhs):
|
726
|
+
def get_direct_rhs_sql(self, connection: BaseDatabaseWrapper, rhs: str) -> str:
|
656
727
|
return "BETWEEN %s AND %s"
|
657
728
|
|
658
|
-
def get_bound_params(self, start, finish):
|
729
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any, Any]:
|
659
730
|
return (start, finish)
|
660
731
|
|
661
732
|
|
662
733
|
class YearGt(YearLookup, GreaterThan):
|
663
|
-
def get_bound_params(self, start, finish):
|
734
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any]:
|
664
735
|
return (finish,)
|
665
736
|
|
666
737
|
|
667
738
|
class YearGte(YearLookup, GreaterThanOrEqual):
|
668
|
-
def get_bound_params(self, start, finish):
|
739
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any]:
|
669
740
|
return (start,)
|
670
741
|
|
671
742
|
|
672
743
|
class YearLt(YearLookup, LessThan):
|
673
|
-
def get_bound_params(self, start, finish):
|
744
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any]:
|
674
745
|
return (start,)
|
675
746
|
|
676
747
|
|
677
748
|
class YearLte(YearLookup, LessThanOrEqual):
|
678
|
-
def get_bound_params(self, start, finish):
|
749
|
+
def get_bound_params(self, start: Any, finish: Any) -> tuple[Any]:
|
679
750
|
return (finish,)
|
680
751
|
|
681
752
|
|
@@ -685,16 +756,20 @@ class UUIDTextMixin:
|
|
685
756
|
a native datatype for UUID.
|
686
757
|
"""
|
687
758
|
|
688
|
-
|
759
|
+
rhs: Any
|
760
|
+
|
761
|
+
def process_rhs(
|
762
|
+
self, qn: SQLCompiler, connection: BaseDatabaseWrapper
|
763
|
+
) -> tuple[str, list[Any]]:
|
689
764
|
if not connection.features.has_native_uuid_field:
|
690
765
|
from plain.models.functions import Replace
|
691
766
|
|
692
|
-
if self.rhs_is_direct_value():
|
767
|
+
if self.rhs_is_direct_value(): # type: ignore[attr-defined]
|
693
768
|
self.rhs = Value(self.rhs)
|
694
769
|
self.rhs = Replace(
|
695
770
|
self.rhs, Value("-"), Value(""), output_field=CharField()
|
696
771
|
)
|
697
|
-
rhs, params = super().process_rhs(qn, connection)
|
772
|
+
rhs, params = super().process_rhs(qn, connection) # type: ignore[misc]
|
698
773
|
return rhs, params
|
699
774
|
|
700
775
|
|