plain.models 0.49.2__py3-none-any.whl → 0.51.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 +27 -0
- plain/models/README.md +26 -42
- plain/models/__init__.py +2 -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 +24 -14
- plain/models/backends/base/features.py +10 -4
- plain/models/backends/base/introspection.py +37 -20
- plain/models/backends/base/operations.py +187 -91
- plain/models/backends/base/schema.py +338 -218
- plain/models/backends/base/validation.py +13 -4
- 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 +13 -4
- 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 +107 -40
- plain/models/backends/mysql/schema.py +52 -28
- 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 +110 -43
- plain/models/backends/postgresql/schema.py +88 -49
- 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 +126 -43
- plain/models/backends/sqlite3/schema.py +127 -92
- 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 +221 -229
- plain/models/cli.py +98 -67
- plain/models/config.py +1 -1
- plain/models/connections.py +23 -7
- plain/models/constraints.py +79 -56
- plain/models/database_url.py +1 -1
- plain/models/db.py +6 -2
- plain/models/deletion.py +80 -56
- plain/models/entrypoints.py +1 -1
- plain/models/enums.py +22 -11
- plain/models/exceptions.py +23 -8
- plain/models/expressions.py +441 -258
- plain/models/fields/__init__.py +272 -217
- plain/models/fields/json.py +123 -57
- plain/models/fields/mixins.py +12 -8
- plain/models/fields/related.py +324 -290
- plain/models/fields/related_descriptors.py +33 -24
- plain/models/fields/related_lookups.py +24 -12
- plain/models/fields/related_managers.py +102 -79
- plain/models/fields/reverse_related.py +66 -63
- plain/models/forms.py +101 -75
- 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 +57 -32
- plain/models/lookups.py +228 -153
- plain/models/meta.py +505 -0
- 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 +38 -20
- plain/models/migrations/operations/fields.py +95 -48
- plain/models/migrations/operations/models.py +246 -142
- 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 +27 -16
- plain/models/migrations/serializer.py +50 -39
- plain/models/migrations/state.py +232 -156
- plain/models/migrations/utils.py +30 -14
- plain/models/migrations/writer.py +17 -14
- plain/models/options.py +189 -518
- plain/models/otel.py +16 -6
- plain/models/preflight.py +42 -17
- plain/models/query.py +400 -251
- plain/models/query_utils.py +109 -69
- plain/models/registry.py +40 -21
- plain/models/sql/compiler.py +190 -127
- plain/models/sql/datastructures.py +38 -25
- plain/models/sql/query.py +320 -225
- plain/models/sql/subqueries.py +36 -25
- 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 +17 -6
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/METADATA +27 -43
- plain_models-0.51.0.dist-info/RECORD +123 -0
- plain_models-0.49.2.dist-info/RECORD +0 -122
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/WHEEL +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.0.dist-info}/entry_points.txt +0 -0
- {plain_models-0.49.2.dist-info → plain_models-0.51.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(
|
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
|
-
|
116
|
+
parsed_dt: date | datetime | None = typecast_timestamp(dt)
|
109
117
|
except (TypeError, ValueError):
|
110
118
|
return None
|
111
119
|
if conn_tzname:
|
112
|
-
|
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
|
-
|
119
|
-
|
120
|
-
return
|
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(
|
124
|
-
dt
|
125
|
-
|
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"{
|
138
|
+
return f"{parsed_dt.year:04d}-01-01"
|
129
139
|
elif lookup_type == "quarter":
|
130
|
-
month_in_quarter =
|
131
|
-
return f"{
|
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"{
|
143
|
+
return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-01"
|
134
144
|
elif lookup_type == "week":
|
135
|
-
|
136
|
-
return f"{
|
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"{
|
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(
|
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
|
-
|
161
|
+
result = typecast_time(dt)
|
149
162
|
except (ValueError, TypeError):
|
150
163
|
return None
|
151
164
|
else:
|
152
|
-
|
165
|
+
result = dt_parsed
|
153
166
|
if lookup_type == "hour":
|
154
|
-
return f"{
|
167
|
+
return f"{result.hour:02d}:00:00" # type: ignore[union-attr]
|
155
168
|
elif lookup_type == "minute":
|
156
|
-
return f"{
|
169
|
+
return f"{result.hour:02d}:{result.minute:02d}:00" # type: ignore[union-attr]
|
157
170
|
elif lookup_type == "second":
|
158
|
-
return f"{
|
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(
|
163
|
-
dt
|
164
|
-
|
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
|
181
|
+
return parsed_dt.date().isoformat() # type: ignore[union-attr]
|
167
182
|
|
168
183
|
|
169
|
-
def _sqlite_datetime_cast_time(
|
170
|
-
dt
|
171
|
-
|
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
|
190
|
+
return parsed_dt.time().isoformat() # type: ignore[union-attr]
|
174
191
|
|
175
192
|
|
176
|
-
def _sqlite_datetime_extract(
|
177
|
-
|
178
|
-
|
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 (
|
203
|
+
return (parsed_dt.isoweekday() % 7) + 1 # type: ignore[union-attr]
|
182
204
|
elif lookup_type == "iso_week_day":
|
183
|
-
return
|
205
|
+
return parsed_dt.isoweekday() # type: ignore[union-attr]
|
184
206
|
elif lookup_type == "week":
|
185
|
-
return
|
207
|
+
return parsed_dt.isocalendar().week # type: ignore[union-attr]
|
186
208
|
elif lookup_type == "quarter":
|
187
|
-
return ceil(
|
209
|
+
return ceil(parsed_dt.month / 3)
|
188
210
|
elif lookup_type == "iso_year":
|
189
|
-
return
|
211
|
+
return parsed_dt.isocalendar().year # type: ignore[union-attr]
|
190
212
|
else:
|
191
|
-
return getattr(
|
213
|
+
return getattr(parsed_dt, lookup_type)
|
192
214
|
|
193
215
|
|
194
|
-
def _sqlite_datetime_trunc(
|
195
|
-
dt
|
196
|
-
|
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"{
|
223
|
+
return f"{parsed_dt.year:04d}-01-01 00:00:00"
|
200
224
|
elif lookup_type == "quarter":
|
201
|
-
month_in_quarter =
|
202
|
-
return f"{
|
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"{
|
228
|
+
return f"{parsed_dt.year:04d}-{parsed_dt.month:02d}-01 00:00:00"
|
205
229
|
elif lookup_type == "week":
|
206
|
-
|
207
|
-
return
|
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
|
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"{
|
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"{
|
215
|
-
f"{
|
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"{
|
220
|
-
f"{
|
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
|
-
|
257
|
+
parsed_time = typecast_time(dt)
|
230
258
|
except (ValueError, TypeError):
|
231
259
|
return None
|
232
|
-
return getattr(
|
260
|
+
return getattr(parsed_time, lookup_type) # type: ignore[union-attr]
|
233
261
|
|
234
262
|
|
235
|
-
def _sqlite_prepare_dtdelta_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(
|
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(
|
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(
|
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)
|