plain.models 0.49.2__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 +13 -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 +31 -22
- 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.2.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.2.dist-info/RECORD +0 -122
- {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.50.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,7 +1,11 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import datetime
|
2
4
|
import decimal
|
3
5
|
import uuid
|
6
|
+
from collections.abc import Callable
|
4
7
|
from functools import cached_property, lru_cache
|
8
|
+
from typing import TYPE_CHECKING, Any
|
5
9
|
|
6
10
|
from plain import models
|
7
11
|
from plain.models.backends.base.operations import BaseDatabaseOperations
|
@@ -12,6 +16,9 @@ from plain.models.expressions import Col
|
|
12
16
|
from plain.utils import timezone
|
13
17
|
from plain.utils.dateparse import parse_date, parse_datetime, parse_time
|
14
18
|
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from plain.models.backends.base.base import BaseDatabaseWrapper
|
21
|
+
|
15
22
|
|
16
23
|
class DatabaseOperations(BaseDatabaseOperations):
|
17
24
|
cast_char_field_without_max_length = "text"
|
@@ -24,7 +31,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
24
31
|
# SQLite. Use JSON_TYPE() instead.
|
25
32
|
jsonfield_datatype_values = frozenset(["null", "false", "true"])
|
26
33
|
|
27
|
-
def bulk_batch_size(self, fields, objs):
|
34
|
+
def bulk_batch_size(self, fields: list[Any], objs: list[Any]) -> int:
|
28
35
|
"""
|
29
36
|
SQLite has a compile-time default (SQLITE_LIMIT_VARIABLE_NUMBER) of
|
30
37
|
999 variables per query.
|
@@ -39,7 +46,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
39
46
|
else:
|
40
47
|
return len(objs)
|
41
48
|
|
42
|
-
def check_expression_support(self, expression):
|
49
|
+
def check_expression_support(self, expression: Any) -> None:
|
43
50
|
bad_fields = (models.DateField, models.DateTimeField, models.TimeField)
|
44
51
|
bad_aggregates = (models.Sum, models.Avg, models.Variance, models.StdDev)
|
45
52
|
if isinstance(expression, bad_aggregates):
|
@@ -67,7 +74,9 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
67
74
|
"accepting multiple arguments."
|
68
75
|
)
|
69
76
|
|
70
|
-
def date_extract_sql(
|
77
|
+
def date_extract_sql(
|
78
|
+
self, lookup_type: str, sql: str, params: list[Any] | tuple[Any, ...]
|
79
|
+
) -> tuple[str, tuple[Any, ...]]:
|
71
80
|
"""
|
72
81
|
Support EXTRACT with a user-defined function plain_date_extract()
|
73
82
|
that's registered in connect(). Use single quotes because this is a
|
@@ -75,69 +84,103 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
75
84
|
"""
|
76
85
|
return f"plain_date_extract(%s, {sql})", (lookup_type.lower(), *params)
|
77
86
|
|
78
|
-
def fetch_returned_insert_rows(self, cursor):
|
87
|
+
def fetch_returned_insert_rows(self, cursor: Any) -> list[Any]:
|
79
88
|
"""
|
80
89
|
Given a cursor object that has just performed an INSERT...RETURNING
|
81
90
|
statement into a table, return the list of returned data.
|
82
91
|
"""
|
83
92
|
return cursor.fetchall()
|
84
93
|
|
85
|
-
def format_for_duration_arithmetic(self, sql):
|
94
|
+
def format_for_duration_arithmetic(self, sql: str) -> str:
|
86
95
|
"""Do nothing since formatting is handled in the custom function."""
|
87
96
|
return sql
|
88
97
|
|
89
|
-
def date_trunc_sql(
|
98
|
+
def date_trunc_sql(
|
99
|
+
self,
|
100
|
+
lookup_type: str,
|
101
|
+
sql: str,
|
102
|
+
params: list[Any] | tuple[Any, ...],
|
103
|
+
tzname: str | None = None,
|
104
|
+
) -> tuple[str, tuple[Any, ...]]:
|
90
105
|
return f"plain_date_trunc(%s, {sql}, %s, %s)", (
|
91
106
|
lookup_type.lower(),
|
92
107
|
*params,
|
93
108
|
*self._convert_tznames_to_sql(tzname),
|
94
109
|
)
|
95
110
|
|
96
|
-
def time_trunc_sql(
|
111
|
+
def time_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, tuple[Any, ...]]:
|
97
118
|
return f"plain_time_trunc(%s, {sql}, %s, %s)", (
|
98
119
|
lookup_type.lower(),
|
99
120
|
*params,
|
100
121
|
*self._convert_tznames_to_sql(tzname),
|
101
122
|
)
|
102
123
|
|
103
|
-
def _convert_tznames_to_sql(
|
124
|
+
def _convert_tznames_to_sql(
|
125
|
+
self, tzname: str | None
|
126
|
+
) -> tuple[str | None, str | None]:
|
104
127
|
if tzname:
|
105
128
|
return tzname, self.connection.timezone_name
|
106
129
|
return None, None
|
107
130
|
|
108
|
-
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, tuple[Any, ...]]:
|
109
134
|
return f"plain_datetime_cast_date({sql}, %s, %s)", (
|
110
135
|
*params,
|
111
136
|
*self._convert_tznames_to_sql(tzname),
|
112
137
|
)
|
113
138
|
|
114
|
-
def datetime_cast_time_sql(
|
139
|
+
def datetime_cast_time_sql(
|
140
|
+
self, sql: str, params: list[Any] | tuple[Any, ...], tzname: str | None
|
141
|
+
) -> tuple[str, tuple[Any, ...]]:
|
115
142
|
return f"plain_datetime_cast_time({sql}, %s, %s)", (
|
116
143
|
*params,
|
117
144
|
*self._convert_tznames_to_sql(tzname),
|
118
145
|
)
|
119
146
|
|
120
|
-
def datetime_extract_sql(
|
147
|
+
def datetime_extract_sql(
|
148
|
+
self,
|
149
|
+
lookup_type: str,
|
150
|
+
sql: str,
|
151
|
+
params: list[Any] | tuple[Any, ...],
|
152
|
+
tzname: str | None,
|
153
|
+
) -> tuple[str, tuple[Any, ...]]:
|
121
154
|
return f"plain_datetime_extract(%s, {sql}, %s, %s)", (
|
122
155
|
lookup_type.lower(),
|
123
156
|
*params,
|
124
157
|
*self._convert_tznames_to_sql(tzname),
|
125
158
|
)
|
126
159
|
|
127
|
-
def datetime_trunc_sql(
|
160
|
+
def datetime_trunc_sql(
|
161
|
+
self,
|
162
|
+
lookup_type: str,
|
163
|
+
sql: str,
|
164
|
+
params: list[Any] | tuple[Any, ...],
|
165
|
+
tzname: str | None,
|
166
|
+
) -> tuple[str, tuple[Any, ...]]:
|
128
167
|
return f"plain_datetime_trunc(%s, {sql}, %s, %s)", (
|
129
168
|
lookup_type.lower(),
|
130
169
|
*params,
|
131
170
|
*self._convert_tznames_to_sql(tzname),
|
132
171
|
)
|
133
172
|
|
134
|
-
def time_extract_sql(
|
173
|
+
def time_extract_sql(
|
174
|
+
self, lookup_type: str, sql: str, params: list[Any] | tuple[Any, ...]
|
175
|
+
) -> tuple[str, tuple[Any, ...]]:
|
135
176
|
return f"plain_time_extract(%s, {sql})", (lookup_type.lower(), *params)
|
136
177
|
|
137
|
-
def pk_default_value(self):
|
178
|
+
def pk_default_value(self) -> str:
|
138
179
|
return "NULL"
|
139
180
|
|
140
|
-
def _quote_params_for_last_executed_query(
|
181
|
+
def _quote_params_for_last_executed_query(
|
182
|
+
self, params: list[Any] | tuple[Any, ...]
|
183
|
+
) -> tuple[Any, ...]:
|
141
184
|
"""
|
142
185
|
Only for last_executed_query! Don't use this to execute SQL queries!
|
143
186
|
"""
|
@@ -164,7 +207,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
164
207
|
finally:
|
165
208
|
cursor.close()
|
166
209
|
|
167
|
-
def last_executed_query(
|
210
|
+
def last_executed_query(
|
211
|
+
self,
|
212
|
+
cursor: Any,
|
213
|
+
sql: str,
|
214
|
+
params: list[Any] | tuple[Any, ...] | dict[str, Any] | None,
|
215
|
+
) -> str:
|
168
216
|
# Python substitutes parameters in Modules/_sqlite/cursor.c with:
|
169
217
|
# bind_parameters(state, self->statement, parameters);
|
170
218
|
# Unfortunately there is no way to reach self->statement from Python,
|
@@ -173,7 +221,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
173
221
|
if isinstance(params, list | tuple):
|
174
222
|
params = self._quote_params_for_last_executed_query(params)
|
175
223
|
else:
|
176
|
-
values = tuple(params.values())
|
224
|
+
values = tuple(params.values()) # type: ignore[union-attr]
|
177
225
|
values = self._quote_params_for_last_executed_query(values)
|
178
226
|
params = dict(zip(params, values))
|
179
227
|
return sql % params
|
@@ -182,15 +230,15 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
182
230
|
else:
|
183
231
|
return sql
|
184
232
|
|
185
|
-
def quote_name(self, name):
|
233
|
+
def quote_name(self, name: str) -> str:
|
186
234
|
if name.startswith('"') and name.endswith('"'):
|
187
235
|
return name # Quoting once is enough.
|
188
236
|
return f'"{name}"'
|
189
237
|
|
190
|
-
def no_limit_value(self):
|
238
|
+
def no_limit_value(self) -> int:
|
191
239
|
return -1
|
192
240
|
|
193
|
-
def __references_graph(self, table_name):
|
241
|
+
def __references_graph(self, table_name: str) -> list[str]:
|
194
242
|
query = """
|
195
243
|
WITH tables AS (
|
196
244
|
SELECT %s name
|
@@ -210,12 +258,14 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
210
258
|
return [row[0] for row in results.fetchall()]
|
211
259
|
|
212
260
|
@cached_property
|
213
|
-
def _references_graph(self):
|
261
|
+
def _references_graph(self) -> Callable[[str], list[str]]:
|
214
262
|
# 512 is large enough to fit the ~330 tables (as of this writing) in
|
215
263
|
# Plain's test suite.
|
216
264
|
return lru_cache(maxsize=512)(self.__references_graph)
|
217
265
|
|
218
|
-
def adapt_datetimefield_value(
|
266
|
+
def adapt_datetimefield_value(
|
267
|
+
self, value: datetime.datetime | Any | None
|
268
|
+
) -> str | Any | None:
|
219
269
|
if value is None:
|
220
270
|
return None
|
221
271
|
|
@@ -229,7 +279,9 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
229
279
|
|
230
280
|
return str(value)
|
231
281
|
|
232
|
-
def adapt_timefield_value(
|
282
|
+
def adapt_timefield_value(
|
283
|
+
self, value: datetime.time | Any | None
|
284
|
+
) -> str | Any | None:
|
233
285
|
if value is None:
|
234
286
|
return None
|
235
287
|
|
@@ -238,12 +290,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
238
290
|
return value
|
239
291
|
|
240
292
|
# SQLite doesn't support tz-aware datetimes
|
241
|
-
if timezone.is_aware(value):
|
293
|
+
if timezone.is_aware(value): # type: ignore[arg-type]
|
242
294
|
raise ValueError("SQLite backend does not support timezone-aware times.")
|
243
295
|
|
244
296
|
return str(value)
|
245
297
|
|
246
|
-
def get_db_converters(self, expression):
|
298
|
+
def get_db_converters(self, expression: Any) -> list[Any]:
|
247
299
|
converters = super().get_db_converters(expression)
|
248
300
|
internal_type = expression.output_field.get_internal_type()
|
249
301
|
if internal_type == "DateTimeField":
|
@@ -260,27 +312,33 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
260
312
|
converters.append(self.convert_booleanfield_value)
|
261
313
|
return converters
|
262
314
|
|
263
|
-
def convert_datetimefield_value(
|
315
|
+
def convert_datetimefield_value(
|
316
|
+
self, value: Any, expression: Any, connection: BaseDatabaseWrapper
|
317
|
+
) -> datetime.datetime | None:
|
264
318
|
if value is not None:
|
265
319
|
if not isinstance(value, datetime.datetime):
|
266
320
|
value = parse_datetime(value)
|
267
|
-
if not timezone.is_aware(value):
|
321
|
+
if value is not None and not timezone.is_aware(value):
|
268
322
|
value = timezone.make_aware(value, self.connection.timezone)
|
269
323
|
return value
|
270
324
|
|
271
|
-
def convert_datefield_value(
|
325
|
+
def convert_datefield_value(
|
326
|
+
self, value: Any, expression: Any, connection: BaseDatabaseWrapper
|
327
|
+
) -> datetime.date | None:
|
272
328
|
if value is not None:
|
273
329
|
if not isinstance(value, datetime.date):
|
274
330
|
value = parse_date(value)
|
275
331
|
return value
|
276
332
|
|
277
|
-
def convert_timefield_value(
|
333
|
+
def convert_timefield_value(
|
334
|
+
self, value: Any, expression: Any, connection: BaseDatabaseWrapper
|
335
|
+
) -> datetime.time | None:
|
278
336
|
if value is not None:
|
279
337
|
if not isinstance(value, datetime.time):
|
280
338
|
value = parse_time(value)
|
281
339
|
return value
|
282
340
|
|
283
|
-
def get_decimalfield_converter(self, expression):
|
341
|
+
def get_decimalfield_converter(self, expression: Any) -> Callable[..., Any]:
|
284
342
|
# SQLite stores only 15 significant digits. Digits coming from
|
285
343
|
# float inaccuracy must be removed.
|
286
344
|
create_decimal = decimal.Context(prec=15).create_decimal_from_float
|
@@ -289,34 +347,46 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
289
347
|
-expression.output_field.decimal_places
|
290
348
|
)
|
291
349
|
|
292
|
-
def converter(
|
350
|
+
def converter(
|
351
|
+
value: Any, expression: Any, connection: BaseDatabaseWrapper
|
352
|
+
) -> decimal.Decimal | None:
|
293
353
|
if value is not None:
|
294
354
|
return create_decimal(value).quantize(
|
295
355
|
quantize_value, context=expression.output_field.context
|
296
356
|
)
|
357
|
+
return None
|
297
358
|
|
298
359
|
else:
|
299
360
|
|
300
|
-
def converter(
|
361
|
+
def converter(
|
362
|
+
value: Any, expression: Any, connection: BaseDatabaseWrapper
|
363
|
+
) -> decimal.Decimal | None:
|
301
364
|
if value is not None:
|
302
365
|
return create_decimal(value)
|
366
|
+
return None
|
303
367
|
|
304
368
|
return converter
|
305
369
|
|
306
|
-
def convert_uuidfield_value(
|
370
|
+
def convert_uuidfield_value(
|
371
|
+
self, value: Any, expression: Any, connection: BaseDatabaseWrapper
|
372
|
+
) -> uuid.UUID | None:
|
307
373
|
if value is not None:
|
308
374
|
value = uuid.UUID(value)
|
309
375
|
return value
|
310
376
|
|
311
|
-
def convert_booleanfield_value(
|
377
|
+
def convert_booleanfield_value(
|
378
|
+
self, value: Any, expression: Any, connection: BaseDatabaseWrapper
|
379
|
+
) -> bool | Any:
|
312
380
|
return bool(value) if value in (1, 0) else value
|
313
381
|
|
314
|
-
def bulk_insert_sql(
|
382
|
+
def bulk_insert_sql(
|
383
|
+
self, fields: list[Any], placeholder_rows: list[list[str]]
|
384
|
+
) -> str:
|
315
385
|
placeholder_rows_sql = (", ".join(row) for row in placeholder_rows)
|
316
386
|
values_sql = ", ".join(f"({sql})" for sql in placeholder_rows_sql)
|
317
387
|
return f"VALUES {values_sql}"
|
318
388
|
|
319
|
-
def combine_expression(self, connector, sub_expressions):
|
389
|
+
def combine_expression(self, connector: str, sub_expressions: list[str]) -> str:
|
320
390
|
# SQLite doesn't have a ^ operator, so use the user-defined POWER
|
321
391
|
# function that's registered in connect().
|
322
392
|
if connector == "^":
|
@@ -325,7 +395,9 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
325
395
|
return "BITXOR({})".format(",".join(sub_expressions))
|
326
396
|
return super().combine_expression(connector, sub_expressions)
|
327
397
|
|
328
|
-
def combine_duration_expression(
|
398
|
+
def combine_duration_expression(
|
399
|
+
self, connector: str, sub_expressions: list[str]
|
400
|
+
) -> str:
|
329
401
|
if connector not in ["+", "-", "*", "/"]:
|
330
402
|
raise DatabaseError(f"Invalid connector for timedelta: {connector}.")
|
331
403
|
fn_params = [f"'{connector}'"] + sub_expressions
|
@@ -333,7 +405,7 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
333
405
|
raise ValueError("Too many params for timedelta operations.")
|
334
406
|
return "plain_format_dtdelta({})".format(", ".join(fn_params))
|
335
407
|
|
336
|
-
def integer_field_range(self, internal_type):
|
408
|
+
def integer_field_range(self, internal_type: str) -> tuple[int, int]:
|
337
409
|
# SQLite doesn't enforce any integer constraints, but sqlite3 supports
|
338
410
|
# integers up to 64 bits.
|
339
411
|
if internal_type in [
|
@@ -344,7 +416,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
344
416
|
return (0, 9223372036854775807)
|
345
417
|
return (-9223372036854775808, 9223372036854775807)
|
346
418
|
|
347
|
-
def subtract_temporals(
|
419
|
+
def subtract_temporals(
|
420
|
+
self,
|
421
|
+
internal_type: str,
|
422
|
+
lhs: tuple[str, list[Any] | tuple[Any, ...]],
|
423
|
+
rhs: tuple[str, list[Any] | tuple[Any, ...]],
|
424
|
+
) -> tuple[str, tuple[Any, ...]]:
|
348
425
|
lhs_sql, lhs_params = lhs
|
349
426
|
rhs_sql, rhs_params = rhs
|
350
427
|
params = (*lhs_params, *rhs_params)
|
@@ -352,12 +429,12 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
352
429
|
return f"plain_time_diff({lhs_sql}, {rhs_sql})", params
|
353
430
|
return f"plain_timestamp_diff({lhs_sql}, {rhs_sql})", params
|
354
431
|
|
355
|
-
def insert_statement(self, on_conflict=None):
|
432
|
+
def insert_statement(self, on_conflict: Any = None) -> str:
|
356
433
|
if on_conflict == OnConflict.IGNORE:
|
357
434
|
return "INSERT OR IGNORE INTO"
|
358
435
|
return super().insert_statement(on_conflict=on_conflict)
|
359
436
|
|
360
|
-
def return_insert_columns(self, fields):
|
437
|
+
def return_insert_columns(self, fields: list[Any]) -> tuple[str, tuple[Any, ...]]:
|
361
438
|
# SQLite < 3.35 doesn't support an INSERT...RETURNING statement.
|
362
439
|
if not fields:
|
363
440
|
return "", ()
|
@@ -367,7 +444,13 @@ class DatabaseOperations(BaseDatabaseOperations):
|
|
367
444
|
]
|
368
445
|
return "RETURNING {}".format(", ".join(columns)), ()
|
369
446
|
|
370
|
-
def on_conflict_suffix_sql(
|
447
|
+
def on_conflict_suffix_sql(
|
448
|
+
self,
|
449
|
+
fields: list[Any],
|
450
|
+
on_conflict: Any,
|
451
|
+
update_fields: list[Any],
|
452
|
+
unique_fields: list[Any],
|
453
|
+
) -> str:
|
371
454
|
if (
|
372
455
|
on_conflict == OnConflict.UPDATE
|
373
456
|
and self.connection.features.supports_update_conflicts_with_target
|