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
@@ -1,6 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import typing as t
|
4
3
|
from unittest import TestCase
|
5
4
|
from unittest.mock import MagicMock, call, patch
|
6
5
|
|
@@ -24,12 +23,12 @@ class TestSchemaDiffer(TestCase):
|
|
24
23
|
"""
|
25
24
|
name_column = Varchar()
|
26
25
|
name_column._meta.name = "name"
|
27
|
-
schema:
|
26
|
+
schema: list[DiffableTable] = [
|
28
27
|
DiffableTable(
|
29
28
|
class_name="Band", tablename="band", columns=[name_column]
|
30
29
|
)
|
31
30
|
]
|
32
|
-
schema_snapshot:
|
31
|
+
schema_snapshot: list[DiffableTable] = []
|
33
32
|
schema_differ = SchemaDiffer(
|
34
33
|
schema=schema, schema_snapshot=schema_snapshot, auto_input="y"
|
35
34
|
)
|
@@ -52,8 +51,8 @@ class TestSchemaDiffer(TestCase):
|
|
52
51
|
"""
|
53
52
|
Test dropping an existing table.
|
54
53
|
"""
|
55
|
-
schema:
|
56
|
-
schema_snapshot:
|
54
|
+
schema: list[DiffableTable] = []
|
55
|
+
schema_snapshot: list[DiffableTable] = [
|
57
56
|
DiffableTable(class_name="Band", tablename="band", columns=[])
|
58
57
|
]
|
59
58
|
schema_differ = SchemaDiffer(
|
@@ -73,12 +72,12 @@ class TestSchemaDiffer(TestCase):
|
|
73
72
|
name_column = Varchar()
|
74
73
|
name_column._meta.name = "name"
|
75
74
|
|
76
|
-
schema:
|
75
|
+
schema: list[DiffableTable] = [
|
77
76
|
DiffableTable(
|
78
77
|
class_name="Act", tablename="act", columns=[name_column]
|
79
78
|
)
|
80
79
|
]
|
81
|
-
schema_snapshot:
|
80
|
+
schema_snapshot: list[DiffableTable] = [
|
82
81
|
DiffableTable(
|
83
82
|
class_name="Band", tablename="band", columns=[name_column]
|
84
83
|
)
|
@@ -101,7 +100,7 @@ class TestSchemaDiffer(TestCase):
|
|
101
100
|
"""
|
102
101
|
Testing changing the schema.
|
103
102
|
"""
|
104
|
-
schema:
|
103
|
+
schema: list[DiffableTable] = [
|
105
104
|
DiffableTable(
|
106
105
|
class_name="Band",
|
107
106
|
tablename="band",
|
@@ -109,7 +108,7 @@ class TestSchemaDiffer(TestCase):
|
|
109
108
|
schema="schema_1",
|
110
109
|
)
|
111
110
|
]
|
112
|
-
schema_snapshot:
|
111
|
+
schema_snapshot: list[DiffableTable] = [
|
113
112
|
DiffableTable(
|
114
113
|
class_name="Band",
|
115
114
|
tablename="band",
|
@@ -142,14 +141,14 @@ class TestSchemaDiffer(TestCase):
|
|
142
141
|
genre_column = Varchar()
|
143
142
|
genre_column._meta.name = "genre"
|
144
143
|
|
145
|
-
schema:
|
144
|
+
schema: list[DiffableTable] = [
|
146
145
|
DiffableTable(
|
147
146
|
class_name="Band",
|
148
147
|
tablename="band",
|
149
148
|
columns=[name_column, genre_column],
|
150
149
|
)
|
151
150
|
]
|
152
|
-
schema_snapshot:
|
151
|
+
schema_snapshot: list[DiffableTable] = [
|
153
152
|
DiffableTable(
|
154
153
|
class_name="Band",
|
155
154
|
tablename="band",
|
@@ -177,14 +176,14 @@ class TestSchemaDiffer(TestCase):
|
|
177
176
|
genre_column = Varchar()
|
178
177
|
genre_column._meta.name = "genre"
|
179
178
|
|
180
|
-
schema:
|
179
|
+
schema: list[DiffableTable] = [
|
181
180
|
DiffableTable(
|
182
181
|
class_name="Band",
|
183
182
|
tablename="band",
|
184
183
|
columns=[name_column],
|
185
184
|
)
|
186
185
|
]
|
187
|
-
schema_snapshot:
|
186
|
+
schema_snapshot: list[DiffableTable] = [
|
188
187
|
DiffableTable(
|
189
188
|
class_name="Band",
|
190
189
|
tablename="band",
|
@@ -213,14 +212,14 @@ class TestSchemaDiffer(TestCase):
|
|
213
212
|
title_column = Varchar()
|
214
213
|
title_column._meta.name = "title"
|
215
214
|
|
216
|
-
schema_snapshot:
|
215
|
+
schema_snapshot: list[DiffableTable] = [
|
217
216
|
DiffableTable(
|
218
217
|
class_name="Band",
|
219
218
|
tablename="band",
|
220
219
|
columns=[title_column],
|
221
220
|
)
|
222
221
|
]
|
223
|
-
schema:
|
222
|
+
schema: list[DiffableTable] = [
|
224
223
|
DiffableTable(
|
225
224
|
class_name="Band",
|
226
225
|
tablename="band",
|
@@ -278,14 +277,14 @@ class TestSchemaDiffer(TestCase):
|
|
278
277
|
b2 = Varchar()
|
279
278
|
b2._meta.name = "b2"
|
280
279
|
|
281
|
-
schema_snapshot:
|
280
|
+
schema_snapshot: list[DiffableTable] = [
|
282
281
|
DiffableTable(
|
283
282
|
class_name="Band",
|
284
283
|
tablename="band",
|
285
284
|
columns=[a1, b1],
|
286
285
|
)
|
287
286
|
]
|
288
|
-
schema:
|
287
|
+
schema: list[DiffableTable] = [
|
289
288
|
DiffableTable(
|
290
289
|
class_name="Band",
|
291
290
|
tablename="band",
|
@@ -355,14 +354,14 @@ class TestSchemaDiffer(TestCase):
|
|
355
354
|
b2 = Varchar()
|
356
355
|
b2._meta.name = "b2"
|
357
356
|
|
358
|
-
schema_snapshot:
|
357
|
+
schema_snapshot: list[DiffableTable] = [
|
359
358
|
DiffableTable(
|
360
359
|
class_name="Band",
|
361
360
|
tablename="band",
|
362
361
|
columns=[a1, b1],
|
363
362
|
)
|
364
363
|
]
|
365
|
-
schema:
|
364
|
+
schema: list[DiffableTable] = [
|
366
365
|
DiffableTable(
|
367
366
|
class_name="Band",
|
368
367
|
tablename="band",
|
@@ -425,14 +424,14 @@ class TestSchemaDiffer(TestCase):
|
|
425
424
|
price_2 = Numeric(digits=(5, 2))
|
426
425
|
price_2._meta.name = "price"
|
427
426
|
|
428
|
-
schema:
|
427
|
+
schema: list[DiffableTable] = [
|
429
428
|
DiffableTable(
|
430
429
|
class_name="Ticket",
|
431
430
|
tablename="ticket",
|
432
431
|
columns=[price_1],
|
433
432
|
)
|
434
433
|
]
|
435
|
-
schema_snapshot:
|
434
|
+
schema_snapshot: list[DiffableTable] = [
|
436
435
|
DiffableTable(
|
437
436
|
class_name="Ticket",
|
438
437
|
tablename="ticket",
|
@@ -463,14 +462,14 @@ class TestSchemaDiffer(TestCase):
|
|
463
462
|
price_2 = Numeric(digits=(5, 2), db_column_name="custom")
|
464
463
|
price_2._meta.name = "price"
|
465
464
|
|
466
|
-
schema:
|
465
|
+
schema: list[DiffableTable] = [
|
467
466
|
DiffableTable(
|
468
467
|
class_name="Ticket",
|
469
468
|
tablename="ticket",
|
470
469
|
columns=[price_1],
|
471
470
|
)
|
472
471
|
]
|
473
|
-
schema_snapshot:
|
472
|
+
schema_snapshot: list[DiffableTable] = [
|
474
473
|
DiffableTable(
|
475
474
|
class_name="Ticket",
|
476
475
|
tablename="ticket",
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import sys
|
4
|
-
|
4
|
+
from typing import TYPE_CHECKING
|
5
5
|
from unittest import TestCase
|
6
6
|
from unittest.mock import MagicMock, call, patch
|
7
7
|
|
@@ -22,10 +22,10 @@ from tests.example_apps.music.tables import (
|
|
22
22
|
Venue,
|
23
23
|
)
|
24
24
|
|
25
|
-
if
|
25
|
+
if TYPE_CHECKING: # pragma: no cover
|
26
26
|
from piccolo.table import Table
|
27
27
|
|
28
|
-
TABLE_CLASSES:
|
28
|
+
TABLE_CLASSES: list[type[Table]] = [
|
29
29
|
Manager,
|
30
30
|
Band,
|
31
31
|
Venue,
|
tests/columns/m2m/base.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
from typing import Optional
|
2
2
|
|
3
3
|
from piccolo.columns.column_types import (
|
4
4
|
ForeignKey,
|
@@ -11,7 +11,7 @@ from piccolo.columns.m2m import M2M
|
|
11
11
|
from piccolo.engine.finder import engine_finder
|
12
12
|
from piccolo.schema import SchemaManager
|
13
13
|
from piccolo.table import Table, create_db_tables_sync, drop_db_tables_sync
|
14
|
-
from tests.base import
|
14
|
+
from tests.base import engines_skip
|
15
15
|
|
16
16
|
engine = engine_finder()
|
17
17
|
|
@@ -41,7 +41,7 @@ class M2MBase:
|
|
41
41
|
(public vs non-public).
|
42
42
|
"""
|
43
43
|
|
44
|
-
def _setUp(self, schema:
|
44
|
+
def _setUp(self, schema: Optional[str] = None):
|
45
45
|
self.schema = schema
|
46
46
|
|
47
47
|
for table_class in (Band, Genre, GenreToBand):
|
@@ -51,54 +51,25 @@ class M2MBase:
|
|
51
51
|
|
52
52
|
create_db_tables_sync(*self.all_tables, if_not_exists=True)
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
Band(name="C-Sharps"),
|
60
|
-
)
|
61
|
-
.returning(Band.id)
|
62
|
-
.run_sync()
|
63
|
-
)
|
64
|
-
|
65
|
-
genres = (
|
66
|
-
Genre.insert(
|
67
|
-
Genre(name="Rock"),
|
68
|
-
Genre(name="Folk"),
|
69
|
-
Genre(name="Classical"),
|
70
|
-
)
|
71
|
-
.returning(Genre.id)
|
72
|
-
.run_sync()
|
73
|
-
)
|
74
|
-
|
75
|
-
GenreToBand.insert(
|
76
|
-
GenreToBand(band=bands[0]["id"], genre=genres[0]["id"]),
|
77
|
-
GenreToBand(band=bands[0]["id"], genre=genres[1]["id"]),
|
78
|
-
GenreToBand(band=bands[1]["id"], genre=genres[1]["id"]),
|
79
|
-
GenreToBand(band=bands[2]["id"], genre=genres[0]["id"]),
|
80
|
-
GenreToBand(band=bands[2]["id"], genre=genres[2]["id"]),
|
81
|
-
).run_sync()
|
82
|
-
else:
|
83
|
-
Band.insert(
|
84
|
-
Band(name="Pythonistas"),
|
85
|
-
Band(name="Rustaceans"),
|
86
|
-
Band(name="C-Sharps"),
|
87
|
-
).run_sync()
|
54
|
+
bands = Band.insert(
|
55
|
+
Band(name="Pythonistas"),
|
56
|
+
Band(name="Rustaceans"),
|
57
|
+
Band(name="C-Sharps"),
|
58
|
+
).run_sync()
|
88
59
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
60
|
+
genres = Genre.insert(
|
61
|
+
Genre(name="Rock"),
|
62
|
+
Genre(name="Folk"),
|
63
|
+
Genre(name="Classical"),
|
64
|
+
).run_sync()
|
94
65
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
66
|
+
GenreToBand.insert(
|
67
|
+
GenreToBand(band=bands[0]["id"], genre=genres[0]["id"]),
|
68
|
+
GenreToBand(band=bands[0]["id"], genre=genres[1]["id"]),
|
69
|
+
GenreToBand(band=bands[1]["id"], genre=genres[1]["id"]),
|
70
|
+
GenreToBand(band=bands[2]["id"], genre=genres[0]["id"]),
|
71
|
+
GenreToBand(band=bands[2]["id"], genre=genres[2]["id"]),
|
72
|
+
).run_sync()
|
102
73
|
|
103
74
|
def tearDown(self):
|
104
75
|
drop_db_tables_sync(*self.all_tables)
|
tests/columns/test_array.py
CHANGED
@@ -186,7 +186,7 @@ class TestArray(TableTest):
|
|
186
186
|
@pytest.mark.cockroach_array_slow
|
187
187
|
def test_cat(self):
|
188
188
|
"""
|
189
|
-
Make sure values can be appended to an array.
|
189
|
+
Make sure values can be appended to an array and that we can concatenate two arrays.
|
190
190
|
|
191
191
|
In CockroachDB <= v22.2.0 we had this error:
|
192
192
|
|
@@ -197,37 +197,47 @@ class TestArray(TableTest):
|
|
197
197
|
* https://github.com/piccolo-orm/piccolo/issues/1005
|
198
198
|
|
199
199
|
""" # noqa: E501
|
200
|
-
MyTable(value=[
|
200
|
+
MyTable(value=[5]).save().run_sync()
|
201
201
|
|
202
202
|
MyTable.update(
|
203
|
-
{MyTable.value: MyTable.value.cat([
|
203
|
+
{MyTable.value: MyTable.value.cat([6])}, force=True
|
204
204
|
).run_sync()
|
205
205
|
|
206
206
|
self.assertEqual(
|
207
207
|
MyTable.select(MyTable.value).run_sync(),
|
208
|
-
[{"value": [
|
208
|
+
[{"value": [5, 6]}],
|
209
209
|
)
|
210
210
|
|
211
|
-
# Try plus symbol
|
211
|
+
# Try plus symbol - add array to the end
|
212
212
|
|
213
213
|
MyTable.update(
|
214
|
-
{MyTable.value: MyTable.value + [
|
214
|
+
{MyTable.value: MyTable.value + [7]}, force=True
|
215
215
|
).run_sync()
|
216
216
|
|
217
217
|
self.assertEqual(
|
218
218
|
MyTable.select(MyTable.value).run_sync(),
|
219
|
-
[{"value": [
|
219
|
+
[{"value": [5, 6, 7]}],
|
220
220
|
)
|
221
221
|
|
222
|
-
#
|
222
|
+
# Add array to the start
|
223
|
+
|
224
|
+
MyTable.update(
|
225
|
+
{MyTable.value: [4] + MyTable.value}, force=True
|
226
|
+
).run_sync()
|
227
|
+
|
228
|
+
self.assertEqual(
|
229
|
+
MyTable.select(MyTable.value).run_sync(),
|
230
|
+
[{"value": [4, 5, 6, 7]}],
|
231
|
+
)
|
223
232
|
|
233
|
+
# Add array to the start and end
|
224
234
|
MyTable.update(
|
225
|
-
{MyTable.value: MyTable.value +
|
235
|
+
{MyTable.value: [3] + MyTable.value + [8]}, force=True
|
226
236
|
).run_sync()
|
227
237
|
|
228
238
|
self.assertEqual(
|
229
239
|
MyTable.select(MyTable.value).run_sync(),
|
230
|
-
[{"value": [
|
240
|
+
[{"value": [3, 4, 5, 6, 7, 8]}],
|
231
241
|
)
|
232
242
|
|
233
243
|
@sqlite_only
|
@@ -238,11 +248,167 @@ class TestArray(TableTest):
|
|
238
248
|
with self.assertRaises(ValueError) as manager:
|
239
249
|
MyTable.value.cat([2])
|
240
250
|
|
251
|
+
self.assertEqual(
|
252
|
+
str(manager.exception),
|
253
|
+
"Only Postgres and Cockroach support array concatenation.",
|
254
|
+
)
|
255
|
+
|
256
|
+
@engines_skip("sqlite")
|
257
|
+
@pytest.mark.cockroach_array_slow
|
258
|
+
def test_prepend(self):
|
259
|
+
"""
|
260
|
+
Make sure values can be added to the beginning of the array.
|
261
|
+
|
262
|
+
In CockroachDB <= v22.2.0 we had this error:
|
263
|
+
|
264
|
+
* https://github.com/cockroachdb/cockroach/issues/71908 "could not decorrelate subquery" error under asyncpg
|
265
|
+
|
266
|
+
In newer CockroachDB versions, it runs but is very slow:
|
267
|
+
|
268
|
+
* https://github.com/piccolo-orm/piccolo/issues/1005
|
269
|
+
|
270
|
+
""" # noqa: E501
|
271
|
+
MyTable(value=[1, 1, 1]).save().run_sync()
|
272
|
+
|
273
|
+
MyTable.update(
|
274
|
+
{MyTable.value: MyTable.value.prepend(3)}, force=True
|
275
|
+
).run_sync()
|
276
|
+
|
277
|
+
self.assertEqual(
|
278
|
+
MyTable.select(MyTable.value).run_sync(),
|
279
|
+
[{"value": [3, 1, 1, 1]}],
|
280
|
+
)
|
281
|
+
|
282
|
+
@sqlite_only
|
283
|
+
def test_prepend_sqlite(self):
|
284
|
+
"""
|
285
|
+
If using SQLite then an exception should be raised currently.
|
286
|
+
"""
|
287
|
+
with self.assertRaises(ValueError) as manager:
|
288
|
+
MyTable.value.prepend(2)
|
289
|
+
|
290
|
+
self.assertEqual(
|
291
|
+
str(manager.exception),
|
292
|
+
"Only Postgres and Cockroach support array prepending.",
|
293
|
+
)
|
294
|
+
|
295
|
+
@engines_skip("sqlite")
|
296
|
+
@pytest.mark.cockroach_array_slow
|
297
|
+
def test_append(self):
|
298
|
+
"""
|
299
|
+
Make sure values can be appended to an array.
|
300
|
+
|
301
|
+
In CockroachDB <= v22.2.0 we had this error:
|
302
|
+
|
303
|
+
* https://github.com/cockroachdb/cockroach/issues/71908 "could not decorrelate subquery" error under asyncpg
|
304
|
+
|
305
|
+
In newer CockroachDB versions, it runs but is very slow:
|
306
|
+
|
307
|
+
* https://github.com/piccolo-orm/piccolo/issues/1005
|
308
|
+
|
309
|
+
""" # noqa: E501
|
310
|
+
MyTable(value=[1, 1, 1]).save().run_sync()
|
311
|
+
|
312
|
+
MyTable.update(
|
313
|
+
{MyTable.value: MyTable.value.append(3)}, force=True
|
314
|
+
).run_sync()
|
315
|
+
|
316
|
+
self.assertEqual(
|
317
|
+
MyTable.select(MyTable.value).run_sync(),
|
318
|
+
[{"value": [1, 1, 1, 3]}],
|
319
|
+
)
|
320
|
+
|
321
|
+
@sqlite_only
|
322
|
+
def test_append_sqlite(self):
|
323
|
+
"""
|
324
|
+
If using SQLite then an exception should be raised currently.
|
325
|
+
"""
|
326
|
+
with self.assertRaises(ValueError) as manager:
|
327
|
+
MyTable.value.append(2)
|
328
|
+
|
241
329
|
self.assertEqual(
|
242
330
|
str(manager.exception),
|
243
331
|
"Only Postgres and Cockroach support array appending.",
|
244
332
|
)
|
245
333
|
|
334
|
+
@engines_skip("sqlite")
|
335
|
+
@pytest.mark.cockroach_array_slow
|
336
|
+
def test_replace(self):
|
337
|
+
"""
|
338
|
+
Make sure values can be swapped in the array.
|
339
|
+
|
340
|
+
In CockroachDB <= v22.2.0 we had this error:
|
341
|
+
|
342
|
+
* https://github.com/cockroachdb/cockroach/issues/71908 "could not decorrelate subquery" error under asyncpg
|
343
|
+
|
344
|
+
In newer CockroachDB versions, it runs but is very slow:
|
345
|
+
|
346
|
+
* https://github.com/piccolo-orm/piccolo/issues/1005
|
347
|
+
|
348
|
+
""" # noqa: E501
|
349
|
+
MyTable(value=[1, 1, 1]).save().run_sync()
|
350
|
+
|
351
|
+
MyTable.update(
|
352
|
+
{MyTable.value: MyTable.value.replace(1, 2)}, force=True
|
353
|
+
).run_sync()
|
354
|
+
|
355
|
+
self.assertEqual(
|
356
|
+
MyTable.select(MyTable.value).run_sync(),
|
357
|
+
[{"value": [2, 2, 2]}],
|
358
|
+
)
|
359
|
+
|
360
|
+
@sqlite_only
|
361
|
+
def test_replace_sqlite(self):
|
362
|
+
"""
|
363
|
+
If using SQLite then an exception should be raised currently.
|
364
|
+
"""
|
365
|
+
with self.assertRaises(ValueError) as manager:
|
366
|
+
MyTable.value.replace(1, 2)
|
367
|
+
|
368
|
+
self.assertEqual(
|
369
|
+
str(manager.exception),
|
370
|
+
"Only Postgres and Cockroach support array substitution.",
|
371
|
+
)
|
372
|
+
|
373
|
+
@engines_skip("sqlite")
|
374
|
+
@pytest.mark.cockroach_array_slow
|
375
|
+
def test_remove(self):
|
376
|
+
"""
|
377
|
+
Make sure values can be removed from an array.
|
378
|
+
|
379
|
+
In CockroachDB <= v22.2.0 we had this error:
|
380
|
+
|
381
|
+
* https://github.com/cockroachdb/cockroach/issues/71908 "could not decorrelate subquery" error under asyncpg
|
382
|
+
|
383
|
+
In newer CockroachDB versions, it runs but is very slow:
|
384
|
+
|
385
|
+
* https://github.com/piccolo-orm/piccolo/issues/1005
|
386
|
+
|
387
|
+
""" # noqa: E501
|
388
|
+
MyTable(value=[1, 2, 3]).save().run_sync()
|
389
|
+
|
390
|
+
MyTable.update(
|
391
|
+
{MyTable.value: MyTable.value.remove(2)}, force=True
|
392
|
+
).run_sync()
|
393
|
+
|
394
|
+
self.assertEqual(
|
395
|
+
MyTable.select(MyTable.value).run_sync(),
|
396
|
+
[{"value": [1, 3]}],
|
397
|
+
)
|
398
|
+
|
399
|
+
@sqlite_only
|
400
|
+
def test_remove_sqlite(self):
|
401
|
+
"""
|
402
|
+
If using SQLite then an exception should be raised currently.
|
403
|
+
"""
|
404
|
+
with self.assertRaises(ValueError) as manager:
|
405
|
+
MyTable.value.remove(2)
|
406
|
+
|
407
|
+
self.assertEqual(
|
408
|
+
str(manager.exception),
|
409
|
+
"Only Postgres and Cockroach support array removing.",
|
410
|
+
)
|
411
|
+
|
246
412
|
|
247
413
|
###############################################################################
|
248
414
|
# Date and time arrays
|
tests/columns/test_boolean.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
from typing import Any
|
2
2
|
|
3
3
|
from piccolo.columns.column_types import Boolean
|
4
4
|
from piccolo.table import Table
|
@@ -14,9 +14,7 @@ class TestBoolean(TableTest):
|
|
14
14
|
|
15
15
|
def test_return_type(self) -> None:
|
16
16
|
for value in (True, False, None, ...):
|
17
|
-
kwargs:
|
18
|
-
{} if value is ... else {"boolean": value}
|
19
|
-
)
|
17
|
+
kwargs: dict[str, Any] = {} if value is ... else {"boolean": value}
|
20
18
|
expected = MyTable.boolean.default if value is ... else value
|
21
19
|
|
22
20
|
row = MyTable(**kwargs)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import unittest
|
2
2
|
|
3
|
-
from tests.example_apps.music.tables import Band
|
3
|
+
from tests.example_apps.music.tables import Band, Concert
|
4
4
|
|
5
5
|
|
6
6
|
class TestWhere(unittest.TestCase):
|
@@ -29,6 +29,20 @@ class TestWhere(unittest.TestCase):
|
|
29
29
|
with self.assertRaises(ValueError):
|
30
30
|
Band.name.is_in([])
|
31
31
|
|
32
|
+
def test_is_in_subquery(self):
|
33
|
+
_where = Band.id.is_in(
|
34
|
+
Concert.select(Concert.band_1).where(Concert.band_1 == 1)
|
35
|
+
)
|
36
|
+
sql = _where.__str__()
|
37
|
+
self.assertEqual(
|
38
|
+
sql,
|
39
|
+
'"band"."id" IN (SELECT ALL "concert"."band_1" AS "band_1" FROM "concert" WHERE "concert"."band_1" = 1)', # noqa: E501
|
40
|
+
)
|
41
|
+
|
42
|
+
# a sub select must only return a single column
|
43
|
+
with self.assertRaises(ValueError):
|
44
|
+
Band.id.is_in(Concert.select().where(Concert.band_1 == 1))
|
45
|
+
|
32
46
|
def test_not_in(self):
|
33
47
|
_where = Band.name.not_in(["CSharps"])
|
34
48
|
sql = _where.__str__()
|
@@ -37,6 +51,20 @@ class TestWhere(unittest.TestCase):
|
|
37
51
|
with self.assertRaises(ValueError):
|
38
52
|
Band.name.not_in([])
|
39
53
|
|
54
|
+
def test_not_in_subquery(self):
|
55
|
+
_where = Band.id.not_in(
|
56
|
+
Concert.select(Concert.band_1).where(Concert.band_1 == 1)
|
57
|
+
)
|
58
|
+
sql = _where.__str__()
|
59
|
+
self.assertEqual(
|
60
|
+
sql,
|
61
|
+
'"band"."id" NOT IN (SELECT ALL "concert"."band_1" AS "band_1" FROM "concert" WHERE "concert"."band_1" = 1)', # noqa: E501
|
62
|
+
)
|
63
|
+
|
64
|
+
# a sub select must only return a single column
|
65
|
+
with self.assertRaises(ValueError):
|
66
|
+
Band.id.not_in(Concert.select().where(Concert.band_1 == 1))
|
67
|
+
|
40
68
|
|
41
69
|
class TestAnd(unittest.TestCase):
|
42
70
|
def test_get_column_values(self):
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
from typing import Optional
|
2
2
|
|
3
3
|
from piccolo.columns.column_types import ForeignKey, Integer, Serial, Varchar
|
4
4
|
from piccolo.table import Table, create_db_tables_sync, drop_db_tables_sync
|
@@ -35,7 +35,7 @@ class TestDBColumnName(DBTestCase):
|
|
35
35
|
def tearDown(self):
|
36
36
|
drop_db_tables_sync(Band, Manager)
|
37
37
|
|
38
|
-
def insert_band(self, manager:
|
38
|
+
def insert_band(self, manager: Optional[Manager] = None) -> Band:
|
39
39
|
band = Band(name="Pythonistas", popularity=1000, manager=manager)
|
40
40
|
band.save().run_sync()
|
41
41
|
return band
|
tests/engine/test_extra_nodes.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
from typing import cast
|
2
2
|
from unittest import TestCase
|
3
3
|
from unittest.mock import MagicMock
|
4
4
|
|
@@ -19,7 +19,7 @@ class TestExtraNodes(TestCase):
|
|
19
19
|
test_engine = engine_finder()
|
20
20
|
assert test_engine is not None
|
21
21
|
|
22
|
-
test_engine =
|
22
|
+
test_engine = cast(PostgresEngine, test_engine)
|
23
23
|
|
24
24
|
EXTRA_NODE = MagicMock(spec=PostgresEngine(config=test_engine.config))
|
25
25
|
EXTRA_NODE.run_querystring = AsyncMock(return_value=[])
|
tests/engine/test_pool.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import asyncio
|
2
2
|
import os
|
3
3
|
import tempfile
|
4
|
-
|
4
|
+
from typing import cast
|
5
5
|
from unittest import TestCase
|
6
6
|
from unittest.mock import call, patch
|
7
7
|
|
@@ -14,7 +14,7 @@ from tests.example_apps.music.tables import Manager
|
|
14
14
|
@engines_only("postgres", "cockroach")
|
15
15
|
class TestPool(DBTestCase):
|
16
16
|
async def _create_pool(self) -> None:
|
17
|
-
engine =
|
17
|
+
engine = cast(PostgresEngine, Manager._meta.db)
|
18
18
|
|
19
19
|
await engine.start_connection_pool()
|
20
20
|
assert engine.pool is not None
|
@@ -72,7 +72,7 @@ class TestPool(DBTestCase):
|
|
72
72
|
@engines_only("postgres", "cockroach")
|
73
73
|
class TestPoolProxyMethods(DBTestCase):
|
74
74
|
async def _create_pool(self) -> None:
|
75
|
-
engine =
|
75
|
+
engine = cast(PostgresEngine, Manager._meta.db)
|
76
76
|
|
77
77
|
# Deliberate typo ('nnn'):
|
78
78
|
await engine.start_connnection_pool()
|