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
@@ -2,11 +2,13 @@
2
2
  Implementations of SQL functions for SQLite.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import functools
6
8
  import random
7
9
  import statistics
8
10
  import zoneinfo
9
- from datetime import timedelta
11
+ from datetime import date, datetime, time, timedelta
10
12
  from hashlib import md5, sha1, sha224, sha256, sha384, sha512
11
13
  from math import (
12
14
  acos,
@@ -27,6 +29,7 @@ from math import (
27
29
  tan,
28
30
  )
29
31
  from re import search as re_search
32
+ from typing import TYPE_CHECKING, Any
30
33
 
31
34
  from plain.models.backends.utils import (
32
35
  split_tzname_delta,
@@ -36,10 +39,13 @@ from plain.models.backends.utils import (
36
39
  from plain.utils import timezone
37
40
  from plain.utils.duration import duration_microseconds
38
41
 
42
+ if TYPE_CHECKING:
43
+ from plain.models.backends.sqlite3.base import SQLiteDatabaseWrapper
44
+
39
45
 
40
- def register(connection):
46
+ def register(connection: SQLiteDatabaseWrapper) -> None:
41
47
  create_deterministic_function = functools.partial(
42
- connection.create_function,
48
+ connection.create_function, # type: ignore[attr-defined]
43
49
  deterministic=True,
44
50
  )
45
51
  create_deterministic_function("plain_date_extract", 2, _sqlite_datetime_extract)
@@ -73,14 +79,14 @@ def register(connection):
73
79
  create_deterministic_function("SIGN", 1, _sqlite_sign)
74
80
  # Don't use the built-in RANDOM() function because it returns a value
75
81
  # in the range [-1 * 2^63, 2^63 - 1] instead of [0, 1).
76
- connection.create_function("RAND", 0, random.random)
77
- connection.create_aggregate("STDDEV_POP", 1, StdDevPop)
78
- connection.create_aggregate("STDDEV_SAMP", 1, StdDevSamp)
79
- connection.create_aggregate("VAR_POP", 1, VarPop)
80
- connection.create_aggregate("VAR_SAMP", 1, VarSamp)
82
+ connection.create_function("RAND", 0, random.random) # type: ignore[attr-defined]
83
+ connection.create_aggregate("STDDEV_POP", 1, StdDevPop) # type: ignore[attr-defined]
84
+ connection.create_aggregate("STDDEV_SAMP", 1, StdDevSamp) # type: ignore[attr-defined]
85
+ connection.create_aggregate("VAR_POP", 1, VarPop) # type: ignore[attr-defined]
86
+ connection.create_aggregate("VAR_SAMP", 1, VarSamp) # type: ignore[attr-defined]
81
87
  # Some math functions are enabled by default in SQLite 3.35+.
82
88
  sql = "select sqlite_compileoption_used('ENABLE_MATH_FUNCTIONS')"
83
- if not connection.execute(sql).fetchone()[0]:
89
+ if not connection.execute(sql).fetchone()[0]: # type: ignore[union-attr]
84
90
  create_deterministic_function("ACOS", 1, _sqlite_acos)
85
91
  create_deterministic_function("ASIN", 1, _sqlite_asin)
86
92
  create_deterministic_function("ATAN", 1, _sqlite_atan)
@@ -101,138 +107,162 @@ def register(connection):
101
107
  create_deterministic_function("TAN", 1, _sqlite_tan)
102
108
 
103
109
 
104
- def _sqlite_datetime_parse(dt, tzname=None, conn_tzname=None):
110
+ def _sqlite_datetime_parse(
111
+ dt: str | None, tzname: str | None = None, conn_tzname: str | None = None
112
+ ) -> date | datetime | None:
105
113
  if dt is None:
106
114
  return None
107
115
  try:
108
- dt = typecast_timestamp(dt)
116
+ parsed_dt: date | datetime | None = typecast_timestamp(dt)
109
117
  except (TypeError, ValueError):
110
118
  return None
111
119
  if conn_tzname:
112
- dt = dt.replace(tzinfo=zoneinfo.ZoneInfo(conn_tzname))
120
+ parsed_dt = parsed_dt.replace(tzinfo=zoneinfo.ZoneInfo(conn_tzname)) # type: ignore[union-attr]
113
121
  if tzname is not None and tzname != conn_tzname:
114
122
  tzname, sign, offset = split_tzname_delta(tzname)
115
123
  if offset:
116
124
  hours, minutes = offset.split(":")
117
125
  offset_delta = timedelta(hours=int(hours), minutes=int(minutes))
118
- dt += offset_delta if sign == "+" else -offset_delta
119
- dt = timezone.localtime(dt, zoneinfo.ZoneInfo(tzname))
120
- return dt
126
+ parsed_dt += offset_delta if sign == "+" else -offset_delta # type: ignore[assignment,operator]
127
+ parsed_dt = timezone.localtime(parsed_dt, zoneinfo.ZoneInfo(tzname)) # type: ignore[arg-type]
128
+ return parsed_dt
121
129
 
122
130
 
123
- def _sqlite_date_trunc(lookup_type, dt, tzname, conn_tzname):
124
- dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
125
- if dt is None:
131
+ def _sqlite_date_trunc(
132
+ lookup_type: str, dt: str | None, tzname: str | None, conn_tzname: str | None
133
+ ) -> str | None:
134
+ parsed_dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
135
+ if parsed_dt is None:
126
136
  return None
127
137
  if lookup_type == "year":
128
- return f"{dt.year:04d}-01-01"
138
+ return f"{parsed_dt.year:04d}-01-01"
129
139
  elif lookup_type == "quarter":
130
- month_in_quarter = dt.month - (dt.month - 1) % 3
131
- return f"{dt.year:04d}-{month_in_quarter:02d}-01"
140
+ month_in_quarter = parsed_dt.month - (parsed_dt.month - 1) % 3
141
+ return f"{parsed_dt.year:04d}-{month_in_quarter:02d}-01"
132
142
  elif lookup_type == "month":
133
- return f"{dt.year:04d}-{dt.month:02d}-01"
143
+ return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-01"
134
144
  elif lookup_type == "week":
135
- dt -= timedelta(days=dt.weekday())
136
- return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}"
145
+ parsed_dt -= timedelta(days=parsed_dt.weekday()) # type: ignore[operator]
146
+ return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d}"
137
147
  elif lookup_type == "day":
138
- return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d}"
148
+ return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d}"
139
149
  raise ValueError(f"Unsupported lookup type: {lookup_type!r}")
