Skip to content

Commit a9defac

Browse files
authored
1280 UUID 3.14 only (#1364)
* initial prototype * fix docstring * fix test * simplify backport * add basic test * don't run test for cockroachdb * add `UUID7` to api reference * load script for older versions of Postgres / CockroachDB * add tutorial * Update uuid_v7_support.rst * add polyfills * try fixing cockroachdb test * disable uuid7 for cockroachdb for now * update docs * just support python 3.14 * tweaks * fix linter error * add docstring * update `python_version_gte` * Update test_uuid.py * make defaults None so it is possible to use on cockroach and sqlite - just with nullable columns * mention extension for older pg versions * Update index.rst * fix `python_version_gte`
1 parent 3807df2 commit a9defac

File tree

6 files changed

+121
-29
lines changed

6 files changed

+121
-29
lines changed

docs/src/piccolo/api_reference/index.rst

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -111,42 +111,31 @@ UUID
111111
~~~~
112112

113113
.. autoclass:: UUID4
114-
:members:
114+
115+
.. autoclass:: UUID7
115116

116117

117-
TimestampCustom
118-
~~~~~~~~~~~~~~~
118+
Timestamp
119+
~~~~~~~~~
119120

120121
.. autoclass:: TimestampCustom
121122
:members:
122123

123-
TimestampOffset
124-
~~~~~~~~~~~~~~~
125-
126124
.. autoclass:: TimestampOffset
127125
:members:
128126

129-
TimestampNow
130-
~~~~~~~~~~~~
131-
132127
.. autoclass:: TimestampNow
133128
:members:
134129

135-
TimestamptzCustom
136-
~~~~~~~~~~~~~~~~~
130+
Timestamptz
131+
~~~~~~~~~~~
137132

138133
.. autoclass:: TimestamptzCustom
139134
:members:
140135

141-
TimestamptzOffset
142-
~~~~~~~~~~~~~~~~~
143-
144136
.. autoclass:: TimestamptzOffset
145137
:members:
146138

147-
TimestamptzNow
148-
~~~~~~~~~~~~~~
149-
150139
.. autoclass:: TimestamptzNow
151140
:members:
152141

docs/src/piccolo/contributing/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ Make sure the test database exists:
2222
.. code-block:: console
2323
2424
cockroach sql --insecure
25-
>>> create database piccolo
26-
>>> use piccolo
25+
>>> create database piccolo;
26+
>>> use piccolo;
2727
2828
-------------------------------------------------------------------------------
2929

piccolo/columns/defaults/uuid.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from enum import Enum
44
from typing import Union
55

6+
from piccolo.utils.uuid import uuid7
7+
68
from .base import Default
79

810

@@ -17,6 +19,18 @@ class UUID4(Default):
1719

1820
@property
1921
def postgres(self):
22+
"""
23+
Historically we had to use `uuid_generate_v4()` from the `uuid-ossp`
24+
extension.
25+
26+
Since Postgres 13 there is a built-in `gen_random_uuid` function which
27+
generates UUID v4 values.
28+
29+
In Postgres 18, `uuidv4` was added, which is the same as
30+
`gen_random_uuid`, but more precisely named. We will move to this at
31+
some point in the future.
32+
33+
"""
2034
return "gen_random_uuid()"
2135

2236
@property
@@ -25,13 +39,55 @@ def cockroach(self):
2539

2640
@property
2741
def sqlite(self):
28-
return "''"
42+
return None
2943

3044
def python(self):
3145
return uuid.uuid4()
3246

3347

34-
UUIDArg = Union[UUID4, uuid.UUID, str, Enum, None, Callable[[], uuid.UUID]]
48+
class UUID7(Default):
49+
"""
50+
This makes the default value for a
51+
:class:`UUID <piccolo.columns.column_types.UUID>` column a randomly
52+
generated UUID v7 value. Postgres >= 18 and Python >= 3.14 only. UUID7 can
53+
be more efficiently indexed than UUID, and inserts can be faster.
54+
55+
For this to work in older versions of Postgres, register an extension such
56+
as `pg_uuidv7 <https://github.com/fboulnois/pg_uuidv7>`_.
57+
58+
""" # noqa: E501
59+
60+
@property
61+
def postgres(self):
62+
"""
63+
Supported in Postgres 18 and above.
64+
"""
65+
return "uuidv7()"
66+
67+
@property
68+
def cockroach(self):
69+
"""
70+
CockroachDB doesn't currently have a uuidv7 function.
71+
"""
72+
return None
73+
74+
@property
75+
def sqlite(self):
76+
return None
77+
78+
def python(self):
79+
return uuid7()
80+
81+
82+
UUIDArg = Union[
83+
UUID4,
84+
UUID7,
85+
uuid.UUID,
86+
str,
87+
Enum,
88+
None,
89+
Callable[[], uuid.UUID],
90+
]
3591

3692

37-
__all__ = ["UUIDArg", "UUID4"]
93+
__all__ = ["UUIDArg", "UUID4", "UUID7"]

piccolo/utils/uuid.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
def uuid7():
2+
from uuid import uuid7 as _uuid7
3+
4+
return _uuid7()

tests/base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import asyncio
4+
import decimal
45
import sys
56
from typing import Optional
67
from unittest import TestCase
@@ -28,6 +29,17 @@ def engine_version_lt(version: float) -> bool:
2829
return ENGINE is not None and run_sync(ENGINE.get_version()) < version
2930

3031

32+
def engine_version_gte(version: float) -> bool:
33+
return ENGINE is not None and run_sync(ENGINE.get_version()) > version
34+
35+
36+
def python_version_gte(version: decimal.Decimal) -> bool:
37+
return (
38+
decimal.Decimal(f"{sys.version_info.major}.{sys.version_info.minor}")
39+
>= version
40+
)
41+
42+
3143
def is_running_postgres() -> bool:
3244
return type(ENGINE) is PostgresEngine
3345

tests/columns/test_uuid.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
1+
import decimal
12
import uuid
23

4+
import pytest
5+
36
from piccolo.columns.column_types import UUID
7+
from piccolo.columns.defaults.uuid import UUID7
48
from piccolo.table import Table
5-
from piccolo.testing.test_case import TableTest
9+
from piccolo.testing.test_case import AsyncTableTest
10+
from tests.base import (
11+
engine_version_gte,
12+
is_running_postgres,
13+
python_version_gte,
14+
)
615

716

8-
class MyTable(Table):
17+
class UUIDTable(Table):
918
uuid = UUID()
1019

1120

12-
class TestUUID(TableTest):
13-
tables = [MyTable]
21+
class TestUUID(AsyncTableTest):
22+
tables = [UUIDTable]
1423

15-
def test_return_type(self):
16-
row = MyTable()
17-
row.save().run_sync()
24+
async def test_return_type(self):
25+
row = UUIDTable()
26+
await row.save()
1827

1928
self.assertIsInstance(row.uuid, uuid.UUID)
29+
30+
31+
class UUID7Table(Table):
32+
uuid_7 = UUID(default=UUID7())
33+
34+
35+
@pytest.mark.skipif(
36+
not (
37+
python_version_gte(decimal.Decimal("3.14"))
38+
and is_running_postgres()
39+
and engine_version_gte(18)
40+
),
41+
reason="Only Python >= 3.14 and Postgres >= 18 are supported.",
42+
)
43+
class TestUUID7(AsyncTableTest):
44+
tables = [UUID7Table]
45+
46+
async def test_return_type(self):
47+
row = UUID7Table()
48+
await row.save()
49+
50+
self.assertIsInstance(row.uuid_7, uuid.UUID)

0 commit comments

Comments
 (0)