Skip to content

Commit

Permalink
feat: verify the service has an identity before updating. (#71)
Browse files Browse the repository at this point in the history
Co-authored-by: Peter Schutt <peter.github@proton.me>
  • Loading branch information
cofin and peterschutt committed Oct 24, 2023
1 parent f74cad4 commit 3a2ced4
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 0 deletions.
7 changes: 7 additions & 0 deletions advanced_alchemy/service/_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from sqlalchemy.orm import InstrumentedAttribute

from advanced_alchemy.exceptions import RepositoryError
from advanced_alchemy.repository._util import model_from_dict
from advanced_alchemy.repository.typing import ModelT

Expand Down Expand Up @@ -316,6 +317,12 @@ async def update(
data = await self.to_model(data, "update")
if isinstance(id_attribute, InstrumentedAttribute):
id_attribute = cast("str", id_attribute.description)
if item_id is None and self.repository.get_id_attribute_value(item=data, id_attribute=id_attribute) is None:
msg = (
"Could not identify ID attribute value. One of the following is required: "
f"``item_id`` or ``data.{id_attribute or self.repository.id_attribute}``"
)
raise RepositoryError(msg)
if item_id is not None:
data = self.repository.set_id_attribute_value(item_id=item_id, item=data, id_attribute=id_attribute)
return await self.repository.update(
Expand Down
7 changes: 7 additions & 0 deletions advanced_alchemy/service/_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from sqlalchemy.orm import InstrumentedAttribute, Session

from advanced_alchemy.exceptions import RepositoryError
from advanced_alchemy.repository._util import model_from_dict
from advanced_alchemy.repository.typing import ModelT

Expand Down Expand Up @@ -317,6 +318,12 @@ def update(
data = self.to_model(data, "update")
if isinstance(id_attribute, InstrumentedAttribute):
id_attribute = cast("str", id_attribute.description)
if item_id is None and self.repository.get_id_attribute_value(item=data, id_attribute=id_attribute) is None:
msg = (
"Could not identify ID attribute value. One of the following is required: "
f"``item_id`` or ``data.{id_attribute or self.repository.id_attribute}``"
)
raise RepositoryError(msg)
if item_id is not None:
data = self.repository.set_id_attribute_value(item_id=item_id, item=data, id_attribute=id_attribute)
return self.repository.update(
Expand Down
5 changes: 5 additions & 0 deletions tests/integration/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,3 +1550,8 @@ async def test_repo_get_or_create_deprecation(author_repo: AuthorRepository, fir
existing_obj, existing_created = await maybe_async(author_repo.get_or_create(name="Agatha Christie"))
assert existing_obj.id == first_author_id
assert existing_created is False


async def test_service_update_no_pk(author_service: AuthorService) -> None:
with pytest.raises(RepositoryError):
_existing_obj = await maybe_async(author_service.update(data={"name": "Agatha Christie"}))

0 comments on commit 3a2ced4

Please sign in to comment.