Skip to content

feat(core): rename_for_user returns the updated row - #184

Merged
InstaZDLL merged 1 commit into
mainfrom
feat/core-profile-rename-returning
May 30, 2026
Merged

feat(core): rename_for_user returns the updated row#184
InstaZDLL merged 1 commit into
mainfrom
feat/core-profile-rename-returning

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up on CodeRabbit's atomicity finding against waveflow-server PR #6. The server's PATCH handler did `rename_for_user` (bool) β†’ `get_for_user` (Option), which can flip to a misleading 404 if a concurrent DELETE commits between the two calls.

Change

`PostgresProfileRepository::rename_for_user` now returns `Option` and runs the SQL as `UPDATE … RETURNING …`. The updated row comes back in one round-trip; the caller no longer needs a post-rename SELECT, which eliminates the race window entirely.

`insert_for_user` and `touch_last_used_for_user` have the same two-statement shape today; left as-is since neither has an active consumer racing the read-back. Worth revisiting if they grow one.

Test plan

  • `cargo check --workspace --all-targets` βœ…
  • `cargo clippy --workspace --all-targets -- -D warnings` βœ…
  • `cargo test --workspace` βœ… (66 + 45 = 111 tests pass; the change is repository-internal, no callers in waveflow yet)
  • waveflow-server's PR chore: bump lofty from 0.22.4 to 0.24.0 in /src-tauriΒ #6 bumps the rev and simplifies the rename handler to consume the new shape.

Summary by CodeRabbit

Notes de version

  • Refactor
    • AmΓ©lioration de la fiabilitΓ© du systΓ¨me de gestion des profils lors des opΓ©rations de renommage, avec une meilleure validation de la propriΓ©tΓ© des donnΓ©es.

Review Change Stack

Follow-up on CodeRabbit's atomicity finding against
waveflow-server PR #6: the server handler did
`rename_for_user` (bool) β†’ `get_for_user` (Option<Profile>),
which can flip to a misleading 404 if a concurrent DELETE
commits between the two calls.

Change the signature to `Option<Profile>` and run the SQL as
`UPDATE … RETURNING id, user_id, name, color_id, avatar_hash,
data_dir, created_at, last_used_at` so the updated row comes
back in one round-trip. The caller no longer needs the post-
rename SELECT β€” eliminating the race window entirely.

`insert_for_user` and `touch_last_used_for_user` have the same
two-statement shape today; they're left as-is since neither has
an active consumer racing the read-back. Worth revisiting when
they grow one.
@InstaZDLL InstaZDLL added the scope: backend Rust/Tauri backend (src-tauri/) label May 30, 2026
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
πŸ“ Walkthrough

Walkthrough

La PR met Γ  jour le contrat et l'implΓ©mentation de la mΓ©thode rename_for_user dans le dΓ©pΓ΄t PostgreSQL, en passant d'un retour boolΓ©en (ligne affectΓ©e) Γ  un retour optionnel du profil mis Γ  jour via UPDATE ... RETURNING.

Changes

Signature et implΓ©mentation de rename_for_user

Couche / Fichier(s) RΓ©sumΓ©
Contrat et implΓ©mentation de rename_for_user
src-tauri/crates/core/src/repository/postgres/profile.rs
rename_for_user change de CoreResult<bool> Γ  CoreResult<Option<Profile>>, remplaΓ§ant rows_affected() par UPDATE ... RETURNING ... avec fetch_optional pour retourner le profil renommΓ© ou None si absent ou non propriΓ©taire.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • InstaZDLL/WaveFlow#183: La PR #183 introduit la mΓ©thode rename_for_user initiale ; cette PR en change le contrat et l'implΓ©mentation pour retourner le profil plutΓ΄t qu'un boolΓ©en.

Suggested labels

type: feat, size: l, scope: backend

Poem

✨ Une signature evolue avec grÒce,
Option<Profile> remplace le boolΓ©en,
RETURNING capture la trace
Du profil transformΓ©, enfin!
Plus juste, plus utile en tout bien. πŸš€

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
Title check βœ… Passed Le titre suit la convention Conventional Commits avec un scope kebab-case (core) et dΓ©crit clairement le changement principal : rename_for_user retourne maintenant la ligne mise Γ  jour.
Docstring Coverage βœ… Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.
Description check βœ… Passed La description suit le template avec un rΓ©sumΓ© clair, un plan de test dΓ©taillΓ© et une explication technique solide. Cependant, le titre n'est pas fourni explicitement et certaines sections du template ne sont pas remplies.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
πŸ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/core-profile-rename-returning

Comment @coderabbitai help to get the list of available commands and usage tips.

@InstaZDLL InstaZDLL added type: feat New feature size: s 10-50 lines labels May 30, 2026
@InstaZDLL InstaZDLL self-assigned this May 30, 2026
@InstaZDLL
InstaZDLL merged commit bfb899b into main May 30, 2026
14 checks passed
@InstaZDLL
InstaZDLL deleted the feat/core-profile-rename-returning branch May 30, 2026 10:52
InstaZDLL added a commit that referenced this pull request May 30, 2026
)

Same shape as the profile work in PRs #181 / #183 / #184: server-only
inherent methods that scope every query to both `profile_id` (the
resource's owning profile) and `user_id` (the request's authenticated
user). The single-tenant `LibraryRepository` trait stays untouched on
the desktop side, and `PostgresLibraryRepository` deliberately does
NOT implement it β€” a careless `Box<dyn LibraryRepository>` over the
Postgres backend would otherwise let user A walk user B's libraries.

Methods (5):
- `list_for_profile(profile_id, user_id)` β€” MRU-first, empty list
  when the user doesn't own the profile (no tenancy leak, no auth
  pre-check round-trip)
- `get_for_profile(id, profile_id, user_id)` β€” single row, `None`
  blurs missing / foreign-profile / foreign-user
- `insert_for_profile(draft, profile_id, user_id)` β€” `INSERT ...
  SELECT FROM profile WHERE id = $1 AND user_id = $7`, returns the
  inserted row via `RETURNING *` so the caller skips a follow-up
  SELECT (same race elimination as PR #184's rename_for_user)
- `update_for_profile(id, patch, now_ms, profile_id, user_id)` β€”
  COALESCE partial update, `UPDATE ... RETURNING *` for the same
  reason
- `delete_for_profile(id, profile_id, user_id)` β€” `EXISTS` clause on
  profile validates ownership without a separate join

Every SQL statement encodes the (profile_id, user_id) ownership pair
in its WHERE clause so the storage layer is the single point of
enforcement β€” no convention-by-comment, no handler-discipline gap.

Domain:
- `Library` gains `profile_id: i64` with `#[sqlx(default)]`, mirroring
  `Profile.user_id`. Desktop SELECTs that omit the column (no
  `profile_id` on the per-profile SQLite `library` table) still
  round-trip cleanly via the default. The lone desktop call site
  (`commands/library::create_library`) now sets `profile_id: 0`
  explicitly to match.

Counts (`track_count`, `album_count`, `artist_count`, `genre_count`,
`folder_count`) are stubbed at `0::bigint` in every SELECT for this
phase; they become real aggregates as tracks / albums / playlists
land in 1.b.5b+, without changing the wire shape.

Schema lives in `waveflow-server/migrations/` (next PR):
`library.profile_id BIGINT NOT NULL REFERENCES profile(id) ON
DELETE CASCADE` + the usual indices.

Zero behaviour change on the desktop. Validated: workspace check +
clippy + 111 tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: backend Rust/Tauri backend (src-tauri/) size: s 10-50 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant