This repository has been archived by the owner on Nov 4, 2024. It is now read-only.
generated from tophat/new-project-kit
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
226 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
version: '3.6' | ||
services: | ||
postgres: | ||
image: postgres:13 | ||
environment: | ||
POSTGRES_USER: DEV_USER | ||
POSTGRES_PASSWORD: DEV_PASSWORD | ||
networks: | ||
- local | ||
ports: | ||
- 5432:5432 | ||
|
||
networks: | ||
local: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .fields import PostgresUUID # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .uuid import PostgresUUID # noqa: F401 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import uuid | ||
from typing import ( | ||
Any, | ||
Optional, | ||
) | ||
|
||
import ormar | ||
from sqlalchemy.dialects import postgresql | ||
from sqlalchemy.engine.default import DefaultDialect | ||
from sqlalchemy.types import TypeDecorator | ||
|
||
|
||
class PostgresUUIDTypeDecorator(TypeDecorator): | ||
""" | ||
Postgres specific GUID type for user with Ormar | ||
""" | ||
|
||
impl = postgresql.UUID | ||
|
||
def process_literal_param( | ||
self, value: Optional[uuid.UUID], dialect: DefaultDialect | ||
) -> Optional[str]: | ||
# Literal parameters for PG UUID values need to be quoted inside | ||
# of single quotes | ||
return f"'{value}'" if value is not None else None | ||
|
||
def process_bind_param( | ||
self, value: Optional[uuid.UUID], dialect: DefaultDialect | ||
) -> Optional[str]: | ||
return str(value) if value is not None else None | ||
|
||
def process_result_value( | ||
self, value: Optional[str], dialect: DefaultDialect | ||
) -> Optional[uuid.UUID]: | ||
if value is None: | ||
return value | ||
if not isinstance(value, uuid.UUID): | ||
return uuid.UUID(value) | ||
return value | ||
|
||
|
||
class PostgresUUID(ormar.UUID): | ||
""" | ||
Custom UUID field for the schema that uses a native PG UUID type | ||
""" | ||
|
||
@classmethod | ||
def get_column_type(cls, **kwargs: Any) -> PostgresUUIDTypeDecorator: | ||
# Tell Ormar that this column should be a postgres UUID type | ||
return PostgresUUIDTypeDecorator() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import pytest | ||
import sqlalchemy | ||
|
||
from .database import ( | ||
DATABASE_URL, | ||
DB_NAME, | ||
database, | ||
metadata, | ||
) | ||
|
||
|
||
@pytest.fixture() | ||
def root_engine(): | ||
root_engine = sqlalchemy.create_engine( | ||
str(DATABASE_URL.replace(database="postgres")), isolation_level="AUTOCOMMIT" | ||
) | ||
return root_engine | ||
|
||
|
||
@pytest.fixture() | ||
def test_database(root_engine): | ||
with root_engine.connect() as conn: | ||
print(f"Creating test database '{DB_NAME}'") | ||
conn.execute(f'DROP DATABASE IF EXISTS "{DB_NAME}";') | ||
conn.execute(f'CREATE DATABASE "{DB_NAME}"') | ||
|
||
yield | ||
|
||
with root_engine.connect() as conn: | ||
root_engine.execute(f'DROP DATABASE "{DB_NAME}"') | ||
|
||
|
||
@pytest.fixture() | ||
async def db(test_database): | ||
# Ensure the DB has the schema we need for testing | ||
engine = sqlalchemy.create_engine(str(DATABASE_URL)) | ||
metadata.create_all(engine) | ||
engine.dispose() | ||
|
||
await database.connect() | ||
yield | ||
await database.disconnect() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import databases | ||
import sqlalchemy | ||
|
||
DB_HOST = "localhost" | ||
DB_NAME = "TEST_DATABASE" | ||
DATABASE_URL = databases.DatabaseURL( | ||
f"postgres://DEV_USER:DEV_PASSWORD@{DB_HOST}:5432/{DB_NAME}" | ||
) | ||
database = databases.Database(str(DATABASE_URL)) | ||
metadata = sqlalchemy.MetaData() |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
from typing import Optional | ||
from uuid import ( | ||
UUID, | ||
uuid4, | ||
) | ||
|
||
import ormar | ||
import pytest | ||
|
||
from ormar_postgres_extensions.fields import PostgresUUID | ||
from tests.database import ( | ||
database, | ||
metadata, | ||
) | ||
|
||
|
||
class UUIDTestModel(ormar.Model): | ||
class Meta: | ||
database = database | ||
metadata = metadata | ||
|
||
id: int = ormar.Integer(primary_key=True) | ||
uid: UUID = PostgresUUID(default=uuid4) | ||
|
||
|
||
class NullableUUIDTestModel(ormar.Model): | ||
class Meta: | ||
database = database | ||
metadata = metadata | ||
|
||
id: int = ormar.Integer(primary_key=True) | ||
uid: Optional[UUID] = PostgresUUID(nullable=True) | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_create_model_with_uuid_specified(db): | ||
created = await UUIDTestModel(uid="2b077a49-0dbe-4dd1-88a1-9aebe3cb7653").save() | ||
assert str(created.uid) == "2b077a49-0dbe-4dd1-88a1-9aebe3cb7653" | ||
assert isinstance(created.uid, UUID) | ||
|
||
# Confirm the model got saved to the DB by querying it back | ||
found = await UUIDTestModel.objects.get() | ||
assert found.uid == created.uid | ||
assert isinstance(found.uid, UUID) | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_get_model_by_uuid(db): | ||
created = await UUIDTestModel(uid="2b077a49-0dbe-4dd1-88a1-9aebe3cb7653").save() | ||
|
||
found = await UUIDTestModel.objects.filter( | ||
uid="2b077a49-0dbe-4dd1-88a1-9aebe3cb7653" | ||
).all() | ||
assert len(found) == 1 | ||
assert found[0] == created | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_create_model_with_nullable_uuid(db): | ||
created = await NullableUUIDTestModel().save() | ||
assert created.uid is None | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_get_model_with_nullable_uuid(db): | ||
created = await NullableUUIDTestModel().save() | ||
|
||
# Ensure querying a model with a null UUID works | ||
found = await NullableUUIDTestModel.objects.get() | ||
assert found == created |