feat(infra): T-205 add LibsqlProjectRepo adapter (closes #73)#97
Conversation
Wire `LibsqlProjectRepo` for the `ProjectRepository` port introduced by T-204, mirroring `LibsqlTaskRepo`: per-call connection with `PRAGMA foreign_keys = ON`, `INSERT … RETURNING id` for the auto-increment rowid, epoch-ms round-trip via the shared time helpers. `map_db_err` routes `UNIQUE constraint failed: projects.path` to `DomainError::Conflict` (honouring the port-doc TOCTOU contract from `domain/projects/ports.rs`) and folds every other libsql error into `DomainError::IllegalState`. Issue #73 said `IllegalState` for the UNIQUE case, but the committed port contract wins as the long-term reference — the test was updated to assert `Conflict` and a companion test on a `NOT NULL` violation guards the substring match from widening into unrelated infrastructure failures. `AppContainer` now exposes `project_repo: Arc<dyn ProjectRepository>` wired from the same `Arc<Database>` as `task_repo`. 10 integration tests against a tempdir libsql DB plus a `di.rs` wiring test that seeds through `container.db` and reads back through `project_repo`. cargo test --workspace 223/223 green, clippy/fmt/architecture clean.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR introduces a libsql-backed ChangesProjectRepository Adapter and DI Integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Review Summary by QodoAdd LibsqlProjectRepo adapter and wire ProjectRepository port (T-205)
WalkthroughsDescription• Implement LibsqlProjectRepo adapter for ProjectRepository domain port • Wire project_repo on AppContainer backed by shared Arc<Database> • Map UNIQUE constraint violations to DomainError::Conflict per port contract • Add 10 integration tests + 1 DI wiring test with 100% coverage Diagramflowchart LR
A["ProjectRepository<br/>Domain Port"] -->|"implements"| B["LibsqlProjectRepo<br/>Adapter"]
B -->|"uses"| C["Arc<Database><br/>Shared Connection"]
D["AppContainer"] -->|"exposes"| E["project_repo:<br/>Arc<dyn ProjectRepository>"]
E -->|"backed by"| C
F["Error Mapping"] -->|"UNIQUE path<br/>→ Conflict"| G["DomainError"]
F -->|"other errors<br/>→ IllegalState"| G
File Changes1. src-tauri/src/infrastructure/persistence/projects_repo.rs
|
Code Review by Qodo
Context used 1. map_db_err returns Conflict
|
|
@qodo-code-review on finding #2 (
Fixed in e47e6b9. Discriminator now matches if msg.contains("UNIQUE constraint failed") && msg.contains("projects.path") {
DomainError::Conflict(...)
} else {
DomainError::IllegalState(...)
}A libsql wrapper-shape change around the SQLite phrase can no longer silently downgrade the duplicate-path case to |
|
@qodo-code-review on finding #3 (
Deferring as out of scope for T-205. The same
Touching only |
Summary
LibsqlProjectRepofor theProjectRepositoryport from T-204, mirroringLibsqlTaskRepo(per-call connection,PRAGMA foreign_keys = ON,INSERT … RETURNING id, epoch-ms round-trip).UNIQUE constraint failed: projects.path→DomainError::Conflict; all other libsql errors →DomainError::IllegalState.project_repo: Arc<dyn ProjectRepository>onAppContainerviaapplication/di.rs.Why
T-204 landed the
projectsdomain context with a port doc that mandatesConflicton a UNIQUE violation. T-205 is the libsql adapter that fulfils that contract so the in-process pre-check increate_projectand the storage-layer enforcement converge on the sameDomainErrorvariant.Contract note (issue text vs. port doc)
Issue #73 acceptance text says the UNIQUE violation should map to
DomainError::IllegalState. The committed port contract insrc-tauri/src/domain/projects/ports.rs(shipped with T-204) explicitly states:I deferred to the port-doc contract — it is the long-term reference future implementers will read, and semantically a duplicate path is a Conflict, not an internal Illegal state. Test asserts
Conflict; a companionnon_unique_db_errors_still_map_to_illegal_statetest (NOT NULL violation onprojects.name) guards the UNIQUE substring match from accidentally widening.Changes
src-tauri/src/infrastructure/persistence/projects_repo.rs— new adapter, 10 integration tests against tempdir libsql DB.src-tauri/src/infrastructure/persistence/mod.rs— register module.src-tauri/src/application/di.rs— wireproject_repoonAppContainer+ new wiring test (build_inner_exposes_project_repo_backed_by_same_database).CHANGELOG.md— Unreleased/Added entry.Test plan
cargo test --manifest-path src-tauri/Cargo.toml --workspace— 223/223 greencargo clippy --manifest-path src-tauri/Cargo.toml --workspace --all-targets -- -D warnings— cleancargo fmt --manifest-path src-tauri/Cargo.toml --check— cleancargo test --manifest-path src-tauri/Cargo.toml --test architecture— 2/2 pass (no infra imports leaked intodomain/)DomainError::ConflictDomainError::IllegalStategetreturnsNonefor unknown idAppContainer.project_repoandAppContainer.dbshare the sameArc<Database>Summary by CodeRabbit