piccolo 0.109.0__py3-none-any.whl → 0.111.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/asgi/commands/new.py +2 -3
- piccolo/apps/asgi/commands/templates/app/{_starlite_app.py.jinja → _litestar_app.py.jinja} +8 -8
- piccolo/apps/asgi/commands/templates/app/app.py.jinja +2 -4
- piccolo/apps/asgi/commands/templates/app/home/{_starlite_endpoints.py.jinja → _litestar_endpoints.py.jinja} +2 -1
- piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja +2 -4
- piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw +1 -6
- piccolo/apps/playground/commands/run.py +24 -8
- piccolo/columns/column_types.py +2 -2
- piccolo/query/methods/insert.py +61 -5
- piccolo/query/methods/objects.py +2 -0
- piccolo/query/methods/select.py +23 -10
- piccolo/query/mixins.py +245 -7
- piccolo/testing/model_builder.py +9 -7
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/METADATA +2 -2
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/RECORD +22 -24
- tests/table/test_insert.py +397 -1
- tests/table/test_select.py +160 -1
- piccolo/apps/asgi/commands/templates/app/_xpresso_app.py.jinja +0 -113
- piccolo/apps/asgi/commands/templates/app/home/_xpresso_endpoints.py.jinja +0 -20
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/LICENSE +0 -0
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/WHEEL +0 -0
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/entry_points.txt +0 -0
- {piccolo-0.109.0.dist-info → piccolo-0.111.0.dist-info}/top_level.txt +0 -0
piccolo/testing/model_builder.py
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import json
|
2
4
|
import typing as t
|
3
5
|
from datetime import date, datetime, time, timedelta
|
@@ -5,7 +7,7 @@ from decimal import Decimal
|
|
5
7
|
from uuid import UUID
|
6
8
|
|
7
9
|
from piccolo.columns import Array, Column
|
8
|
-
from piccolo.
|
10
|
+
from piccolo.custom_types import TableInstance
|
9
11
|
from piccolo.testing.random_builder import RandomBuilder
|
10
12
|
from piccolo.utils.sync import run_sync
|
11
13
|
|
@@ -27,11 +29,11 @@ class ModelBuilder:
|
|
27
29
|
@classmethod
|
28
30
|
async def build(
|
29
31
|
cls,
|
30
|
-
table_class: t.Type[
|
32
|
+
table_class: t.Type[TableInstance],
|
31
33
|
defaults: t.Dict[t.Union[Column, str], t.Any] = None,
|
32
34
|
persist: bool = True,
|
33
35
|
minimal: bool = False,
|
34
|
-
) ->
|
36
|
+
) -> TableInstance:
|
35
37
|
"""
|
36
38
|
Build a ``Table`` instance with random data and save async.
|
37
39
|
If the ``Table`` has any foreign keys, then the related rows are also
|
@@ -78,11 +80,11 @@ class ModelBuilder:
|
|
78
80
|
@classmethod
|
79
81
|
def build_sync(
|
80
82
|
cls,
|
81
|
-
table_class: t.Type[
|
83
|
+
table_class: t.Type[TableInstance],
|
82
84
|
defaults: t.Dict[t.Union[Column, str], t.Any] = None,
|
83
85
|
persist: bool = True,
|
84
86
|
minimal: bool = False,
|
85
|
-
) ->
|
87
|
+
) -> TableInstance:
|
86
88
|
"""
|
87
89
|
A sync wrapper around :meth:`build`.
|
88
90
|
"""
|
@@ -98,11 +100,11 @@ class ModelBuilder:
|
|
98
100
|
@classmethod
|
99
101
|
async def _build(
|
100
102
|
cls,
|
101
|
-
table_class: t.Type[
|
103
|
+
table_class: t.Type[TableInstance],
|
102
104
|
defaults: t.Dict[t.Union[Column, str], t.Any] = None,
|
103
105
|
minimal: bool = False,
|
104
106
|
persist: bool = True,
|
105
|
-
) ->
|
107
|
+
) -> TableInstance:
|
106
108
|
model = table_class(_ignore_missing=True)
|
107
109
|
defaults = {} if not defaults else defaults
|
108
110
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: piccolo
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.111.0
|
4
4
|
Summary: A fast, user friendly ORM and query builder which supports asyncio.
|
5
5
|
Home-page: https://github.com/piccolo-orm/piccolo
|
6
6
|
Author: Daniel Townsend
|
@@ -144,7 +144,7 @@ Let Piccolo scaffold you an ASGI web app, using Piccolo as the ORM:
|
|
144
144
|
piccolo asgi new
|
145
145
|
```
|
146
146
|
|
147
|
-
[Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [BlackSheep](https://www.neoteroi.dev/blacksheep/)
|
147
|
+
[Starlette](https://www.starlette.io/), [FastAPI](https://fastapi.tiangolo.com/), [BlackSheep](https://www.neoteroi.dev/blacksheep/) and [Litestar](https://litestar.dev/) are currently supported.
|
148
148
|
|
149
149
|
## Are you a Django user?
|
150
150
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
piccolo/__init__.py,sha256=
|
1
|
+
piccolo/__init__.py,sha256=FD-yuKtGvNyh8GH2WGzOJQnF7v7XuGXevze_b_yuJ4g,24
|
2
2
|
piccolo/custom_types.py,sha256=7HMQAze-5mieNLfbQ5QgbRQgR2abR7ol0qehv2SqROY,604
|
3
3
|
piccolo/main.py,sha256=2W2EXXEr-EN1PG8s8xHIWCvU7t7kT004fBChK9CZhzo,5024
|
4
4
|
piccolo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -16,14 +16,13 @@ piccolo/apps/app/commands/templates/tables.py.jinja,sha256=revzdrvDDwe78VedBKz0z
|
|
16
16
|
piccolo/apps/asgi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
17
17
|
piccolo/apps/asgi/piccolo_app.py,sha256=7VUvqQJbB-ScO0A62S6MiJmQL9F5DS-SdlqlDLbAblE,217
|
18
18
|
piccolo/apps/asgi/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
-
piccolo/apps/asgi/commands/new.py,sha256=
|
19
|
+
piccolo/apps/asgi/commands/new.py,sha256=P64IwftHM3uHkUObl6tVXmBfsTaFon7im6LEgDFwg10,4100
|
20
20
|
piccolo/apps/asgi/commands/templates/app/README.md.jinja,sha256=As3gNEZt9qcRmTVkjCzNtXJ8r4-3g0fCSe7Q-P39ezI,214
|
21
21
|
piccolo/apps/asgi/commands/templates/app/_blacksheep_app.py.jinja,sha256=bgAGe0a9nWk0LAqK3VNDhPcKGqg0z8V-eIX2YmMoZLk,3117
|
22
22
|
piccolo/apps/asgi/commands/templates/app/_fastapi_app.py.jinja,sha256=cCmRVAN8gw6zfHBcLI_NxapwN7LGM5QSXM7K94imDh8,2436
|
23
|
+
piccolo/apps/asgi/commands/templates/app/_litestar_app.py.jinja,sha256=e0784WBJSsrAPmDXjVuYfmrUJWLAkQyDxoSDl80ucWQ,2622
|
23
24
|
piccolo/apps/asgi/commands/templates/app/_starlette_app.py.jinja,sha256=YvNUlJuTd4mj-pm3WQKbQq3w3x3VfDb_Wz6aQLUsORo,1271
|
24
|
-
piccolo/apps/asgi/commands/templates/app/
|
25
|
-
piccolo/apps/asgi/commands/templates/app/_xpresso_app.py.jinja,sha256=D3D3ScpItr0V4InaqBMFwy4BvnSMI2AM_6E6sKmUjJE,2855
|
26
|
-
piccolo/apps/asgi/commands/templates/app/app.py.jinja,sha256=Hsoq3xsCc3yzNFHXV3zRBxrh42J9W04qyVc7FZ7Bg4Y,387
|
25
|
+
piccolo/apps/asgi/commands/templates/app/app.py.jinja,sha256=NnpkkIFswR4SUsOrhB6x2rNrDfR_QOaGewRv_mP5zgQ,314
|
27
26
|
piccolo/apps/asgi/commands/templates/app/conftest.py.jinja,sha256=ZG1pRVMv3LhIfOsO3_08c_fF3EV4_EApuDHiIFFPJdk,497
|
28
27
|
piccolo/apps/asgi/commands/templates/app/main.py.jinja,sha256=azwXyWZGkrIbZv5bZF_4Tvbly7AXkw5yFWGCHYImGeo,421
|
29
28
|
piccolo/apps/asgi/commands/templates/app/piccolo_conf.py.jinja,sha256=f9Nb08_yipi0_mDUYrUvVoGCz7MRRS5QjCdUGBHN760,379
|
@@ -31,15 +30,14 @@ piccolo/apps/asgi/commands/templates/app/piccolo_conf_test.py.jinja,sha256=ZB32I
|
|
31
30
|
piccolo/apps/asgi/commands/templates/app/requirements.txt.jinja,sha256=gR_AvX3YH0bsjkAY28eXNy_D1YuJAvEnT1tGtVzMnnY,152
|
32
31
|
piccolo/apps/asgi/commands/templates/app/home/__init__.py.jinja,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
32
|
piccolo/apps/asgi/commands/templates/app/home/_blacksheep_endpoints.py.jinja,sha256=Rri_xzDkl87G5ME74qTxY25cwKIKufuzgkRsy__mNts,510
|
33
|
+
piccolo/apps/asgi/commands/templates/app/home/_litestar_endpoints.py.jinja,sha256=mk0LTygP-HOaiWYO4SDnJ3C-WZxLxRFYxUrIYwatAyc,531
|
34
34
|
piccolo/apps/asgi/commands/templates/app/home/_starlette_endpoints.py.jinja,sha256=KEjNEUKiZNBIWYAt9EgPHe4yCbkKLtlhaCBce9YI-RQ,498
|
35
|
-
piccolo/apps/asgi/commands/templates/app/home/
|
36
|
-
piccolo/apps/asgi/commands/templates/app/home/_xpresso_endpoints.py.jinja,sha256=JO9SCIL2jDAkoop8zPhdTeUt_oP-Zent2KqIt6NAPy4,402
|
37
|
-
piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja,sha256=dgpHlA8mjmYCnNs5RiToUj3S3u6mZObOVC1VU-jbRCc,351
|
35
|
+
piccolo/apps/asgi/commands/templates/app/home/endpoints.py.jinja,sha256=OeRMBHjjxVyGIXAuSLQzl6qsWOmD7-pZcToA3V5gWx4,272
|
38
36
|
piccolo/apps/asgi/commands/templates/app/home/piccolo_app.py.jinja,sha256=4gETiW9ukTNsomeJOvrRkqPbToZ_FU0b3LsNIaEYyP8,505
|
39
37
|
piccolo/apps/asgi/commands/templates/app/home/tables.py.jinja,sha256=wk34RAsuoFn5iJ4OHlQzUqgatq6QB2G9tFE0BYkaers,197
|
40
38
|
piccolo/apps/asgi/commands/templates/app/home/piccolo_migrations/README.md,sha256=ji6UOtHvzHX-eS_qhhKTN36ZXNZ7QwtjwjdE4Qgm35A,59
|
41
39
|
piccolo/apps/asgi/commands/templates/app/home/templates/base.html.jinja_raw,sha256=3RqiNuyAap_P-xNK3uhNaQQ6rC365VzPmRqmmXSLO8o,451
|
42
|
-
piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw,sha256=
|
40
|
+
piccolo/apps/asgi/commands/templates/app/home/templates/home.html.jinja_raw,sha256=u_oXpGzR3o_eCufFPRpjD6iL1SdiixvrmOOeWp7WF10,2278
|
43
41
|
piccolo/apps/asgi/commands/templates/app/static/favicon.ico,sha256=IvcgeJHObd9kj2mNIXkJdXYxMU8OaOymyYQWnWfbtHo,7406
|
44
42
|
piccolo/apps/asgi/commands/templates/app/static/main.css,sha256=vudarPLglQ6NOgJiNeU2x0yQl0DiWScqb09QZv2wAzM,1056
|
45
43
|
piccolo/apps/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -74,7 +72,7 @@ piccolo/apps/migrations/commands/templates/migration.py.jinja,sha256=wMC8RTIcQj3
|
|
74
72
|
piccolo/apps/playground/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
75
73
|
piccolo/apps/playground/piccolo_app.py,sha256=zs6nGxt-lgUF8nEwI0uDTNZDKQqjZaNDH8le5RqrMNE,222
|
76
74
|
piccolo/apps/playground/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
77
|
-
piccolo/apps/playground/commands/run.py,sha256=
|
75
|
+
piccolo/apps/playground/commands/run.py,sha256=PaY3ls4C0j0TnVSTY85abv6e2SuTsII0H33HlkXlZzc,7350
|
78
76
|
piccolo/apps/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
77
|
piccolo/apps/project/piccolo_app.py,sha256=mT3O0m3QcCfS0oOr3jt0QZ9TX6gUavGPjJeNn2C_fdM,220
|
80
78
|
piccolo/apps/project/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -113,7 +111,7 @@ piccolo/apps/user/piccolo_migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
|
|
113
111
|
piccolo/columns/__init__.py,sha256=OYhO_n9anMiU9nL-K6ATq9FhAtm8RyMpqYQ7fTVbhxI,1120
|
114
112
|
piccolo/columns/base.py,sha256=lD3fzhpHCVlfieME2q9gCiHdpJqKNo2Te67HrjUX2c0,31355
|
115
113
|
piccolo/columns/choices.py,sha256=-HNQuk9vMmVZIPZ5PMeXGTfr23o4nzKPSAkvcG1k0y8,723
|
116
|
-
piccolo/columns/column_types.py,sha256=
|
114
|
+
piccolo/columns/column_types.py,sha256=X0nTvlc8epfcu8Q8uuIBlnHv_R_GTJ58dehC343vNgA,77278
|
117
115
|
piccolo/columns/combination.py,sha256=vMXC2dfY7pvnCFhsT71XFVyb4gdQzfRsCMaiduu04Ss,6900
|
118
116
|
piccolo/columns/indexes.py,sha256=NfNok3v_791jgDlN28KmhP9ZCjl6031BXmjxV3ovXJk,372
|
119
117
|
piccolo/columns/m2m.py,sha256=C7IKMg7ik2yE3143Gwdbx3YNB3VrZbltJAlX0XxQwAI,14067
|
@@ -143,7 +141,7 @@ piccolo/engine/postgres.py,sha256=UvGihQeUgg2MniTN5mABlSMPkBgtQQSmx9QE32uv9SA,18
|
|
143
141
|
piccolo/engine/sqlite.py,sha256=io3fBdXxXjOoSzLgP-HYGKgTDgHIRpmFa7mU6ifbqn8,21915
|
144
142
|
piccolo/query/__init__.py,sha256=WkG78nTz4Ww3rE9Pu5tZI130JMVfGnwyghhu97XFk0w,617
|
145
143
|
piccolo/query/base.py,sha256=BsrzbeuJo7k-KJn4YlRUibxITw_J7xslbgJg0eVFB8s,15124
|
146
|
-
piccolo/query/mixins.py,sha256=
|
144
|
+
piccolo/query/mixins.py,sha256=N6HAN_A4kd-PC07q3OIzwrkRy3ZwGMtB2xLueYefBSM,21649
|
147
145
|
piccolo/query/proxy.py,sha256=Hg5S6tp1EiKD899eYdDKHscFYucHdKtL3YC2GTcL2Jk,1833
|
148
146
|
piccolo/query/methods/__init__.py,sha256=_PfGUdOd6AsKq1sqXeZUHhESHE-e1cNpwFr8Lyz7QoY,421
|
149
147
|
piccolo/query/methods/alter.py,sha256=gyx4kVF4EiN4sSFjIqcKykxcKB808j1ioa2lKrLdP4Y,14935
|
@@ -154,15 +152,15 @@ piccolo/query/methods/delete.py,sha256=JkDMkee3LVKtZdAS2AQnNFkDbxcus3xq7kbDAu6Fk
|
|
154
152
|
piccolo/query/methods/drop_index.py,sha256=SOX5wfm-Tbb5TrN6kaLRVHUWdEhyrmCQwF33JfWdtwE,1043
|
155
153
|
piccolo/query/methods/exists.py,sha256=LAeWpGKEMYZJeNGEcxbucxWDxAjn84jduNz2ZjzukPc,1181
|
156
154
|
piccolo/query/methods/indexes.py,sha256=_Io7vy_yIjPYHIw1ILGhAiWQAEOIe-Lwn3mEELw8mOc,1083
|
157
|
-
piccolo/query/methods/insert.py,sha256=
|
158
|
-
piccolo/query/methods/objects.py,sha256=
|
155
|
+
piccolo/query/methods/insert.py,sha256=BwIJb1g0PFqMws060Wn0uSAK1ybLbkK9mKUfOOmzroc,4716
|
156
|
+
piccolo/query/methods/objects.py,sha256=i71GHPJZJcRpgM6e69Vk7vVcCuAFokOsMnR5EXbZq1w,11673
|
159
157
|
piccolo/query/methods/raw.py,sha256=VhYpCB52mZk4zqFTsqK5CHKTDGskUjISXTBV7UjohmA,600
|
160
158
|
piccolo/query/methods/refresh.py,sha256=P1Eo_HYU_L7kcGM_cvDDgyLi1boCXY7Pc4tv_eDAzvc,2769
|
161
|
-
piccolo/query/methods/select.py,sha256=
|
159
|
+
piccolo/query/methods/select.py,sha256=6LVVNJEIooB0cQItI77rxwURsA88ifTOm1dj-wFlHRY,25406
|
162
160
|
piccolo/query/methods/table_exists.py,sha256=rPY20QNdJI9TvKjGyTPVvGGEuD3bDnQim8K1ZurthmU,1211
|
163
161
|
piccolo/query/methods/update.py,sha256=0hURc7PQU9NX7QQFJ1XgFJvw3nXYIrWUjE-D_7W5JV4,3625
|
164
162
|
piccolo/testing/__init__.py,sha256=pRFSqRInfx95AakOq54atmvqoB-ue073q2aR8u8zR40,83
|
165
|
-
piccolo/testing/model_builder.py,sha256=
|
163
|
+
piccolo/testing/model_builder.py,sha256=_tss3L-n-hwIaygNJ3dVmWvZxXE035h2QdDaLYJhH7c,5734
|
166
164
|
piccolo/testing/random_builder.py,sha256=o3Ebzak1AG_3nG1iIYN2ZNn5NKQTRECha4ZEubAl9yQ,2005
|
167
165
|
piccolo/utils/__init__.py,sha256=SDFFraauI9Op8dCRkreQv1dwUcab8Mi1eC-n0EwlTy8,36
|
168
166
|
piccolo/utils/dictionary.py,sha256=8vRPxgaXadDVhqihP1UxL7nUBgM6Gpe_Eu3xJq7zzGM,1886
|
@@ -305,7 +303,7 @@ tests/table/test_exists.py,sha256=AHvhodkRof7PVd4IDdGQ2nyOj_1Cag1Rpg1H84s4jU0,28
|
|
305
303
|
tests/table/test_from_dict.py,sha256=I4PMxuzgkgi3-adaw9Gr3u5tQHexc31Vrq7RSPcPcJs,840
|
306
304
|
tests/table/test_indexes.py,sha256=GdlPfLmvM0s2fe-4-2XSqQLYYjwsBu5dzf6o7ZvlPj4,1990
|
307
305
|
tests/table/test_inheritance.py,sha256=s5JIo8hZN7xqOPlZ9EDkkNLo5_kWirsfCJAqaXSHn88,3034
|
308
|
-
tests/table/test_insert.py,sha256=
|
306
|
+
tests/table/test_insert.py,sha256=LeYNvApZ2T-PZ9fseINLZ6hnrY5F1Axe3QHqidwzbAQ,13668
|
309
307
|
tests/table/test_join.py,sha256=tk2r5OUaay9-4U37aj2-qul1XybchBG3xr-k7K_IQh0,14705
|
310
308
|
tests/table/test_join_on.py,sha256=NhJRg_7_YQ0o2ox5mF330ZaIvmtq09Xl2lfDTwKtUng,2719
|
311
309
|
tests/table/test_metaclass.py,sha256=liJuKArpco1qb3lshSQTwRsqXXZZNgzmFoMDP9r2uHw,2637
|
@@ -315,7 +313,7 @@ tests/table/test_raw.py,sha256=AxT6qB0bEjVbOz6lmGQ9_IiDuEoVmh5c72gzyiatBwo,1683
|
|
315
313
|
tests/table/test_ref.py,sha256=eYNRnYHzNMXuMbV3B1ca5EidpIg4500q6hr1ccuVaso,269
|
316
314
|
tests/table/test_refresh.py,sha256=tZktBoUQth3S2_vou5NcKiwOJDFrhF6CIuC7YZ2janw,2694
|
317
315
|
tests/table/test_repr.py,sha256=dKdM0HRygvqjmSPz-l95SJQXQ-O18MHUGrcIzzYKrsQ,411
|
318
|
-
tests/table/test_select.py,sha256=
|
316
|
+
tests/table/test_select.py,sha256=sjSzJfHaYG8Zrg2jXbp7eNprqXilMzDHDxpM3k0BCFg,39678
|
319
317
|
tests/table/test_str.py,sha256=eztWNULcjARR1fr9X5n4tojhDNgDfatVyNHwuYrzHAo,1731
|
320
318
|
tests/table/test_table_exists.py,sha256=9Qqwbg6Q3OfasSH4FUqD3z99ExvJqpHSu0pYu7aa998,375
|
321
319
|
tests/table/test_update.py,sha256=ZEkIDgQ9PHcAn58dlN4WIHRJm0RENi6AVDsmgLX9Qlw,20342
|
@@ -342,9 +340,9 @@ tests/utils/test_sql_values.py,sha256=vzxRmy16FfLZPH-sAQexBvsF9MXB8n4smr14qoEOS5
|
|
342
340
|
tests/utils/test_sync.py,sha256=9ytVo56y2vPQePvTeIi9lHIouEhWJbodl1TmzkGFrSo,799
|
343
341
|
tests/utils/test_table_reflection.py,sha256=SIzuat-IpcVj1GCFyOWKShI8YkhdOPPFH7qVrvfyPNE,3794
|
344
342
|
tests/utils/test_warnings.py,sha256=NvSC_cvJ6uZcwAGf1m-hLzETXCqprXELL8zg3TNLVMw,269
|
345
|
-
piccolo-0.
|
346
|
-
piccolo-0.
|
347
|
-
piccolo-0.
|
348
|
-
piccolo-0.
|
349
|
-
piccolo-0.
|
350
|
-
piccolo-0.
|
343
|
+
piccolo-0.111.0.dist-info/LICENSE,sha256=zFIpi-16uIJ420UMIG75NU0JbDBykvrdnXcj5U_EYBI,1059
|
344
|
+
piccolo-0.111.0.dist-info/METADATA,sha256=mtWcL-RTGmGGTTQuSJT8wm_KPoQerNk1MHE_8It-4Mo,5113
|
345
|
+
piccolo-0.111.0.dist-info/WHEEL,sha256=00yskusixUoUt5ob_CiUp6LsnN5lqzTJpoqOFg_FVIc,92
|
346
|
+
piccolo-0.111.0.dist-info/entry_points.txt,sha256=zYhu-YNtMlh2N_8wptCS8YWKOgc81UPL3Ji5gly8ouc,47
|
347
|
+
piccolo-0.111.0.dist-info/top_level.txt,sha256=-SR74VGbk43VoPy1HH-mHm97yoGukLK87HE5kdBW6qM,24
|
348
|
+
piccolo-0.111.0.dist-info/RECORD,,
|
tests/table/test_insert.py
CHANGED
@@ -1,8 +1,22 @@
|
|
1
|
+
import sqlite3
|
2
|
+
from unittest import TestCase
|
3
|
+
|
1
4
|
import pytest
|
2
5
|
|
3
|
-
from
|
6
|
+
from piccolo.columns import Integer, Varchar
|
7
|
+
from piccolo.query.methods.insert import OnConflictAction
|
8
|
+
from piccolo.table import Table
|
9
|
+
from piccolo.utils.lazy_loader import LazyLoader
|
10
|
+
from tests.base import (
|
11
|
+
DBTestCase,
|
12
|
+
engine_version_lt,
|
13
|
+
engines_only,
|
14
|
+
is_running_sqlite,
|
15
|
+
)
|
4
16
|
from tests.example_apps.music.tables import Band, Manager
|
5
17
|
|
18
|
+
asyncpg = LazyLoader("asyncpg", globals(), "asyncpg")
|
19
|
+
|
6
20
|
|
7
21
|
class TestInsert(DBTestCase):
|
8
22
|
def test_insert(self):
|
@@ -76,3 +90,385 @@ class TestInsert(DBTestCase):
|
|
76
90
|
)
|
77
91
|
|
78
92
|
self.assertListEqual(response, [{"manager_name": "Maz"}])
|
93
|
+
|
94
|
+
|
95
|
+
@pytest.mark.skipif(
|
96
|
+
is_running_sqlite() and engine_version_lt(3.24),
|
97
|
+
reason="SQLite version not supported",
|
98
|
+
)
|
99
|
+
class TestOnConflict(TestCase):
|
100
|
+
class Band(Table):
|
101
|
+
name = Varchar(unique=True)
|
102
|
+
popularity = Integer()
|
103
|
+
|
104
|
+
def setUp(self) -> None:
|
105
|
+
Band = self.Band
|
106
|
+
Band.create_table().run_sync()
|
107
|
+
self.band = Band({Band.name: "Pythonistas", Band.popularity: 1000})
|
108
|
+
self.band.save().run_sync()
|
109
|
+
|
110
|
+
def tearDown(self) -> None:
|
111
|
+
Band = self.Band
|
112
|
+
Band.alter().drop_table().run_sync()
|
113
|
+
|
114
|
+
def test_do_update(self):
|
115
|
+
"""
|
116
|
+
Make sure that `DO UPDATE` works.
|
117
|
+
"""
|
118
|
+
Band = self.Band
|
119
|
+
|
120
|
+
new_popularity = self.band.popularity + 1000
|
121
|
+
|
122
|
+
Band.insert(
|
123
|
+
Band(name=self.band.name, popularity=new_popularity)
|
124
|
+
).on_conflict(
|
125
|
+
target=Band.name,
|
126
|
+
action="DO UPDATE",
|
127
|
+
values=[Band.popularity],
|
128
|
+
).run_sync()
|
129
|
+
|
130
|
+
self.assertListEqual(
|
131
|
+
Band.select().run_sync(),
|
132
|
+
[
|
133
|
+
{
|
134
|
+
"id": self.band.id,
|
135
|
+
"name": self.band.name,
|
136
|
+
"popularity": new_popularity, # changed
|
137
|
+
}
|
138
|
+
],
|
139
|
+
)
|
140
|
+
|
141
|
+
def test_do_update_tuple_values(self):
|
142
|
+
"""
|
143
|
+
Make sure we can use tuples in ``values``.
|
144
|
+
"""
|
145
|
+
Band = self.Band
|
146
|
+
|
147
|
+
new_popularity = self.band.popularity + 1000
|
148
|
+
new_name = "Rustaceans"
|
149
|
+
|
150
|
+
Band.insert(
|
151
|
+
Band(
|
152
|
+
id=self.band.id,
|
153
|
+
name=new_name,
|
154
|
+
popularity=new_popularity,
|
155
|
+
)
|
156
|
+
).on_conflict(
|
157
|
+
action="DO UPDATE",
|
158
|
+
target=Band.id,
|
159
|
+
values=[
|
160
|
+
(Band.name, new_name),
|
161
|
+
(Band.popularity, new_popularity + 2000),
|
162
|
+
],
|
163
|
+
).run_sync()
|
164
|
+
|
165
|
+
self.assertListEqual(
|
166
|
+
Band.select().run_sync(),
|
167
|
+
[
|
168
|
+
{
|
169
|
+
"id": self.band.id,
|
170
|
+
"name": new_name,
|
171
|
+
"popularity": new_popularity + 2000,
|
172
|
+
}
|
173
|
+
],
|
174
|
+
)
|
175
|
+
|
176
|
+
def test_do_update_no_values(self):
|
177
|
+
"""
|
178
|
+
Make sure that `DO UPDATE` with no `values` raises an exception.
|
179
|
+
"""
|
180
|
+
Band = self.Band
|
181
|
+
|
182
|
+
new_popularity = self.band.popularity + 1000
|
183
|
+
|
184
|
+
with self.assertRaises(ValueError) as manager:
|
185
|
+
Band.insert(
|
186
|
+
Band(name=self.band.name, popularity=new_popularity)
|
187
|
+
).on_conflict(
|
188
|
+
target=Band.name,
|
189
|
+
action="DO UPDATE",
|
190
|
+
).run_sync()
|
191
|
+
|
192
|
+
self.assertEqual(
|
193
|
+
manager.exception.__str__(),
|
194
|
+
"No values specified for `on conflict`",
|
195
|
+
)
|
196
|
+
|
197
|
+
@engines_only("postgres", "cockroach")
|
198
|
+
def test_target_tuple(self):
|
199
|
+
"""
|
200
|
+
Make sure that a composite unique constraint can be used as a target.
|
201
|
+
|
202
|
+
We only run it on Postgres and Cockroach because we use ALTER TABLE
|
203
|
+
to add a contraint, which SQLite doesn't support.
|
204
|
+
"""
|
205
|
+
Band = self.Band
|
206
|
+
|
207
|
+
# Add a composite unique constraint:
|
208
|
+
Band.raw(
|
209
|
+
"ALTER TABLE band ADD CONSTRAINT id_name_unique UNIQUE (id, name)"
|
210
|
+
).run_sync()
|
211
|
+
|
212
|
+
Band.insert(
|
213
|
+
Band(
|
214
|
+
id=self.band.id,
|
215
|
+
name=self.band.name,
|
216
|
+
popularity=self.band.popularity,
|
217
|
+
)
|
218
|
+
).on_conflict(
|
219
|
+
target=(Band.id, Band.name),
|
220
|
+
action="DO NOTHING",
|
221
|
+
).run_sync()
|
222
|
+
|
223
|
+
@engines_only("postgres", "cockroach")
|
224
|
+
def test_target_string(self):
|
225
|
+
"""
|
226
|
+
Make sure we can explicitly specify the name of target constraint using
|
227
|
+
a string.
|
228
|
+
|
229
|
+
We just test this on Postgres for now, as we have to get the constraint
|
230
|
+
name from the database.
|
231
|
+
"""
|
232
|
+
Band = self.Band
|
233
|
+
|
234
|
+
constraint_name = Band.raw(
|
235
|
+
"""
|
236
|
+
SELECT constraint_name
|
237
|
+
FROM information_schema.constraint_column_usage
|
238
|
+
WHERE column_name = 'name'
|
239
|
+
AND table_name = 'band';
|
240
|
+
"""
|
241
|
+
).run_sync()[0]["constraint_name"]
|
242
|
+
|
243
|
+
query = Band.insert(Band(name=self.band.name)).on_conflict(
|
244
|
+
target=constraint_name,
|
245
|
+
action="DO NOTHING",
|
246
|
+
)
|
247
|
+
self.assertIn(f'ON CONSTRAINT "{constraint_name}"', query.__str__())
|
248
|
+
query.run_sync()
|
249
|
+
|
250
|
+
def test_violate_non_target(self):
|
251
|
+
"""
|
252
|
+
Make sure that if we specify a target constraint, but violate a
|
253
|
+
different constraint, then we still get the error.
|
254
|
+
"""
|
255
|
+
Band = self.Band
|
256
|
+
|
257
|
+
new_popularity = self.band.popularity + 1000
|
258
|
+
|
259
|
+
with self.assertRaises(Exception) as manager:
|
260
|
+
Band.insert(
|
261
|
+
Band(name=self.band.name, popularity=new_popularity)
|
262
|
+
).on_conflict(
|
263
|
+
target=Band.id, # Target the primary key instead.
|
264
|
+
action="DO UPDATE",
|
265
|
+
values=[Band.popularity],
|
266
|
+
).run_sync()
|
267
|
+
|
268
|
+
if self.Band._meta.db.engine_type in ("postgres", "cockroach"):
|
269
|
+
self.assertIsInstance(
|
270
|
+
manager.exception, asyncpg.exceptions.UniqueViolationError
|
271
|
+
)
|
272
|
+
elif self.Band._meta.db.engine_type == "sqlite":
|
273
|
+
self.assertIsInstance(manager.exception, sqlite3.IntegrityError)
|
274
|
+
|
275
|
+
def test_where(self):
|
276
|
+
"""
|
277
|
+
Make sure we can pass in a `where` argument.
|
278
|
+
"""
|
279
|
+
Band = self.Band
|
280
|
+
|
281
|
+
new_popularity = self.band.popularity + 1000
|
282
|
+
|
283
|
+
query = Band.insert(
|
284
|
+
Band(name=self.band.name, popularity=new_popularity)
|
285
|
+
).on_conflict(
|
286
|
+
target=Band.name,
|
287
|
+
action="DO UPDATE",
|
288
|
+
values=[Band.popularity],
|
289
|
+
where=Band.popularity < self.band.popularity,
|
290
|
+
)
|
291
|
+
|
292
|
+
self.assertIn(
|
293
|
+
f'WHERE "band"."popularity" < {self.band.popularity}',
|
294
|
+
query.__str__(),
|
295
|
+
)
|
296
|
+
|
297
|
+
query.run_sync()
|
298
|
+
|
299
|
+
def test_do_nothing_where(self):
|
300
|
+
"""
|
301
|
+
Make sure an error is raised if `where` is used with `DO NOTHING`.
|
302
|
+
"""
|
303
|
+
Band = self.Band
|
304
|
+
|
305
|
+
with self.assertRaises(ValueError) as manager:
|
306
|
+
Band.insert(Band()).on_conflict(
|
307
|
+
action="DO NOTHING",
|
308
|
+
where=Band.popularity < self.band.popularity,
|
309
|
+
)
|
310
|
+
|
311
|
+
self.assertEqual(
|
312
|
+
manager.exception.__str__(),
|
313
|
+
"The `where` option can only be used with DO NOTHING.",
|
314
|
+
)
|
315
|
+
|
316
|
+
def test_do_nothing(self):
|
317
|
+
"""
|
318
|
+
Make sure that `DO NOTHING` works.
|
319
|
+
"""
|
320
|
+
Band = self.Band
|
321
|
+
|
322
|
+
new_popularity = self.band.popularity + 1000
|
323
|
+
|
324
|
+
Band.insert(
|
325
|
+
Band(name="Pythonistas", popularity=new_popularity)
|
326
|
+
).on_conflict(action="DO NOTHING").run_sync()
|
327
|
+
|
328
|
+
self.assertListEqual(
|
329
|
+
Band.select().run_sync(),
|
330
|
+
[
|
331
|
+
{
|
332
|
+
"id": self.band.id,
|
333
|
+
"name": self.band.name,
|
334
|
+
"popularity": self.band.popularity,
|
335
|
+
}
|
336
|
+
],
|
337
|
+
)
|
338
|
+
|
339
|
+
@engines_only("sqlite")
|
340
|
+
def test_multiple_do_update(self):
|
341
|
+
"""
|
342
|
+
Make sure multiple `ON CONFLICT` clauses work for SQLite.
|
343
|
+
"""
|
344
|
+
Band = self.Band
|
345
|
+
|
346
|
+
new_popularity = self.band.popularity + 1000
|
347
|
+
|
348
|
+
# Conflicting with name - should update.
|
349
|
+
Band.insert(
|
350
|
+
Band(name="Pythonistas", popularity=new_popularity)
|
351
|
+
).on_conflict(action="DO NOTHING", target=Band.id).on_conflict(
|
352
|
+
action="DO UPDATE", target=Band.name, values=[Band.popularity]
|
353
|
+
).run_sync()
|
354
|
+
|
355
|
+
self.assertListEqual(
|
356
|
+
Band.select().run_sync(),
|
357
|
+
[
|
358
|
+
{
|
359
|
+
"id": self.band.id,
|
360
|
+
"name": self.band.name,
|
361
|
+
"popularity": new_popularity, # changed
|
362
|
+
}
|
363
|
+
],
|
364
|
+
)
|
365
|
+
|
366
|
+
@engines_only("sqlite")
|
367
|
+
def test_multiple_do_nothing(self):
|
368
|
+
"""
|
369
|
+
Make sure multiple `ON CONFLICT` clauses work for SQLite.
|
370
|
+
"""
|
371
|
+
Band = self.Band
|
372
|
+
|
373
|
+
new_popularity = self.band.popularity + 1000
|
374
|
+
|
375
|
+
# Conflicting with ID - should be ignored.
|
376
|
+
Band.insert(
|
377
|
+
Band(
|
378
|
+
id=self.band.id,
|
379
|
+
name="Pythonistas",
|
380
|
+
popularity=new_popularity,
|
381
|
+
)
|
382
|
+
).on_conflict(action="DO NOTHING", target=Band.id).on_conflict(
|
383
|
+
action="DO UPDATE",
|
384
|
+
target=Band.name,
|
385
|
+
values=[Band.popularity],
|
386
|
+
).run_sync()
|
387
|
+
|
388
|
+
self.assertListEqual(
|
389
|
+
Band.select().run_sync(),
|
390
|
+
[
|
391
|
+
{
|
392
|
+
"id": self.band.id,
|
393
|
+
"name": self.band.name,
|
394
|
+
"popularity": self.band.popularity,
|
395
|
+
}
|
396
|
+
],
|
397
|
+
)
|
398
|
+
|
399
|
+
@engines_only("postgres", "cockroach")
|
400
|
+
def test_mutiple_error(self):
|
401
|
+
"""
|
402
|
+
Postgres and Cockroach don't support multiple `ON CONFLICT` clauses.
|
403
|
+
"""
|
404
|
+
with self.assertRaises(NotImplementedError) as manager:
|
405
|
+
Band = self.Band
|
406
|
+
|
407
|
+
Band.insert(Band()).on_conflict(action="DO NOTHING").on_conflict(
|
408
|
+
action="DO UPDATE",
|
409
|
+
).run_sync()
|
410
|
+
|
411
|
+
assert manager.exception.__str__() == (
|
412
|
+
"Postgres and Cockroach only support a single ON CONFLICT clause."
|
413
|
+
)
|
414
|
+
|
415
|
+
def test_all_columns(self):
|
416
|
+
"""
|
417
|
+
We can use ``all_columns`` instead of specifying the ``values``
|
418
|
+
manually.
|
419
|
+
"""
|
420
|
+
Band = self.Band
|
421
|
+
|
422
|
+
new_popularity = self.band.popularity + 1000
|
423
|
+
new_name = "Rustaceans"
|
424
|
+
|
425
|
+
# Conflicting with ID - should be ignored.
|
426
|
+
q = Band.insert(
|
427
|
+
Band(
|
428
|
+
id=self.band.id,
|
429
|
+
name=new_name,
|
430
|
+
popularity=new_popularity,
|
431
|
+
)
|
432
|
+
).on_conflict(
|
433
|
+
action="DO UPDATE",
|
434
|
+
target=Band.id,
|
435
|
+
values=Band.all_columns(),
|
436
|
+
)
|
437
|
+
q.run_sync()
|
438
|
+
|
439
|
+
self.assertListEqual(
|
440
|
+
Band.select().run_sync(),
|
441
|
+
[
|
442
|
+
{
|
443
|
+
"id": self.band.id,
|
444
|
+
"name": new_name,
|
445
|
+
"popularity": new_popularity,
|
446
|
+
}
|
447
|
+
],
|
448
|
+
)
|
449
|
+
|
450
|
+
def test_enum(self):
|
451
|
+
"""
|
452
|
+
A string literal can be passed in, or an enum, to determine the action.
|
453
|
+
Make sure that the enum works.
|
454
|
+
"""
|
455
|
+
Band = self.Band
|
456
|
+
|
457
|
+
Band.insert(
|
458
|
+
Band(
|
459
|
+
id=self.band.id,
|
460
|
+
name=self.band.name,
|
461
|
+
popularity=self.band.popularity,
|
462
|
+
)
|
463
|
+
).on_conflict(action=OnConflictAction.do_nothing).run_sync()
|
464
|
+
|
465
|
+
self.assertListEqual(
|
466
|
+
Band.select().run_sync(),
|
467
|
+
[
|
468
|
+
{
|
469
|
+
"id": self.band.id,
|
470
|
+
"name": self.band.name,
|
471
|
+
"popularity": self.band.popularity,
|
472
|
+
}
|
473
|
+
],
|
474
|
+
)
|