split tests into packages

This commit is contained in:
collerek
2021-03-30 12:48:39 +02:00
parent f0023773e3
commit da05e5ba1d
85 changed files with 5 additions and 4 deletions

View File

View File

@ -0,0 +1,177 @@
from typing import Optional
import databases
import pytest
import sqlalchemy
import ormar
from ormar.exceptions import QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class BaseMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Author(ormar.Model):
class Meta(BaseMeta):
tablename = "authors"
order_by = ["-name"]
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Book(ormar.Model):
class Meta(BaseMeta):
tablename = "books"
order_by = ["year", "-ranking"]
id: int = ormar.Integer(primary_key=True)
author: Optional[Author] = ormar.ForeignKey(Author)
title: str = ormar.String(max_length=100)
year: int = ormar.Integer(nullable=True)
ranking: int = ormar.Integer(nullable=True)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.fixture(autouse=True, scope="function")
async def cleanup():
yield
async with database:
await Book.objects.delete(each=True)
await Author.objects.delete(each=True)
async def sample_data():
author = await Author(name="Author 1").save()
await Book(title="Book 1", year=1920, ranking=3, author=author).save()
await Book(title="Book 2", year=1930, ranking=1, author=author).save()
await Book(title="Book 3", year=1923, ranking=5, author=author).save()
@pytest.mark.asyncio
async def test_min_method():
async with database:
await sample_data()
assert await Book.objects.min("year") == 1920
result = await Book.objects.min(["year", "ranking"])
assert result == dict(year=1920, ranking=1)
assert await Book.objects.min("title") == "Book 1"
assert await Author.objects.select_related("books").min("books__year") == 1920
result = await Author.objects.select_related("books").min(
["books__year", "books__ranking"]
)
assert result == dict(books__year=1920, books__ranking=1)
assert (
await Author.objects.select_related("books")
.filter(books__year__gt=1925)
.min("books__year")
== 1930
)
@pytest.mark.asyncio
async def test_max_method():
async with database:
await sample_data()
assert await Book.objects.max("year") == 1930
result = await Book.objects.max(["year", "ranking"])
assert result == dict(year=1930, ranking=5)
assert await Book.objects.max("title") == "Book 3"
assert await Author.objects.select_related("books").max("books__year") == 1930
result = await Author.objects.select_related("books").max(
["books__year", "books__ranking"]
)
assert result == dict(books__year=1930, books__ranking=5)
assert (
await Author.objects.select_related("books")
.filter(books__year__lt=1925)
.max("books__year")
== 1923
)
@pytest.mark.asyncio
async def test_sum_method():
async with database:
await sample_data()
assert await Book.objects.sum("year") == 5773
result = await Book.objects.sum(["year", "ranking"])
assert result == dict(year=5773, ranking=9)
with pytest.raises(QueryDefinitionError):
await Book.objects.sum("title")
assert await Author.objects.select_related("books").sum("books__year") == 5773
result = await Author.objects.select_related("books").sum(
["books__year", "books__ranking"]
)
assert result == dict(books__year=5773, books__ranking=9)
assert (
await Author.objects.select_related("books")
.filter(books__year__lt=1925)
.sum("books__year")
== 3843
)
@pytest.mark.asyncio
async def test_avg_method():
async with database:
await sample_data()
assert round(float(await Book.objects.avg("year")), 2) == 1924.33
result = await Book.objects.avg(["year", "ranking"])
assert round(float(result.get("year")), 2) == 1924.33
assert result.get("ranking") == 3.0
with pytest.raises(QueryDefinitionError):
await Book.objects.avg("title")
result = await Author.objects.select_related("books").avg("books__year")
assert round(float(result), 2) == 1924.33
result = await Author.objects.select_related("books").avg(
["books__year", "books__ranking"]
)
assert round(float(result.get("books__year")), 2) == 1924.33
assert result.get("books__ranking") == 3.0
assert (
await Author.objects.select_related("books")
.filter(books__year__lt=1925)
.avg("books__year")
== 1921.5
)
@pytest.mark.asyncio
async def test_queryset_method():
async with database:
await sample_data()
author = await Author.objects.select_related("books").get()
assert await author.books.min("year") == 1920
assert await author.books.max("year") == 1930
assert await author.books.sum("ranking") == 9
assert await author.books.avg("ranking") == 3.0
assert await author.books.max(["year", "title"]) == dict(
year=1930, title="Book 3"
)

View File

