Skip to content

feat(domain): SQLite repo for Package aggregate (task 26)#130

Merged
mpiton merged 4 commits intomainfrom
feat/task-26-repo-sqlite-packages
Apr 29, 2026
Merged

feat(domain): SQLite repo for Package aggregate (task 26)#130
mpiton merged 4 commits intomainfrom
feat/task-26-repo-sqlite-packages

Conversation

@mpiton
Copy link
Copy Markdown
Owner

@mpiton mpiton commented Apr 29, 2026

Summary

Persists the Package aggregate to SQLite with full CRUD operations and proper foreign key handling. Implements the repository pattern per PRD-v2 §P1.7, unblocking downstream package management tasks (27–31).

Why

Packages (containers, playlists, manual groups, split archives) were in-memory only. Persistence enables user workflows: install container → convert to package → redownload members, or group related downloads manually. Foreign key ON DELETE SET NULL preserves download records even if their package is deleted.

Changes

  • Domain : Refactored Package aggregate with typed PackageId (String, not u64) and new PackageSourceType enum (Container, Playlist, Manual, SplitArchive). Added setters for folder_path, password, auto_extract, priority. Kept in-memory download_ids vec separate from persisted FK inverse.
  • Port : New PackageRepository trait with methods find_by_id, save, list, delete, list_downloads. Contracts match hexagonal architecture (domain never knows about ORM).
  • Migration : m20260429_000007_create_packages creates table with TEXT primary key, source_type enum, optional folder_path/password, defaults for auto_extract (1) and priority (5). Adds package_id FK to downloads with SET NULL cascade. Creates idx_downloads_package.
  • Adapter : SqlitePackageRepo implements trait via sea-orm upsert (insert…on_conflict). Preserves created_at timestamp on update. Uses raw SQL for list_downloads since download entity FK not yet exposed (future task).
  • Entity : sea-orm model with into_domain() and from_domain() converters. Handles type conversions: source_type string ↔ enum, i64 timestamp → u64, validation on unknown enum variants.

Testing

  • 23 unit tests in package.rs covering creation, setters, source-type round-trip, reconstruction.
  • 19 unit tests in package_repo.rs covering save/find/list/delete, upsert with created_at preservation, FK SET NULL validation, list_downloads ordering.
  • 5 unit tests in ports/driven/tests.rs in-memory mock implementation.
  • In-database migration test verifies schema on fresh and migrated DBs (from pre-packages state).
  • Coverage: 99.73% (domain), 100% (entity), 98.82% (adapter). Acceptance criteria: [x] migration applies on fresh + existing, [x] FK SET NULL works, [x] all fields round-trip, [x] ≥85% coverage.

```bash
cargo test --workspace -- --nocapture
cargo llvm-cov --workspace --fail-under-lines 85
```

All 1204 tests pass (1201 existing + 3 new error-path).

Related Issues

  • Closes #Task-26
  • Refs PRD-v2 §P1.7, PRD §6.3
  • Unblocks Task-27 (Commands), Task-28 (Queries), Task-29 (Vue), Task-30 (Auto-grouping), Task-31 (Split archives)

Notes for Reviewer

  • package_id type changed from u64 to String (TEXT primary key in SQL). Required touching DomainEvent::PackageCreated to use PackageId wrapper instead of raw u64.
  • list_downloads() uses raw SQL parameterized query because download entity hasn't yet exposed the new package_id FK field (that wiring happens in future tasks). This keeps the repo self-contained without blocking on downstream changes.
  • save() explicitly excludes created_at from the upsert update columns via sea-orm's on_conflict().do_update().col() chain. This prevents timestamp mutation on subsequent saves.

Checklist

  • Tests added and passing (1204 total)
  • CHANGELOG.md updated
  • No .unwrap() outside tests
  • No new external dependencies
  • No warnings or clippy errors
  • Git workflow followed (feat/task-26 branch, conventional commit, clean tree)
  • Acceptance criteria met (85% coverage, FK validation, round-trip preservation, fresh + existing DB)
  • Self-reviewed diff
  • CI will be green

Summary by cubic

Adds SQLite persistence for packages with a new PackageRepository + SqlitePackageRepo, full CRUD, and strict validation. Implements Task-26 (PRD-v2 §P1.7) and updates events to use string PackageId.

  • New Features

    • Repository: find_by_id, save (upsert, preserves created_at), list (ordered by (created_at, id)), delete, list_downloads (ordered by queue_position; raw SQL now uses ? placeholder for SQLite).
    • Domain: PackageId(String), PackageSourceType (serializes as split_archive), setters; priority 1..=10 enforced; auto_extract is 0/1; created_at must be non-negative; DomainEvent::PackageCreated.id is PackageId.
  • Migration

    • Create real packages table; add downloads.package_id TEXT REFERENCES packages(id) ON DELETE SET NULL and idx_downloads_package.
    • Down migration restores the legacy packages table (BIGINT id, name, created_at).

Written for commit f13c1b2. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Persistent package storage with richer metadata, deterministic ordering, safe upserts, and preserved downloads when packages are removed.
    • Full Accounts management UI with quota-driven rotation, cooldown/expiry rules, extended selection strategies (including exclusions), credential import/export, and keyring-backed credential storage.
    • Improved package events and repository wiring for UI interactions via the app bridge.
  • Tests

    • Expanded migration, persistence, and round-trip tests covering ordering, upsert stability, detach behavior, and error cases.

Adds the persistence layer for packages per PRD-v2 §P1.7 / PRD §6.3:
- Migration `m20260429_000007` recreates the `packages` table with the
  full schema (TEXT id, source_type, folder_path, password, auto_extract,
  priority, created_at) and adds `downloads.package_id` as a FK with
  ON DELETE SET NULL plus the supporting index. The legacy stub table
  from migration 1 is dropped (never wired to a repo or query).
- New `PackageRepository` driven port with save/find_by_id/list/delete/
  list_downloads. `SqlitePackageRepo` adapter upserts via sea-orm with
  a stable `created_at` and orders `list_downloads` by queue_position.
- Domain `Package` aggregate gains `PackageId(String)` typed wrapper,
  `PackageSourceType` enum, plus the new persisted fields. The
  in-memory `download_ids` collection is unchanged (FK is the on-disk
  source of truth).
- `DomainEvent::PackageCreated.id` switches from u64 to PackageId.

Twenty-one new unit tests cover the four acceptance criteria
(fresh + existing-DB migration, FK SET NULL semantics, full-field
round-trip, ≥85% adapter coverage), plus error paths, source-type
round-trip per variant, and the `InMemoryPackageRepository` mock for
upcoming command/query handlers.

Unblocks tasks 27, 28, 30, 31.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

Adds full Package persistence: new SQLite migration, SeaORM entity, Package domain model with typed PackageId, a PackageRepository driven port and SQLite implementation with tests, updates DomainEvent/Tauri bridge to use PackageId, and re-exports the sqlite repo from the crate root.

Changes

