Conversation
|
run |
7f8889f to
bceb163
Compare
There was a problem hiding this comment.
Pull request overview
Implements full Donors CRUD functionality in the FastAPI backend, replacing the prior placeholder endpoints and introducing a small service layer to hold donor business logic.
Changes:
- Added donor CRUD service functions (list/create/get/update/delete) using
AsyncSession. - Implemented full REST CRUD endpoints for
/api/donorswired to the new service layer. - Introduced a
servicespackage initializer exportingdonor_service.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| backend/app/services/donors.py | Adds async CRUD service functions for the Donor model (DB read/write + rollback on failure). |
| backend/app/services/init.py | Exposes donor_service from the new services package. |
| backend/app/api/donors.py | Replaces placeholder donors endpoints with full CRUD routes calling into donor_service. |
Comments suppressed due to low confidence (3)
backend/app/api/donors.py:70
- This
except HTTPException: raise/except Exceptionpattern is repeated and largely redundant (re-raising an HTTPException has no effect). To keep endpoints consistent and reduce duplication, prefer letting exceptions bubble to a global handler (or catching specific DB exceptions) rather than wrapping each route.
except HTTPException:
raise
except Exception as e:
if get_settings().DEBUG:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=str(e),
) from e
raise
backend/app/services/donors.py:28
- Catching
Exceptionbroadly in the service makes it easy to accidentally treat non-DB failures (e.g., programmer errors) as transactional errors. Consider catching SQLAlchemy-specific exceptions (e.g., SQLAlchemyError) for the rollback path, and let unexpected exceptions propagate without being wrapped here.
try:
db_donor = Donor(**donor.model_dump())
db.add(db_donor)
await db.commit()
await db.refresh(db_donor)
return db_donor
except Exception:
await db.rollback()
raise
backend/app/services/donors.py:70
- Same broad
except Exceptionrollback pattern as create/update: consider narrowing this to SQLAlchemyError (or similar) so only DB/transaction errors trigger rollback handling, while unexpected exceptions can surface normally during development.
try:
await db.delete(donor)
await db.commit()
return True
except Exception:
await db.rollback()
raise
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
| if not donor: | ||
| return False | ||
| try: | ||
| await db.delete(donor) |
There was a problem hiding this comment.
Deleting a donor can fail here if that donor is still referenced by furniture.donor_id. In that case this will raise a foreign key error and the endpoint returns a 500 instead of a controlled client response.
Should either block deletion with a 4xx (for example 409) when linked furniture exists, or explicitly handle those dependent records.
There was a problem hiding this comment.
This is a good point, we might want to think about whether furniture should still exist if the donor is deleted. Is it safe to assume that if a donor is deleted, we should also delete all furniture associated with that donor?
To me, it doesn’t make much sense to throw an error just because a furniture item references a donor that’s being deleted. A bulk delete might make more sense here, otherwise someone would have to delete all the furniture before deleting the donor?
@kenzysoror thoughts?
There was a problem hiding this comment.
mmm really good catch! i spoke with the PMs and it seems we actually want to allow furniture to exist without a donor (e.g., if HAFB adds existing inventory into the platform when they first adopt it).
it turns out that we don't currently foresee any use cases where HAFB would need to delete a donor from the system. so for now, and given the above, we'd want deleting a donor to simply nullify the donor field within the associated furniture and keep the furniture intact.
updating the furniture schema to reflect this can be another PR, and i believe this delete logic should work as-is once that's done.
does this make sense @nuthanan06 @petersenmatthew ?
Jira ticket link
Jira ticket
Implementation description
Steps to test
What should reviewers focus on?
Checklist
Format for branch, commit, and PR title: docs/GIT.md.