piccolo 1.27.1__py3-none-any.whl → 1.28.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.
- piccolo/__init__.py +1 -1
- piccolo/apps/app/commands/new.py +3 -3
- piccolo/apps/asgi/commands/new.py +1 -2
- piccolo/apps/fixtures/commands/dump.py +8 -8
- piccolo/apps/fixtures/commands/load.py +5 -5
- piccolo/apps/fixtures/commands/shared.py +9 -9
- piccolo/apps/migrations/auto/diffable_table.py +12 -12
- piccolo/apps/migrations/auto/migration_manager.py +59 -66
- piccolo/apps/migrations/auto/operations.py +14 -14
- piccolo/apps/migrations/auto/schema_differ.py +35 -34
- piccolo/apps/migrations/auto/schema_snapshot.py +3 -4
- piccolo/apps/migrations/auto/serialisation.py +27 -24
- piccolo/apps/migrations/auto/serialisation_legacy.py +2 -2
- piccolo/apps/migrations/commands/backwards.py +1 -2
- piccolo/apps/migrations/commands/base.py +12 -12
- piccolo/apps/migrations/commands/check.py +2 -3
- piccolo/apps/migrations/commands/clean.py +3 -3
- piccolo/apps/migrations/commands/forwards.py +1 -2
- piccolo/apps/migrations/commands/new.py +6 -6
- piccolo/apps/migrations/tables.py +3 -3
- piccolo/apps/playground/commands/run.py +29 -13
- piccolo/apps/schema/commands/generate.py +49 -49
- piccolo/apps/schema/commands/graph.py +5 -5
- piccolo/apps/shell/commands/run.py +1 -2
- piccolo/apps/sql_shell/commands/run.py +4 -4
- piccolo/apps/tester/commands/run.py +3 -3
- piccolo/apps/user/commands/change_permissions.py +6 -6
- piccolo/apps/user/commands/create.py +7 -7
- piccolo/apps/user/commands/list.py +2 -2
- piccolo/apps/user/tables.py +8 -8
- piccolo/columns/base.py +84 -52
- piccolo/columns/choices.py +2 -2
- piccolo/columns/column_types.py +297 -175
- piccolo/columns/combination.py +15 -12
- piccolo/columns/defaults/base.py +4 -4
- piccolo/columns/defaults/date.py +4 -3
- piccolo/columns/defaults/interval.py +4 -3
- piccolo/columns/defaults/time.py +4 -3
- piccolo/columns/defaults/timestamp.py +4 -3
- piccolo/columns/defaults/timestamptz.py +4 -3
- piccolo/columns/defaults/uuid.py +3 -2
- piccolo/columns/m2m.py +28 -35
- piccolo/columns/readable.py +4 -3
- piccolo/columns/reference.py +9 -9
- piccolo/conf/apps.py +53 -54
- piccolo/custom_types.py +28 -6
- piccolo/engine/base.py +14 -14
- piccolo/engine/cockroach.py +5 -4
- piccolo/engine/finder.py +2 -2
- piccolo/engine/postgres.py +20 -19
- piccolo/engine/sqlite.py +23 -22
- piccolo/query/base.py +30 -29
- piccolo/query/functions/__init__.py +12 -0
- piccolo/query/functions/aggregate.py +4 -3
- piccolo/query/functions/array.py +151 -0
- piccolo/query/functions/base.py +3 -3
- piccolo/query/functions/datetime.py +22 -22
- piccolo/query/functions/string.py +4 -4
- piccolo/query/functions/type_conversion.py +30 -15
- piccolo/query/methods/alter.py +47 -46
- piccolo/query/methods/count.py +11 -10
- piccolo/query/methods/create.py +6 -5
- piccolo/query/methods/create_index.py +9 -8
- piccolo/query/methods/delete.py +7 -6
- piccolo/query/methods/drop_index.py +7 -6
- piccolo/query/methods/exists.py +6 -5
- piccolo/query/methods/indexes.py +4 -4
- piccolo/query/methods/insert.py +21 -14
- piccolo/query/methods/objects.py +60 -50
- piccolo/query/methods/raw.py +7 -6
- piccolo/query/methods/refresh.py +8 -7
- piccolo/query/methods/select.py +56 -49
- piccolo/query/methods/table_exists.py +5 -5
- piccolo/query/methods/update.py +8 -7
- piccolo/query/mixins.py +56 -61
- piccolo/query/operators/json.py +11 -11
- piccolo/query/proxy.py +8 -9
- piccolo/querystring.py +14 -15
- piccolo/schema.py +10 -10
- piccolo/table.py +93 -94
- piccolo/table_reflection.py +9 -9
- piccolo/testing/model_builder.py +12 -11
- piccolo/testing/random_builder.py +2 -2
- piccolo/testing/test_case.py +4 -4
- piccolo/utils/dictionary.py +3 -3
- piccolo/utils/encoding.py +5 -5
- piccolo/utils/lazy_loader.py +3 -3
- piccolo/utils/list.py +7 -8
- piccolo/utils/objects.py +4 -6
- piccolo/utils/pydantic.py +21 -24
- piccolo/utils/sql_values.py +3 -3
- piccolo/utils/sync.py +4 -3
- piccolo/utils/warnings.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/METADATA +1 -1
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/RECORD +122 -121
- tests/apps/fixtures/commands/test_dump_load.py +1 -2
- tests/apps/migrations/auto/integration/test_migrations.py +32 -7
- tests/apps/migrations/auto/test_migration_manager.py +2 -2
- tests/apps/migrations/auto/test_schema_differ.py +22 -23
- tests/apps/migrations/commands/test_forwards_backwards.py +3 -3
- tests/columns/m2m/base.py +2 -2
- tests/columns/test_array.py +176 -10
- tests/columns/test_boolean.py +2 -4
- tests/columns/test_combination.py +29 -1
- tests/columns/test_db_column_name.py +2 -2
- tests/engine/test_extra_nodes.py +2 -2
- tests/engine/test_pool.py +3 -3
- tests/engine/test_transaction.py +4 -4
- tests/query/test_freeze.py +4 -4
- tests/table/instance/test_get_related.py +2 -2
- tests/table/test_alter.py +4 -4
- tests/table/test_indexes.py +1 -2
- tests/table/test_refresh.py +2 -2
- tests/table/test_select.py +58 -0
- tests/table/test_update.py +3 -3
- tests/testing/test_model_builder.py +1 -2
- tests/utils/test_pydantic.py +36 -36
- tests/utils/test_table_reflection.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/WHEEL +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/entry_points.txt +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/licenses/LICENSE +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.28.0.dist-info}/top_level.txt +0 -0
piccolo/columns/combination.py
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import TYPE_CHECKING, Any, Union
|
4
4
|
|
5
5
|
from piccolo.columns.operators.comparison import (
|
6
6
|
ComparisonOperator,
|
7
7
|
Equal,
|
8
8
|
IsNull,
|
9
9
|
)
|
10
|
-
from piccolo.custom_types import Combinable,
|
10
|
+
from piccolo.custom_types import Combinable, CustomIterable
|
11
11
|
from piccolo.querystring import QueryString
|
12
12
|
from piccolo.utils.sql_values import convert_to_sql_value
|
13
13
|
|
14
|
-
if
|
14
|
+
if TYPE_CHECKING:
|
15
15
|
from piccolo.columns.base import Column
|
16
16
|
|
17
17
|
|
@@ -59,7 +59,7 @@ class Combination(CombinableMixin):
|
|
59
59
|
class And(Combination):
|
60
60
|
operator = "AND"
|
61
61
|
|
62
|
-
def get_column_values(self) ->
|
62
|
+
def get_column_values(self) -> dict[Column, Any]:
|
63
63
|
"""
|
64
64
|
This is used by `get_or_create` to know which values to assign if
|
65
65
|
the row doesn't exist in the database.
|
@@ -109,7 +109,7 @@ UNDEFINED = Undefined()
|
|
109
109
|
class WhereRaw(CombinableMixin):
|
110
110
|
__slots__ = ("querystring",)
|
111
111
|
|
112
|
-
def __init__(self, sql: str, *args:
|
112
|
+
def __init__(self, sql: str, *args: Any) -> None:
|
113
113
|
"""
|
114
114
|
Execute raw SQL queries in your where clause. Use with caution!
|
115
115
|
|
@@ -145,9 +145,9 @@ class Where(CombinableMixin):
|
|
145
145
|
def __init__(
|
146
146
|
self,
|
147
147
|
column: Column,
|
148
|
-
value:
|
149
|
-
values:
|
150
|
-
operator:
|
148
|
+
value: Any = UNDEFINED,
|
149
|
+
values: Union[CustomIterable, Undefined, QueryString] = UNDEFINED,
|
150
|
+
operator: type[ComparisonOperator] = ComparisonOperator,
|
151
151
|
) -> None:
|
152
152
|
"""
|
153
153
|
We use the UNDEFINED value to show the value was deliberately
|
@@ -156,14 +156,14 @@ class Where(CombinableMixin):
|
|
156
156
|
self.column = column
|
157
157
|
|
158
158
|
self.value = value if value == UNDEFINED else self.clean_value(value)
|
159
|
-
if values == UNDEFINED:
|
159
|
+
if (values == UNDEFINED) or isinstance(values, QueryString):
|
160
160
|
self.values = values
|
161
161
|
else:
|
162
162
|
self.values = [self.clean_value(i) for i in values] # type: ignore
|
163
163
|
|
164
164
|
self.operator = operator
|
165
165
|
|
166
|
-
def clean_value(self, value:
|
166
|
+
def clean_value(self, value: Any) -> Any:
|
167
167
|
"""
|
168
168
|
If a where clause contains a ``Table`` instance, we should convert that
|
169
169
|
to a column reference. For example:
|
@@ -192,6 +192,9 @@ class Where(CombinableMixin):
|
|
192
192
|
def values_querystring(self) -> QueryString:
|
193
193
|
values = self.values
|
194
194
|
|
195
|
+
if isinstance(values, QueryString):
|
196
|
+
return values
|
197
|
+
|
195
198
|
if isinstance(values, Undefined):
|
196
199
|
raise ValueError("values is undefined")
|
197
200
|
|
@@ -200,7 +203,7 @@ class Where(CombinableMixin):
|
|
200
203
|
|
201
204
|
@property
|
202
205
|
def querystring(self) -> QueryString:
|
203
|
-
args:
|
206
|
+
args: list[Any] = []
|
204
207
|
if self.value != UNDEFINED:
|
205
208
|
args.append(self.value)
|
206
209
|
|
@@ -219,7 +222,7 @@ class Where(CombinableMixin):
|
|
219
222
|
|
220
223
|
@property
|
221
224
|
def querystring_for_update_and_delete(self) -> QueryString:
|
222
|
-
args:
|
225
|
+
args: list[Any] = []
|
223
226
|
if self.value != UNDEFINED:
|
224
227
|
args.append(self.value)
|
225
228
|
|
piccolo/columns/defaults/base.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import typing as t
|
4
3
|
from abc import ABC, abstractmethod
|
4
|
+
from typing import Any
|
5
5
|
|
6
6
|
from piccolo.utils.repr import repr_class_instance
|
7
7
|
|
@@ -18,10 +18,10 @@ class Default(ABC):
|
|
18
18
|
pass
|
19
19
|
|
20
20
|
@abstractmethod
|
21
|
-
def python(self) ->
|
21
|
+
def python(self) -> Any:
|
22
22
|
pass
|
23
23
|
|
24
|
-
def get_postgres_interval_string(self, attributes:
|
24
|
+
def get_postgres_interval_string(self, attributes: list[str]) -> str:
|
25
25
|
"""
|
26
26
|
Returns a string usable as an interval argument in Postgres e.g.
|
27
27
|
"1 day 2 hour".
|
@@ -39,7 +39,7 @@ class Default(ABC):
|
|
39
39
|
|
40
40
|
return " ".join(interval_components)
|
41
41
|
|
42
|
-
def get_sqlite_interval_string(self, attributes:
|
42
|
+
def get_sqlite_interval_string(self, attributes: list[str]) -> str:
|
43
43
|
"""
|
44
44
|
Returns a string usable as an interval argument in SQLite e.g.
|
45
45
|
"'-2 hours', '1 days'".
|
piccolo/columns/defaults/date.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from collections.abc import Callable
|
5
5
|
from enum import Enum
|
6
|
+
from typing import Union
|
6
7
|
|
7
8
|
from .base import Default
|
8
9
|
|
@@ -102,14 +103,14 @@ class DateCustom(Default):
|
|
102
103
|
|
103
104
|
|
104
105
|
# Might add an enum back which encapsulates all of the options.
|
105
|
-
DateArg =
|
106
|
+
DateArg = Union[
|
106
107
|
DateOffset,
|
107
108
|
DateCustom,
|
108
109
|
DateNow,
|
109
110
|
Enum,
|
110
111
|
None,
|
111
112
|
datetime.date,
|
112
|
-
|
113
|
+
Callable[[], datetime.date],
|
113
114
|
]
|
114
115
|
|
115
116
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from collections.abc import Callable
|
5
5
|
from enum import Enum
|
6
|
+
from typing import Union
|
6
7
|
|
7
8
|
from .base import Default
|
8
9
|
|
@@ -75,12 +76,12 @@ class IntervalCustom(Default):
|
|
75
76
|
|
76
77
|
###############################################################################
|
77
78
|
|
78
|
-
IntervalArg =
|
79
|
+
IntervalArg = Union[
|
79
80
|
IntervalCustom,
|
80
81
|
Enum,
|
81
82
|
None,
|
82
83
|
datetime.timedelta,
|
83
|
-
|
84
|
+
Callable[[], datetime.timedelta],
|
84
85
|
]
|
85
86
|
|
86
87
|
|
piccolo/columns/defaults/time.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from collections.abc import Callable
|
5
5
|
from enum import Enum
|
6
|
+
from typing import Union
|
6
7
|
|
7
8
|
from .base import Default
|
8
9
|
|
@@ -89,14 +90,14 @@ class TimeCustom(Default):
|
|
89
90
|
)
|
90
91
|
|
91
92
|
|
92
|
-
TimeArg =
|
93
|
+
TimeArg = Union[
|
93
94
|
TimeCustom,
|
94
95
|
TimeNow,
|
95
96
|
TimeOffset,
|
96
97
|
Enum,
|
97
98
|
None,
|
98
99
|
datetime.time,
|
99
|
-
|
100
|
+
Callable[[], datetime.time],
|
100
101
|
]
|
101
102
|
|
102
103
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from collections.abc import Callable
|
5
5
|
from enum import Enum
|
6
|
+
from typing import Union
|
6
7
|
|
7
8
|
from .base import Default
|
8
9
|
|
@@ -134,7 +135,7 @@ class DatetimeDefault:
|
|
134
135
|
|
135
136
|
###############################################################################
|
136
137
|
|
137
|
-
TimestampArg =
|
138
|
+
TimestampArg = Union[
|
138
139
|
TimestampCustom,
|
139
140
|
TimestampNow,
|
140
141
|
TimestampOffset,
|
@@ -142,7 +143,7 @@ TimestampArg = t.Union[
|
|
142
143
|
None,
|
143
144
|
datetime.datetime,
|
144
145
|
DatetimeDefault,
|
145
|
-
|
146
|
+
Callable[[], datetime.datetime],
|
146
147
|
]
|
147
148
|
|
148
149
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from collections.abc import Callable
|
5
5
|
from enum import Enum
|
6
|
+
from typing import Union
|
6
7
|
|
7
8
|
from .timestamp import TimestampCustom, TimestampNow, TimestampOffset
|
8
9
|
|
@@ -68,14 +69,14 @@ class TimestamptzCustom(TimestampCustom):
|
|
68
69
|
)
|
69
70
|
|
70
71
|
|
71
|
-
TimestamptzArg =
|
72
|
+
TimestamptzArg = Union[
|
72
73
|
TimestamptzCustom,
|
73
74
|
TimestamptzNow,
|
74
75
|
TimestamptzOffset,
|
75
76
|
Enum,
|
76
77
|
None,
|
77
78
|
datetime.datetime,
|
78
|
-
|
79
|
+
Callable[[], datetime.datetime],
|
79
80
|
]
|
80
81
|
|
81
82
|
|
piccolo/columns/defaults/uuid.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
import typing as t
|
2
1
|
import uuid
|
2
|
+
from collections.abc import Callable
|
3
3
|
from enum import Enum
|
4
|
+
from typing import Union
|
4
5
|
|
5
6
|
from .base import Default
|
6
7
|
|
@@ -22,7 +23,7 @@ class UUID4(Default):
|
|
22
23
|
return uuid.uuid4()
|
23
24
|
|
24
25
|
|
25
|
-
UUIDArg =
|
26
|
+
UUIDArg = Union[UUID4, uuid.UUID, str, Enum, None, Callable[[], uuid.UUID]]
|
26
27
|
|
27
28
|
|
28
29
|
__all__ = ["UUIDArg", "UUID4"]
|
piccolo/columns/m2m.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import inspect
|
4
|
-
|
4
|
+
from collections.abc import Sequence
|
5
5
|
from dataclasses import dataclass
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
6
7
|
|
7
8
|
from piccolo.columns.column_types import (
|
8
9
|
JSON,
|
@@ -15,7 +16,7 @@ from piccolo.querystring import QueryString, Selectable
|
|
15
16
|
from piccolo.utils.list import flatten
|
16
17
|
from piccolo.utils.sync import run_sync
|
17
18
|
|
18
|
-
if
|
19
|
+
if TYPE_CHECKING: # pragma: no cover
|
19
20
|
from piccolo.table import Table
|
20
21
|
|
21
22
|
|
@@ -151,12 +152,12 @@ class M2MSelect(Selectable):
|
|
151
152
|
|
152
153
|
@dataclass
|
153
154
|
class M2MMeta:
|
154
|
-
joining_table:
|
155
|
-
_foreign_key_columns:
|
155
|
+
joining_table: Union[type[Table], LazyTableReference]
|
156
|
+
_foreign_key_columns: Optional[list[ForeignKey]] = None
|
156
157
|
|
157
158
|
# Set by the Table Metaclass:
|
158
|
-
_name:
|
159
|
-
_table:
|
159
|
+
_name: Optional[str] = None
|
160
|
+
_table: Optional[type[Table]] = None
|
160
161
|
|
161
162
|
@property
|
162
163
|
def name(self) -> str:
|
@@ -167,7 +168,7 @@ class M2MMeta:
|
|
167
168
|
return self._name
|
168
169
|
|
169
170
|
@property
|
170
|
-
def table(self) ->
|
171
|
+
def table(self) -> type[Table]:
|
171
172
|
if not self._table:
|
172
173
|
raise ValueError(
|
173
174
|
"`_table` isn't defined - the Table Metaclass should set it."
|
@@ -175,7 +176,7 @@ class M2MMeta:
|
|
175
176
|
return self._table
|
176
177
|
|
177
178
|
@property
|
178
|
-
def resolved_joining_table(self) ->
|
179
|
+
def resolved_joining_table(self) -> type[Table]:
|
179
180
|
"""
|
180
181
|
Evaluates the ``joining_table`` attribute if it's a
|
181
182
|
``LazyTableReference``, raising a ``ValueError`` if it fails, otherwise
|
@@ -196,7 +197,7 @@ class M2MMeta:
|
|
196
197
|
)
|
197
198
|
|
198
199
|
@property
|
199
|
-
def foreign_key_columns(self) ->
|
200
|
+
def foreign_key_columns(self) -> list[ForeignKey]:
|
200
201
|
if not self._foreign_key_columns:
|
201
202
|
self._foreign_key_columns = (
|
202
203
|
self.resolved_joining_table._meta.foreign_key_columns[:2]
|
@@ -236,7 +237,7 @@ class M2MMeta:
|
|
236
237
|
raise ValueError("No matching foreign key column found!")
|
237
238
|
|
238
239
|
@property
|
239
|
-
def primary_table(self) ->
|
240
|
+
def primary_table(self) -> type[Table]:
|
240
241
|
return self.primary_foreign_key._foreign_key_meta.resolved_references
|
241
242
|
|
242
243
|
@property
|
@@ -251,7 +252,7 @@ class M2MMeta:
|
|
251
252
|
raise ValueError("No matching foreign key column found!")
|
252
253
|
|
253
254
|
@property
|
254
|
-
def secondary_table(self) ->
|
255
|
+
def secondary_table(self) -> type[Table]:
|
255
256
|
return self.secondary_foreign_key._foreign_key_meta.resolved_references
|
256
257
|
|
257
258
|
|
@@ -259,11 +260,11 @@ class M2MMeta:
|
|
259
260
|
class M2MAddRelated:
|
260
261
|
target_row: Table
|
261
262
|
m2m: M2M
|
262
|
-
rows:
|
263
|
-
extra_column_values:
|
263
|
+
rows: Sequence[Table]
|
264
|
+
extra_column_values: dict[Union[Column, str], Any]
|
264
265
|
|
265
266
|
@property
|
266
|
-
def resolved_extra_column_values(self) ->
|
267
|
+
def resolved_extra_column_values(self) -> dict[str, Any]:
|
267
268
|
return {
|
268
269
|
i._meta.name if isinstance(i, Column) else i: j
|
269
270
|
for i, j in self.extra_column_values.items()
|
@@ -327,7 +328,7 @@ class M2MAddRelated:
|
|
327
328
|
class M2MRemoveRelated:
|
328
329
|
target_row: Table
|
329
330
|
m2m: M2M
|
330
|
-
rows:
|
331
|
+
rows: Sequence[Table]
|
331
332
|
|
332
333
|
async def run(self):
|
333
334
|
fk = self.m2m._meta.secondary_foreign_key
|
@@ -372,24 +373,16 @@ class M2MGetRelated:
|
|
372
373
|
|
373
374
|
secondary_table = self.m2m._meta.secondary_table
|
374
375
|
|
375
|
-
#
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
.output(as_list=True)
|
385
|
-
)
|
386
|
-
|
387
|
-
results = (
|
388
|
-
await secondary_table.objects().where(
|
389
|
-
secondary_table._meta.primary_key.is_in(ids)
|
376
|
+
# use a subquery to make only one db query
|
377
|
+
results = await secondary_table.objects().where(
|
378
|
+
secondary_table._meta.primary_key.is_in(
|
379
|
+
joining_table.select(
|
380
|
+
getattr(
|
381
|
+
self.m2m._meta.secondary_foreign_key,
|
382
|
+
secondary_table._meta.primary_key._meta.name,
|
383
|
+
)
|
384
|
+
).where(self.m2m._meta.primary_foreign_key == self.row)
|
390
385
|
)
|
391
|
-
if len(ids) > 0
|
392
|
-
else []
|
393
386
|
)
|
394
387
|
|
395
388
|
return results
|
@@ -404,8 +397,8 @@ class M2MGetRelated:
|
|
404
397
|
class M2M:
|
405
398
|
def __init__(
|
406
399
|
self,
|
407
|
-
joining_table:
|
408
|
-
foreign_key_columns:
|
400
|
+
joining_table: Union[type[Table], LazyTableReference],
|
401
|
+
foreign_key_columns: Optional[list[ForeignKey]] = None,
|
409
402
|
):
|
410
403
|
"""
|
411
404
|
:param joining_table:
|
@@ -428,7 +421,7 @@ class M2M:
|
|
428
421
|
|
429
422
|
def __call__(
|
430
423
|
self,
|
431
|
-
*columns:
|
424
|
+
*columns: Union[Column, list[Column]],
|
432
425
|
as_list: bool = False,
|
433
426
|
load_json: bool = False,
|
434
427
|
) -> M2MSelect:
|
piccolo/columns/readable.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from collections.abc import Sequence
|
4
4
|
from dataclasses import dataclass
|
5
|
+
from typing import TYPE_CHECKING
|
5
6
|
|
6
7
|
from piccolo.querystring import QueryString, Selectable
|
7
8
|
|
8
|
-
if
|
9
|
+
if TYPE_CHECKING: # pragma: no cover
|
9
10
|
from piccolo.columns.base import Column
|
10
11
|
|
11
12
|
|
@@ -18,7 +19,7 @@ class Readable(Selectable):
|
|
18
19
|
"""
|
19
20
|
|
20
21
|
template: str
|
21
|
-
columns:
|
22
|
+
columns: Sequence[Column]
|
22
23
|
output_name: str = "readable"
|
23
24
|
|
24
25
|
@property
|
piccolo/columns/reference.py
CHANGED
@@ -6,10 +6,10 @@ from __future__ import annotations
|
|
6
6
|
|
7
7
|
import importlib
|
8
8
|
import inspect
|
9
|
-
import typing as t
|
10
9
|
from dataclasses import dataclass, field
|
10
|
+
from typing import TYPE_CHECKING, Optional
|
11
11
|
|
12
|
-
if
|
12
|
+
if TYPE_CHECKING: # pragma: no cover
|
13
13
|
from piccolo.columns.column_types import ForeignKey
|
14
14
|
from piccolo.table import Table
|
15
15
|
|
@@ -36,8 +36,8 @@ class LazyTableReference:
|
|
36
36
|
"""
|
37
37
|
|
38
38
|
table_class_name: str
|
39
|
-
app_name:
|
40
|
-
module_path:
|
39
|
+
app_name: Optional[str] = None
|
40
|
+
module_path: Optional[str] = None
|
41
41
|
|
42
42
|
def __post_init__(self):
|
43
43
|
if self.app_name is None and self.module_path is None:
|
@@ -49,7 +49,7 @@ class LazyTableReference:
|
|
49
49
|
"Specify either app_name or module_path - not both."
|
50
50
|
)
|
51
51
|
|
52
|
-
def resolve(self) ->
|
52
|
+
def resolve(self) -> type[Table]:
|
53
53
|
if self.app_name is not None:
|
54
54
|
from piccolo.conf.apps import Finder
|
55
55
|
|
@@ -60,7 +60,7 @@ class LazyTableReference:
|
|
60
60
|
|
61
61
|
if self.module_path:
|
62
62
|
module = importlib.import_module(self.module_path)
|
63
|
-
table:
|
63
|
+
table: Optional[type[Table]] = getattr(
|
64
64
|
module, self.table_class_name, None
|
65
65
|
)
|
66
66
|
|
@@ -91,9 +91,9 @@ class LazyTableReference:
|
|
91
91
|
|
92
92
|
@dataclass
|
93
93
|
class LazyColumnReferenceStore:
|
94
|
-
foreign_key_columns:
|
94
|
+
foreign_key_columns: list[ForeignKey] = field(default_factory=list)
|
95
95
|
|
96
|
-
def for_table(self, table:
|
96
|
+
def for_table(self, table: type[Table]) -> list[ForeignKey]:
|
97
97
|
return [
|
98
98
|
i
|
99
99
|
for i in self.foreign_key_columns
|
@@ -101,7 +101,7 @@ class LazyColumnReferenceStore:
|
|
101
101
|
and i._foreign_key_meta.references.resolve() is table
|
102
102
|
]
|
103
103
|
|
104
|
-
def for_tablename(self, tablename: str) ->
|
104
|
+
def for_tablename(self, tablename: str) -> list[ForeignKey]:
|
105
105
|
return [
|
106
106
|
i
|
107
107
|
for i in self.foreign_key_columns
|