Skip to content

Add SQLite persistent repository - #38

Merged
patrickleet merged 3 commits into
feat/asyncfrom
feat/sqllite
May 25, 2026
Merged

patrickleet merged 3 commits into
feat/asyncfrom
feat/sqllite

Conversation

@patrickleet

@patrickleet patrickleet commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add feature-gated SqliteRepository with explicit SQLite migrations
  • persist async aggregate streams, transactional document read models, processed-message marks, and snapshots
  • add SQLite integration coverage and async repository docs

Verification

  • cargo check
  • cargo fmt --check
  • git diff --check
  • cargo test --test sqlite_repository --features sqlite
  • cargo test --all-features
  • cargo clippy --lib --all-features -- -D warnings
  • cargo clippy --test sqlite_repository --features sqlite -- -D warnings

Note: cargo clippy --all-targets --all-features -- -D warnings still fails on pre-existing unrelated test-target lints in tests/todos, tests/bomberman, and tests/sagas.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added optional SQLite support for async repositories, enabling event sourcing with SQLite as a database backend, including transactional commits, read models, and snapshots.
  • Documentation

    • Added SQLite adapter documentation with configuration and migration examples.
  • Tests

    • Added SQLite repository tests covering migrations, concurrency, and persistence.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f4f68348-e798-4fb5-8918-8c80cf5e3b98

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request adds a complete SQLite repository implementation as an optional feature for an event-sourced Rust framework. The PR includes schema migrations, the core SqliteRepository adapter with full transactional semantics, comprehensive end-to-end tests, and user documentation.

Changes

SQLite Repository Feature

Layer / File(s) Summary
Feature and dependency setup
Cargo.toml
Adds sqlite feature flag enabling optional sqlx and tokio dependencies; configures sqlx for SQLite runtime with default features disabled.
SQLite schema and migrations
migrations/sqlite/0001_initial.sql
Initial migration creates four tables: aggregate_events (composite PK on aggregate_type/id/sequence with CHECK constraints and indexes), transactional_read_models (document storage), read_model_processed_messages (processed-marker tracking), and aggregate_snapshots (version-keyed snapshots).
Module wiring and public API
src/lib.rs
Feature-gated conditional exposure of sqlite_repo module and public re-export of SqliteRepository at crate root.
SqliteRepository implementation
src/sqlite_repo/mod.rs
Implements AsyncGetStream (ordered event history loading), AsyncTransactionalCommit (single-transaction batched commits with version checks, read-model deduplication, snapshot upserts), AsyncReadModelSessionStore and AsyncReadModelStore (transactional document CRUD with explicit versioning), AsyncSnapshotStore (snapshot persistence), plus helpers for time serialization, codec validation, and SQLx error mapping.
End-to-end test coverage
tests/sqlite_repository/main.rs
Test aggregates, read models, and repository helper; validates event round-trip and ordering, stream identity isolation, optimistic concurrency conflicts, read-model and processed-marker persistence with deduplication, snapshot isolation, and unsupported codec error handling.
User documentation
docs/async-repositories.md
Documents SQLite adapter as optional feature with connection/migration examples, persistence scope (events, read-model documents, processed-messages, snapshots), and production-readiness positioning.

Sequence Diagram

sequenceDiagram
  participant Client
  participant SqliteRepository
  participant SQLTransaction
  participant Pool
  Client->>SqliteRepository: commit_batch(events, read_models)
  SqliteRepository->>Pool: begin transaction
  SQLTransaction->>SQLTransaction: check MAX(sequence) for version
  SQLTransaction->>SQLTransaction: validate codecs and sequence numbers
  SQLTransaction->>SQLTransaction: insert events<br/>(handle unique constraint→ConcurrentWrite)
  SQLTransaction->>SQLTransaction: apply read-model writes<br/>(upsert with dedup)
  SQLTransaction->>SQLTransaction: upsert snapshots
  Pool->>SQLTransaction: commit
  SqliteRepository-->>Client: ✓ streams marked committed
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 Hop-hop, a new store so bright,
SQLite tables hold events right,
Snapshots dance, reads persist true,
Transactions lock, concurrency too!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% 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 'Add SQLite persistent repository' is clear, specific, and directly describes the main change: introducing a new SQLite-backed repository implementation as evidenced by the new SqliteRepository struct, migrations, documentation, and tests.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sqllite

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

