Skip to content

Commit

Permalink
refactor: check that the user-defined table has 1 and only 1 primary …
Browse files Browse the repository at this point in the history
…key.

Update test_meta_errors.py

style: pre-commit

style: pre-commit

fix: test case
  • Loading branch information
vvanglro committed Jan 17, 2024
1 parent a67bca2 commit f85273b
Show file tree
Hide file tree
Showing 61 changed files with 146 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ insert_final_newline = true
indent_size = 2

[*.html]
insert_final_newline = true
insert_final_newline = true
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ target/
.coverage
.python-version
coverage.*
example.sqlite
example.sqlite
5 changes: 2 additions & 3 deletions docs/test-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Let us assume you have a database url like this following:
DATABASE_URL = "postgresql+asyncpg://postgres:postgres@localhost:5432/my_db"
```

We know the database is called `my_db`, right?
We know the database is called `my_db`, right?

When using the `DatabaseTestClient`, the client will ensure the tests will land on a `test_my_db`.

Expand All @@ -74,8 +74,7 @@ Well, this is rather complex test and actually a real one from Saffier and what
that is using the `DatabaseTestClient` which means the tests against models, fields or whatever
database operation you want will be on a `test_` database.

But you can see a `drop_database=True`, so what is that?
But you can see a `drop_database=True`, so what is that?

Well `drop_database=True` means that by the end of the tests finish running, drops the database
into oblivion.

2 changes: 1 addition & 1 deletion docs/transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Let us also assume we want to create a `user` and a `profile` for that user in a
This is probably one of the less common ways of using transactions but still very useful if you
want all of your endpoint to be atomic.

We want to create an endpoint where we save the `user` and the `profile` in one go. Since the
We want to create an endpoint where we save the `user` and the `profile` in one go. Since the
author of Saffier is the same as [Esmerald](https://esmerald.dymmond.com), it makes sense to use
it as example.

Expand Down
3 changes: 3 additions & 0 deletions saffier/contrib/multi_tenancy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class TenantMixin(saffier.Model):
the tenants with saffier contrib.
"""

id = saffier.BigIntegerField(primary_key=True)
schema_name = saffier.CharField(max_length=63, unique=True, index=True)
domain_url = saffier.URLField(null=True, default=settings.domain, max_length=2048)
tenant_name = saffier.CharField(max_length=100, unique=True, null=False)
Expand Down Expand Up @@ -101,6 +102,7 @@ class DomainMixin(saffier.Model):
All models that store the domains must use this class
"""

id = saffier.BigIntegerField(primary_key=True)
domain = saffier.CharField(max_length=253, unique=True, db_index=True)
tenant = saffier.ForeignKey(
settings.tenant_model, index=True, on_delete=saffier.CASCADE, related_name="domains"
Expand Down Expand Up @@ -144,6 +146,7 @@ class TenantUserMixin(saffier.Model):
Mapping between user and a client (tenant).
"""

id = saffier.BigIntegerField(primary_key=True)
user = saffier.ForeignKey(
settings.auth_user_model,
null=False,
Expand Down
32 changes: 13 additions & 19 deletions saffier/core/db/models/metaclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from saffier.core.connection.registry import Registry
from saffier.core.db import fields as saffier_fields
from saffier.core.db.datastructures import Index, UniqueConstraint
from saffier.core.db.fields import BigIntegerField, Field
from saffier.core.db.fields import Field
from saffier.core.db.models.managers import Manager
from saffier.core.db.relationships.related import RelatedField
from saffier.core.db.relationships.relation import Relation
Expand Down Expand Up @@ -241,27 +241,21 @@ def __search_for_fields(base: Type, attrs: Any) -> None:
# Making sure the inherited fields are before the new defined.
attrs = {**inherited_fields, **attrs}

# Handle with multiple primary keys and auto generated field if no primary key is provided
if name != "Model":
is_pk_present = False
# Check that the user-defined table has 1 and only 1 primary key.
meta = MetaInfo(meta_class)
pk_name_list = []
if meta.registry and not meta.abstract:
for key, value in attrs.items():
if isinstance(value, Field):
if value.primary_key:
if is_pk_present:
raise ImproperlyConfigured(
f"Cannot create model {name} with multiple primary keys."
)
is_pk_present = True
pk_attribute = key

if not is_pk_present and not getattr(meta_class, "abstract", None):
if "id" not in attrs:
attrs = {"id": BigIntegerField(primary_key=True, autoincrement=True), **attrs}

if not isinstance(attrs["id"], Field) or not attrs["id"].primary_key:
raise ImproperlyConfigured(
f"Cannot create model {name} without explicit primary key if field 'id' is already present."
)
pk_name_list.append(key)
if not pk_name_list:
raise ImproperlyConfigured("Table has to have a primary key.")
if len(pk_name_list) > 1:
raise ImproperlyConfigured(
f"Cannot create model {name} with multiple primary keys."
)
pk_attribute = pk_name_list.pop()

for key, value in attrs.items():
if isinstance(value, Field):
Expand Down
1 change: 0 additions & 1 deletion saffier/py.typed
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@

2 changes: 2 additions & 0 deletions tests/clauses/test_and_clauses.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)
language = saffier.CharField(max_length=200, null=True)
email = saffier.EmailField(null=True, max_length=255)
Expand All @@ -21,6 +22,7 @@ class Meta:


class Product(saffier.Model):
id = saffier.IntegerField(primary_key=True)
user = saffier.ForeignKey(User, related_name="products")

class Meta:
Expand Down
1 change: 1 addition & 0 deletions tests/clauses/test_not_clauses.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)
language = saffier.CharField(max_length=200, null=True)
email = saffier.EmailField(null=True, max_length=255)
Expand Down
2 changes: 2 additions & 0 deletions tests/clauses/test_or_clauses.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)
language = saffier.CharField(max_length=200, null=True)
email = saffier.EmailField(null=True, max_length=255)
Expand All @@ -21,6 +22,7 @@ class Meta:


class Product(saffier.Model):
id = saffier.IntegerField(primary_key=True)
user = saffier.ForeignKey(User, related_name="products")

class Meta:
Expand Down
1 change: 1 addition & 0 deletions tests/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


class AppUser(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)

class Meta:
Expand Down
1 change: 1 addition & 0 deletions tests/cli/main_extra.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@


class AppUser(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)

class Meta:
Expand Down
3 changes: 3 additions & 0 deletions tests/cli/test_inspectdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255, index=True)
title = saffier.CharField(max_length=255, null=True)

Expand All @@ -21,6 +22,7 @@ class Meta:


class HubUser(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
title = saffier.CharField(max_length=255, null=True)
description = saffier.CharField(max_length=255, null=True)
Expand All @@ -34,6 +36,7 @@ class Meta:


class Transaction(saffier.Model):
id = saffier.IntegerField(primary_key=True)
amount = saffier.DecimalField(max_digits=9, decimal_places=2)
total = saffier.FloatField()

Expand Down
2 changes: 2 additions & 0 deletions tests/exclude_secrets/test_exclude.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@


class Base(saffier.Model):
id = saffier.IntegerField(primary_key=True)

class Meta:
abstract = True
registry = models
Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/m2m_string/test_many_to_many.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -37,6 +38,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToManyField("User")
albums = saffier.ManyToManyField("Album")
Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/m2m_string/test_many_to_many_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -37,6 +38,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToMany("User")
albums = saffier.ManyToMany("Album")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -36,6 +37,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToManyField("User", related_name="studio_users")
albums = saffier.ManyToManyField("Album", related_name="studio_albums")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -36,6 +37,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToMany("User", related_name="studio_users")
albums = saffier.ManyToMany("Album", related_name="studio_albums")
Expand Down
1 change: 1 addition & 0 deletions tests/foreign_keys/test_fk_related_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class Meta:


class Profile(saffier.Model):
id = saffier.IntegerField(primary_key=True)
user = saffier.ForeignKey(User, on_delete=saffier.CASCADE, null=False, related_name="profiles")
profile_type = saffier.CharField(max_length=255, null=False)

Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/test_many_to_many.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -37,6 +38,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToManyField(User)
albums = saffier.ManyToManyField(Album)
Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/test_many_to_many_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -37,6 +38,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToMany(User)
albums = saffier.ManyToMany(Album)
Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/test_many_to_many_field_related_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -36,6 +37,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToManyField(User, related_name="studio_users")
albums = saffier.ManyToManyField(Album, related_name="studio_albums")
Expand Down
2 changes: 2 additions & 0 deletions tests/foreign_keys/test_many_to_many_related_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)

class Meta:
Expand All @@ -36,6 +37,7 @@ class Meta:


class Studio(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
users = saffier.ManyToMany(User, related_name="studio_users")
albums = saffier.ManyToMany(Album, related_name="studio_albums")
Expand Down
2 changes: 2 additions & 0 deletions tests/indexes/test_indexes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def get_random_string(length):


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255, index=True)
title = saffier.CharField(max_length=255, null=True)

Expand All @@ -30,6 +31,7 @@ class Meta:


class HubUser(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
title = saffier.CharField(max_length=255, null=True)
description = saffier.CharField(max_length=255, null=True)
Expand Down
2 changes: 2 additions & 0 deletions tests/indexes/test_indexes_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def test_raises_value_error_on_wrong_max_length():
with pytest.raises(ValueError):

class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
title = saffier.CharField(max_length=255)

Expand All @@ -36,6 +37,7 @@ def test_raises_value_error_on_wrong_type_passed_fields():
with pytest.raises(ValueError):

class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=255)
title = saffier.CharField(max_length=255)

Expand Down
1 change: 1 addition & 0 deletions tests/integration/test_esmerald_tenant_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Meta:


class TenantUser(TenantUserMixin):
id = fields.IntegerField(primary_key=True)
user = fields.ForeignKey(
"User", null=False, blank=False, related_name="tenant_user_users_test"
)
Expand Down
2 changes: 2 additions & 0 deletions tests/managers/test_managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def get_queryset(self) -> QuerySet:


class User(saffier.Model):
id = saffier.IntegerField(primary_key=True)
name = saffier.CharField(max_length=100)
language = saffier.CharField(max_length=200, null=True)

Expand All @@ -27,6 +28,7 @@ class Meta:


class Product(saffier.Model):
id = saffier.IntegerField(primary_key=True)
active = ActiveManager()

name = saffier.CharField(max_length=100)
Expand Down
Loading

0 comments on commit f85273b

Please sign in to comment.