Cohort / File(s) Summary
Migrations / Schema
src-tauri/src/adapters/driven/sqlite/migrations/m20260429_000007_create_packages.rs, src-tauri/src/adapters/driven/sqlite/migrations/mod.rs
Adds migration replacing legacy packages table with TEXT id, creates nullable downloads.package_id FK (ON DELETE SET NULL) and index; includes rollback restoring legacy stub.
SQLite Entities
src-tauri/src/adapters/driven/sqlite/entities/package.rs, src-tauri/src/adapters/driven/sqlite/entities/mod.rs
New SeaORM entity for packages with Model ↔ domain Package conversions, validation for auto_extract, priority, created_at; exports package entity module.
SQLite Repository & Adapter
src-tauri/src/adapters/driven/sqlite/package_repo.rs, src-tauri/src/adapters/driven/sqlite/mod.rs
Implements SqlitePackageRepo (find/save upsert preserving created_at, list ordered by created_at+id, delete, list_downloads via raw SQL) and re-exports module.
Migration Test
src-tauri/src/adapters/driven/sqlite/connection.rs
Adds Tokio integration test exercising partial → full migrations, asserting schema, index, FK column addition, and preservation of seeded data.
Domain Model & Types
src-tauri/src/domain/model/package.rs, src-tauri/src/domain/model/mod.rs
Replaces numeric id with PackageId newtype; expands model with source_type, optional folder_path/password, auto_extract, validated priority, created_at; adds new/reconstruct, getters, and tests.
Domain Ports & Tests
src-tauri/src/domain/ports/driven/package_repository.rs, src-tauri/src/domain/ports/driven/mod.rs, src-tauri/src/domain/ports/driven/tests.rs
Adds PackageRepository trait and in-memory test double mirroring SQLite semantics; tests for upsert behavior, ordering, delete/detach, and download listing.
Domain Events & Tauri Bridge
src-tauri/src/domain/event.rs, src-tauri/src/adapters/driven/event/tauri_bridge.rs
DomainEvent::PackageCreated now carries typed PackageId; updated tests assert Tauri payload mapping (id, name) and use PackageId.
Public API & Changelog
src-tauri/src/lib.rs, CHANGELOG.md
Re-exports SqlitePackageRepo from crate root; changelog updated to document package persistence and related changes.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Domain as DomainService
  participant Repo as SqlitePackageRepo
  participant DB as SQLite
  participant Tauri as TauriBridge

  Client->>Domain: create Package(PackageId, source, created_at)
  Domain->>Repo: save(package)
  Repo->>DB: UPSERT INTO packages (...) ON CONFLICT(id) DO UPDATE ...
  DB-->>Repo: OK / Row data
  Repo-->>Domain: saved
  Domain->>Tauri: emit DomainEvent::PackageCreated(PackageId,...)
  Tauri->>Client: to_tauri_event(payload{id: "pkg-1", name: "..."})
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🥕 I hop through rows and indexes bright,

Package ids now wear a proper name,
From domain burrow to SQLite night,
FK nibbles keep downloads tame,
I test and cheer — the repo's game! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: implementing a SQLite repository for the Package aggregate, which is the central focus of this PR's domain, port, migration, adapter, and testing additions.
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.

✏️ 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/task-26-repo-sqlite-packages

Review rate limit: 3/5 reviews remaining, refill in 13 minutes and 23 seconds.

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

@github-actions github-actions Bot added documentation Improvements or additions to documentation rust labels Apr 29, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b6be4c6ae2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src-tauri/src/adapters/driven/event/tauri_bridge.rs (1)

393-395: Assert the PackageCreated payload shape here too.

This change mostly affects the frontend contract: id is now a string. The test only checks the event name, so the bridge could regress back to a numeric payload unnoticed.

Suggested assertion
         assert_eq!(
             event_name(&DomainEvent::PackageCreated {
                 id: crate::domain::model::package::PackageId::new("pkg-1"),
                 name: "pkg".into()
             }),
             "package-created"
         );