@ -0,0 +1,158 @@
import databases
import pytest
from sqlalchemy import func
import ormar
import sqlalchemy
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Chart(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "charts"
database = database
metadata = metadata
chart_id = ormar.Integer(primary_key=True, autoincrement=True)
name = ormar.String(max_length=200, unique=True, index=True)
query_text = ormar.Text()
datasets = ormar.JSON()
layout = ormar.JSON()
data_config = ormar.JSON()
created_date = ormar.DateTime(server_default=func.now())
library = ormar.String(max_length=200, default="plotly")
used_filters = ormar.JSON()
class Report(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "reports"
database = database
metadata = metadata
report_id = ormar.Integer(primary_key=True, autoincrement=True)
name = ormar.String(max_length=200, unique=True, index=True)
filters_position = ormar.String(max_length=200)
created_date = ormar.DateTime(server_default=func.now())
class Language(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "languages"
database = database
metadata = metadata
language_id = ormar.Integer(primary_key=True, autoincrement=True)
code = ormar.String(max_length=5)
name = ormar.String(max_length=200)
class TranslationNode(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "translation_nodes"
database = database
metadata = metadata
node_id = ormar.Integer(primary_key=True, autoincrement=True)
node_type = ormar.String(max_length=200)
class Translation(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "translations"
database = database
metadata = metadata
translation_id = ormar.Integer(primary_key=True, autoincrement=True)
node_id = ormar.ForeignKey(TranslationNode, related_name="translations")
language = ormar.ForeignKey(Language, name="language_id")
value = ormar.String(max_length=500)
class Filter(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "filters"
database = database
metadata = metadata
filter_id = ormar.Integer(primary_key=True, autoincrement=True)
name = ormar.String(max_length=200, unique=True, index=True)
label = ormar.String(max_length=200)
query_text = ormar.Text()
allow_multiselect = ormar.Boolean(default=True)
created_date = ormar.DateTime(server_default=func.now())
is_dynamic = ormar.Boolean(default=True)
is_date = ormar.Boolean(default=False)
translation = ormar.ForeignKey(TranslationNode, name="translation_node_id")
class FilterValue(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "filter_values"
database = database
metadata = metadata
value_id = ormar.Integer(primary_key=True, autoincrement=True)
value = ormar.String(max_length=300)
label = ormar.String(max_length=300)
filter = ormar.ForeignKey(Filter, name="filter_id", related_name="values")
translation = ormar.ForeignKey(TranslationNode, name="translation_node_id")
class FilterXReport(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "filters_x_reports"
database = database
metadata = metadata
filter_x_report_id = ormar.Integer(primary_key=True)
filter = ormar.ForeignKey(Filter, name="filter_id", related_name="reports")
report = ormar.ForeignKey(Report, name="report_id", related_name="filters")
sort_order = ormar.Integer()
default_value = ormar.Text()
is_visible = ormar.Boolean()
class ChartXReport(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "charts_x_reports"
database = database
metadata = metadata
chart_x_report_id = ormar.Integer(primary_key=True)
chart = ormar.ForeignKey(Chart, name="chart_id", related_name="reports")
report = ormar.ForeignKey(Report, name="report_id", related_name="charts")
sort_order = ormar.Integer()
width = ormar.Integer()
class ChartColumn(ormar.Model):
class Meta(ormar.ModelMeta):
tablename = "charts_columns"
database = database
metadata = metadata
column_id = ormar.Integer(primary_key=True, autoincrement=True)
chart = ormar.ForeignKey(Chart, name="chart_id", related_name="columns")
column_name = ormar.String(max_length=200)
column_type = ormar.String(max_length=200)
translation = ormar.ForeignKey(TranslationNode, name="translation_node_id")
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_saving_related_fk_rel():
async with database:
async with database.transaction(force_rollback=True):
await Report.objects.select_all(follow=True).all()

View File

@ -0,0 +1,141 @@
from typing import Optional
import databases
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class BaseMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Author(ormar.Model):
class Meta(BaseMeta):
tablename = "authors"
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Book(ormar.Model):
class Meta(BaseMeta):
tablename = "books"
id: int = ormar.Integer(primary_key=True)
author: Optional[Author] = ormar.ForeignKey(Author)
title: str = ormar.String(max_length=100)
year: int = ormar.Integer(nullable=True)
def test_or_group():
result = ormar.or_(name="aa", books__title="bb")
result.resolve(model_cls=Author)
assert len(result.actions) == 2
assert result.actions[0].target_model == Author
assert result.actions[1].target_model == Book
assert (
str(result.get_text_clause()) == f"( authors.name = 'aa' OR "
f"{result.actions[1].table_prefix}"
f"_books.title = 'bb' )"
)
def test_and_group():
result = ormar.and_(name="aa", books__title="bb")
result.resolve(model_cls=Author)
assert len(result.actions) == 2
assert result.actions[0].target_model == Author
assert result.actions[1].target_model == Book
assert (
str(result.get_text_clause()) == f"( authors.name = 'aa' AND "
f"{result.actions[1].table_prefix}"
f"_books.title = 'bb' )"
)
def test_nested_and():
result = ormar.and_(
ormar.or_(name="aa", books__title="bb"), ormar.or_(name="cc", books__title="dd")
)
result.resolve(model_cls=Author)
assert len(result.actions) == 0
assert len(result._nested_groups) == 2
book_prefix = result._nested_groups[0].actions[1].table_prefix
assert (
str(result.get_text_clause()) == f"( ( authors.name = 'aa' OR "
f"{book_prefix}"
f"_books.title = 'bb' ) AND "
f"( authors.name = 'cc' OR "
f"{book_prefix}"
f"_books.title = 'dd' ) )"
)
def test_nested_group_and_action():
result = ormar.and_(ormar.or_(name="aa", books__title="bb"), books__title="dd")
result.resolve(model_cls=Author)
assert len(result.actions) == 1
assert len(result._nested_groups) == 1
book_prefix = result._nested_groups[0].actions[1].table_prefix
assert (
str(result.get_text_clause()) == f"( ( authors.name = 'aa' OR "
f"{book_prefix}"
f"_books.title = 'bb' ) AND "
f"{book_prefix}"
f"_books.title = 'dd' )"
)
def test_deeply_nested_or():
result = ormar.or_(
ormar.and_(
ormar.or_(name="aa", books__title="bb"),
ormar.or_(name="cc", books__title="dd"),
),
ormar.and_(
ormar.or_(books__year__lt=1900, books__title="11"),
ormar.or_(books__year__gt="xx", books__title="22"),
),
)
result.resolve(model_cls=Author)
assert len(result.actions) == 0
assert len(result._nested_groups) == 2
assert len(result._nested_groups[0]._nested_groups) == 2
book_prefix = result._nested_groups[0]._nested_groups[0].actions[1].table_prefix
result_qry = str(result.get_text_clause())
expected_qry = (
f"( ( ( authors.name = 'aa' OR {book_prefix}_books.title = 'bb' ) AND "
f"( authors.name = 'cc' OR {book_prefix}_books.title = 'dd' ) ) "
f"OR ( ( {book_prefix}_books.year < 1900 OR {book_prefix}_books.title = '11' ) AND "
f"( {book_prefix}_books.year > 'xx' OR {book_prefix}_books.title = '22' ) ) )"
)
assert result_qry.replace("\n", "") == expected_qry.replace("\n", "")
def test_one_model_group():
result = ormar.and_(year__gt=1900, title="bb")
result.resolve(model_cls=Book)
assert len(result.actions) == 2
assert len(result._nested_groups) == 0
def test_one_model_nested_group():
result = ormar.and_(
ormar.or_(year__gt=1900, title="bb"), ormar.or_(year__lt=1800, title="aa")
)
result.resolve(model_cls=Book)
assert len(result.actions) == 0
assert len(result._nested_groups) == 2
def test_one_model_with_group():
result = ormar.or_(ormar.and_(year__gt=1900, title="bb"), title="uu")
result.resolve(model_cls=Book)
assert len(result.actions) == 1
assert len(result._nested_groups) == 1

View File

@ -0,0 +1,76 @@
from typing import Optional
import databases
import pytest
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class BaseMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Author(ormar.Model):
class Meta(BaseMeta):
tablename = "authors"
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Book(ormar.Model):
class Meta(BaseMeta):
tablename = "books"
id: int = ormar.Integer(primary_key=True)
author: Optional[Author] = ormar.ForeignKey(Author)
title: str = ormar.String(max_length=100)
year: int = ormar.Integer(nullable=True)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_is_null():
async with database:
tolkien = await Author.objects.create(name="J.R.R. Tolkien")
await Book.objects.create(author=tolkien, title="The Hobbit")
await Book.objects.create(
author=tolkien, title="The Lord of the Rings", year=1955
)
await Book.objects.create(author=tolkien, title="The Silmarillion", year=1977)
books = await Book.objects.all(year__isnull=True)
assert len(books) == 1
assert books[0].year is None
assert books[0].title == "The Hobbit"
books = await Book.objects.all(year__isnull=False)
assert len(books) == 2
tolkien = await Author.objects.select_related("books").get(
books__year__isnull=True
)
assert len(tolkien.books) == 1
assert tolkien.books[0].year is None
assert tolkien.books[0].title == "The Hobbit"
tolkien = await Author.objects.select_related("books").get(
books__year__isnull=False
)
assert len(tolkien.books) == 2
assert tolkien.books[0].year == 1955
assert tolkien.books[0].title == "The Lord of the Rings"

View File

@ -0,0 +1,238 @@
from typing import Optional
import databases
import pytest
import sqlalchemy
import ormar
from ormar.exceptions import QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class BaseMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Author(ormar.Model):
class Meta(BaseMeta):
tablename = "authors"
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Book(ormar.Model):
class Meta(BaseMeta):
tablename = "books"
id: int = ormar.Integer(primary_key=True)
author: Optional[Author] = ormar.ForeignKey(Author)
title: str = ormar.String(max_length=100)
year: int = ormar.Integer(nullable=True)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_or_filters():
async with database:
tolkien = await Author(name="J.R.R. Tolkien").save()
await Book(author=tolkien, title="The Hobbit", year=1933).save()
await Book(author=tolkien, title="The Lord of the Rings", year=1955).save()
await Book(author=tolkien, title="The Silmarillion", year=1977).save()
sapkowski = await Author(name="Andrzej Sapkowski").save()
await Book(author=sapkowski, title="The Witcher", year=1990).save()
await Book(author=sapkowski, title="The Tower of Fools", year=2002).save()
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(author__name="J.R.R. Tolkien", year__gt=1970))
.all()
)
assert len(books) == 5
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(author__name="J.R.R. Tolkien", year__lt=1995))
.all()
)
assert len(books) == 4
assert not any([x.title == "The Tower of Fools" for x in books])
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(year__gt=1960, year__lt=1940))
.filter(author__name="J.R.R. Tolkien")
.all()
)
assert len(books) == 2
assert books[0].title == "The Hobbit"
assert books[1].title == "The Silmarillion"
books = (
await Book.objects.select_related("author")
.filter(
ormar.and_(
ormar.or_(year__gt=1960, year__lt=1940),
author__name="J.R.R. Tolkien",
)
)
.all()
)
assert len(books) == 2
assert books[0].title == "The Hobbit"
assert books[1].title == "The Silmarillion"
books = (
await Book.objects.select_related("author")
.filter(
ormar.or_(
ormar.and_(year__gt=1960, author__name="J.R.R. Tolkien"),
ormar.and_(year__lt=2000, author__name="Andrzej Sapkowski"),
)
)
.filter(title__startswith="The")
.all()
)
assert len(books) == 2
assert books[0].title == "The Silmarillion"
assert books[1].title == "The Witcher"
books = (
await Book.objects.select_related("author")
.filter(
ormar.or_(
ormar.and_(
ormar.or_(year__gt=1960, year__lt=1940),
author__name="J.R.R. Tolkien",
),
ormar.and_(year__lt=2000, author__name="Andrzej Sapkowski"),
)
)
.all()
)
assert len(books) == 3
assert books[0].title == "The Hobbit"
assert books[1].title == "The Silmarillion"
assert books[2].title == "The Witcher"
books = (
await Book.objects.select_related("author")
.exclude(
ormar.or_(
ormar.and_(year__gt=1960, author__name="J.R.R. Tolkien"),
ormar.and_(year__lt=2000, author__name="Andrzej Sapkowski"),
)
)
.filter(title__startswith="The")
.all()
)
assert len(books) == 3
assert not any([x.title in ["The Silmarillion", "The Witcher"] for x in books])
books = (
await Book.objects.select_related("author")
.filter(
ormar.or_(
ormar.and_(year__gt=1960, author__name="J.R.R. Tolkien"),
ormar.and_(year__lt=2000, author__name="Andrzej Sapkowski"),
title__icontains="hobbit",
)
)
.filter(title__startswith="The")
.all()
)
assert len(books) == 3
assert not any(
[x.title in ["The Tower of Fools", "The Lord of the Rings"] for x in books]
)
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(year__gt=1980, year__lt=1910))
.filter(title__startswith="The")
.limit(1)
.all()
)
assert len(books) == 1
assert books[0].title == "The Witcher"
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(year__gt=1980, author__name="Andrzej Sapkowski"))
.filter(title__startswith="The")
.limit(1)
.all()
)
assert len(books) == 1
assert books[0].title == "The Witcher"
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(year__gt=1980, author__name="Andrzej Sapkowski"))
.filter(title__startswith="The")
.limit(1)
.offset(1)
.all()
)
assert len(books) == 1
assert books[0].title == "The Tower of Fools"
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(year__gt=1980, author__name="Andrzej Sapkowski"))
.filter(title__startswith="The")
.limit(1)
.offset(1)
.order_by("-id")
.all()
)
assert len(books) == 1
assert books[0].title == "The Witcher"
with pytest.raises(QueryDefinitionError):
await Book.objects.select_related("author").filter("wrong").all()
books = await tolkien.books.filter(
ormar.or_(year__lt=1940, year__gt=1960)
).all()
assert len(books) == 2
books = await tolkien.books.filter(
ormar.and_(
ormar.or_(year__lt=1940, year__gt=1960), title__icontains="hobbit"
)
).all()
assert len(books) == 1
assert tolkien.books[0].title == "The Hobbit"
books = (
await Book.objects.select_related("author")
.filter(ormar.or_(author__name="J.R.R. Tolkien"))
.all()
)
assert len(books) == 3
books = (
await Book.objects.select_related("author")
.filter(
ormar.or_(
ormar.and_(author__name__icontains="tolkien"),
ormar.and_(author__name__icontains="sapkowski"),
)
)
.all()
)
assert len(books) == 5

View File

@ -0,0 +1,345 @@
from typing import List, Optional
import databases
import pytest
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Song(ormar.Model):
class Meta:
tablename = "songs"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
sort_order: int = ormar.Integer()
class Owner(ormar.Model):
class Meta:
tablename = "owners"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class AliasNested(ormar.Model):
class Meta:
tablename = "aliases_nested"
metadata = metadata
database = database
id: int = ormar.Integer(name="alias_id", primary_key=True)
name: str = ormar.String(name="alias_name", max_length=100)
class AliasTest(ormar.Model):
class Meta:
tablename = "aliases"
metadata = metadata
database = database
id: int = ormar.Integer(name="alias_id", primary_key=True)
name: str = ormar.String(name="alias_name", max_length=100)
nested = ormar.ForeignKey(AliasNested, name="nested_alias")
class Toy(ormar.Model):
class Meta:
tablename = "toys"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
owner: Owner = ormar.ForeignKey(Owner)
class Factory(ormar.Model):
class Meta:
tablename = "factories"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Car(ormar.Model):
class Meta:
tablename = "cars"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
factory: Optional[Factory] = ormar.ForeignKey(Factory)
class User(ormar.Model):
class Meta:
tablename = "users"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
cars: List[Car] = ormar.ManyToMany(Car)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_sort_order_on_main_model():
async with database:
await Song.objects.create(name="Song 3", sort_order=3)
await Song.objects.create(name="Song 1", sort_order=1)
await Song.objects.create(name="Song 2", sort_order=2)
songs = await Song.objects.all()
assert songs[0].name == "Song 3"
assert songs[1].name == "Song 1"
assert songs[2].name == "Song 2"
songs = await Song.objects.order_by("-sort_order").all()
assert songs[0].name == "Song 3"
assert songs[1].name == "Song 2"
assert songs[2].name == "Song 1"
songs = await Song.objects.order_by("sort_order").all()
assert songs[0].name == "Song 1"
assert songs[1].name == "Song 2"
assert songs[2].name == "Song 3"
songs = await Song.objects.order_by("name").all()
assert songs[0].name == "Song 1"
assert songs[1].name == "Song 2"
assert songs[2].name == "Song 3"
songs = await Song.objects.order_by("name").limit(2).all()
assert len(songs) == 2
assert songs[0].name == "Song 1"
assert songs[1].name == "Song 2"
await Song.objects.create(name="Song 4", sort_order=1)
songs = await Song.objects.order_by(["sort_order", "name"]).all()
assert songs[0].name == "Song 1"
assert songs[1].name == "Song 4"
assert songs[2].name == "Song 2"
assert songs[3].name == "Song 3"
@pytest.mark.asyncio
async def test_sort_order_on_related_model():
async with database:
aphrodite = await Owner.objects.create(name="Aphrodite")
hermes = await Owner.objects.create(name="Hermes")
zeus = await Owner.objects.create(name="Zeus")
await Toy.objects.create(name="Toy 4", owner=zeus)
await Toy.objects.create(name="Toy 5", owner=hermes)
await Toy.objects.create(name="Toy 2", owner=aphrodite)
await Toy.objects.create(name="Toy 1", owner=zeus)
await Toy.objects.create(name="Toy 3", owner=aphrodite)
await Toy.objects.create(name="Toy 6", owner=hermes)
toys = await Toy.objects.select_related("owner").order_by("name").all()
assert [x.name.replace("Toy ", "") for x in toys] == [
str(x + 1) for x in range(6)
]
assert toys[0].owner == zeus
assert toys[1].owner == aphrodite
toys = await Toy.objects.select_related("owner").order_by("owner__name").all()
assert toys[0].owner.name == toys[1].owner.name == "Aphrodite"
assert toys[2].owner.name == toys[3].owner.name == "Hermes"
assert toys[4].owner.name == toys[5].owner.name == "Zeus"
owner = (
await Owner.objects.select_related("toys")
.order_by("toys__name")
.filter(name="Zeus")
.get()
)
assert owner.toys[0].name == "Toy 1"
assert owner.toys[1].name == "Toy 4"
owner = (
await Owner.objects.select_related("toys")
.order_by("-toys__name")
.filter(name="Zeus")
.get()
)
assert owner.toys[0].name == "Toy 4"
assert owner.toys[1].name == "Toy 1"
owners = (
await Owner.objects.select_related("toys")
.order_by("-toys__name")
.filter(name__in=["Zeus", "Hermes"])
.all()
)
assert owners[0].toys[0].name == "Toy 6"
assert owners[0].toys[1].name == "Toy 5"
assert owners[0].name == "Hermes"
assert owners[1].toys[0].name == "Toy 4"
assert owners[1].toys[1].name == "Toy 1"
assert owners[1].name == "Zeus"
await Toy.objects.create(name="Toy 7", owner=zeus)
owners = (
await Owner.objects.select_related("toys")
.order_by("-toys__name")
.filter(name__in=["Zeus", "Hermes"])
.all()
)
assert owners[0].toys[0].name == "Toy 7"
assert owners[0].toys[1].name == "Toy 4"
assert owners[0].toys[2].name == "Toy 1"
assert owners[0].name == "Zeus"
assert owners[1].toys[0].name == "Toy 6"
assert owners[1].toys[1].name == "Toy 5"
assert owners[1].name == "Hermes"
toys = (
await Toy.objects.select_related("owner")
.order_by(["owner__name", "name"])
.limit(2)
.all()
)
assert len(toys) == 2
assert toys[0].name == "Toy 2"
assert toys[1].name == "Toy 3"
@pytest.mark.asyncio
async def test_sort_order_on_many_to_many():
async with database:
factory1 = await Factory.objects.create(name="Factory 1")
factory2 = await Factory.objects.create(name="Factory 2")
car1 = await Car.objects.create(name="Buggy", factory=factory1)
car2 = await Car.objects.create(name="Volkswagen", factory=factory2)
car3 = await Car.objects.create(name="Ferrari", factory=factory1)
car4 = await Car.objects.create(name="Volvo", factory=factory2)
car5 = await Car.objects.create(name="Skoda", factory=factory1)
car6 = await Car.objects.create(name="Seat", factory=factory2)
user1 = await User.objects.create(name="Mark")
user2 = await User.objects.create(name="Julie")
await user1.cars.add(car1)
await user1.cars.add(car3)
await user1.cars.add(car4)
await user1.cars.add(car5)
await user2.cars.add(car1)
await user2.cars.add(car2)
await user2.cars.add(car5)
await user2.cars.add(car6)
user = (
await User.objects.select_related("cars")
.filter(name="Mark")
.order_by("cars__name")
.get()
)
assert user.cars[0].name == "Buggy"
assert user.cars[1].name == "Ferrari"
assert user.cars[2].name == "Skoda"
assert user.cars[3].name == "Volvo"
user = (
await User.objects.select_related("cars")
.filter(name="Mark")
.order_by("-cars__name")
.get()
)
assert user.cars[3].name == "Buggy"
assert user.cars[2].name == "Ferrari"
assert user.cars[1].name == "Skoda"
assert user.cars[0].name == "Volvo"
users = await User.objects.select_related("cars").order_by("-cars__name").all()
assert users[0].name == "Mark"
assert users[1].cars[0].name == "Volkswagen"
assert users[1].cars[1].name == "Skoda"
assert users[1].cars[2].name == "Seat"
assert users[1].cars[3].name == "Buggy"
users = (
await User.objects.select_related(["cars__factory"])
.order_by(["-cars__factory__name", "cars__name"])
.all()
)
assert users[0].name == "Julie"
assert users[0].cars[0].name == "Seat"
assert users[0].cars[1].name == "Volkswagen"
assert users[0].cars[2].name == "Buggy"
assert users[0].cars[3].name == "Skoda"
assert users[1].name == "Mark"
assert users[1].cars[0].name == "Volvo"
assert users[1].cars[1].name == "Buggy"
assert users[1].cars[2].name == "Ferrari"
assert users[1].cars[3].name == "Skoda"
@pytest.mark.asyncio
async def test_sort_order_with_aliases():
async with database:
al1 = await AliasTest.objects.create(name="Test4")
al2 = await AliasTest.objects.create(name="Test2")
al3 = await AliasTest.objects.create(name="Test1")
al4 = await AliasTest.objects.create(name="Test3")
aliases = await AliasTest.objects.order_by("-name").all()
assert [alias.name[-1] for alias in aliases] == ["4", "3", "2", "1"]
nest1 = await AliasNested.objects.create(name="Try1")
nest2 = await AliasNested.objects.create(name="Try2")
nest3 = await AliasNested.objects.create(name="Try3")
nest4 = await AliasNested.objects.create(name="Try4")
al1.nested = nest1
await al1.update()
al2.nested = nest2
await al2.update()
al3.nested = nest3
await al3.update()
al4.nested = nest4
await al4.update()
aliases = (
await AliasTest.objects.select_related("nested")
.order_by("-nested__name")
.all()
)
assert aliases[0].nested.name == "Try4"
assert aliases[1].nested.name == "Try3"
assert aliases[2].nested.name == "Try2"
assert aliases[3].nested.name == "Try1"

View File

@ -0,0 +1,110 @@
import databases
import pytest
import sqlalchemy
import ormar
from ormar import ModelMeta
from ormar.exceptions import QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class BaseMeta(ModelMeta):
metadata = metadata
database = database
class Car(ormar.Model):
class Meta(BaseMeta):
pass
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class UsersCar(ormar.Model):
class Meta(BaseMeta):
tablename = "cars_x_users"
class User(ormar.Model):
class Meta(BaseMeta):
pass
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
cars = ormar.ManyToMany(Car, through=UsersCar)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_pagination_errors():
async with database:
async with database.transaction(force_rollback=True):
with pytest.raises(QueryDefinitionError):
await Car.objects.paginate(0).all()
with pytest.raises(QueryDefinitionError):
await Car.objects.paginate(1, page_size=0).all()
@pytest.mark.asyncio
async def test_pagination_on_single_model():
async with database:
async with database.transaction(force_rollback=True):
for i in range(20):
await Car(name=f"{i}").save()
cars_page1 = await Car.objects.paginate(1, page_size=5).all()
assert len(cars_page1) == 5
assert cars_page1[0].name == "0"
assert cars_page1[4].name == "4"
cars_page2 = await Car.objects.paginate(2, page_size=5).all()
assert len(cars_page2) == 5
assert cars_page2[0].name == "5"
assert cars_page2[4].name == "9"
all_cars = await Car.objects.paginate(1).all()
assert len(all_cars) == 20
half_cars = await Car.objects.paginate(2, page_size=10).all()
assert len(half_cars) == 10
assert half_cars[0].name == "10"
@pytest.mark.asyncio
async def test_proxy_pagination():
async with database:
async with database.transaction(force_rollback=True):
user = await User(name="Jon").save()
for i in range(20):
c = await Car(name=f"{i}").save()
await user.cars.add(c)
await user.cars.paginate(1, page_size=5).all()
assert len(user.cars) == 5
assert user.cars[0].name == "0"
assert user.cars[4].name == "4"
await user.cars.paginate(2, page_size=5).all()
assert len(user.cars) == 5
assert user.cars[0].name == "5"
assert user.cars[4].name == "9"
await user.cars.paginate(1).all()
assert len(user.cars) == 20
await user.cars.paginate(2, page_size=10).all()
assert len(user.cars) == 10
assert user.cars[0].name == "10"

View File

@ -0,0 +1,222 @@
import asyncio
from typing import List, Optional, Union
import databases
import pytest
import sqlalchemy
import ormar
from ormar.exceptions import QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Subject(ormar.Model):
class Meta:
tablename = "subjects"
database = database
metadata = metadata
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=80)
class Author(ormar.Model):
class Meta:
tablename = "authors"
database = database
metadata = metadata
id: int = ormar.Integer(primary_key=True)
first_name: str = ormar.String(max_length=80)
last_name: str = ormar.String(max_length=80)
class Category(ormar.Model):
class Meta:
tablename = "categories"
database = database
metadata = metadata
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=40)
sort_order: int = ormar.Integer(nullable=True)
subject: Optional[Subject] = ormar.ForeignKey(Subject)
class PostCategory(ormar.Model):
class Meta:
tablename = "posts_categories"
database = database
metadata = metadata
class Post(ormar.Model):
class Meta:
tablename = "posts"
database = database
metadata = metadata
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories: Optional[Union[Category, List[Category]]] = ormar.ManyToMany(
Category, through=PostCategory
)
author: Optional[Author] = ormar.ForeignKey(Author)
@pytest.fixture(scope="module")
def event_loop():
loop = asyncio.get_event_loop()
yield loop
loop.close()
@pytest.fixture(autouse=True, scope="module")
async def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_queryset_methods():
async with database:
async with database.transaction(force_rollback=True):
guido = await Author.objects.create(
first_name="Guido", last_name="Van Rossum"
)
subject = await Subject(name="Random").save()
post = await Post.objects.create(title="Hello, M2M", author=guido)
news = await Category.objects.create(
name="News", sort_order=1, subject=subject
)
breaking = await Category.objects.create(
name="Breaking", sort_order=3, subject=subject
)
# Add a category to a post.
await post.categories.add(news)
await post.categories.add(breaking)
category = await post.categories.get_or_create(name="News")
assert category == news
assert len(post.categories) == 1
category = await post.categories.get_or_create(name="Breaking News")
assert category != breaking
assert category.pk is not None
assert len(post.categories) == 2
await post.categories.update_or_create(pk=category.pk, name="Urgent News")
assert len(post.categories) == 2
cat = await post.categories.get_or_create(name="Urgent News")
assert cat.pk == category.pk
assert len(post.categories) == 1
await post.categories.remove(cat)
await cat.delete()
assert len(post.categories) == 0
category = await post.categories.update_or_create(
name="Weather News", sort_order=2, subject=subject
)
assert category.pk is not None
assert category.posts[0] == post
assert len(post.categories) == 1
categories = await post.categories.all()
assert len(categories) == 3 == len(post.categories)
assert await post.categories.exists()
assert 3 == await post.categories.count()
categories = await post.categories.limit(2).all()
assert len(categories) == 2 == len(post.categories)
categories2 = await post.categories.limit(2).offset(1).all()
assert len(categories2) == 2 == len(post.categories)
assert categories != categories2
categories = await post.categories.order_by("-sort_order").all()
assert len(categories) == 3 == len(post.categories)
assert post.categories[2].name == "News"
assert post.categories[0].name == "Breaking"
categories = await post.categories.exclude(name__icontains="news").all()
assert len(categories) == 1 == len(post.categories)
assert post.categories[0].name == "Breaking"
categories = (
await post.categories.filter(name__icontains="news")
.order_by("-name")
.all()
)
assert len(categories) == 2 == len(post.categories)
assert post.categories[0].name == "Weather News"
assert post.categories[1].name == "News"
categories = await post.categories.fields("name").all()
assert len(categories) == 3 == len(post.categories)
for cat in post.categories:
assert cat.sort_order is None
categories = await post.categories.exclude_fields("sort_order").all()
assert len(categories) == 3 == len(post.categories)
for cat in post.categories:
assert cat.sort_order is None
assert cat.subject.name is None
categories = await post.categories.select_related("subject").all()
assert len(categories) == 3 == len(post.categories)
for cat in post.categories:
assert cat.subject.name is not None
categories = await post.categories.prefetch_related("subject").all()
assert len(categories) == 3 == len(post.categories)
for cat in post.categories:
assert cat.subject.name is not None
@pytest.mark.asyncio
async def test_queryset_update():
async with database:
async with database.transaction(force_rollback=True):
guido = await Author.objects.create(
first_name="Guido", last_name="Van Rossum"
)
subject = await Subject(name="Random").save()
post = await Post.objects.create(title="Hello, M2M", author=guido)
await post.categories.create(name="News", sort_order=1, subject=subject)
await post.categories.create(name="Breaking", sort_order=3, subject=subject)
await post.categories.order_by("sort_order").all()
assert len(post.categories) == 2
assert post.categories[0].sort_order == 1
assert post.categories[0].name == "News"
assert post.categories[1].sort_order == 3
assert post.categories[1].name == "Breaking"
updated = await post.categories.update(each=True, name="Test")
assert updated == 2
await post.categories.order_by("sort_order").all()
assert len(post.categories) == 2
assert post.categories[0].name == "Test"
assert post.categories[1].name == "Test"
updated = await post.categories.filter(sort_order=3).update(name="Test 2")
assert updated == 1
await post.categories.order_by("sort_order").all()
assert len(post.categories) == 2
assert post.categories[0].name == "Test"
assert post.categories[1].name == "Test 2"
with pytest.raises(QueryDefinitionError):
await post.categories.update(name="Test WRONG")