@patrickleet

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review this

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

@patrickleet Sure! I'll start reviewing PR #38 right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
docs/async-repositories.md (1)

45-46: ⚡ Quick win

Consider adding a brief note about enabling the feature flag.

While the documentation mentions the feature is optional, users might benefit from a quick reminder that they need to enable it in Cargo.toml:

sourced_rust = { version = "...", features = ["sqlite"] }

This would make the documentation more self-contained for developers unfamiliar with the codebase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/async-repositories.md` around lines 45 - 46, Add a short note telling
users to enable the optional sqlite feature in Cargo.toml so the exported
SqliteRepository is available; mention the exact feature name ("sqlite") and
show that they should add a dependency entry like sourced_rust with features =
["sqlite"] in their Cargo.toml, and place this note near the sentence that
introduces SqliteRepository in docs/async-repositories.md so readers see how to
enable the feature flag.
src/sqlite_repo/mod.rs (1)

1004-1015: 💤 Low value

Consider logging or flagging malformed timestamps.

system_time_from_storage silently returns UNIX_EPOCH when parsing fails. While this provides graceful degradation, it could mask data corruption issues. Since timestamps are metadata and not critical for correctness, this tradeoff is acceptable, but you may want to add tracing/logging for observability in production.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/sqlite_repo/mod.rs` around lines 1004 - 1015, The function
system_time_from_storage currently swallows malformed timestamp strings and
returns UNIX_EPOCH silently; update it to emit an observability signal (e.g.,
tracing::warn! or log::warn!) whenever parsing fails so malformed values are
visible in logs. Specifically, inside system_time_from_storage, when
split_once('.') returns None, when secs.parse::<u64>() fails, or when
nanos.parse::<u32>() fails, log a warning that includes the original value and
the parsing error/context (referencing the value, secs, nanos parsing attempts)
and then continue returning UNIX_EPOCH to preserve current behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@docs/async-repositories.md`:
- Around line 45-46: Add a short note telling users to enable the optional
sqlite feature in Cargo.toml so the exported SqliteRepository is available;
mention the exact feature name ("sqlite") and show that they should add a
dependency entry like sourced_rust with features = ["sqlite"] in their
Cargo.toml, and place this note near the sentence that introduces
SqliteRepository in docs/async-repositories.md so readers see how to enable the
feature flag.

In `@src/sqlite_repo/mod.rs`:
- Around line 1004-1015: The function system_time_from_storage currently
swallows malformed timestamp strings and returns UNIX_EPOCH silently; update it
to emit an observability signal (e.g., tracing::warn! or log::warn!) whenever
parsing fails so malformed values are visible in logs. Specifically, inside
system_time_from_storage, when split_once('.') returns None, when
secs.parse::<u64>() fails, or when nanos.parse::<u32>() fails, log a warning
that includes the original value and the parsing error/context (referencing the
value, secs, nanos parsing attempts) and then continue returning UNIX_EPOCH to
preserve current behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c396a1ab-ea6a-44b7-be85-d8a325e0118b

📥 Commits

Reviewing files that changed from the base of the PR and between 05618e4 and 742dedf.

📒 Files selected for processing (6)
  • Cargo.toml
  • docs/async-repositories.md
  • migrations/sqlite/0001_initial.sql
  • src/lib.rs
  • src/sqlite_repo/mod.rs
  • tests/sqlite_repository/main.rs

Implements [[tasks/extract-shared-sqlx-repository-helpers]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant