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
@@ -1,7 +1,10 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import datetime
|
2
4
|
import decimal
|
3
5
|
import json
|
4
6
|
from importlib import import_module
|
7
|
+
from typing import TYPE_CHECKING, Any
|
5
8
|
|
6
9
|
import sqlparse
|
7
10
|
|
@@ -10,6 +13,12 @@ from plain.models.db import NotSupportedError
|
|
10
13
|
from plain.utils import timezone
|
11
14
|
from plain.utils.encoding import force_str
|
12
15
|
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from types import ModuleType
|
18
|
+
|
19
|
+
from plain.models.backends.base.base import BaseDatabaseWrapper
|
20
|
+
from plain.models.fields import Field
|
21
|
+
|
13
22
|
|
14
23
|
class BaseDatabaseOperations:
|
15
24
|
"""
|
@@ -17,11 +26,11 @@ class BaseDatabaseOperations:
|
|
17
26
|
performs ordering or calculates the ID of a recently-inserted row.
|
18
27
|
"""
|
19
28
|
|
20
|
-
compiler_module = "plain.models.sql.compiler"
|
29
|
+
compiler_module: str = "plain.models.sql.compiler"
|
21
30
|
|
22
31
|
# Integer field safe ranges by `internal_type` as documented
|
23
32
|
# in docs/ref/models/fields.txt.
|
24
|
-
integer_field_ranges = {
|
33
|
+
integer_field_ranges: dict[str, tuple[int, int]] = {
|
25
34
|
"SmallIntegerField": (-32768, 32767),
|
26
35
|
"IntegerField": (-2147483648, 2147483647),
|
27
36
|
"BigIntegerField": (-9223372036854775808, 9223372036854775807),
|
@@ -30,7 +39,7 @@ class BaseDatabaseOperations:
|
|
30
39
|
"PositiveIntegerField": (0, 2147483647),
|
31
40
|
"PrimaryKeyField": (-9223372036854775808, 9223372036854775807),
|
32
41
|
}
|
33
|
-
set_operators = {
|
42
|
+
set_operators: dict[str, str] = {
|
34
43
|
"union": "UNION",
|
35
44
|
"intersection": "INTERSECT",
|
36
45
|
"difference": "EXCEPT",
|
@@ -38,25 +47,25 @@ class BaseDatabaseOperations:
|
|
38
47
|
# Mapping of Field.get_internal_type() (typically the model field's class
|
39
48
|
# name) to the data type to use for the Cast() function, if different from
|
40
49
|
# DatabaseWrapper.data_types.
|
41
|
-
cast_data_types = {}
|
50
|
+
cast_data_types: dict[str, str] = {}
|
42
51
|
# CharField data type if the max_length argument isn't provided.
|
43
|
-
cast_char_field_without_max_length = None
|
52
|
+
cast_char_field_without_max_length: str | None = None
|
44
53
|
|
45
54
|
# Start and end points for window expressions.
|
46
|
-
PRECEDING = "PRECEDING"
|
47
|
-
FOLLOWING = "FOLLOWING"
|
48
|
-
UNBOUNDED_PRECEDING = "UNBOUNDED " + PRECEDING
|
49
|
-
UNBOUNDED_FOLLOWING = "UNBOUNDED " + FOLLOWING
|
50
|
-
CURRENT_ROW = "CURRENT ROW"
|
55
|
+
PRECEDING: str = "PRECEDING"
|
56
|
+
FOLLOWING: str = "FOLLOWING"
|
57
|
+
UNBOUNDED_PRECEDING: str = "UNBOUNDED " + PRECEDING
|
58
|
+
UNBOUNDED_FOLLOWING: str = "UNBOUNDED " + FOLLOWING
|
59
|
+
CURRENT_ROW: str = "CURRENT ROW"
|
51
60
|
|
52
61
|
# Prefix for EXPLAIN queries, or None EXPLAIN isn't supported.
|
53
|
-
explain_prefix = None
|
62
|
+
explain_prefix: str | None = None
|
54
63
|
|
55
|
-
def __init__(self, connection):
|
64
|
+
def __init__(self, connection: BaseDatabaseWrapper):
|
56
65
|
self.connection = connection
|
57
|
-
self._cache = None
|
66
|
+
self._cache: ModuleType | None = None
|
58
67
|
|
59
|
-
def autoinc_sql(self, table, column):
|
68
|
+
def autoinc_sql(self, table: str, column: str) -> str | None:
|
60
69
|
"""
|
61
70
|
Return any SQL needed to support auto-incrementing primary keys, or
|
62
71
|
None if no SQL is necessary.
|
@@ -65,7 +74,7 @@ class BaseDatabaseOperations:
|
|
65
74
|
"""
|
66
75
|
return None
|
67
76
|
|
68
|
-
def bulk_batch_size(self, fields, objs):
|
77
|
+
def bulk_batch_size(self, fields: list[Field], objs: list[Any]) -> int:
|
69
78
|
"""
|
70
79
|
Return the maximum allowed batch size for the backend. The fields
|
71
80
|
are the fields going to be inserted in the batch, the objs contains
|
@@ -73,13 +82,13 @@ class BaseDatabaseOperations:
|
|
73
82
|
"""
|
74
83
|
return len(objs)
|
75
84
|
|
76
|
-
def format_for_duration_arithmetic(self, sql):
|
85
|
+
def format_for_duration_arithmetic(self, sql: str) -> str:
|
77
86
|
raise NotImplementedError(
|
78
87
|
"subclasses of BaseDatabaseOperations may require a "
|
79
88
|
"format_for_duration_arithmetic() method."
|
80
89
|
)
|
81
90
|
|
82
|
-
def unification_cast_sql(self, output_field):
|
91
|
+
def unification_cast_sql(self, output_field: Field) -> str:
|
83
92
|
"""
|
84
93
|
Given a field instance, return the SQL that casts the result of a union
|
85
94
|
to that type. The resulting string should contain a '%s' placeholder
|
@@ -87,7 +96,9 @@ class BaseDatabaseOperations:
|
|
87
96
|
"""
|
88
97
|
return "%s"
|
89
98
|
|
90
|
-
def date_extract_sql(
|
99
|
+
def date_extract_sql(
|
100
|
+
self, lookup_type: str, sql: str, params: list[Any] | tuple[Any, ...]
|
101
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
91
102
|
"""
|
92
103
|
Given a lookup_type of 'year', 'month', or 'day', return the SQL that
|
93
104
|
extracts a value from the given date field field_name.
|
@@ -97,7 +108,13 @@ class BaseDatabaseOperations:
|
|
97
108
|
"method"
|
98
109
|
)
|
99
110
|
|
100
|
-
def date_trunc_sql(
|
111
|
+
def date_trunc_sql(
|
112
|
+
self,
|
113
|
+
lookup_type: str,
|
114
|
+
sql: str,
|
115
|
+
params: list[Any] | tuple[Any, ...],
|
116
|
+
tzname: str | None = None,
|
117
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
101
118
|
"""
|
102
119
|
Given a lookup_type of 'year', 'month', or 'day', return the SQL that
|
103
120
|
truncates the given date or datetime field field_name to a date object
|
@@ -111,7 +128,9 @@ class BaseDatabaseOperations:
|
|
111
128
|
"method."
|
112
129
|
)
|
113
130
|
|
114
|
-
def datetime_cast_date_sql(
|
131
|
+
def datetime_cast_date_sql(
|
132
|
+
self, sql: str, params: list[Any] | tuple[Any, ...], tzname: str | None
|
133
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
115
134
|
"""
|
116
135
|
Return the SQL to cast a datetime value to date value.
|
117
136
|
"""
|
@@ -120,7 +139,9 @@ class BaseDatabaseOperations:
|
|
120
139
|
"datetime_cast_date_sql() method."
|
121
140
|
)
|
122
141
|
|
123
|
-
def datetime_cast_time_sql(
|
142
|
+
def datetime_cast_time_sql(
|
143
|
+
self, sql: str, params: list[Any] | tuple[Any, ...], tzname: str | None
|
144
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
124
145
|
"""
|
125
146
|
Return the SQL to cast a datetime value to time value.
|
126
147
|
"""
|
@@ -129,7 +150,13 @@ class BaseDatabaseOperations:
|
|
129
150
|
"datetime_cast_time_sql() method"
|
130
151
|
)
|
131
152
|
|
132
|
-
def datetime_extract_sql(
|
153
|
+
def datetime_extract_sql(
|
154
|
+
self,
|
155
|
+
lookup_type: str,
|
156
|
+
sql: str,
|
157
|
+
params: list[Any] | tuple[Any, ...],
|
158
|
+
tzname: str | None,
|
159
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
133
160
|
"""
|
134
161
|
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute', or
|
135
162
|
'second', return the SQL that extracts a value from the given
|
@@ -140,7 +167,13 @@ class BaseDatabaseOperations:
|
|
140
167
|
"method"
|
141
168
|
)
|
142
169
|
|
143
|
-
def datetime_trunc_sql(
|
170
|
+
def datetime_trunc_sql(
|
171
|
+
self,
|
172
|
+
lookup_type: str,
|
173
|
+
sql: str,
|
174
|
+
params: list[Any] | tuple[Any, ...],
|
175
|
+
tzname: str | None,
|
176
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
144
177
|
"""
|
145
178
|
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute', or
|
146
179
|
'second', return the SQL that truncates the given datetime field
|
@@ -151,7 +184,13 @@ class BaseDatabaseOperations:
|
|
151
184
|
"method"
|
152
185
|
)
|
153
186
|
|
154
|
-
def time_trunc_sql(
|
187
|
+
def time_trunc_sql(
|
188
|
+
self,
|
189
|
+
lookup_type: str,
|
190
|
+
sql: str,
|
191
|
+
params: list[Any] | tuple[Any, ...],
|
192
|
+
tzname: str | None = None,
|
193
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
155
194
|
"""
|
156
195
|
Given a lookup_type of 'hour', 'minute' or 'second', return the SQL
|
157
196
|
that truncates the given time or datetime field field_name to a time
|
@@ -164,21 +203,25 @@ class BaseDatabaseOperations:
|
|
164
203
|
"subclasses of BaseDatabaseOperations may require a time_trunc_sql() method"
|
165
204
|
)
|
166
205
|
|
167
|
-
def time_extract_sql(
|
206
|
+
def time_extract_sql(
|
207
|
+
self, lookup_type: str, sql: str, params: list[Any] | tuple[Any, ...]
|
208
|
+
) -> tuple[str, list[Any] | tuple[Any, ...]]:
|
168
209
|
"""
|
169
210
|
Given a lookup_type of 'hour', 'minute', or 'second', return the SQL
|
170
211
|
that extracts a value from the given time field field_name.
|
171
212
|
"""
|
172
213
|
return self.date_extract_sql(lookup_type, sql, params)
|
173
214
|
|
174
|
-
def deferrable_sql(self):
|
215
|
+
def deferrable_sql(self) -> str:
|
175
216
|
"""
|
176
217
|
Return the SQL to make a constraint "initially deferred" during a
|
177
218
|
CREATE TABLE statement.
|
178
219
|
"""
|
179
220
|
return ""
|
180
221
|
|
181
|
-
def distinct_sql(
|
222
|
+
def distinct_sql(
|
223
|
+
self, fields: list[str], params: list[Any] | tuple[Any, ...]
|
224
|
+
) -> tuple[list[str], list[Any]]:
|
182
225
|
"""
|
183
226
|
Return an SQL DISTINCT clause which removes duplicate rows from the
|
184
227
|
result set. If any fields are given, only check the given fields for
|
@@ -191,14 +234,14 @@ class BaseDatabaseOperations:
|
|
191
234
|
else:
|
192
235
|
return ["DISTINCT"], []
|
193
236
|
|
194
|
-
def fetch_returned_insert_columns(self, cursor, returning_params):
|
237
|
+
def fetch_returned_insert_columns(self, cursor: Any, returning_params: Any) -> Any:
|
195
238
|
"""
|
196
239
|
Given a cursor object that has just performed an INSERT...RETURNING
|
197
240
|
statement into a table, return the newly created data.
|
198
241
|
"""
|
199
242
|
return cursor.fetchone()
|
200
243
|
|
201
|
-
def field_cast_sql(self, db_type, internal_type):
|
244
|
+
def field_cast_sql(self, db_type: str | None, internal_type: str) -> str:
|
202
245
|
"""
|
203
246
|
Given a column type (e.g. 'BLOB', 'VARCHAR') and an internal type
|
204
247
|
(e.g. 'GenericIPAddressField'), return the SQL to cast it before using
|
@@ -207,14 +250,20 @@ class BaseDatabaseOperations:
|
|
207
250
|
"""
|
208
251
|
return "%s"
|
209
252
|
|
210
|
-
def force_no_ordering(self):
|
253
|
+
def force_no_ordering(self) -> list[str]:
|
211
254
|
"""
|
212
255
|
Return a list used in the "ORDER BY" clause to force no ordering at
|
213
256
|
all. Return an empty list to include nothing in the ordering.
|
214
257
|
"""
|
215
258
|
return []
|
216
259
|
|
217
|
-
def for_update_sql(
|
260
|
+
def for_update_sql(
|
261
|
+
self,
|
262
|
+
nowait: bool = False,
|
263
|
+
skip_locked: bool = False,
|
264
|
+
of: tuple[str, ...] = (),
|
265
|
+
no_key: bool = False,
|
266
|
+
) -> str:
|
218
267
|
"""
|
219
268
|
Return the FOR UPDATE SQL clause to lock rows for an update operation.
|
220
269
|
"""
|
@@ -225,7 +274,9 @@ class BaseDatabaseOperations:
|
|
225
274
|
" SKIP LOCKED" if skip_locked else "",
|
226
275
|
)
|
227
276
|
|
228
|
-
def _get_limit_offset_params(
|
277
|
+
def _get_limit_offset_params(
|
278
|
+
self, low_mark: int | None, high_mark: int | None
|
279
|
+
) -> tuple[int | None, int]:
|
229
280
|
offset = low_mark or 0
|
230
281
|
if high_mark is not None:
|
231
282
|
return (high_mark - offset), offset
|
@@ -233,7 +284,7 @@ class BaseDatabaseOperations:
|
|
233
284
|
return self.connection.ops.no_limit_value(), offset
|
234
285
|
return None, offset
|
235
286
|
|
236
|
-
def limit_offset_sql(self, low_mark, high_mark):
|
287
|
+
def limit_offset_sql(self, low_mark: int | None, high_mark: int | None) -> str:
|
237
288
|
"""Return LIMIT/OFFSET SQL clause."""
|
238
289
|
limit, offset = self._get_limit_offset_params(low_mark, high_mark)
|
239
290
|
return " ".join(
|
@@ -245,7 +296,12 @@ class BaseDatabaseOperations:
|
|
245
296
|
if sql
|
246
297
|
)
|
247
298
|
|
248
|
-
def last_executed_query(
|
299
|
+
def last_executed_query(
|
300
|
+
self,
|
301
|
+
cursor: Any,
|
302
|
+
sql: str,
|
303
|
+
params: list[Any] | tuple[Any, ...] | dict[str, Any] | None,
|
304
|
+
) -> str:
|
249
305
|
"""
|
250
306
|
Return a string of the query last executed by the given cursor, with
|
251
307
|
placeholders replaced with actual values.
|
@@ -257,19 +313,20 @@ class BaseDatabaseOperations:
|
|
257
313
|
"""
|
258
314
|
|
259
315
|
# Convert params to contain string values.
|
260
|
-
def to_string(s):
|
316
|
+
def to_string(s: Any) -> str:
|
261
317
|
return force_str(s, strings_only=True, errors="replace")
|
262
318
|
|
263
|
-
|
319
|
+
u_params: tuple[str, ...] | dict[str, str]
|
320
|
+
if isinstance(params, (list, tuple)): # noqa: UP038
|
264
321
|
u_params = tuple(to_string(val) for val in params)
|
265
322
|
elif params is None:
|
266
323
|
u_params = ()
|
267
324
|
else:
|
268
|
-
u_params = {to_string(k): to_string(v) for k, v in params.items()}
|
325
|
+
u_params = {to_string(k): to_string(v) for k, v in params.items()} # type: ignore[union-attr]
|
269
326
|
|
270
327
|
return f"QUERY = {sql!r} - PARAMS = {u_params!r}"
|
271
328
|
|
272
|
-
def last_insert_id(self, cursor, table_name, pk_name):
|
329
|
+
def last_insert_id(self, cursor: Any, table_name: str, pk_name: str) -> int:
|
273
330
|
"""
|
274
331
|
Given a cursor object that has just performed an INSERT statement into
|
275
332
|
a table that has an auto-incrementing ID, return the newly created ID.
|
@@ -278,7 +335,7 @@ class BaseDatabaseOperations:
|
|
278
335
|
"""
|
279
336
|
return cursor.lastrowid
|
280
337
|
|
281
|
-
def lookup_cast(self, lookup_type, internal_type=None):
|
338
|
+
def lookup_cast(self, lookup_type: str, internal_type: str | None = None) -> str:
|
282
339
|
"""
|
283
340
|
Return the string to use in a query when performing lookups
|
284
341
|
("contains", "like", etc.). It should contain a '%s' placeholder for
|
@@ -286,21 +343,21 @@ class BaseDatabaseOperations:
|
|
286
343
|
"""
|
287
344
|
return "%s"
|
288
345
|
|
289
|
-
def max_in_list_size(self):
|
346
|
+
def max_in_list_size(self) -> int | None:
|
290
347
|
"""
|
291
348
|
Return the maximum number of items that can be passed in a single 'IN'
|
292
349
|
list condition, or None if the backend does not impose a limit.
|
293
350
|
"""
|
294
351
|
return None
|
295
352
|
|
296
|
-
def max_name_length(self):
|
353
|
+
def max_name_length(self) -> int | None:
|
297
354
|
"""
|
298
355
|
Return the maximum length of table and column names, or None if there
|
299
356
|
is no limit.
|
300
357
|
"""
|
301
358
|
return None
|
302
359
|
|
303
|
-
def no_limit_value(self):
|
360
|
+
def no_limit_value(self) -> int | None:
|
304
361
|
"""
|
305
362
|
Return the value to use for the LIMIT when we are wanting "LIMIT
|
306
363
|
infinity". Return None if the limit clause can be omitted in this case.
|
@@ -309,14 +366,14 @@ class BaseDatabaseOperations:
|
|
309
366
|
"subclasses of BaseDatabaseOperations may require a no_limit_value() method"
|
310
367
|
)
|
311
368
|
|
312
|
-
def pk_default_value(self):
|
369
|
+
def pk_default_value(self) -> str:
|
313
370
|
"""
|
314
371
|
Return the value to use during an INSERT statement to specify that
|
315
372
|
the field should use its default value.
|
316
373
|
"""
|
317
374
|
return "DEFAULT"
|
318
375
|
|
319
|
-
def prepare_sql_script(self, sql):
|
376
|
+
def prepare_sql_script(self, sql: str) -> list[str]:
|
320
377
|
"""
|
321
378
|
Take an SQL script that may contain multiple lines and return a list
|
322
379
|
of statements to feed to successive cursor.execute() calls.
|
@@ -331,15 +388,17 @@ class BaseDatabaseOperations:
|
|
331
388
|
if statement
|
332
389
|
]
|
333
390
|
|
334
|
-
def return_insert_columns(
|
391
|
+
def return_insert_columns(
|
392
|
+
self, fields: list[Field]
|
393
|
+
) -> tuple[str, list[Any]] | None:
|
335
394
|
"""
|
336
395
|
For backends that support returning columns as part of an insert query,
|
337
396
|
return the SQL and params to append to the INSERT query. The returned
|
338
397
|
fragment should contain a format string to hold the appropriate column.
|
339
398
|
"""
|
340
|
-
|
399
|
+
return None
|
341
400
|
|
342
|
-
def compiler(self, compiler_name):
|
401
|
+
def compiler(self, compiler_name: str) -> type[Any]:
|
343
402
|
"""
|
344
403
|
Return the SQLCompiler class corresponding to the given name,
|
345
404
|
in the namespace corresponding to the `compiler_module` attribute
|
@@ -349,7 +408,7 @@ class BaseDatabaseOperations:
|
|
349
408
|
self._cache = import_module(self.compiler_module)
|
350
409
|
return getattr(self._cache, compiler_name)
|
351
410
|
|
352
|
-
def quote_name(self, name):
|
411
|
+
def quote_name(self, name: str) -> str:
|
353
412
|
"""
|
354
413
|
Return a quoted version of the given table, index, or column name. Do
|
355
414
|
not quote the given name if it's already been quoted.
|
@@ -358,7 +417,7 @@ class BaseDatabaseOperations:
|
|
358
417
|
"subclasses of BaseDatabaseOperations may require a quote_name() method"
|
359
418
|
)
|
360
419
|
|
361
|
-
def regex_lookup(self, lookup_type):
|
420
|
+
def regex_lookup(self, lookup_type: str) -> str:
|
362
421
|
"""
|
363
422
|
Return the string to use in a query when performing regular expression
|
364
423
|
lookups (using "regex" or "iregex"). It should contain a '%s'
|
@@ -371,7 +430,7 @@ class BaseDatabaseOperations:
|
|
371
430
|
"subclasses of BaseDatabaseOperations may require a regex_lookup() method"
|
372
431
|
)
|
373
432
|
|
374
|
-
def savepoint_create_sql(self, sid):
|
433
|
+
def savepoint_create_sql(self, sid: str) -> str:
|
375
434
|
"""
|
376
435
|
Return the SQL for starting a new savepoint. Only required if the
|
377
436
|
"uses_savepoints" feature is True. The "sid" parameter is a string
|
@@ -379,19 +438,19 @@ class BaseDatabaseOperations:
|
|
379
438
|
"""
|
380
439
|
return f"SAVEPOINT {self.quote_name(sid)}"
|
381
440
|
|
382
|
-
def savepoint_commit_sql(self, sid):
|
441
|
+
def savepoint_commit_sql(self, sid: str) -> str:
|
383
442
|
"""
|
384
443
|
Return the SQL for committing the given savepoint.
|
385
444
|
"""
|
386
445
|
return f"RELEASE SAVEPOINT {self.quote_name(sid)}"
|
387
446
|
|
388
|
-
def savepoint_rollback_sql(self, sid):
|
447
|
+
def savepoint_rollback_sql(self, sid: str) -> str:
|
389
448
|
"""
|
390
449
|
Return the SQL for rolling back the given savepoint.
|
391
450
|
"""
|
392
451
|
return f"ROLLBACK TO SAVEPOINT {self.quote_name(sid)}"
|
393
452
|
|
394
|
-
def set_time_zone_sql(self):
|
453
|
+
def set_time_zone_sql(self) -> str:
|
395
454
|
"""
|
396
455
|
Return the SQL that will set the connection's time zone.
|
397
456
|
|
@@ -399,7 +458,7 @@ class BaseDatabaseOperations:
|
|
399
458
|
"""
|
400
459
|
return ""
|
401
460
|
|
402
|
-
def prep_for_like_query(self, x):
|
461
|
+
def prep_for_like_query(self, x: str) -> str:
|
403
462
|
"""Prepare a value for use in a LIKE query."""
|
404
463
|
return str(x).replace("\\", "\\\\").replace("%", r"\%").replace("_", r"\_")
|
405
464
|
|
@@ -407,7 +466,7 @@ class BaseDatabaseOperations:
|
|
407
466
|
# need not necessarily be implemented using "LIKE" in the backend.
|
408
467
|
prep_for_iexact_query = prep_for_like_query
|
409
468
|
|
410
|
-
def validate_autopk_value(self, value):
|
469
|
+
def validate_autopk_value(self, value: int) -> int:
|
411
470
|
"""
|
412
471
|
Certain backends do not accept some values for "serial" fields
|
413
472
|
(for example zero in MySQL). Raise a ValueError if the value is
|
@@ -415,7 +474,7 @@ class BaseDatabaseOperations:
|
|
415
474
|
"""
|
416
475
|
return value
|
417
476
|
|
418
|
-
def adapt_unknown_value(self, value):
|
477
|
+
def adapt_unknown_value(self, value: Any) -> Any:
|
419
478
|
"""
|
420
479
|
Transform a value to something compatible with the backend driver.
|
421
480
|
|
@@ -434,10 +493,12 @@ class BaseDatabaseOperations:
|
|
434
493
|
else:
|
435
494
|
return value
|
436
495
|
|
437
|
-
def adapt_integerfield_value(
|
496
|
+
def adapt_integerfield_value(
|
497
|
+
self, value: int | None, internal_type: str
|
498
|
+
) -> int | None:
|
438
499
|
return value
|
439
500
|
|
440
|
-
def adapt_datefield_value(self, value):
|
501
|
+
def adapt_datefield_value(self, value: datetime.date | None) -> str | None:
|
441
502
|
"""
|
442
503
|
Transform a date value to an object compatible with what is expected
|
443
504
|
by the backend driver for date columns.
|
@@ -446,7 +507,9 @@ class BaseDatabaseOperations:
|
|
446
507
|
return None
|
447
508
|
return str(value)
|
448
509
|
|
449
|
-
def adapt_datetimefield_value(
|
510
|
+
def adapt_datetimefield_value(
|
511
|
+
self, value: datetime.datetime | Any | None
|
512
|
+
) -> str | Any | None:
|
450
513
|
"""
|
451
514
|
Transform a datetime value to an object compatible with what is expected
|
452
515
|
by the backend driver for datetime columns.
|
@@ -459,7 +522,9 @@ class BaseDatabaseOperations:
|
|
459
522
|
|
460
523
|
return str(value)
|
461
524
|
|
462
|
-
def adapt_timefield_value(
|
525
|
+
def adapt_timefield_value(
|
526
|
+
self, value: datetime.time | Any | None
|
527
|
+
) -> str | Any | None:
|
463
528
|
"""
|
464
529
|
Transform a time value to an object compatible with what is expected
|
465
530
|
by the backend driver for time columns.
|
@@ -470,28 +535,35 @@ class BaseDatabaseOperations:
|
|
470
535
|
if hasattr(value, "resolve_expression"):
|
471
536
|
return value
|
472
537
|
|
473
|
-
if timezone.is_aware(value):
|
538
|
+
if timezone.is_aware(value): # type: ignore[arg-type]
|
474
539
|
raise ValueError("Plain does not support timezone-aware times.")
|
475
540
|
return str(value)
|
476
541
|
|
477
|
-
def adapt_decimalfield_value(
|
542
|
+
def adapt_decimalfield_value(
|
543
|
+
self,
|
544
|
+
value: decimal.Decimal | None,
|
545
|
+
max_digits: int | None = None,
|
546
|
+
decimal_places: int | None = None,
|
547
|
+
) -> str | None:
|
478
548
|
"""
|
479
549
|
Transform a decimal.Decimal value to an object compatible with what is
|
480
550
|
expected by the backend driver for decimal (numeric) columns.
|
481
551
|
"""
|
482
552
|
return utils.format_number(value, max_digits, decimal_places)
|
483
553
|
|
484
|
-
def adapt_ipaddressfield_value(self, value):
|
554
|
+
def adapt_ipaddressfield_value(self, value: str | None) -> str | None:
|
485
555
|
"""
|
486
556
|
Transform a string representation of an IP address into the expected
|
487
557
|
type for the backend driver.
|
488
558
|
"""
|
489
559
|
return value or None
|
490
560
|
|
491
|
-
def adapt_json_value(self, value, encoder):
|
561
|
+
def adapt_json_value(self, value: Any, encoder: type[json.JSONEncoder]) -> str:
|
492
562
|
return json.dumps(value, cls=encoder)
|
493
563
|
|
494
|
-
def year_lookup_bounds_for_date_field(
|
564
|
+
def year_lookup_bounds_for_date_field(
|
565
|
+
self, value: int, iso_year: bool = False
|
566
|
+
) -> list[str | None]:
|
495
567
|
"""
|
496
568
|
Return a two-elements list with the lower and upper bound to be used
|
497
569
|
with a BETWEEN operator to query a DateField value using a year
|
@@ -508,11 +580,13 @@ class BaseDatabaseOperations:
|
|
508
580
|
else:
|
509
581
|
first = datetime.date(value, 1, 1)
|
510
582
|
second = datetime.date(value, 12, 31)
|
511
|
-
|
512
|
-
|
513
|
-
return [
|
583
|
+
first_adapted = self.adapt_datefield_value(first)
|
584
|
+
second_adapted = self.adapt_datefield_value(second)
|
585
|
+
return [first_adapted, second_adapted]
|
514
586
|
|
515
|
-
def year_lookup_bounds_for_datetime_field(
|
587
|
+
def year_lookup_bounds_for_datetime_field(
|
588
|
+
self, value: int, iso_year: bool = False
|
589
|
+
) -> list[str | Any | None]:
|
516
590
|
"""
|
517
591
|
Return a two-elements list with the lower and upper bound to be used
|
518
592
|
with a BETWEEN operator to query a DateTimeField value using a year
|
@@ -535,11 +609,11 @@ class BaseDatabaseOperations:
|
|
535
609
|
first = timezone.make_aware(first, tz)
|
536
610
|
second = timezone.make_aware(second, tz)
|
537
611
|
|
538
|
-
|
539
|
-
|
540
|
-
return [
|
612
|
+
first_adapted = self.adapt_datetimefield_value(first)
|
613
|
+
second_adapted = self.adapt_datetimefield_value(second)
|
614
|
+
return [first_adapted, second_adapted]
|
541
615
|
|
542
|
-
def get_db_converters(self, expression):
|
616
|
+
def get_db_converters(self, expression: Any) -> list[Any]:
|
543
617
|
"""
|
544
618
|
Return a list of functions needed to convert field data.
|
545
619
|
|
@@ -548,11 +622,14 @@ class BaseDatabaseOperations:
|
|
548
622
|
"""
|
549
623
|
return []
|
550
624
|
|
551
|
-
def convert_durationfield_value(
|
625
|
+
def convert_durationfield_value(
|
626
|
+
self, value: int | None, expression: Any, connection: BaseDatabaseWrapper
|
627
|
+
) -> datetime.timedelta | None:
|
552
628
|
if value is not None:
|
553
629
|
return datetime.timedelta(0, 0, value)
|
630
|
+
return None
|
554
631
|
|
555
|
-
def check_expression_support(self, expression):
|
632
|
+
def check_expression_support(self, expression: Any) -> None:
|
556
633
|
"""
|
557
634
|
Check that the backend supports the provided expression.
|
558
635
|
|
@@ -561,16 +638,16 @@ class BaseDatabaseOperations:
|
|
561
638
|
expression has a known problem, the backend should raise
|
562
639
|
NotSupportedError.
|
563
640
|
"""
|
564
|
-
|
641
|
+
return None
|
565
642
|
|
566
|
-
def conditional_expression_supported_in_where_clause(self, expression):
|
643
|
+
def conditional_expression_supported_in_where_clause(self, expression: Any) -> bool:
|
567
644
|
"""
|
568
645
|
Return True, if the conditional expression is supported in the WHERE
|
569
646
|
clause.
|
570
647
|
"""
|
571
648
|
return True
|
572
649
|
|
573
|
-
def combine_expression(self, connector, sub_expressions):
|
650
|
+
def combine_expression(self, connector: str, sub_expressions: list[str]) -> str:
|
574
651
|
"""
|
575
652
|
Combine a list of subexpressions into a single expression, using
|
576
653
|
the provided connecting operator. This is required because operators
|
@@ -580,24 +657,28 @@ class BaseDatabaseOperations:
|
|
580
657
|
conn = f" {connector} "
|
581
658
|
return conn.join(sub_expressions)
|
582
659
|
|
583
|
-
def combine_duration_expression(
|
660
|
+
def combine_duration_expression(
|
661
|
+
self, connector: str, sub_expressions: list[str]
|
662
|
+
) -> str:
|
584
663
|
return self.combine_expression(connector, sub_expressions)
|
585
664
|
|
586
|
-
def binary_placeholder_sql(self, value):
|
665
|
+
def binary_placeholder_sql(self, value: Any) -> str:
|
587
666
|
"""
|
588
667
|
Some backends require special syntax to insert binary content (MySQL
|
589
668
|
for example uses '_binary %s').
|
590
669
|
"""
|
591
670
|
return "%s"
|
592
671
|
|
593
|
-
def modify_insert_params(
|
672
|
+
def modify_insert_params(
|
673
|
+
self, placeholder: str, params: list[Any] | tuple[Any, ...]
|
674
|
+
) -> list[Any] | tuple[Any, ...]:
|
594
675
|
"""
|
595
676
|
Allow modification of insert parameters. Needed for Oracle Spatial
|
596
677
|
backend due to #10888.
|
597
678
|
"""
|
598
679
|
return params
|
599
680
|
|
600
|
-
def integer_field_range(self, internal_type):
|
681
|
+
def integer_field_range(self, internal_type: str) -> tuple[int, int]:
|
601
682
|
"""
|
602
683
|
Given an integer field internal type (e.g. 'PositiveIntegerField'),
|
603
684
|
return a tuple of the (min_value, max_value) form representing the
|
@@ -605,7 +686,12 @@ class BaseDatabaseOperations:
|
|
605
686
|
"""
|
606
687
|
return self.integer_field_ranges[internal_type]
|
607
688
|
|
608
|
-
def subtract_temporals(
|
689
|
+
def subtract_temporals(
|
690
|
+
self,
|
691
|
+
internal_type: str,
|
692
|
+
lhs: tuple[str, list[Any] | tuple[Any, ...]],
|
693
|
+
rhs: tuple[str, list[Any] | tuple[Any, ...]],
|
694
|
+
) -> tuple[str, tuple[Any, ...]]:
|
609
695
|
if self.connection.features.supports_temporal_subtraction:
|
610
696
|
lhs_sql, lhs_params = lhs
|
611
697
|
rhs_sql, rhs_params = rhs
|
@@ -614,7 +700,7 @@ class BaseDatabaseOperations:
|
|
614
700
|
f"This backend does not support {internal_type} subtraction."
|
615
701
|
)
|
616
702
|
|
617
|
-
def window_frame_start(self, start):
|
703
|
+
def window_frame_start(self, start: int | None) -> str:
|
618
704
|
if isinstance(start, int):
|
619
705
|
if start < 0:
|
620
706
|
return "%d %s" % (abs(start), self.PRECEDING) # noqa: UP031
|
@@ -626,7 +712,7 @@ class BaseDatabaseOperations:
|
|
626
712
|
f"start argument must be a negative integer, zero, or None, but got '{start}'."
|
627
713
|
)
|
628
714
|
|
629
|
-
def window_frame_end(self, end):
|
715
|
+
def window_frame_end(self, end: int | None) -> str:
|
630
716
|
if isinstance(end, int):
|
631
717
|
if end == 0:
|
632
718
|
return self.CURRENT_ROW
|
@@ -638,7 +724,9 @@ class BaseDatabaseOperations:
|
|
638
724
|
f"end argument must be a positive integer, zero, or None, but got '{end}'."
|
639
725
|
)
|
640
726
|
|
641
|
-
def window_frame_rows_start_end(
|
727
|
+
def window_frame_rows_start_end(
|
728
|
+
self, start: int | None = None, end: int | None = None
|
729
|
+
) -> tuple[str, str]:
|
642
730
|
"""
|
643
731
|
Return SQL for start and end points in an OVER clause window frame.
|
644
732
|
"""
|
@@ -646,7 +734,9 @@ class BaseDatabaseOperations:
|
|
646
734
|
raise NotSupportedError("This backend does not support window expressions.")
|
647
735
|
return self.window_frame_start(start), self.window_frame_end(end)
|
648
736
|
|
649
|
-
def window_frame_range_start_end(
|
737
|
+
def window_frame_range_start_end(
|
738
|
+
self, start: int | None = None, end: int | None = None
|
739
|
+
) -> tuple[str, str]:
|
650
740
|
start_, end_ = self.window_frame_rows_start_end(start, end)
|
651
741
|
features = self.connection.features
|
652
742
|
if features.only_supports_unbounded_with_preceding_and_following and (
|
@@ -658,7 +748,7 @@ class BaseDatabaseOperations:
|
|
658
748
|
)
|
659
749
|
return start_, end_
|
660
750
|
|
661
|
-
def explain_query_prefix(self, format=None, **options):
|
751
|
+
def explain_query_prefix(self, format: str | None = None, **options: Any) -> str:
|
662
752
|
if not self.connection.features.supports_explaining_query_execution:
|
663
753
|
raise NotSupportedError(
|
664
754
|
"This backend does not support explaining query execution."
|
@@ -681,10 +771,16 @@ class BaseDatabaseOperations:
|
|
681
771
|
raise ValueError(
|
682
772
|
"Unknown options: {}".format(", ".join(sorted(options.keys())))
|
683
773
|
)
|
684
|
-
return self.explain_prefix
|
774
|
+
return self.explain_prefix # type: ignore[return-value]
|
685
775
|
|
686
|
-
def insert_statement(self, on_conflict=None):
|
776
|
+
def insert_statement(self, on_conflict: Any = None) -> str:
|
687
777
|
return "INSERT INTO"
|
688
778
|
|
689
|
-
def on_conflict_suffix_sql(
|
779
|
+
def on_conflict_suffix_sql(
|
780
|
+
self,
|
781
|
+
fields: list[Field],
|
782
|
+
on_conflict: Any,
|
783
|
+
update_fields: list[Field],
|
784
|
+
unique_fields: list[Field],
|
785
|
+
) -> str:
|
690
786
|
return ""
|