140
150
 
141
151
 
142
- def _sqlite_time_trunc(lookup_type, dt, tzname, conn_tzname):
152
+ def _sqlite_time_trunc(
153
+ lookup_type: str, dt: str | None, tzname: str | None, conn_tzname: str | None
154
+ ) -> str | None:
143
155
  if dt is None:
144
156
  return None
145
157
  dt_parsed = _sqlite_datetime_parse(dt, tzname, conn_tzname)
158
+ result: date | datetime | time | None
146
159
  if dt_parsed is None:
147
160
  try:
148
- dt = typecast_time(dt)
161
+ result = typecast_time(dt)
149
162
  except (ValueError, TypeError):
150
163
  return None
151
164
  else:
152
- dt = dt_parsed
165
+ result = dt_parsed
153
166
  if lookup_type == "hour":
154
- return f"{dt.hour:02d}:00:00"
167
+ return f"{result.hour:02d}:00:00" # type: ignore[union-attr]
155
168
  elif lookup_type == "minute":
156
- return f"{dt.hour:02d}:{dt.minute:02d}:00"
169
+ return f"{result.hour:02d}:{result.minute:02d}:00" # type: ignore[union-attr]
157
170
  elif lookup_type == "second":
158
- return f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
171
+ return f"{result.hour:02d}:{result.minute:02d}:{result.second:02d}" # type: ignore[union-attr]
159
172
  raise ValueError(f"Unsupported lookup type: {lookup_type!r}")
160
173
 
161
174
 
162
- def _sqlite_datetime_cast_date(dt, tzname, conn_tzname):
163
- dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
164
- if dt is None:
175
+ def _sqlite_datetime_cast_date(
176
+ dt: str | None, tzname: str | None, conn_tzname: str | None
177
+ ) -> str | None:
178
+ parsed_dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
179
+ if parsed_dt is None:
165
180
  return None
166
- return dt.date().isoformat()
181
+ return parsed_dt.date().isoformat() # type: ignore[union-attr]
167
182
 
