merge from master, simplify props in meta inheritance

This commit is contained in:
collerek
2020-12-14 20:56:58 +01:00
23 changed files with 540 additions and 296 deletions

View File

@ -8,7 +8,7 @@ import sqlalchemy as sa
from sqlalchemy import create_engine
import ormar
from ormar import ModelDefinitionError
from ormar import ModelDefinitionError, property_field
from ormar.exceptions import ModelError
from tests.settings import DATABASE_URL
@ -24,6 +24,10 @@ class AuditModel(ormar.Model):
created_by: str = ormar.String(max_length=100)
updated_by: str = ormar.String(max_length=100, default="Sam")
@property_field
def audit(self): # pragma: no cover
return f"{self.created_by} {self.updated_by}"
class DateFieldsModelNoSubclass(ormar.Model):
class Meta:
@ -41,6 +45,7 @@ class DateFieldsModel(ormar.Model):
abstract = True
metadata = metadata
database = db
constraints = [ormar.UniqueColumns("created_date", "updated_date")]
created_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
updated_date: datetime.datetime = ormar.DateTime(default=datetime.datetime.now)
@ -49,11 +54,20 @@ class DateFieldsModel(ormar.Model):
class Category(DateFieldsModel, AuditModel):
class Meta(ormar.ModelMeta):
tablename = "categories"
constraints = [ormar.UniqueColumns("name", "code")]
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=50, unique=True, index=True)
code: int = ormar.Integer()
@property_field
def code_name(self):
return f"{self.code}:{self.name}"
@property_field
def audit(self):
return f"{self.created_by} {self.updated_by}"
class Subject(DateFieldsModel):
class Meta(ormar.ModelMeta):
@ -99,6 +113,13 @@ def test_model_subclassing_non_abstract_raises_error():
id: int = ormar.Integer(primary_key=True)
def test_params_are_inherited():
assert Category.Meta.metadata == metadata
assert Category.Meta.database == db
assert len(Category.Meta.constraints) == 2
assert len(Category.Meta.property_fields) == 2
def round_date_to_seconds(
date: datetime.datetime,
) -> datetime.datetime: # pragma: no cover
@ -132,7 +153,9 @@ async def test_fields_inherited_from_mixin():
inspector = sa.inspect(engine)
assert "categories" in inspector.get_table_names()
table_columns = [x.get("name") for x in inspector.get_columns("categories")]
assert all(col in table_columns for col in mixin_columns) # + mixin2_columns)
assert all(
col in table_columns for col in mixin_columns
) # + mixin2_columns)
assert "subjects" in inspector.get_table_names()
table_columns = [x.get("name") for x in inspector.get_columns("subjects")]

View File

@ -7,7 +7,7 @@ from fastapi import FastAPI
from starlette.testclient import TestClient
from tests.settings import DATABASE_URL
from tests.test_inheritance_concrete import Category, Subject, metadata
from tests.test_inheritance_concrete import Category, Subject, metadata # type: ignore
app = FastAPI()
database = databases.Database(DATABASE_URL, force_rollback=True)
@ -53,25 +53,25 @@ def test_read_main():
test_category = dict(name="Foo", code=123, created_by="Sam", updated_by="Max")
test_subject = dict(name="Bar")
response = client.post(
"/categories/", json=test_category
)
response = client.post("/categories/", json=test_category)
assert response.status_code == 200
cat = Category(**response.json())
assert cat.name == 'Foo'
assert cat.created_by == 'Sam'
assert cat.name == "Foo"
assert cat.created_by == "Sam"
assert cat.created_date is not None
assert cat.id == 1
cat_dict = cat.dict()
cat_dict['updated_date'] = cat_dict['updated_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
cat_dict['created_date'] = cat_dict['created_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
test_subject['category'] = cat_dict
response = client.post(
"/subjects/", json=test_subject
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
"%Y-%m-%d %H:%M:%S.%f"
)
cat_dict["created_date"] = cat_dict["created_date"].strftime(
"%Y-%m-%d %H:%M:%S.%f"
)
test_subject["category"] = cat_dict
response = client.post("/subjects/", json=test_subject)
assert response.status_code == 200
sub = Subject(**response.json())
assert sub.name == 'Bar'
assert sub.name == "Bar"
assert sub.category.pk == cat.pk
assert isinstance(sub.updated_date, datetime.datetime)

View File

@ -7,7 +7,7 @@ from fastapi import FastAPI
from starlette.testclient import TestClient
from tests.settings import DATABASE_URL
from tests.test_inheritance_mixins import Category, Subject, metadata
from tests.test_inheritance_mixins import Category, Subject, metadata # type: ignore
app = FastAPI()
database = databases.Database(DATABASE_URL, force_rollback=True)
@ -53,25 +53,25 @@ def test_read_main():
test_category = dict(name="Foo", code=123, created_by="Sam", updated_by="Max")
test_subject = dict(name="Bar")
response = client.post(
"/categories/", json=test_category
)
response = client.post("/categories/", json=test_category)
assert response.status_code == 200
cat = Category(**response.json())
assert cat.name == 'Foo'
assert cat.created_by == 'Sam'
assert cat.name == "Foo"
assert cat.created_by == "Sam"
assert cat.created_date is not None
assert cat.id == 1
cat_dict = cat.dict()
cat_dict['updated_date'] = cat_dict['updated_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
cat_dict['created_date'] = cat_dict['created_date'].strftime("%Y-%m-%d %H:%M:%S.%f")
test_subject['category'] = cat_dict
response = client.post(
"/subjects/", json=test_subject
cat_dict["updated_date"] = cat_dict["updated_date"].strftime(
"%Y-%m-%d %H:%M:%S.%f"
)
cat_dict["created_date"] = cat_dict["created_date"].strftime(
"%Y-%m-%d %H:%M:%S.%f"
)
test_subject["category"] = cat_dict
response = client.post("/subjects/", json=test_subject)
assert response.status_code == 200
sub = Subject(**response.json())
assert sub.name == 'Bar'
assert sub.name == "Bar"
assert sub.category.pk == cat.pk
assert isinstance(sub.updated_date, datetime.datetime)

View File

@ -1,115 +0,0 @@
import asyncio
from datetime import date
from typing import List, Optional, Union
import databases
import pytest
import sqlalchemy
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class MainMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Role(ormar.Model):
class Meta(MainMeta):
pass
name: str = ormar.Text(primary_key=True)
order: int = ormar.Integer(default=0)
description: str = ormar.Text()
class Company(ormar.Model):
class Meta(MainMeta):
pass
name: str = ormar.Text(primary_key=True)
class UserRoleCompany(ormar.Model):
class Meta(MainMeta):
pass
class User(ormar.Model):
class Meta(MainMeta):
pass
registrationnumber: str = ormar.Text(primary_key=True)
company: Company = ormar.ForeignKey(Company)
name: str = ormar.Text()
role: Optional[Role] = ormar.ForeignKey(Role)
roleforcompanies: Optional[Union[Company, List[Company]]] = ormar.ManyToMany(Company, through=UserRoleCompany)
lastupdate: date = ormar.DateTime(server_default=sqlalchemy.func.now())
@pytest.mark.asyncio
async def test_create_primary_models():
async with database:
print("adding role")
role_0 = await Role.objects.create(name="user", order=0, description="no administration right")
role_1 = await Role.objects.create(name="admin", order=1, description="standard administration right")
role_2 = await Role.objects.create(name="super_admin", order=2, description="super administration right")
assert await Role.objects.count() == 3
print("adding company")
company_0 = await Company.objects.create(name="Company")
company_1 = await Company.objects.create(name="Subsidiary Company 1")
company_2 = await Company.objects.create(name="Subsidiary Company 2")
company_3 = await Company.objects.create(name="Subsidiary Company 3")
assert await Company.objects.count() == 4
print("adding user")
user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1)
assert await User.objects.count() == 1
print("removing user")
await user.delete()
assert await User.objects.count() == 0
print("adding user with company-role")
companies: List[Company] = [company_1, company_2]
# user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1, roleforcompanies=companies)
user = await User.objects.create(registrationnumber="00-00000", company=company_0, name="admin", role=role_1)
# print(User.__fields__)
await user.roleforcompanies.add(company_1)
await user.roleforcompanies.add(company_2)
users = await User.objects.select_related("roleforcompanies").all()
# print(jsonpickle.encode(jsonable_encoder(users), unpicklable=False, keys=True))
"""
This is the request generated:
'SELECT
users.registrationnumber as registrationnumber,
users.company as company,
users.name as name, users.role as role,
users.lastupdate as lastupdate,
cy24b4_userrolecompanys.id as cy24b4_id,
cy24b4_userrolecompanys.company as cy24b4_company,
cy24b4_userrolecompanys.user as cy24b4_user,
jn50a4_companys.name as jn50a4_name \n
FROM users
LEFT OUTER JOIN userrolecompanys cy24b4_userrolecompanys ON cy24b4_userrolecompanys.user=users.id
LEFT OUTER JOIN companys jn50a4_companys ON jn50a4_companys.name=cy24b4_userrolecompanys.company
ORDER BY users.registrationnumber, jn50a4_companys.name'
There is an error in the First LEFT OUTER JOIN generated:
... companys.user=users.id
should be:
... companys.user=users.registrationnumber
There is also a \n in the midle of the string...
The execution produce the error: column users.id does not exist
"""

View File

@ -102,7 +102,7 @@ async def test_model_multiple_instances_of_same_table_in_schema():
async with database.transaction(force_rollback=True):
await create_data()
classes = await SchoolClass.objects.select_related(
["teachers__category", "students"]
["teachers__category", "students__schoolclass"]
).all()
assert classes[0].name == "Math"
assert classes[0].students[0].name == "Jane"

View File

@ -56,8 +56,7 @@ class SecondaryModel(ormar.Model):
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)
primary_model: PrimaryModel = ormar.ForeignKey(
PrimaryModel,
related_name="secondary_models",
PrimaryModel, related_name="secondary_models",
)
@ -74,7 +73,8 @@ async def test_create_primary_models():
("Primary 7", "Some text 7", "Some other text 7"),
("Primary 8", "Some text 8", "Some other text 8"),
("Primary 9", "Some text 9", "Some other text 9"),
("Primary 10", "Some text 10", "Some other text 10")]:
("Primary 10", "Some text 10", "Some other text 10"),
]:
await PrimaryModel(
name=name, some_text=some_text, some_other_text=some_other_text
).save()

View File

@ -0,0 +1,130 @@
# type: ignore
from datetime import date
from typing import List, Optional, Union
import databases
import pytest
import sqlalchemy
from sqlalchemy import create_engine
import ormar
from ormar import ModelDefinitionError
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class MainMeta(ormar.ModelMeta):
metadata = metadata
database = database
class Role(ormar.Model):
class Meta(MainMeta):
pass
name: str = ormar.String(primary_key=True, max_length=1000)
order: int = ormar.Integer(default=0, name="sort_order")
description: str = ormar.Text()
class Company(ormar.Model):
class Meta(MainMeta):
pass
name: str = ormar.String(primary_key=True, max_length=1000)
class UserRoleCompany(ormar.Model):
class Meta(MainMeta):
pass
class User(ormar.Model):
class Meta(MainMeta):
pass
registrationnumber: str = ormar.String(primary_key=True, max_length=1000)
company: Company = ormar.ForeignKey(Company)
company2: Company = ormar.ForeignKey(Company, related_name="secondary_users")
name: str = ormar.Text()
role: Optional[Role] = ormar.ForeignKey(Role)
roleforcompanies: Optional[Union[Company, List[Company]]] = ormar.ManyToMany(
Company, through=UserRoleCompany, related_name="role_users"
)
lastupdate: date = ormar.DateTime(server_default=sqlalchemy.func.now())
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = create_engine(DATABASE_URL)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
def test_wrong_model():
with pytest.raises(ModelDefinitionError):
class User(ormar.Model):
class Meta(MainMeta):
pass
registrationnumber: str = ormar.Text(primary_key=True)
company: Company = ormar.ForeignKey(Company)
company2: Company = ormar.ForeignKey(Company)
@pytest.mark.asyncio
async def test_create_primary_models():
async with database:
await Role.objects.create(
name="user", order=0, description="no administration right"
)
role_1 = await Role.objects.create(
name="admin", order=1, description="standard administration right"
)
await Role.objects.create(
name="super_admin", order=2, description="super administration right"
)
assert await Role.objects.count() == 3
company_0 = await Company.objects.create(name="Company")
company_1 = await Company.objects.create(name="Subsidiary Company 1")
company_2 = await Company.objects.create(name="Subsidiary Company 2")
company_3 = await Company.objects.create(name="Subsidiary Company 3")
assert await Company.objects.count() == 4
user = await User.objects.create(
registrationnumber="00-00000", company=company_0, name="admin", role=role_1
)
assert await User.objects.count() == 1
await user.delete()
assert await User.objects.count() == 0
user = await User.objects.create(
registrationnumber="00-00000",
company=company_0,
company2=company_3,
name="admin",
role=role_1,
)
await user.roleforcompanies.add(company_1)
await user.roleforcompanies.add(company_2)
users = await User.objects.select_related(
["company", "company2", "roleforcompanies"]
).all()
assert len(users) == 1
assert len(users[0].roleforcompanies) == 2
assert len(users[0].roleforcompanies[0].role_users) == 1
assert users[0].company.name == "Company"
assert len(users[0].company.users) == 1
assert users[0].company2.name == "Subsidiary Company 3"
assert len(users[0].company2.secondary_users) == 1
users = await User.objects.select_related("roleforcompanies").all()
assert len(users) == 1
assert len(users[0].roleforcompanies) == 2

