piccolo 1.27.1__py3-none-any.whl → 1.29.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 +2 -3
- piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja +57 -29
- piccolo/apps/asgi/commands/templates/app/_esmerald_app.py.jinja +48 -21
- piccolo/apps/asgi/commands/templates/app/_falcon_app.py.jinja +63 -8
- piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja +51 -24
- piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja +34 -10
- piccolo/apps/asgi/commands/templates/app/_quart_app.py.jinja +38 -15
- piccolo/apps/asgi/commands/templates/app/_sanic_app.py.jinja +34 -11
- 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 +72 -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 +299 -177
- 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 +105 -98
- piccolo/table_reflection.py +9 -9
- piccolo/testing/model_builder.py +16 -13
- piccolo/testing/random_builder.py +14 -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.29.0.dist-info}/METADATA +1 -1
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/RECORD +132 -131
- 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 +20 -49
- 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_metaclass.py +7 -3
- tests/table/test_refresh.py +2 -2
- tests/table/test_select.py +58 -0
- tests/table/test_str.py +30 -22
- tests/table/test_update.py +18 -3
- tests/testing/test_model_builder.py +1 -2
- tests/testing/test_random_builder.py +5 -0
- tests/utils/test_pydantic.py +152 -134
- tests/utils/test_table_reflection.py +1 -2
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/WHEEL +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/entry_points.txt +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/licenses/LICENSE +0 -0
- {piccolo-1.27.1.dist-info → piccolo-1.29.0.dist-info}/top_level.txt +0 -0
@@ -5,12 +5,13 @@ import builtins
|
|
5
5
|
import datetime
|
6
6
|
import decimal
|
7
7
|
import inspect
|
8
|
-
import typing as t
|
9
8
|
import uuid
|
10
9
|
import warnings
|
10
|
+
from collections.abc import Callable, Iterable
|
11
11
|
from copy import deepcopy
|
12
12
|
from dataclasses import dataclass, field
|
13
13
|
from enum import Enum
|
14
|
+
from typing import Any, Optional
|
14
15
|
|
15
16
|
from piccolo.columns import Column
|
16
17
|
from piccolo.columns.defaults.base import Default
|
@@ -61,8 +62,8 @@ class UniqueGlobalNamesMeta(type):
|
|
61
62
|
|
62
63
|
@staticmethod
|
63
64
|
def get_unique_class_attribute_values(
|
64
|
-
class_attributes:
|
65
|
-
) ->
|
65
|
+
class_attributes: dict[str, Any],
|
66
|
+
) -> set[Any]:
|
66
67
|
"""
|
67
68
|
Return class attribute values.
|
68
69
|
|
@@ -87,9 +88,9 @@ class UniqueGlobalNamesMeta(type):
|
|
87
88
|
|
88
89
|
@staticmethod
|
89
90
|
def merge_class_attributes(
|
90
|
-
class_attributes1:
|
91
|
-
class_attributes2:
|
92
|
-
) ->
|
91
|
+
class_attributes1: dict[str, Any],
|
92
|
+
class_attributes2: dict[str, Any],
|
93
|
+
) -> dict[str, Any]:
|
93
94
|
"""
|
94
95
|
Merges two class attribute dictionaries.
|
95
96
|
|
@@ -104,12 +105,12 @@ class UniqueGlobalNamesMeta(type):
|
|
104
105
|
return dict(**class_attributes1, **class_attributes2)
|
105
106
|
|
106
107
|
@staticmethod
|
107
|
-
def get_column_class_attributes() ->
|
108
|
+
def get_column_class_attributes() -> dict[str, str]:
|
108
109
|
"""Automatically generates global names for each column type."""
|
109
110
|
|
110
111
|
import piccolo.columns.column_types
|
111
112
|
|
112
|
-
class_attributes:
|
113
|
+
class_attributes: dict[str, str] = {}
|
113
114
|
for module_global in piccolo.columns.column_types.__dict__.values():
|
114
115
|
try:
|
115
116
|
if module_global is not Column and issubclass(
|
@@ -150,7 +151,7 @@ class UniqueGlobalNames(metaclass=UniqueGlobalNamesMeta):
|
|
150
151
|
EXTERNAL_UUID = f"{EXTERNAL_MODULE_UUID}.{uuid.UUID.__name__}"
|
151
152
|
|
152
153
|
# This attribute is set in metaclass
|
153
|
-
unique_names:
|
154
|
+
unique_names: set[str]
|
154
155
|
|
155
156
|
@classmethod
|
156
157
|
def warn_if_is_conflicting_name(
|
@@ -172,7 +173,7 @@ class UniqueGlobalNames(metaclass=UniqueGlobalNamesMeta):
|
|
172
173
|
|
173
174
|
@staticmethod
|
174
175
|
def warn_if_are_conflicting_objects(
|
175
|
-
objects:
|
176
|
+
objects: Iterable[CanConflictWithGlobalNames],
|
176
177
|
) -> None:
|
177
178
|
"""
|
178
179
|
Call each object's ``raise_if_is_conflicting_with_global_name`` method.
|
@@ -192,8 +193,8 @@ class UniqueGlobalNameConflictWarning(UserWarning):
|
|
192
193
|
@dataclass
|
193
194
|
class Import(CanConflictWithGlobalNames):
|
194
195
|
module: str
|
195
|
-
target:
|
196
|
-
expect_conflict_with_global_name:
|
196
|
+
target: Optional[str] = None
|
197
|
+
expect_conflict_with_global_name: Optional[str] = None
|
197
198
|
|
198
199
|
def __post_init__(self) -> None:
|
199
200
|
if (
|
@@ -256,9 +257,9 @@ class Definition(CanConflictWithGlobalNames, abc.ABC):
|
|
256
257
|
|
257
258
|
@dataclass
|
258
259
|
class SerialisedParams:
|
259
|
-
params:
|
260
|
-
extra_imports:
|
261
|
-
extra_definitions:
|
260
|
+
params: dict[str, Any]
|
261
|
+
extra_imports: list[Import]
|
262
|
+
extra_definitions: list[Definition] = field(default_factory=list)
|
262
263
|
|
263
264
|
|
264
265
|
###############################################################################
|
@@ -273,7 +274,7 @@ def check_equality(self, other):
|
|
273
274
|
|
274
275
|
@dataclass
|
275
276
|
class SerialisedBuiltin:
|
276
|
-
builtin:
|
277
|
+
builtin: Any
|
277
278
|
|
278
279
|
def __hash__(self):
|
279
280
|
return hash(self.builtin.__name__)
|
@@ -335,7 +336,7 @@ class SerialisedEnumInstance:
|
|
335
336
|
|
336
337
|
@dataclass
|
337
338
|
class SerialisedTableType(Definition):
|
338
|
-
table_type:
|
339
|
+
table_type: type[Table]
|
339
340
|
|
340
341
|
def __hash__(self):
|
341
342
|
return hash(
|
@@ -361,7 +362,7 @@ class SerialisedTableType(Definition):
|
|
361
362
|
|
362
363
|
# When creating a ForeignKey, the user can specify a column other than
|
363
364
|
# the primary key to reference.
|
364
|
-
serialised_target_columns:
|
365
|
+
serialised_target_columns: set[SerialisedColumnInstance] = set()
|
365
366
|
|
366
367
|
for fk_column in self.table_type._meta._foreign_key_references:
|
367
368
|
target_column = fk_column._foreign_key_meta.target_column
|
@@ -426,7 +427,7 @@ class SerialisedTableType(Definition):
|
|
426
427
|
|
427
428
|
@dataclass
|
428
429
|
class SerialisedEnumType:
|
429
|
-
enum_type:
|
430
|
+
enum_type: type[Enum]
|
430
431
|
|
431
432
|
def __hash__(self):
|
432
433
|
return hash(self.__repr__())
|
@@ -442,7 +443,7 @@ class SerialisedEnumType:
|
|
442
443
|
|
443
444
|
@dataclass
|
444
445
|
class SerialisedCallable:
|
445
|
-
callable_:
|
446
|
+
callable_: Callable
|
446
447
|
|
447
448
|
def __hash__(self):
|
448
449
|
return hash(self.callable_.__name__)
|
@@ -487,14 +488,14 @@ class SerialisedDecimal:
|
|
487
488
|
###############################################################################
|
488
489
|
|
489
490
|
|
490
|
-
def serialise_params(params:
|
491
|
+
def serialise_params(params: dict[str, Any]) -> SerialisedParams:
|
491
492
|
"""
|
492
493
|
When writing column params to a migration file, we need to serialise some
|
493
494
|
of the values.
|
494
495
|
"""
|
495
496
|
params = deepcopy(params)
|
496
|
-
extra_imports:
|
497
|
-
extra_definitions:
|
497
|
+
extra_imports: list[Import] = []
|
498
|
+
extra_definitions: list[Definition] = []
|
498
499
|
|
499
500
|
for key, value in params.items():
|
500
501
|
# Builtins, such as str, list and dict.
|
@@ -725,7 +726,7 @@ def serialise_params(params: t.Dict[str, t.Any]) -> SerialisedParams:
|
|
725
726
|
)
|
726
727
|
|
727
728
|
|
728
|
-
def deserialise_params(params:
|
729
|
+
def deserialise_params(params: dict[str, Any]) -> dict[str, Any]:
|
729
730
|
"""
|
730
731
|
When reading column params from a migration file, we need to convert
|
731
732
|
them from their serialised form.
|
@@ -737,6 +738,8 @@ def deserialise_params(params: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
|
|
737
738
|
if isinstance(value, str) and not isinstance(value, Enum):
|
738
739
|
if value != "self":
|
739
740
|
params[key] = deserialise_legacy_params(name=key, value=value)
|
741
|
+
elif isinstance(value, SerialisedColumnInstance):
|
742
|
+
params[key] = value.instance
|
740
743
|
elif isinstance(value, SerialisedClassInstance):
|
741
744
|
params[key] = value.instance
|
742
745
|
elif isinstance(value, SerialisedUUID):
|
@@ -1,14 +1,14 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import datetime
|
4
|
-
|
4
|
+
from typing import Any
|
5
5
|
|
6
6
|
from piccolo.columns.column_types import OnDelete, OnUpdate
|
7
7
|
from piccolo.columns.defaults.timestamp import TimestampNow
|
8
8
|
from piccolo.table import create_table_class
|
9
9
|
|
10
10
|
|
11
|
-
def deserialise_legacy_params(name: str, value: str) ->
|
11
|
+
def deserialise_legacy_params(name: str, value: str) -> Any:
|
12
12
|
"""
|
13
13
|
Earlier versions of Piccolo serialised parameters differently. This is
|
14
14
|
here purely for backwards compatibility.
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
import sys
|
5
|
-
import typing as t
|
6
5
|
|
7
6
|
from piccolo.apps.migrations.auto.migration_manager import MigrationManager
|
8
7
|
from piccolo.apps.migrations.commands.base import (
|
@@ -31,7 +30,7 @@ class BackwardsMigrationManager(BaseMigrationManager):
|
|
31
30
|
super().__init__()
|
32
31
|
|
33
32
|
async def run_migrations_backwards(self, app_config: AppConfig):
|
34
|
-
migration_modules:
|
33
|
+
migration_modules: dict[str, MigrationModule] = (
|
35
34
|
self.get_migration_modules(
|
36
35
|
app_config.resolved_migrations_folder_path
|
37
36
|
)
|
@@ -3,8 +3,8 @@ from __future__ import annotations
|
|
3
3
|
import importlib
|
4
4
|
import os
|
5
5
|
import sys
|
6
|
-
import typing as t
|
7
6
|
from dataclasses import dataclass
|
7
|
+
from typing import Optional, cast
|
8
8
|
|
9
9
|
from piccolo.apps.migrations.auto.diffable_table import DiffableTable
|
10
10
|
from piccolo.apps.migrations.auto.migration_manager import MigrationManager
|
@@ -16,7 +16,7 @@ from piccolo.conf.apps import AppConfig, Finder, MigrationModule
|
|
16
16
|
@dataclass
|
17
17
|
class MigrationResult:
|
18
18
|
success: bool
|
19
|
-
message:
|
19
|
+
message: Optional[str] = None
|
20
20
|
|
21
21
|
|
22
22
|
class BaseMigrationManager(Finder):
|
@@ -32,7 +32,7 @@ class BaseMigrationManager(Finder):
|
|
32
32
|
|
33
33
|
def get_migration_modules(
|
34
34
|
self, folder_path: str
|
35
|
-
) ->
|
35
|
+
) -> dict[str, MigrationModule]:
|
36
36
|
"""
|
37
37
|
Imports the migration modules in the given folder path, and returns
|
38
38
|
a mapping of migration ID to the corresponding migration module.
|
@@ -50,8 +50,8 @@ class BaseMigrationManager(Finder):
|
|
50
50
|
if ((i not in excluded) and i.endswith(".py"))
|
51
51
|
]
|
52
52
|
|
53
|
-
modules:
|
54
|
-
|
53
|
+
modules: list[MigrationModule] = [
|
54
|
+
cast(MigrationModule, importlib.import_module(name))
|
55
55
|
for name in migration_names
|
56
56
|
]
|
57
57
|
for m in modules:
|
@@ -62,8 +62,8 @@ class BaseMigrationManager(Finder):
|
|
62
62
|
return migration_modules
|
63
63
|
|
64
64
|
def get_migration_ids(
|
65
|
-
self, migration_module_dict:
|
66
|
-
) ->
|
65
|
+
self, migration_module_dict: dict[str, MigrationModule]
|
66
|
+
) -> list[str]:
|
67
67
|
"""
|
68
68
|
Returns a list of migration IDs, from the Python migration files.
|
69
69
|
"""
|
@@ -72,9 +72,9 @@ class BaseMigrationManager(Finder):
|
|
72
72
|
async def get_migration_managers(
|
73
73
|
self,
|
74
74
|
app_config: AppConfig,
|
75
|
-
max_migration_id:
|
75
|
+
max_migration_id: Optional[str] = None,
|
76
76
|
offset: int = 0,
|
77
|
-
) ->
|
77
|
+
) -> list[MigrationManager]:
|
78
78
|
"""
|
79
79
|
Call the forwards coroutine in each migration module. Each one should
|
80
80
|
return a `MigrationManger`. Combine all of the results, and return in
|
@@ -84,11 +84,11 @@ class BaseMigrationManager(Finder):
|
|
84
84
|
If set, only MigrationManagers up to and including the given
|
85
85
|
migration ID will be returned.
|
86
86
|
"""
|
87
|
-
migration_managers:
|
87
|
+
migration_managers: list[MigrationManager] = []
|
88
88
|
|
89
89
|
migrations_folder = app_config.resolved_migrations_folder_path
|
90
90
|
|
91
|
-
migration_modules:
|
91
|
+
migration_modules: dict[str, MigrationModule] = (
|
92
92
|
self.get_migration_modules(migrations_folder)
|
93
93
|
)
|
94
94
|
|
@@ -118,7 +118,7 @@ class BaseMigrationManager(Finder):
|
|
118
118
|
self,
|
119
119
|
app_name: str,
|
120
120
|
table_class_name: str,
|
121
|
-
max_migration_id:
|
121
|
+
max_migration_id: Optional[str] = None,
|
122
122
|
offset: int = 0,
|
123
123
|
) -> DiffableTable:
|
124
124
|
"""
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import dataclasses
|
2
|
-
import typing as t
|
3
2
|
|
4
3
|
from piccolo.apps.migrations.commands.base import BaseMigrationManager
|
5
4
|
from piccolo.apps.migrations.tables import Migration
|
@@ -19,11 +18,11 @@ class CheckMigrationManager(BaseMigrationManager):
|
|
19
18
|
self.app_name = app_name
|
20
19
|
super().__init__()
|
21
20
|
|
22
|
-
async def get_migration_statuses(self) ->
|
21
|
+
async def get_migration_statuses(self) -> list[MigrationStatus]:
|
23
22
|
# Make sure the migration table exists, otherwise we'll get an error.
|
24
23
|
await self.create_migration_table()
|
25
24
|
|
26
|
-
migration_statuses:
|
25
|
+
migration_statuses: list[MigrationStatus] = []
|
27
26
|
|
28
27
|
app_modules = self.get_app_modules()
|
29
28
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import cast
|
4
4
|
|
5
5
|
from piccolo.apps.migrations.commands.base import BaseMigrationManager
|
6
6
|
from piccolo.apps.migrations.tables import Migration
|
@@ -12,7 +12,7 @@ class CleanMigrationManager(BaseMigrationManager):
|
|
12
12
|
self.auto_agree = auto_agree
|
13
13
|
super().__init__()
|
14
14
|
|
15
|
-
def get_migration_ids_to_remove(self) ->
|
15
|
+
def get_migration_ids_to_remove(self) -> list[str]:
|
16
16
|
"""
|
17
17
|
Returns a list of migration ID strings, which are rows in the table,
|
18
18
|
but don't have a corresponding migration module on disk.
|
@@ -37,7 +37,7 @@ class CleanMigrationManager(BaseMigrationManager):
|
|
37
37
|
if len(migration_ids) > 0:
|
38
38
|
query = query.where(Migration.name.not_in(migration_ids))
|
39
39
|
|
40
|
-
return
|
40
|
+
return cast(list[str], query.run_sync())
|
41
41
|
|
42
42
|
async def run(self):
|
43
43
|
print("Checking the migration table ...")
|
@@ -1,7 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import sys
|
4
|
-
import typing as t
|
5
4
|
|
6
5
|
from piccolo.apps.migrations.auto.migration_manager import MigrationManager
|
7
6
|
from piccolo.apps.migrations.commands.base import (
|
@@ -32,7 +31,7 @@ class ForwardsMigrationManager(BaseMigrationManager):
|
|
32
31
|
app_name=app_config.app_name
|
33
32
|
)
|
34
33
|
|
35
|
-
migration_modules:
|
34
|
+
migration_modules: dict[str, MigrationModule] = (
|
36
35
|
self.get_migration_modules(
|
37
36
|
app_config.resolved_migrations_folder_path
|
38
37
|
)
|
@@ -3,10 +3,10 @@ from __future__ import annotations
|
|
3
3
|
import datetime
|
4
4
|
import os
|
5
5
|
import string
|
6
|
-
import typing as t
|
7
6
|
from dataclasses import dataclass
|
8
7
|
from itertools import chain
|
9
8
|
from types import ModuleType
|
9
|
+
from typing import Optional
|
10
10
|
|
11
11
|
import black
|
12
12
|
import jinja2
|
@@ -33,7 +33,7 @@ JINJA_ENV = jinja2.Environment(
|
|
33
33
|
loader=jinja2.FileSystemLoader(searchpath=TEMPLATE_DIRECTORY),
|
34
34
|
)
|
35
35
|
|
36
|
-
MIGRATION_MODULES:
|
36
|
+
MIGRATION_MODULES: dict[str, ModuleType] = {}
|
37
37
|
|
38
38
|
VALID_PYTHON_MODULE_CHARACTERS = string.ascii_lowercase + string.digits + "_"
|
39
39
|
|
@@ -115,7 +115,7 @@ async def _create_new_migration(
|
|
115
115
|
app_config: AppConfig,
|
116
116
|
auto: bool = False,
|
117
117
|
description: str = "",
|
118
|
-
auto_input:
|
118
|
+
auto_input: Optional[str] = None,
|
119
119
|
) -> NewMigrationMeta:
|
120
120
|
"""
|
121
121
|
Creates a new migration file on disk.
|
@@ -170,13 +170,13 @@ async def _create_new_migration(
|
|
170
170
|
|
171
171
|
|
172
172
|
class AutoMigrationManager(BaseMigrationManager):
|
173
|
-
def __init__(self, auto_input:
|
173
|
+
def __init__(self, auto_input: Optional[str] = None, *args, **kwargs):
|
174
174
|
self.auto_input = auto_input
|
175
175
|
super().__init__(*args, **kwargs)
|
176
176
|
|
177
177
|
async def get_alter_statements(
|
178
178
|
self, app_config: AppConfig
|
179
|
-
) ->
|
179
|
+
) -> list[AlterStatements]:
|
180
180
|
"""
|
181
181
|
Works out which alter statements are required.
|
182
182
|
"""
|
@@ -214,7 +214,7 @@ async def new(
|
|
214
214
|
app_name: str,
|
215
215
|
auto: bool = False,
|
216
216
|
desc: str = "",
|
217
|
-
auto_input:
|
217
|
+
auto_input: Optional[str] = None,
|
218
218
|
):
|
219
219
|
"""
|
220
220
|
Creates a new migration file in the migrations folder.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
from piccolo.columns import Timestamp, Varchar
|
6
6
|
from piccolo.columns.defaults.timestamp import TimestampNow
|
@@ -14,8 +14,8 @@ class Migration(Table):
|
|
14
14
|
|
15
15
|
@classmethod
|
16
16
|
async def get_migrations_which_ran(
|
17
|
-
cls, app_name:
|
18
|
-
) ->
|
17
|
+
cls, app_name: Optional[str] = None
|
18
|
+
) -> list[str]:
|
19
19
|
"""
|
20
20
|
Returns the names of migrations which have already run, by inspecting
|
21
21
|
the database.
|
@@ -8,15 +8,19 @@ import sys
|
|
8
8
|
import uuid
|
9
9
|
from decimal import Decimal
|
10
10
|
from enum import Enum
|
11
|
+
from typing import Optional
|
11
12
|
|
12
13
|
from piccolo.columns import (
|
13
14
|
JSON,
|
15
|
+
M2M,
|
14
16
|
UUID,
|
17
|
+
Array,
|
15
18
|
Boolean,
|
16
19
|
Date,
|
17
20
|
ForeignKey,
|
18
21
|
Integer,
|
19
22
|
Interval,
|
23
|
+
LazyTableReference,
|
20
24
|
Numeric,
|
21
25
|
Serial,
|
22
26
|
Text,
|
@@ -24,7 +28,7 @@ from piccolo.columns import (
|
|
24
28
|
Varchar,
|
25
29
|
)
|
26
30
|
from piccolo.columns.readable import Readable
|
27
|
-
from piccolo.engine import PostgresEngine, SQLiteEngine
|
31
|
+
from piccolo.engine import CockroachEngine, PostgresEngine, SQLiteEngine
|
28
32
|
from piccolo.engine.base import Engine
|
29
33
|
from piccolo.table import Table
|
30
34
|
from piccolo.utils.warnings import colored_string
|
@@ -47,6 +51,7 @@ class Band(Table):
|
|
47
51
|
name = Varchar(length=50)
|
48
52
|
manager = ForeignKey(references=Manager, null=True)
|
49
53
|
popularity = Integer()
|
54
|
+
genres = M2M(LazyTableReference("GenreToBand", module_path=__name__))
|
50
55
|
|
51
56
|
@classmethod
|
52
57
|
def get_readable(cls) -> Readable:
|
@@ -149,6 +154,7 @@ class Album(Table):
|
|
149
154
|
band = ForeignKey(Band)
|
150
155
|
release_date = Date()
|
151
156
|
recorded_at = ForeignKey(RecordingStudio)
|
157
|
+
awards = Array(Varchar())
|
152
158
|
|
153
159
|
@classmethod
|
154
160
|
def get_readable(cls) -> Readable:
|
@@ -158,6 +164,26 @@ class Album(Table):
|
|
158
164
|
)
|
159
165
|
|
160
166
|
|
167
|
+
class Genre(Table):
|
168
|
+
id: Serial
|
169
|
+
name = Varchar()
|
170
|
+
bands = M2M(LazyTableReference("GenreToBand", module_path=__name__))
|
171
|
+
|
172
|
+
@classmethod
|
173
|
+
def get_readable(cls) -> Readable:
|
174
|
+
return Readable(
|
175
|
+
template="%s",
|
176
|
+
columns=[cls.name],
|
177
|
+
)
|
178
|
+
|
179
|
+
|
180
|
+
class GenreToBand(Table):
|
181
|
+
id: Serial
|
182
|
+
band = ForeignKey(Band)
|
183
|
+
genre = ForeignKey(Genre)
|
184
|
+
reason = Text(null=True, default=None)
|
185
|
+
|
186
|
+
|
161
187
|
TABLES = (
|
162
188
|
Manager,
|
163
189
|
Band,
|
@@ -168,6 +194,8 @@ TABLES = (
|
|
168
194
|
DiscountCode,
|
169
195
|
RecordingStudio,
|
170
196
|
Album,
|
197
|
+
Genre,
|
198
|
+
GenreToBand,
|
171
199
|
)
|
172
200
|
|
173
201
|
|
@@ -265,6 +293,7 @@ def populate():
|
|
265
293
|
Album.recorded_at: recording_studio_1,
|
266
294
|
Album.band: pythonistas,
|
267
295
|
Album.release_date: datetime.date(year=2021, month=1, day=1),
|
296
|
+
Album.awards: ["Grammy Award 2021"],
|
268
297
|
}
|
269
298
|
),
|
270
299
|
Album(
|
@@ -273,35 +302,55 @@ def populate():
|
|
273
302
|
Album.recorded_at: recording_studio_2,
|
274
303
|
Album.band: rustaceans,
|
275
304
|
Album.release_date: datetime.date(year=2022, month=2, day=2),
|
305
|
+
Album.awards: ["Mercury Prize 2022"],
|
276
306
|
}
|
277
307
|
),
|
278
308
|
).run_sync()
|
279
309
|
|
310
|
+
genres = Genre.insert(
|
311
|
+
Genre(name="Rock"),
|
312
|
+
Genre(name="Classical"),
|
313
|
+
Genre(name="Folk"),
|
314
|
+
).run_sync()
|
315
|
+
|
316
|
+
GenreToBand.insert(
|
317
|
+
GenreToBand(
|
318
|
+
band=pythonistas.id,
|
319
|
+
genre=genres[0]["id"],
|
320
|
+
reason="Because they rock.",
|
321
|
+
),
|
322
|
+
GenreToBand(band=pythonistas.id, genre=genres[2]["id"]),
|
323
|
+
GenreToBand(band=rustaceans.id, genre=genres[2]["id"]),
|
324
|
+
GenreToBand(band=c_sharps.id, genre=genres[0]["id"]),
|
325
|
+
GenreToBand(band=c_sharps.id, genre=genres[1]["id"]),
|
326
|
+
).run_sync()
|
327
|
+
|
280
328
|
|
281
329
|
def run(
|
282
330
|
engine: str = "sqlite",
|
283
|
-
user: str =
|
284
|
-
password: str =
|
331
|
+
user: Optional[str] = None,
|
332
|
+
password: Optional[str] = None,
|
285
333
|
database: str = "piccolo_playground",
|
286
334
|
host: str = "localhost",
|
287
|
-
port: int =
|
335
|
+
port: Optional[int] = None,
|
288
336
|
ipython_profile: bool = False,
|
289
337
|
):
|
290
338
|
"""
|
291
339
|
Creates a test database to play with.
|
292
340
|
|
293
341
|
:param engine:
|
294
|
-
Which database engine to use - options are sqlite or
|
342
|
+
Which database engine to use - options are sqlite, postgres or
|
343
|
+
cockroach
|
295
344
|
:param user:
|
296
|
-
|
345
|
+
Database user (ignored for SQLite)
|
297
346
|
:param password:
|
298
|
-
|
347
|
+
Database password (ignored for SQLite)
|
299
348
|
:param database:
|
300
|
-
|
349
|
+
Database name (ignored for SQLite)
|
301
350
|
:param host:
|
302
|
-
|
351
|
+
Database host (ignored for SQLite)
|
303
352
|
:param port:
|
304
|
-
|
353
|
+
Database port (ignored for SQLite)
|
305
354
|
:param ipython_profile:
|
306
355
|
Set to true to use your own IPython profile. Located at ~/.ipython/.
|
307
356
|
For more info see the IPython docs
|
@@ -320,9 +369,19 @@ def run(
|
|
320
369
|
{
|
321
370
|
"host": host,
|
322
371
|
"database": database,
|
323
|
-
"user": user,
|
324
|
-
"password": password,
|
325
|
-
"port": port,
|
372
|
+
"user": user or "piccolo",
|
373
|
+
"password": password or "piccolo",
|
374
|
+
"port": port or 5432,
|
375
|
+
}
|
376
|
+
)
|
377
|
+
elif engine.upper() == "COCKROACH":
|
378
|
+
db = CockroachEngine(
|
379
|
+
{
|
380
|
+
"host": host,
|
381
|
+
"database": database,
|
382
|
+
"user": user or "root",
|
383
|
+
"password": password or "",
|
384
|
+
"port": port or 26257,
|
326
385
|
}
|
327
386
|
)
|
328
387
|
else:
|