168
183
 
169
- def _sqlite_datetime_cast_time(dt, tzname, conn_tzname):
170
- dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
171
- if dt is None:
184
+ def _sqlite_datetime_cast_time(
185
+ dt: str | None, tzname: str | None, conn_tzname: str | None
186
+ ) -> str | None:
187
+ parsed_dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
188
+ if parsed_dt is None:
172
189
  return None
173
- return dt.time().isoformat()
190
+ return parsed_dt.time().isoformat() # type: ignore[union-attr]
174
191
 
175
192
 
176
- def _sqlite_datetime_extract(lookup_type, dt, tzname=None, conn_tzname=None):
177
- dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
178
- if dt is None:
193
+ def _sqlite_datetime_extract(
194
+ lookup_type: str,
195
+ dt: str | None,
196
+ tzname: str | None = None,
197
+ conn_tzname: str | None = None,
198
+ ) -> int | None:
199
+ parsed_dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
200
+ if parsed_dt is None:
179
201
  return None
180
202
  if lookup_type == "week_day":
181
- return (dt.isoweekday() % 7) + 1
203
+ return (parsed_dt.isoweekday() % 7) + 1 # type: ignore[union-attr]
182
204
  elif lookup_type == "iso_week_day":
183
- return dt.isoweekday()
205
+ return parsed_dt.isoweekday() # type: ignore[union-attr]
184
206
  elif lookup_type == "week":
185
- return dt.isocalendar().week
207
+ return parsed_dt.isocalendar().week # type: ignore[union-attr]
186
208
  elif lookup_type == "quarter":
187
- return ceil(dt.month / 3)
209
+ return ceil(parsed_dt.month / 3)
188
210
  elif lookup_type == "iso_year":
189
- return dt.isocalendar().year
211
+ return parsed_dt.isocalendar().year # type: ignore[union-attr]
190
212
  else:
191
- return getattr(dt, lookup_type)
213
+ return getattr(parsed_dt, lookup_type)
192
214
 
193
215
 
194
- def _sqlite_datetime_trunc(lookup_type, dt, tzname, conn_tzname):
195
- dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
196
- if dt is None:
216
+ def _sqlite_datetime_trunc(
217
+ lookup_type: str, dt: str | None, tzname: str | None, conn_tzname: str | None
218
+ ) -> str | None:
219
+ parsed_dt = _sqlite_datetime_parse(dt, tzname, conn_tzname)
220
+ if parsed_dt is None:
197
221
  return None
198
222
  if lookup_type == "year":
199
- return f"{dt.year:04d}-01-01 00:00:00"
223
+ return f"{parsed_dt.year:04d}-01-01 00:00:00"
200
224
  elif lookup_type == "quarter":
201
- month_in_quarter = dt.month - (dt.month - 1) % 3
202
- return f"{dt.year:04d}-{month_in_quarter:02d}-01 00:00:00"
225
+ month_in_quarter = parsed_dt.month - (parsed_dt.month - 1) % 3
226
+ return f"{parsed_dt.year:04d}-{month_in_quarter:02d}-01 00:00:00"
203
227
  elif lookup_type == "month":
204
- return f"{dt.year:04d}-{dt.month:02d}-01 00:00:00"
228
+ return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-01 00:00:00"
205
229
  elif lookup_type == "week":
206
- dt -= timedelta(days=dt.weekday())
207
- return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} 00:00:00"
230
+ parsed_dt -= timedelta(days=parsed_dt.weekday()) # type: ignore[operator]
231
+ return (
232
+ f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d} 00:00:00"
233
+ )
208
234
  elif lookup_type == "day":
209
- return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} 00:00:00"
235
+ return (
236
+ f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d} 00:00:00"
237
+ )
210
238
  elif lookup_type == "hour":
211
- return f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} {dt.hour:02d}:00:00"
239
+ return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d} {parsed_dt.hour:02d}:00:00" # type: ignore[union-attr]
212
240
  elif lookup_type == "minute":
213
241
  return (
214
- f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
215
- f"{dt.hour:02d}:{dt.minute:02d}:00"
242
+ f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d} "
243
+ f"{parsed_dt.hour:02d}:{parsed_dt.minute:02d}:00" # type: ignore[union-attr]
216
244
  )