View File

@ -0,0 +1,311 @@
from typing import Optional
import databases
import pytest
import sqlalchemy
import ormar
from ormar.exceptions import ModelPersistenceError, QueryDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Book(ormar.Model):
class Meta:
tablename = "books"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
author: str = ormar.String(max_length=100)
genre: str = ormar.String(
max_length=100,
default="Fiction",
choices=["Fiction", "Adventure", "Historic", "Fantasy"],
)
class ToDo(ormar.Model):
class Meta:
tablename = "todos"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
text: str = ormar.String(max_length=500)
completed: bool = ormar.Boolean(default=False)
class Category(ormar.Model):
class Meta:
tablename = "categories"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=500)
class Note(ormar.Model):
class Meta:
tablename = "notes"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
text: str = ormar.String(max_length=500)
category: Optional[Category] = ormar.ForeignKey(Category)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_delete_and_update():
async with database:
async with database.transaction(force_rollback=True):
await Book.objects.create(
title="Tom Sawyer", author="Twain, Mark", genre="Adventure"
)
await Book.objects.create(
title="War and Peace", author="Tolstoy, Leo", genre="Fiction"
)
await Book.objects.create(
title="Anna Karenina", author="Tolstoy, Leo", genre="Fiction"
)
await Book.objects.create(
title="Harry Potter", author="Rowling, J.K.", genre="Fantasy"
)
await Book.objects.create(
title="Lord of the Rings", author="Tolkien, J.R.", genre="Fantasy"
)
all_books = await Book.objects.all()
assert len(all_books) == 5
await Book.objects.filter(author="Tolstoy, Leo").update(
author="Lenin, Vladimir"
)
all_books = await Book.objects.filter(author="Lenin, Vladimir").all()
assert len(all_books) == 2
historic_books = await Book.objects.filter(genre="Historic").all()
assert len(historic_books) == 0
with pytest.raises(QueryDefinitionError):
await Book.objects.update(genre="Historic")
await Book.objects.filter(author="Lenin, Vladimir").update(genre="Historic")
historic_books = await Book.objects.filter(genre="Historic").all()
assert len(historic_books) == 2
await Book.objects.delete(genre="Fantasy")
all_books = await Book.objects.all()
assert len(all_books) == 3
await Book.objects.update(each=True, genre="Fiction")
all_books = await Book.objects.filter(genre="Fiction").all()
assert len(all_books) == 3
with pytest.raises(QueryDefinitionError):
await Book.objects.delete()
await Book.objects.delete(each=True)
all_books = await Book.objects.all()
assert len(all_books) == 0
@pytest.mark.asyncio
async def test_get_or_create():
async with database:
tom = await Book.objects.get_or_create(
title="Volume I", author="Anonymous", genre="Fiction"
)
assert await Book.objects.count() == 1
assert (
await Book.objects.get_or_create(
title="Volume I", author="Anonymous", genre="Fiction"
)
== tom
)
assert await Book.objects.count() == 1
assert await Book.objects.create(
title="Volume I", author="Anonymous", genre="Fiction"
)
with pytest.raises(ormar.exceptions.MultipleMatches):
await Book.objects.get_or_create(
title="Volume I", author="Anonymous", genre="Fiction"
)
@pytest.mark.asyncio
async def test_update_or_create():
async with database:
tom = await Book.objects.update_or_create(
title="Volume I", author="Anonymous", genre="Fiction"
)
assert await Book.objects.count() == 1
assert await Book.objects.update_or_create(id=tom.id, genre="Historic")
assert await Book.objects.count() == 1
assert await Book.objects.update_or_create(pk=tom.id, genre="Fantasy")
assert await Book.objects.count() == 1
assert await Book.objects.create(
title="Volume I", author="Anonymous", genre="Fantasy"
)
with pytest.raises(ormar.exceptions.MultipleMatches):
await Book.objects.get(
title="Volume I", author="Anonymous", genre="Fantasy"
)
@pytest.mark.asyncio
async def test_bulk_create():
async with database:
await ToDo.objects.bulk_create(
[
ToDo(text="Buy the groceries."),
ToDo(text="Call Mum.", completed=True),
ToDo(text="Send invoices.", completed=True),
]
)
todoes = await ToDo.objects.all()
assert len(todoes) == 3
for todo in todoes:
assert todo.pk is not None
completed = await ToDo.objects.filter(completed=True).all()
assert len(completed) == 2
@pytest.mark.asyncio
async def test_bulk_create_with_relation():
async with database:
category = await Category.objects.create(name="Sample Category")
await Note.objects.bulk_create(
[
Note(text="Buy the groceries.", category=category),
Note(text="Call Mum.", category=category),
]
)
todoes = await Note.objects.all()
assert len(todoes) == 2
for todo in todoes:
assert todo.category.pk == category.pk
@pytest.mark.asyncio
async def test_bulk_update():
async with database:
await ToDo.objects.bulk_create(
[
ToDo(text="Buy the groceries."),
ToDo(text="Call Mum.", completed=True),
ToDo(text="Send invoices.", completed=True),
]
)
todoes = await ToDo.objects.all()
assert len(todoes) == 3
for todo in todoes:
todo.text = todo.text + "_1"
todo.completed = False
await ToDo.objects.bulk_update(todoes)
completed = await ToDo.objects.filter(completed=False).all()
assert len(completed) == 3
todoes = await ToDo.objects.all()
assert len(todoes) == 3
for todo in todoes:
assert todo.text[-2:] == "_1"
@pytest.mark.asyncio
async def test_bulk_update_with_only_selected_columns():
async with database:
await ToDo.objects.bulk_create(
[
ToDo(text="Reset the world simulation.", completed=False),
ToDo(text="Watch kittens.", completed=True),
]
)
todoes = await ToDo.objects.all()
assert len(todoes) == 2
for todo in todoes:
todo.text = todo.text + "_1"
todo.completed = False
await ToDo.objects.bulk_update(todoes, columns=["completed"])
completed = await ToDo.objects.filter(completed=False).all()
assert len(completed) == 2
todoes = await ToDo.objects.all()
assert len(todoes) == 2
for todo in todoes:
assert todo.text[-2:] != "_1"
@pytest.mark.asyncio
async def test_bulk_update_with_relation():
async with database:
category = await Category.objects.create(name="Sample Category")
category2 = await Category.objects.create(name="Sample II Category")
await Note.objects.bulk_create(
[
Note(text="Buy the groceries.", category=category),
Note(text="Call Mum.", category=category),
Note(text="Text skynet.", category=category),
]
)
notes = await Note.objects.all()
assert len(notes) == 3
for note in notes:
note.category = category2
await Note.objects.bulk_update(notes)
notes_upd = await Note.objects.all()
assert len(notes_upd) == 3
for note in notes_upd:
assert note.category.pk == category2.pk
@pytest.mark.asyncio
async def test_bulk_update_not_saved_objts():
async with database:
category = await Category.objects.create(name="Sample Category")
with pytest.raises(ModelPersistenceError):
await Note.objects.bulk_update(
[
Note(text="Buy the groceries.", category=category),
Note(text="Call Mum.", category=category),
]
)

View File

@ -0,0 +1,99 @@
import databases
import pytest
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class BaseMeta(ormar.ModelMeta):
metadata = metadata
database = database
class User(ormar.Model):
class Meta(BaseMeta):
tablename = "user"
id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False)
user: str = ormar.String(
unique=True, index=True, nullable=False, max_length=255
) # ID of the user on auth0
first: str = ormar.String(nullable=False, max_length=255)
last: str = ormar.String(nullable=False, max_length=255)
email: str = ormar.String(unique=True, index=True, nullable=False, max_length=255)
display_name: str = ormar.String(
unique=True, index=True, nullable=False, max_length=255
)
pic_url: str = ormar.Text(nullable=True)
class Task(ormar.Model):
class Meta(BaseMeta):
tablename = "task"
id: int = ormar.Integer(primary_key=True, autoincrement=True, nullable=False)
from_: str = ormar.String(name="from", nullable=True, max_length=200)
user = ormar.ForeignKey(User)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_single_model_quotes():
async with database:
await User.objects.create(
user="test",
first="first",
last="last",
email="email@com.com",
display_name="first last",
)
user = await User.objects.order_by("user").get(first="first")
assert user.last == "last"
assert user.email == "email@com.com"
@pytest.mark.asyncio
async def test_two_model_quotes():
async with database:
user = await User.objects.create(
user="test",
first="first",
last="last",
email="email@com.com",
display_name="first last",
)
await Task(user=user, from_="aa").save()
await Task(user=user, from_="bb").save()
task = (
await Task.objects.select_related("user")
.order_by("user__user")
.get(from_="aa")
)
assert task.user.last == "last"
assert task.user.email == "email@com.com"
tasks = await Task.objects.select_related("user").order_by("-from").all()
assert len(tasks) == 2
assert tasks[0].user.last == "last"
assert tasks[0].user.email == "email@com.com"
assert tasks[0].from_ == "bb"
assert tasks[1].user.last == "last"
assert tasks[1].user.email == "email@com.com"
assert tasks[1].from_ == "aa"

View File

@ -0,0 +1,258 @@
from typing import Optional
import databases
import pytest
import sqlalchemy
import ormar
from ormar import NoMatch
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class Album(ormar.Model):
class Meta:
tablename = "albums"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
is_best_seller: bool = ormar.Boolean(default=False)
class Writer(ormar.Model):
class Meta:
tablename = "writers"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
class Track(ormar.Model):
class Meta:
tablename = "tracks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
album: Optional[Album] = ormar.ForeignKey(Album)
title: str = ormar.String(max_length=100)
position: int = ormar.Integer()
play_count: int = ormar.Integer(nullable=True)
written_by: Optional[Writer] = ormar.ForeignKey(Writer)
async def get_sample_data():
album = await Album(name="Malibu").save()
writer1 = await Writer.objects.create(name="John")
writer2 = await Writer.objects.create(name="Sue")
track1 = await Track(
album=album, title="The Bird", position=1, play_count=30, written_by=writer1
).save()
track2 = await Track(
album=album,
title="Heart don't stand a chance",
position=2,
play_count=20,
written_by=writer2,
).save()
tracks3 = await Track(
album=album, title="The Waters", position=3, play_count=10, written_by=writer1
).save()
return album, [track1, track2, tracks3]
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_quering_by_reverse_fk():
async with database:
async with database.transaction(force_rollback=True):
sample_data = await get_sample_data()
track1 = sample_data[1][0]
album = await Album.objects.first()
assert await album.tracks.exists()
assert await album.tracks.count() == 3
track = await album.tracks.get_or_create(
title="The Bird", position=1, play_count=30
)
assert track == track1
assert len(album.tracks) == 1
track = await album.tracks.get_or_create(
title="The Bird2", position=4, play_count=5
)
assert track != track1
assert track.pk is not None
assert len(album.tracks) == 2
await album.tracks.update_or_create(pk=track.pk, play_count=50)
assert len(album.tracks) == 2
track = await album.tracks.get_or_create(title="The Bird2")
assert track.play_count == 50
assert len(album.tracks) == 1
await album.tracks.remove(track)
assert track.album is None
await track.delete()
assert len(album.tracks) == 0
track6 = await album.tracks.update_or_create(
title="The Bird3", position=4, play_count=5
)
assert track6.pk is not None
assert track6.play_count == 5
assert len(album.tracks) == 1
await album.tracks.remove(track6)
assert track6.album is None
await track6.delete()
assert len(album.tracks) == 0
@pytest.mark.asyncio
async def test_getting():
async with database:
async with database.transaction(force_rollback=True):
sample_data = await get_sample_data()
album = sample_data[0]
track1 = await album.tracks.fields(["album", "title", "position"]).get(
title="The Bird"
)
track2 = await album.tracks.exclude_fields("play_count").get(
title="The Bird"
)
for track in [track1, track2]:
assert track.title == "The Bird"
assert track.album == album
assert track.play_count is None
assert len(album.tracks) == 1
tracks = await album.tracks.all()
assert len(tracks) == 3
assert len(album.tracks) == 3
tracks = await album.tracks.order_by("play_count").all()
assert len(tracks) == 3
assert tracks[0].title == "The Waters"
assert tracks[2].title == "The Bird"
assert len(album.tracks) == 3
track = await album.tracks.create(
title="The Bird Fly Away", position=4, play_count=10
)
assert track.title == "The Bird Fly Away"
assert track.position == 4
assert track.album == album
assert len(album.tracks) == 4
tracks = await album.tracks.all()
assert len(tracks) == 4
tracks = await album.tracks.limit(2).all()
assert len(tracks) == 2
tracks2 = await album.tracks.limit(2).offset(2).all()
assert len(tracks2) == 2
assert tracks != tracks2
tracks3 = await album.tracks.filter(play_count__lt=15).all()
assert len(tracks3) == 2
tracks4 = await album.tracks.exclude(play_count__lt=15).all()
assert len(tracks4) == 2
assert tracks3 != tracks4
assert len(album.tracks) == 2
await album.tracks.clear()
tracks = await album.tracks.all()
assert len(tracks) == 0
assert len(album.tracks) == 0
still_tracks = await Track.objects.all()
assert len(still_tracks) == 4
for track in still_tracks:
assert track.album is None
@pytest.mark.asyncio
async def test_cleaning_related():
async with database:
async with database.transaction(force_rollback=True):
sample_data = await get_sample_data()
album = sample_data[0]
await album.tracks.clear(keep_reversed=False)
tracks = await album.tracks.all()
assert len(tracks) == 0
assert len(album.tracks) == 0
no_tracks = await Track.objects.all()
assert len(no_tracks) == 0
@pytest.mark.asyncio
async def test_loading_related():
async with database:
async with database.transaction(force_rollback=True):
sample_data = await get_sample_data()
album = sample_data[0]
tracks = await album.tracks.select_related("written_by").all()
assert len(tracks) == 3
assert len(album.tracks) == 3
for track in tracks:
assert track.written_by is not None
tracks = await album.tracks.prefetch_related("written_by").all()
assert len(tracks) == 3
assert len(album.tracks) == 3
for track in tracks:
assert track.written_by is not None
@pytest.mark.asyncio
async def test_adding_removing():
async with database:
async with database.transaction(force_rollback=True):
sample_data = await get_sample_data()
album = sample_data[0]
track_new = await Track(title="Rainbow", position=5, play_count=300).save()
await album.tracks.add(track_new)
assert track_new.album == album
assert len(album.tracks) == 4
track_check = await Track.objects.get(title="Rainbow")
assert track_check.album == album
await album.tracks.remove(track_new)
assert track_new.album is None
assert len(album.tracks) == 3
track1 = album.tracks[0]
await album.tracks.remove(track1, keep_reversed=False)
with pytest.raises(NoMatch):
await track1.load()
track_test = await Track.objects.get(title="Rainbow")
assert track_test.album is None