+        let (_, payload) = to_tauri_event(&DomainEvent::PackageCreated {
+            id: crate::domain::model::package::PackageId::new("pkg-1"),
+            name: "pkg".into(),
+        });
+        assert_eq!(payload["id"], "pkg-1");
+        assert_eq!(payload["name"], "pkg");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/adapters/driven/event/tauri_bridge.rs` around lines 393 - 395,
The test currently only asserts the event name when constructing
DomainEvent::PackageCreated; update the test to also assert the event payload
shape by extracting/deserializing the emitted event payload and verifying that
the PackageCreated payload contains id as a string (e.g., "pkg-1") and name
"pkg"; locate the test that uses event_name(&DomainEvent::PackageCreated { ...
}) and add assertions against the payload (or use the existing helper that
returns the full event object) to check DomainEvent::PackageCreated.id is a
string and DomainEvent::PackageCreated.name == "pkg".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src-tauri/src/adapters/driven/sqlite/entities/package.rs`:
- Around line 27-44: The converter method into_domain currently coerces
self.auto_extract via self.auto_extract != 0 which silently treats invalid
values (e.g., 2 or -1) as true; change into_domain to explicitly validate
auto_extract so only 0 maps to false and 1 maps to true and return a
DomainError::ValidationError for any other value (include package id and the
invalid auto_extract value in the error message); update the call to
Package::reconstruct to pass the validated bool instead of self.auto_extract !=
0.

In `@src-tauri/src/domain/model/package.rs`:
- Around line 29-67: The enum PackageSourceType currently documents that values
are persisted as lower-snake-case but the Display/FromStr implementations use
"split-archive" for PackageSourceType::SplitArchive; update the
formatting/parsing to use "split_archive" to match the documented
lower_snake_case contract: change the fmt::Display match arm for
PackageSourceType::SplitArchive to return "split_archive" and change the FromStr
arm to accept "split_archive" (and keep other arms as-is) so Display and FromStr
round-trip consistently.
- Around line 70-71: The Package aggregate must enforce the 1..=10 priority
invariant at creation and mutation: update the reconstruct function and
set_priority method (and any constructor/associated fn that accepts a priority)
to validate the incoming u8 and reject values outside 1..=10 rather than
accepting them; return a Result (or domain error) on invalid input so the
aggregate cannot hold an invalid priority (use DEFAULT_PACKAGE_PRIORITY only as
a default when no explicit value is provided), and ensure error type/message
clearly indicates "priority must be between 1 and 10" while referencing the
Package::reconstruct and Package::set_priority code paths.

In `@src-tauri/src/domain/ports/driven/tests.rs`:
- Around line 746-753: The mock's attach_download currently appends downloads
but must preserve the ordering contract used by list_downloads/SqlitePackageRepo
(ordered by queue_position); change attach_download (and the similar helper
around the other occurrence) to insert each DownloadId into the package's Vec in
queue_position order instead of push-only — e.g., grab the Vec via
members.lock().unwrap().entry(...).or_default(), find the insertion index by
comparing download.queue_position with existing entries (binary_search_by or
linear scan) and insert at that index so list_downloads will return members
sorted by queue_position.

---

Nitpick comments:
In `@src-tauri/src/adapters/driven/event/tauri_bridge.rs`:
- Around line 393-395: The test currently only asserts the event name when
constructing DomainEvent::PackageCreated; update the test to also assert the
event payload shape by extracting/deserializing the emitted event payload and
verifying that the PackageCreated payload contains id as a string (e.g.,
"pkg-1") and name "pkg"; locate the test that uses
event_name(&DomainEvent::PackageCreated { ... }) and add assertions against the
payload (or use the existing helper that returns the full event object) to check
DomainEvent::PackageCreated.id is a string and DomainEvent::PackageCreated.name
== "pkg".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 48440ed0-f718-40e2-b5a1-755625ec63e2

📥 Commits

Reviewing files that changed from the base of the PR and between 96fe2fe and b6be4c6.

📒 Files selected for processing (16)
  • CHANGELOG.md
  • src-tauri/src/adapters/driven/event/tauri_bridge.rs
  • src-tauri/src/adapters/driven/sqlite/connection.rs
  • src-tauri/src/adapters/driven/sqlite/entities/mod.rs
  • src-tauri/src/adapters/driven/sqlite/entities/package.rs
  • src-tauri/src/adapters/driven/sqlite/migrations/m20260429_000007_create_packages.rs
  • src-tauri/src/adapters/driven/sqlite/migrations/mod.rs
  • src-tauri/src/adapters/driven/sqlite/mod.rs
  • src-tauri/src/adapters/driven/sqlite/package_repo.rs
  • src-tauri/src/domain/event.rs
  • src-tauri/src/domain/model/mod.rs
  • src-tauri/src/domain/model/package.rs
  • src-tauri/src/domain/ports/driven/mod.rs
  • src-tauri/src/domain/ports/driven/package_repository.rs
  • src-tauri/src/domain/ports/driven/tests.rs
  • src-tauri/src/lib.rs