217
245
  elif lookup_type == "second":
218
246
  return (
219
- f"{dt.year:04d}-{dt.month:02d}-{dt.day:02d} "
220
- f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"
247
+ f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-{parsed_dt.day:02d} "
248
+ f"{parsed_dt.hour:02d}:{parsed_dt.minute:02d}:{parsed_dt.second:02d}" # type: ignore[union-attr]
221
249
  )
222
250
  raise ValueError(f"Unsupported lookup type: {lookup_type!r}")
223
251
 
224
252
 
225
- def _sqlite_time_extract(lookup_type, dt):
253
+ def _sqlite_time_extract(lookup_type: str, dt: str | None) -> int | None:
226
254
  if dt is None:
227
255
  return None
228
256
  try:
229
- dt = typecast_time(dt)
257
+ parsed_time = typecast_time(dt)
230
258
  except (ValueError, TypeError):
231
259
  return None
232
- return getattr(dt, lookup_type)
260
+ return getattr(parsed_time, lookup_type) # type: ignore[union-attr]
233
261
 
234
262
 
235
- def _sqlite_prepare_dtdelta_param(conn, param):
263
+ def _sqlite_prepare_dtdelta_param(
264
+ conn: str, param: Any
265
+ ) -> timedelta | date | datetime | Any:
236
266
  if conn in ["+", "-"]:
237
267
  if isinstance(param, int):
238
268
  return timedelta(0, 0, param)
@@ -241,7 +271,9 @@ def _sqlite_prepare_dtdelta_param(conn, param):
241
271
  return param
242
272
 
243
273
 