View File

@ -0,0 +1,93 @@
from typing import List, Optional
import databases
import pytest
import sqlalchemy
from sqlalchemy import create_engine
import ormar
from tests.settings import DATABASE_URL
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()
class User(ormar.Model):
class Meta:
metadata = metadata
database = database
tablename = "test_users"
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=50)
class Signup(ormar.Model):
class Meta:
metadata = metadata
database = database
tablename = "test_signup"
id: int = ormar.Integer(primary_key=True)
class Session(ormar.Model):
class Meta:
metadata = metadata
database = database
tablename = "test_sessions"
id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=255, index=True)
some_text: str = ormar.Text()
some_other_text: Optional[str] = ormar.Text(nullable=True)
students: Optional[List[User]] = ormar.ManyToMany(User, through=Signup)
@pytest.fixture(autouse=True, scope="module")
def create_test_database():
engine = create_engine(DATABASE_URL)
metadata.create_all(engine)
yield
metadata.drop_all(engine)
@pytest.mark.asyncio
async def test_list_sessions_for_user():
async with database:
for user_id in [1, 2, 3, 4, 5]:
await User.objects.create(name=f"User {user_id}")
for name, some_text, some_other_text in [
("Session 1", "Some text 1", "Some other text 1"),
("Session 2", "Some text 2", "Some other text 2"),
("Session 3", "Some text 3", "Some other text 3"),
("Session 4", "Some text 4", "Some other text 4"),
("Session 5", "Some text 5", "Some other text 5"),
]:
await Session(
name=name, some_text=some_text, some_other_text=some_other_text
).save()
s1 = await Session.objects.get(pk=1)
s2 = await Session.objects.get(pk=2)
users = {}
for i in range(1, 6):
user = await User.objects.get(pk=i)
users[f"user_{i}"] = user
if i % 2 == 0:
await s1.students.add(user)
else:
await s2.students.add(user)
assert len(s1.students) == 2
assert len(s2.students) == 3
assert [x.pk for x in s1.students] == [2, 4]
assert [x.pk for x in s2.students] == [1, 3, 5]
user = await User.objects.select_related("sessions").get(pk=1)
assert user.sessions is not None
assert len(user.sessions) > 0