Comment thread src-tauri/src/adapters/driven/sqlite/entities/package.rs Outdated
Comment thread src-tauri/src/domain/model/package.rs
Comment thread src-tauri/src/domain/model/package.rs
Comment thread src-tauri/src/domain/ports/driven/tests.rs Outdated
- Migration m20260429_000007 down() now restores the legacy packages
  table (BIGINT id, name, created_at) so rolling back lands on the
  same shape migration 6 had pre-007 instead of leaving migration
  state 6 with no packages table at all.
- entities/package.rs::Model::into_domain now rejects auto_extract
  values outside {0,1} via DomainError::ValidationError, matching the
  fail-fast behaviour already in place for source_type / priority /
  created_at.
- PackageSourceType::SplitArchive now serialises as "split_archive"
  (lower_snake_case) instead of "split-archive", matching the doc
  contract on the enum.
- Package::reconstruct + Package::set_priority enforce the documented
  1..=10 priority invariant inside the aggregate via a new
  validate_package_priority helper. reconstruct now returns
  Result<Self, DomainError>; set_priority returns Result<(), _>.
  All call sites updated.
- InMemoryPackageRepository mock now stores members as
  (queue_position, DownloadId) tuples and list_downloads sorts by
  queue_position, mirroring the SqlitePackageRepo contract so
  port-level tests cannot diverge from production.
- tauri_bridge PackageCreated test asserts the payload shape (id as
  string, name) in addition to the event name, so a regression to the
  numeric id payload would be caught.
@mpiton
Copy link
Copy Markdown
Owner Author

mpiton commented Apr 29, 2026

@coderabbitai

Addressed the nitpick on src-tauri/src/adapters/driven/event/tauri_bridge.rs:393-395 in b387f39 — the PackageCreated test now asserts the payload shape via to_tauri_event(&evt) and checks payload["id"] == "pkg-1" and payload["name"] == "pkg", so a regression to a numeric id payload would fail the test instead of slipping through.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Tip

For best results, initiate chat on the files or code changes.