244
- def _sqlite_format_dtdelta(connector, lhs, rhs):
274
+ def _sqlite_format_dtdelta(
275
+ connector: str | None, lhs: Any, rhs: Any
276
+ ) -> str | int | float | None:
245
277
  """
246
278
  LHS and RHS can be either:
247
279
  - An integer number of microseconds
@@ -259,42 +291,42 @@ def _sqlite_format_dtdelta(connector, lhs, rhs):
259
291
  if connector == "+":
260
292
  # typecast_timestamp() returns a date or a datetime without timezone.
261
293
  # It will be formatted as "%Y-%m-%d" or "%Y-%m-%d %H:%M:%S[.%f]"
262
- out = str(real_lhs + real_rhs)
294
+ out = str(real_lhs + real_rhs) # type: ignore[operator]
263
295
  elif connector == "-":
264
- out = str(real_lhs - real_rhs)
296
+ out = str(real_lhs - real_rhs) # type: ignore[operator]
265
297
  elif connector == "*":
266
- out = real_lhs * real_rhs
298
+ out = real_lhs * real_rhs # type: ignore[operator]
267
299
  else:
268
- out = real_lhs / real_rhs
300
+ out = real_lhs / real_rhs # type: ignore[operator]
269
301
  return out
270
302
 
271
303
 
272
- def _sqlite_time_diff(lhs, rhs):
304
+ def _sqlite_time_diff(lhs: str | None, rhs: str | None) -> int | None:
273
305
  if lhs is None or rhs is None:
274
306
  return None
275
307
  left = typecast_time(lhs)
276
308
  right = typecast_time(rhs)
277
309
  return (
278
- (left.hour * 60 * 60 * 1000000)
279
- + (left.minute * 60 * 1000000)
280
- + (left.second * 1000000)
281
- + (left.microsecond)
282
- - (right.hour * 60 * 60 * 1000000)
283
- - (right.minute * 60 * 1000000)
284
- - (right.second * 1000000)
285
- - (right.microsecond)
310
+ (left.hour * 60 * 60 * 1000000) # type: ignore[union-attr]
311
+ + (left.minute * 60 * 1000000) # type: ignore[union-attr]
312
+ + (left.second * 1000000) # type: ignore[union-attr]
313
+ + (left.microsecond) # type: ignore[union-attr]
314
+ - (right.hour * 60 * 60 * 1000000) # type: ignore[union-attr]
315
+ - (right.minute * 60 * 1000000) # type: ignore[union-attr]
316
+ - (right.second * 1000000) # type: ignore[union-attr]
317
+ - (right.microsecond) # type: ignore[union-attr]
286
318
  )
287
319
 
288
320
 
289
- def _sqlite_timestamp_diff(lhs, rhs):
321
+ def _sqlite_timestamp_diff(lhs: str | None, rhs: str | None) -> int | None:
290
322
  if lhs is None or rhs is None:
291
323
  return None
292
324
  left = typecast_timestamp(lhs)
293
325
  right = typecast_timestamp(rhs)
294
- return duration_microseconds(left - right)
326
+ return duration_microseconds(left - right) # type: ignore[arg-type,operator]
295
327
 
296
328
 
297
- def _sqlite_regexp(pattern, string):
329
+ def _sqlite_regexp(pattern: str | None, string: Any) -> bool | None:
298
330
  if pattern is None or string is None:
299
331
  return None
300
332
  if not isinstance(string, str):
@@ -302,86 +334,88 @@ def _sqlite_regexp(pattern, string):
302
334
  return bool(re_search(pattern, string))
303
335
 
304
336
 
305
- def _sqlite_acos(x):
337
+ def _sqlite_acos(x: float | None) -> float | None:
306
338
  if x is None:
307
339
  return None
308
340
  return acos(x)
309
341
 
310
342
 
311
- def _sqlite_asin(x):
343
+ def _sqlite_asin(x: float | None) -> float | None:
312
344
  if x is None:
313
345
  return None
314
346
  return asin(x)
315
347
 
316
348
 
317
- def _sqlite_atan(x):
349
+ def _sqlite_atan(x: float | None) -> float | None:
318
350
  if x is None:
319
351
  return None
320
352
  return atan(x)
321
353
 
322
354
 
323
- def _sqlite_atan2(y, x):
355
+ def _sqlite_atan2(y: float | None, x: float | None) -> float | None:
324
356
  if y is None or x is None:
325
357
  return None
326
358
  return atan2(y, x)
327
359
 
328
360
 
329
- def _sqlite_bitxor(x, y):
361
+ def _sqlite_bitxor(x: int | None, y: int | None) -> int | None:
330
362
  if x is None or y is None:
331
363
  return None
332
364
  return x ^ y
333
365
 
334
366
 
335
- def _sqlite_ceiling(x):
367
+ def _sqlite_ceiling(x: float | None) -> float | None:
336
368
  if x is None:
337
369
  return None
338
370
  return ceil(x)
339
371
 
340
372
 
341
- def _sqlite_cos(x):
373
+ def _sqlite_cos(x: float | None) -> float | None:
342
374
  if x is None:
343
375
  return None
344
376
  return cos(x)
345
377
 
346
378
 
347
- def _sqlite_cot(x):
379
+ def _sqlite_cot(x: float | None) -> float | None:
348
380
  if x is None:
349
381
  return None
350
382
  return 1 / tan(x)
351
383
 
352
384
 
353
- def _sqlite_degrees(x):
385
+ def _sqlite_degrees(x: float | None) -> float | None:
354
386
  if x is None:
355
387
  return None
356
388
  return degrees(x)
357
389
 
358
390
 
359
- def _sqlite_exp(x):
391
+ def _sqlite_exp(x: float | None) -> float | None:
360
392
  if x is None:
361
393
  return None
362
394
  return exp(x)
363
395
 
364
396
 
365
- def _sqlite_floor(x):
397
+ def _sqlite_floor(x: float | None) -> float | None:
366
398
  if x is None:
367
399
  return None
368
400
  return floor(x)
369
401
 
370
402
 
371
- def _sqlite_ln(x):
403
+ def _sqlite_ln(x: float | None) -> float | None:
372
404
  if x is None:
373
405
  return None
374
406
  return log(x)
375
407
 
376
408
 
377
- def _sqlite_log(base, x):
409
+ def _sqlite_log(base: float | None, x: float | None) -> float | None:
378
410
  if base is None or x is None:
379
411
  return None
380
412
  # Arguments reversed to match SQL standard.
381
413
  return log(x, base)
382
414
 
383
415
 
384
- def _sqlite_lpad(text, length, fill_text):
416
+ def _sqlite_lpad(
417
+ text: str | None, length: int | None, fill_text: str | None
418
+ ) -> str | None:
385
419
  if text is None or length is None or fill_text is None:
386
420
  return None
387
421
  delta = length - len(text)
@@ -390,101 +424,103 @@ def _sqlite_lpad(text, length, fill_text):
390
424
  return (fill_text * length)[:delta] + text
391
425
 
392
426
 
393
- def _sqlite_md5(text):
427
+ def _sqlite_md5(text: str | None) -> str | None:
394
428
  if text is None:
395
429
  return None
396
430
  return md5(text.encode()).hexdigest()
397
431
 
398
432
 
399
- def _sqlite_mod(x, y):
433
+ def _sqlite_mod(x: float | None, y: float | None) -> float | None:
400
434
  if x is None or y is None:
401
435
  return None
402
436
  return fmod(x, y)
403
437
 
404
438
 
405
- def _sqlite_pi():
439
+ def _sqlite_pi() -> float:
406
440
  return pi
407
441
 
408
442
 
409
- def _sqlite_power(x, y):
443
+ def _sqlite_power(x: float | None, y: float | None) -> float | None:
410
444
  if x is None or y is None:
411
445
  return None
412
446
  return x**y
413
447
 
414
448
 
415
- def _sqlite_radians(x):
449
+ def _sqlite_radians(x: float | None) -> float | None:
416
450
  if x is None:
417
451
  return None
418
452
  return radians(x)
419
453
 
420
454
 
421
- def _sqlite_repeat(text, count):
455
+ def _sqlite_repeat(text: str | None, count: int | None) -> str | None:
422
456
  if text is None or count is None:
423
457
  return None
424
458
  return text * count
425
459
 
426
460
 
427
- def _sqlite_reverse(text):
461
+ def _sqlite_reverse(text: str | None) -> str | None:
428
462
  if text is None:
429
463
  return None
430
464
  return text[::-1]
431
465
 
432
466
 
433
- def _sqlite_rpad(text, length, fill_text):
467
+ def _sqlite_rpad(
468
+ text: str | None, length: int | None, fill_text: str | None
469
+ ) -> str | None:
434
470
  if text is None or length is None or fill_text is None:
435
471
  return None
436
472
  return (text + fill_text * length)[:length]
437
473
 
438
474
 
439
- def _sqlite_sha1(text):
475
+ def _sqlite_sha1(text: str | None) -> str | None:
440
476
  if text is None:
441
477
  return None
442
478
  return sha1(text.encode()).hexdigest()
443
479
 
444
480
 
445
- def _sqlite_sha224(text):
481
+ def _sqlite_sha224(text: str | None) -> str | None:
446
482
  if text is None:
447
483
  return None
448
484
  return sha224(text.encode()).hexdigest()
449
485
 
450
486
 
451
- def _sqlite_sha256(text):
487
+ def _sqlite_sha256(text: str | None) -> str | None:
452
488
  if text is None:
453
489
  return None
454
490
  return sha256(text.encode()).hexdigest()
455
491
 
456
492
 
457
- def _sqlite_sha384(text):
493
+ def _sqlite_sha384(text: str | None) -> str | None:
458
494
  if text is None:
459
495
  return None
460
496
  return sha384(text.encode()).hexdigest()
461
497
 
462
498
 
463
- def _sqlite_sha512(text):
499
+ def _sqlite_sha512(text: str | None) -> str | None:
464
500
  if text is None:
465
501
  return None
466
502
  return sha512(text.encode()).hexdigest()
467
503
 
468
504
 
469
- def _sqlite_sign(x):
505
+ def _sqlite_sign(x: float | None) -> int | None:
470
506
  if x is None:
471
507
  return None
472
508
  return (x > 0) - (x < 0)
473
509
 
474
510
 
475
- def _sqlite_sin(x):
511
+ def _sqlite_sin(x: float | None) -> float | None:
476
512
  if x is None:
477
513
  return None
478
514
  return sin(x)
479
515
 
480
516
 
481
- def _sqlite_sqrt(x):
517
+ def _sqlite_sqrt(x: float | None) -> float | None:
482
518
  if x is None:
483
519
  return None
484
520
  return sqrt(x)
485
521
 
486
522
 
487
- def _sqlite_tan(x):
523
+ def _sqlite_tan(x: float | None) -> float | None:
488
524
  if x is None:
489
525
  return None
490
526
  return tan(x)