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.
Files changed (105) hide show
  1. plain/models/CHANGELOG.md +23 -0
  2. plain/models/aggregates.py +42 -19
  3. plain/models/backends/base/base.py +125 -105
  4. plain/models/backends/base/client.py +11 -3
  5. plain/models/backends/base/creation.py +22 -12
  6. plain/models/backends/base/features.py +10 -4
  7. plain/models/backends/base/introspection.py +29 -16
  8. plain/models/backends/base/operations.py +187 -91
  9. plain/models/backends/base/schema.py +267 -165
  10. plain/models/backends/base/validation.py +12 -3
  11. plain/models/backends/ddl_references.py +85 -43
  12. plain/models/backends/mysql/base.py +29 -26
  13. plain/models/backends/mysql/client.py +7 -2
  14. plain/models/backends/mysql/compiler.py +12 -3
  15. plain/models/backends/mysql/creation.py +5 -2
  16. plain/models/backends/mysql/features.py +24 -22
  17. plain/models/backends/mysql/introspection.py +22 -13
  18. plain/models/backends/mysql/operations.py +106 -39
  19. plain/models/backends/mysql/schema.py +48 -24
  20. plain/models/backends/mysql/validation.py +13 -6
  21. plain/models/backends/postgresql/base.py +41 -34
  22. plain/models/backends/postgresql/client.py +7 -2
  23. plain/models/backends/postgresql/creation.py +10 -5
  24. plain/models/backends/postgresql/introspection.py +15 -8
  25. plain/models/backends/postgresql/operations.py +109 -42
  26. plain/models/backends/postgresql/schema.py +85 -46
  27. plain/models/backends/sqlite3/_functions.py +151 -115
  28. plain/models/backends/sqlite3/base.py +37 -23
  29. plain/models/backends/sqlite3/client.py +7 -1
  30. plain/models/backends/sqlite3/creation.py +9 -5
  31. plain/models/backends/sqlite3/features.py +5 -3
  32. plain/models/backends/sqlite3/introspection.py +32 -16
  33. plain/models/backends/sqlite3/operations.py +125 -42
  34. plain/models/backends/sqlite3/schema.py +82 -58
  35. plain/models/backends/utils.py +52 -29
  36. plain/models/backups/cli.py +8 -6
  37. plain/models/backups/clients.py +16 -7
  38. plain/models/backups/core.py +24 -13
  39. plain/models/base.py +113 -74
  40. plain/models/cli.py +94 -63
  41. plain/models/config.py +1 -1
  42. plain/models/connections.py +23 -7
  43. plain/models/constraints.py +65 -47
  44. plain/models/database_url.py +1 -1
  45. plain/models/db.py +6 -2
  46. plain/models/deletion.py +66 -43
  47. plain/models/entrypoints.py +1 -1
  48. plain/models/enums.py +22 -11
  49. plain/models/exceptions.py +23 -8
  50. plain/models/expressions.py +440 -257
  51. plain/models/fields/__init__.py +253 -202
  52. plain/models/fields/json.py +120 -54
  53. plain/models/fields/mixins.py +12 -8
  54. plain/models/fields/related.py +284 -252
  55. plain/models/fields/related_descriptors.py +34 -25
  56. plain/models/fields/related_lookups.py +23 -11
  57. plain/models/fields/related_managers.py +81 -47
  58. plain/models/fields/reverse_related.py +58 -55
  59. plain/models/forms.py +89 -63
  60. plain/models/functions/comparison.py +71 -18
  61. plain/models/functions/datetime.py +79 -29
  62. plain/models/functions/math.py +43 -10
  63. plain/models/functions/mixins.py +24 -7
  64. plain/models/functions/text.py +104 -25
  65. plain/models/functions/window.py +12 -6
  66. plain/models/indexes.py +52 -28
  67. plain/models/lookups.py +228 -153
  68. plain/models/migrations/autodetector.py +86 -43
  69. plain/models/migrations/exceptions.py +7 -3
  70. plain/models/migrations/executor.py +33 -7
  71. plain/models/migrations/graph.py +79 -50
  72. plain/models/migrations/loader.py +45 -22
  73. plain/models/migrations/migration.py +23 -18
  74. plain/models/migrations/operations/base.py +37 -19
  75. plain/models/migrations/operations/fields.py +89 -42
  76. plain/models/migrations/operations/models.py +245 -143
  77. plain/models/migrations/operations/special.py +82 -25
  78. plain/models/migrations/optimizer.py +7 -2
  79. plain/models/migrations/questioner.py +58 -31
  80. plain/models/migrations/recorder.py +18 -11
  81. plain/models/migrations/serializer.py +50 -39
  82. plain/models/migrations/state.py +220 -133
  83. plain/models/migrations/utils.py +29 -13
  84. plain/models/migrations/writer.py +17 -14
  85. plain/models/options.py +63 -56
  86. plain/models/otel.py +16 -6
  87. plain/models/preflight.py +35 -12
  88. plain/models/query.py +323 -228
  89. plain/models/query_utils.py +93 -58
  90. plain/models/registry.py +34 -16
  91. plain/models/sql/compiler.py +146 -97
  92. plain/models/sql/datastructures.py +38 -25
  93. plain/models/sql/query.py +255 -169
  94. plain/models/sql/subqueries.py +32 -21
  95. plain/models/sql/where.py +54 -29
  96. plain/models/test/pytest.py +15 -11
  97. plain/models/test/utils.py +4 -2
  98. plain/models/transaction.py +20 -7
  99. plain/models/utils.py +13 -5
  100. {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/METADATA +1 -1
  101. plain_models-0.50.0.dist-info/RECORD +122 -0
  102. plain_models-0.49.1.dist-info/RECORD +0 -122
  103. {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/WHEEL +0 -0
  104. {plain_models-0.49.1.dist-info → plain_models-0.50.0.dist-info}/entry_points.txt +0 -0
  105. {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(self, lookup_type, sql, params):
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(self, lookup_type, sql, params, tzname=None):
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(self, sql, params, tzname):
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(self, sql, params, tzname):
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(self, lookup_type, sql, params, tzname):
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(self, lookup_type, sql, params, tzname):
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(self, lookup_type, sql, params, tzname=None):
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(self, lookup_type, sql, params):
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(self, fields, params):
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(self, nowait=False, skip_locked=False, of=(), no_key=False):
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(self, low_mark, high_mark):
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(self, cursor, sql, params):
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
- if isinstance(params, list | tuple):
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(self, fields):
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
- pass
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(self, value, internal_type):
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(self, 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(self, 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(self, value, max_digits=None, decimal_places=None):
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(self, value, iso_year=False):
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
- first = self.adapt_datefield_value(first)
512
- second = self.adapt_datefield_value(second)
513
- return [first, second]
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(self, value, iso_year=False):
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
- first = self.adapt_datetimefield_value(first)
539
- second = self.adapt_datetimefield_value(second)
540
- return [first, second]
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(self, value, expression, connection):
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
- pass
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(self, connector, sub_expressions):
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(self, placeholder, 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(self, internal_type, lhs, rhs):
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(self, start=None, end=None):
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(self, start=None, end=None):
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(self, fields, on_conflict, update_fields, unique_fields):
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 ""