View File

@ -0,0 +1,220 @@
import itertools
from typing import Optional, List
import databases
import pydantic
import pytest
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL, force_rollback=True)
metadata = sqlalchemy.MetaData()
class NickNames(ormar.Model):
class Meta:
tablename = "nicks"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
is_lame: bool = ormar.Boolean(nullable=True)
class NicksHq(ormar.Model):
class Meta:
tablename = "nicks_x_hq"
metadata = metadata
database = database
class HQ(ormar.Model):
class Meta:
tablename = "hqs"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100, nullable=False, name="hq_name")
nicks: List[NickNames] = ormar.ManyToMany(NickNames, through=NicksHq)
class Company(ormar.Model):
class Meta:
tablename = "companies"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100, nullable=False, name="company_name")
founded: int = ormar.Integer(nullable=True)
hq: HQ = ormar.ForeignKey(HQ)
class Car(ormar.Model):
class Meta:
tablename = "cars"
metadata = metadata
database = database
id: int = ormar.Integer(primary_key=True)
manufacturer: Optional[Company] = ormar.ForeignKey(Company)
name: str = ormar.String(max_length=100)
year: int = ormar.Integer(nullable=True)
gearbox_type: str = ormar.String(max_length=20, nullable=True)
gears: int = ormar.Integer(nullable=True)
aircon_type: str = ormar.String(max_length=20, nullable=True)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = sqlalchemy.create_engine(DATABASE_URL)
metadata.drop_all(engine)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_selecting_subset():
async with database:
async with database.transaction(force_rollback=True):
nick1 = await NickNames.objects.create(name="Nippon", is_lame=False)
nick2 = await NickNames.objects.create(name="EroCherry", is_lame=True)
hq = await HQ.objects.create(name="Japan")
await hq.nicks.add(nick1)
await hq.nicks.add(nick2)
toyota = await Company.objects.create(name="Toyota", founded=1937, hq=hq)
await Car.objects.create(
manufacturer=toyota,
name="Corolla",
year=2020,
gearbox_type="Manual",
gears=5,
aircon_type="Manual",
)
await Car.objects.create(
manufacturer=toyota,
name="Yaris",
year=2019,
gearbox_type="Manual",
gears=5,
aircon_type="Manual",
)
await Car.objects.create(
manufacturer=toyota,
name="Supreme",
year=2020,
gearbox_type="Auto",
gears=6,
aircon_type="Auto",
)
all_cars = (
await Car.objects.select_related(["manufacturer__hq__nicks"])
.fields(
[
"id",
"name",
"manufacturer__name",
"manufacturer__hq__name",
"manufacturer__hq__nicks__name",
]
)
.all()
)
all_cars2 = (
await Car.objects.select_related(["manufacturer__hq__nicks"])
.fields(
{
"id": ...,
"name": ...,
"manufacturer": {
"name": ...,
"hq": {"name": ..., "nicks": {"name": ...}},
},
}
)
.all()
)
all_cars3 = (
await Car.objects.select_related(["manufacturer__hq__nicks"])
.fields(
{
"id": ...,
"name": ...,
"manufacturer": {
"name": ...,
"hq": {"name": ..., "nicks": {"name"}},
},
}
)
.all()
)
assert all_cars3 == all_cars
for car in itertools.chain(all_cars, all_cars2):
assert all(
getattr(car, x) is None
for x in ["year", "gearbox_type", "gears", "aircon_type"]
)
assert car.manufacturer.name == "Toyota"
assert car.manufacturer.founded is None
assert car.manufacturer.hq.name == "Japan"
assert len(car.manufacturer.hq.nicks) == 2
assert car.manufacturer.hq.nicks[0].is_lame is None
all_cars = (
await Car.objects.select_related("manufacturer")
.fields("id")
.fields(["name"])
.all()
)
for car in all_cars:
assert all(
getattr(car, x) is None
for x in ["year", "gearbox_type", "gears", "aircon_type"]
)
assert car.manufacturer.name == "Toyota"
assert car.manufacturer.founded == 1937
assert car.manufacturer.hq.name is None
all_cars_check = await Car.objects.select_related("manufacturer").all()
all_cars_with_whole_nested = (
await Car.objects.select_related("manufacturer")
.fields(["id", "name", "year", "gearbox_type", "gears", "aircon_type"])
.fields({"manufacturer": ...})
.all()
)
for car in itertools.chain(all_cars_check, all_cars_with_whole_nested):
assert all(
getattr(car, x) is not None
for x in ["year", "gearbox_type", "gears", "aircon_type"]
)
assert car.manufacturer.name == "Toyota"
assert car.manufacturer.founded == 1937
all_cars_dummy = (
await Car.objects.select_related("manufacturer")
.fields(["id", "name", "year", "gearbox_type", "gears", "aircon_type"])
# .fields({"manufacturer": ...})
# .exclude_fields({"manufacturer": ...})
.fields({"manufacturer": {"name"}})
.exclude_fields({"manufacturer__founded"})
.all()
)
assert all_cars_dummy[0].manufacturer.founded is None
with pytest.raises(pydantic.error_wrappers.ValidationError):
# cannot exclude mandatory model columns - company__name in this example
await Car.objects.select_related("manufacturer").fields(
["id", "name", "manufacturer__founded"]
).all()