Use RETURNING clause for INSERT, UPDATE, DELETE#426
Conversation
Replace the flush()+refresh() pattern with single-query RETURNING: - INSERT: insert().returning(LampModel) eliminates post-insert SELECT - UPDATE: update().returning(LampModel) eliminates pre-UPDATE SELECT and post-UPDATE refresh; trigger-updated updated_at is captured in the same query - DELETE: update().returning(LampModel.id) eliminates pre-UPDATE SELECT; missing row (not found) is detected from empty RETURNING result Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Refactors the PostgreSQL lamp repository to leverage PostgreSQL RETURNING via SQLAlchemy insert()/update().returning() so create/update/delete operations can retrieve affected rows in a single round-trip, and updates Claude local settings permissions.
Changes:
- Refactor
create()to useinsert(...).returning(...)instead ofadd()/flush()/refresh(). - Refactor
update()and softdelete()to useupdate(...).returning(...)rather thanselect()+ manual mutation. - Add
git fetch/git rebasecommands to Claude local settings allow-list.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/python/src/openapi_server/repositories/postgres_lamp_repository.py |
Moves CRUD writes to RETURNING-based SQLAlchemy statements to fetch updated rows in one operation. |
.claude/settings.local.json |
Expands allowed bash commands for local Claude tooling workflows. |
| update(LampModel) | ||
| .where(LampModel.id == UUID(lamp_entity.id), LampModel.deleted_at.is_(None)) | ||
| .values(is_on=lamp_entity.status) # Map status -> is_on; updated_at set by trigger | ||
| .returning(LampModel) |
There was a problem hiding this comment.
update(LampModel)...values(is_on=...) will execute an UPDATE every time update() is called, even when lamp_entity.status matches the current is_on value. With the updated_at trigger, this will bump updated_at and take a write lock on idempotent updates, which is a behavioral/operational change vs loading the row and letting the ORM skip no-op writes. Consider guarding the UPDATE with a predicate (e.g., only update when is_on is distinct from the new value) so no-op updates don’t modify timestamps or generate unnecessary writes.
| "Bash(tree:*)", | ||
| "Bash(git fetch origin main)", | ||
| "Bash(git rebase origin/main)" |
There was a problem hiding this comment.
This repo’s .gitignore ignores .claude/ except for .claude/settings.json and .claude/hooks/, so committing/modifying .claude/settings.local.json appears to go against the intended convention of keeping local-only Claude settings out of version control. Consider moving these permission additions into .claude/settings.json (if they should be shared) or removing/untracking settings.local.json from the repository so developers can keep local overrides without PR churn.
Refactor PostgreSQL operations to use SQLAlchemy's
insert(),update()statements with.returning()instead of manual object manipulation and flush/refresh cycles.Changes:
LampModel()instantiation +add()+flush()+refresh()withinsert().values().returning()select()+ manual attribute updates withupdate().values().returning()select()+ manual soft-delete withupdate().values(deleted_at=...).returning()This approach is more efficient and aligns with PostgreSQL best practices by retrieving updated rows in a single operation.