@mpiton: Thanks for the update! The strengthened assertion — checking payload["id"] == "pkg-1" and payload["name"] == "pkg" via to_tauri_event(&evt) — is exactly the right approach. It ties the test to the actual serialised payload shape, so any future regression back to a numeric id will surface immediately as a test failure rather than silently passing.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src-tauri/src/adapters/driven/sqlite/entities/package.rs`:
- Around line 27-54: The converter into_domain currently silently normalizes
negative created_at via safe_u64(self.created_at); change it to validate
created_at first: if self.created_at is negative return
Err(DomainError::ValidationError(...)) with a clear message including self.id
and the invalid value, otherwise convert to u64 (e.g., call safe_u64 or cast)
and pass that into Package::reconstruct; update the into_domain function to
perform this check before constructing the Package so negative timestamps are
rejected like source_type, auto_extract, and priority.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e68c0beb-e3ec-47eb-a5a8-2e550c2b3296

📥 Commits

Reviewing files that changed from the base of the PR and between b6be4c6 and b387f39.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • src-tauri/src/adapters/driven/event/tauri_bridge.rs
  • src-tauri/src/adapters/driven/sqlite/entities/package.rs
  • src-tauri/src/adapters/driven/sqlite/migrations/m20260429_000007_create_packages.rs
  • src-tauri/src/adapters/driven/sqlite/package_repo.rs
  • src-tauri/src/domain/model/package.rs
  • src-tauri/src/domain/ports/driven/tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src-tauri/src/adapters/driven/sqlite/migrations/m20260429_000007_create_packages.rs

Comment thread src-tauri/src/adapters/driven/sqlite/entities/package.rs
Replace safe_u64(self.created_at) with strict u64::try_from on
Model::into_domain so a corrupt row carrying a negative timestamp
surfaces as DomainError::ValidationError instead of being silently
coerced to 0 and jumping to the front of the (created_at asc, id asc)
ordering used by find_by_id / list. Matches the fail-fast contract
already in place for source_type, auto_extract, and priority.
Drops the now-unused safe_u64 import. New regression test
test_find_by_id_rejects_negative_created_at seeds a row with
created_at = -1 and asserts the validation path.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src-tauri/src/adapters/driven/sqlite/package_repo.rs`:
- Around line 101-104: The SQL string passed to Statement::from_sql_and_values
with sea_orm::DatabaseBackend::Sqlite uses a PostgreSQL-style placeholder `$1`,
which SQLite does not accept; update the query in the call to query_all /
Statement::from_sql_and_values to use a `?` placeholder ("SELECT id FROM
downloads WHERE package_id = ? ORDER BY queue_position ASC, id ASC") and leave
the parameter list ([id_value.into()]) unchanged so the binding still works.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5d23d20f-86cf-4277-b40d-7d18086c920b

📥 Commits

Reviewing files that changed from the base of the PR and between b387f39 and 94558cf.

📒 Files selected for processing (2)
  • src-tauri/src/adapters/driven/sqlite/entities/package.rs
  • src-tauri/src/adapters/driven/sqlite/package_repo.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src-tauri/src/adapters/driven/sqlite/entities/package.rs

Comment thread src-tauri/src/adapters/driven/sqlite/package_repo.rs
Replace PostgreSQL-style `$1` placeholder with SQLite-native `?` in
the raw SQL passed to Statement::from_sql_and_values with
DatabaseBackend::Sqlite. Per SeaORM's raw SQL docs, SQLite expects
`?` and `$N` is reserved for the PostgreSQL backend. The query
behaviour was incidentally correct in tests but relied on SQLx's
compatibility layer; switching to `?` matches the documented
contract and the convention already used elsewhere in the
sqlite/ module.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src-tauri/src/adapters/driven/sqlite/package_repo.rs (1)

136-155: Parameterize the download seed helper instead of formatting package_id into SQL.

Now that PackageId is a String, this helper breaks on ids containing quotes and can hide repository failures behind malformed test SQL. Reuse Statement::from_sql_and_values here too; while you’re touching it, the doc comment above should stop claiming the helper returns an id.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/src/adapters/driven/sqlite/package_repo.rs` around lines 136 - 155,
The helper insert_download_in_package currently formats package_id directly into
the SQL string which breaks on quotes; change it to use a parameterized
statement via Statement::from_sql_and_values, binding download_id,
queue_position and package_id (use NULL when package_id is None) instead of
interpolating pkg, and call db.execute with that statement; also update the doc
comment above insert_download_in_package to remove the incorrect claim that it
returns an id.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src-tauri/src/adapters/driven/sqlite/package_repo.rs`:
- Around line 136-155: The helper insert_download_in_package currently formats
package_id directly into the SQL string which breaks on quotes; change it to use
a parameterized statement via Statement::from_sql_and_values, binding
download_id, queue_position and package_id (use NULL when package_id is None)
instead of interpolating pkg, and call db.execute with that statement; also
update the doc comment above insert_download_in_package to remove the incorrect
claim that it returns an id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 939320d6-0181-4dbc-8be1-9c7973e29e27

📥 Commits

Reviewing files that changed from the base of the PR and between 94558cf and f13c1b2.

📒 Files selected for processing (1)
  • src-tauri/src/adapters/driven/sqlite/package_repo.rs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation rust

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant