Skip to content

chore: drop sqlx-crud from mostro-core#155

Merged
grunch merged 2 commits into
mainfrom
chore/remove-sqlx-crud
Jun 24, 2026
Merged

chore: drop sqlx-crud from mostro-core#155
grunch merged 2 commits into
mainfrom
chore/remove-sqlx-crud

Conversation

@arkanoider

@arkanoider arkanoider commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Remove the sqlx-crud dependency and SqlxCrud derives from Order, Dispute, and the four Restored* helpers (they only need FromRow).
  • Persistence for Order / Dispute is exclusively via mostro_core::db::Crud (landed in feat: add local Crud trait for Order and Dispute #154).
  • Refactor db/order.rs to drive INSERT/UPDATE SQL from a single ORDER_INSERT_COLUMNS list, with a guard test so column names and bind loops cannot diverge.

Follow-up (separate mostro PR): implement Crud for Bond, switch daemon imports to mostro_core::db::Crud, and remove sqlx-crud from mostrod.

Summary by CodeRabbit

  • Refactor
    • Streamlined database integration by removing an optional CRUD helper dependency and updating the SQL feature wiring accordingly.
    • Simplified SQL-backed data mapping to rely on standard row mapping rather than added CRUD-derived behavior.
    • Improved order insertion SQL generation by using a single, consistent set of persisted insert columns to keep column binding and round-trip behavior aligned.

Remove the unmaintained sqlx-crud dependency and SqlxCrud derives now
that Order and Dispute use db::Crud. Centralize Order INSERT columns
so insert/update SQL cannot drift from the bind list.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 53484cd4-7c54-4b26-b56e-83fd24840049

📥 Commits

Reviewing files that changed from the base of the PR and between 4a29cd4 and 88ba2cc.

📒 Files selected for processing (1)
  • src/db/order.rs

Walkthrough

Removes the sqlx-crud optional dependency from Cargo.toml and strips all SqlxCrud derives and imports from Order, Dispute, and four message helper structs. Introduces an ORDER_INSERT_COLUMNS constant in src/db/order.rs and updates Order::create to iterate over it instead of manually pushing column names.

Changes

Remove sqlx-crud and replace with custom SQL binding

Layer / File(s) Summary
Cargo.toml: drop sqlx-crud dependency and feature wiring
Cargo.toml
Removes the optional sqlx-crud dependency and removes dep:sqlx-crud from the sqlx feature list.
Strip SqlxCrud derives from Order, Dispute, and message helpers
src/order.rs, src/dispute.rs, src/message.rs
Removes SqlxCrud imports and narrows cfg_attr derives to FromRow-only on Order, Dispute, RestoredOrderHelper, RestoredDisputeHelper, RestoredOrdersInfo, and RestoredDisputesInfo.
Centralize order INSERT column list with ORDER_INSERT_COLUMNS
src/db/order.rs
Introduces ORDER_INSERT_COLUMNS constant listing persisted columns in bind order and updates Order::create to iterate over the constant instead of manually pushing each column name.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • MostroP2P/mostro-core#154: Introduced the in-tree db::Crud trait and custom Order/Dispute SQL implementations that this PR completes by removing the now-superseded SqlxCrud derives.

Suggested reviewers

  • AndreaDiazCorreia
  • Catrya
  • grunch

Poem

🐇 Hop away, sqlx-crud, off you go—
Hand-rolled columns steal the show!
ORDER_INSERT_COLUMNS, a list so clear,
No more magic traits, just what we steer.
The rabbit approves: explicit beats obscure,
Rust without the clutter, the code stays pure! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 'chore: drop sqlx-crud from mostro-core' is concise and clearly summarizes the main change: removing the sqlx-crud dependency and SqlxCrud derives from the codebase.
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 chore/remove-sqlx-crud

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@mostronatorcoder

Copy link
Copy Markdown

I did a pass on this PR and I do not currently see a blocker.

This looks like the right follow-up to #154.

What I specifically checked:

  • the removal of sqlx-crud derives from Order, Dispute, and the restored helper structs
  • the refactor in src/db/order.rs that centralizes the persisted column list instead of duplicating it across multiple insert/update helpers
  • whether the migration leaves mostro-core with a single obvious persistence path for Order / Dispute

From what I can see, the direction is cleaner now: the persistence story is more explicit, the dependency surface is smaller, and the risk of the old macro path drifting away from the in-tree path is gone.

I also like the move toward a single ORDER_INSERT_COLUMNS source of truth. That is a much better maintenance shape than repeating the same field list in several places.

So from my side this looks like a solid cleanup PR and a sensible completion step for the sqlx-crud removal on the core side.

@arkanoider arkanoider requested a review from grunch June 22, 2026 14:58

@ermeme ermeme 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.

Reviewed current head. The sqlx-crud removal looks clean and the new Crud path is well-scoped. One small nit: order_insert_bind_count() in src/db/order.rs currently returns ORDER_INSERT_COLUMNS.len(), so the new guard test compares the constant to itself and doesn't really catch bind-list drift. If you want that test to protect against regressions, consider asserting the generated bind count or removing the helper.

@grunch grunch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Strict review

Dropping sqlx-crud and the SqlxCrud derives is correct and well done — Order, Dispute, and the four Restored* helpers only need FromRow. I verified locally with the sqlx feature: build is green, 88 tests pass, clippy and fmt are clean, and the generated SQL is byte-for-byte equivalent to the previous hand-written builders. Cargo.lock is gitignored (library crate), so no lockfile churn is expected.

My concerns are entirely about the db/order.rs binding refactor that ships alongside the dependency removal. It does not deliver the safety the PR description claims, and it trades compile-time guarantees for a runtime panic path.

1. The "guard test" asserts nothing

The description sells "a guard test so column names and bind loops cannot diverge", but insert_column_list_matches_bind_count is tautological: order_insert_bind_count() returns ORDER_INSERT_COLUMNS.len(), so the headline assertion is len == len. The third assertion is also a tautology (order_update_columns() is literally &ORDER_INSERT_COLUMNS[1..]). The only real guard against drift is the roundtrip integration test, not this unit test. See inline comment.

2. Stringly-typed dispatch replaces compile errors with runtime panics

The old code was verbose but fully compile-checked. The new match column { "id" => ..., other => panic!(...) } means a column added to ORDER_INSERT_COLUMNS without a matching arm is no longer a compile error — it is a panic on the first INSERT/UPDATE in production. See inline comment.

3. "Single source of truth" is only partially true

There are now three full enumerations of the 46 columns that must stay in sync: ORDER_INSERT_COLUMNS, the 46 match arms in bind_order_column, and the Order struct / its FromRow. The refactor only removes the desync between the INSERT column list and the INSERT bind order (they now share one iterator) — a real but narrow win. The name→value mapping is still manual and can still drift; it now fails at runtime instead of at compile time. The drift surface was moved, not eliminated, at the cost of static checking.

Recommendation

  • Ship the sqlx-crud removal as-is.
  • Reconsider the db/order.rs refactor. Either keep the direct push_bind sequence (compile-time safe) plus the ORDER_INSERT_COLUMNS constant for names and rely on the roundtrip test, or — if a single exhaustive source is the goal — drive bind_order_column off an exhaustive enum OrderColumn instead of &str, so the compiler forces every new column to be handled. That would actually make divergence impossible.
  • At minimum, fix or delete insert_column_list_matches_bind_count; as written it gives false confidence.

Comment thread src/db/order.rs Outdated
"cashu_mint_url" => bind_column_value(sep, &order.cashu_mint_url, style),
"cashu_escrow_token" => bind_column_value(sep, &order.cashu_escrow_token, style),
"cashu_escrow_locked_at" => bind_column_value(sep, order.cashu_escrow_locked_at, style),
other => panic!("unmapped order column: {other}"),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Compile-time safety regression. This panic! arm only exists because dispatch is now keyed on a &str column name. If a column is added to ORDER_INSERT_COLUMNS but its match arm is forgotten, this is no longer a compile error — it panics on the first INSERT/UPDATE at runtime. The previous direct push_bind sequence had this checked by the compiler. If you want a single exhaustive source, key this on an exhaustive enum OrderColumn instead of &str so the compiler forces every new column to be handled.

Comment thread src/db/order.rs Outdated
Comment on lines +216 to +226
/// Mirrors the INSERT bind loop in [`push_order_insert_binds`].
fn order_insert_bind_count() -> usize {
ORDER_INSERT_COLUMNS.len()
}

#[test]
fn insert_column_list_matches_bind_count() {
assert_eq!(ORDER_INSERT_COLUMNS.len(), order_insert_bind_count());
assert_eq!(ORDER_INSERT_COLUMNS.first(), Some(&"id"));
assert_eq!(order_update_columns().len(), ORDER_INSERT_COLUMNS.len() - 1);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This guard test does not guard anything. order_insert_bind_count() returns ORDER_INSERT_COLUMNS.len(), so line 223 asserts len == len — a tautology. Line 225 is also tautological: order_update_columns() is defined as &ORDER_INSERT_COLUMNS[1..], so its length is always len - 1. Only the first() == Some(&"id") check carries weak signal. The PR description cites this as the mechanism that keeps column names and bind loops from diverging, but the actual divergence guard is the roundtrip test (which would hit the panic! arm). Please fix it to test something real (e.g. bind a sample order and assert no unmapped-column panic) or delete it — as-is it gives false confidence.

@arkanoider arkanoider requested a review from grunch June 23, 2026 20:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/db/order.rs`:
- Around line 61-107: The `Order` struct is missing a field that exists in the
`ORDERS_DDL` schema named `dispute_initiator_pubkey`, and the corresponding
binding call is missing from the INSERT statement. Add the
`dispute_initiator_pubkey` field to the `Order` struct with the appropriate
type, include it in the `ORDER_INSERT_COLUMNS` constant between
`cancel_initiator_pubkey` and `buyer_pubkey`, and add a
`.push_bind(&order.dispute_initiator_pubkey)` call in the binding function
between the push_bind calls for `cancel_initiator_pubkey` and `buyer_pubkey` to
match the schema column order.
🪄 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: 53484cd4-7c54-4b26-b56e-83fd24840049

📥 Commits

Reviewing files that changed from the base of the PR and between 4a29cd4 and 88ba2cc.

📒 Files selected for processing (1)
  • src/db/order.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@src/db/order.rs`:
- Around line 61-107: The `Order` struct is missing a field that exists in the
`ORDERS_DDL` schema named `dispute_initiator_pubkey`, and the corresponding
binding call is missing from the INSERT statement. Add the
`dispute_initiator_pubkey` field to the `Order` struct with the appropriate
type, include it in the `ORDER_INSERT_COLUMNS` constant between
`cancel_initiator_pubkey` and `buyer_pubkey`, and add a
`.push_bind(&order.dispute_initiator_pubkey)` call in the binding function
between the push_bind calls for `cancel_initiator_pubkey` and `buyer_pubkey` to
match the schema column order.
🪄 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: 53484cd4-7c54-4b26-b56e-83fd24840049

📥 Commits

Reviewing files that changed from the base of the PR and between 4a29cd4 and 88ba2cc.

📒 Files selected for processing (1)
  • src/db/order.rs
🛑 Comments failed to post (1)
src/db/order.rs (1)

61-107: 🗄️ Data Integrity & Integration | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if dispute_initiator_pubkey exists in Order struct and ORDER_INSERT_COLUMNS

# Check Order struct definition
echo "=== Order struct fields ==="
rg -n 'pub struct Order' -A 100 src/order.rs | rg 'dispute_initiator_pubkey'

# Check ORDER_INSERT_COLUMNS constant
echo -e "\n=== ORDER_INSERT_COLUMNS ==="
sed -n '11,59p' src/db/order.rs | rg -C2 'dispute_initiator_pubkey|ORDER_INSERT_COLUMNS'

# Verify column count
echo -e "\n=== Column count analysis ==="
echo "Schema columns (from test_support.rs):"
rg 'CREATE TABLE orders' -A 50 src/db/test_support.rs | rg '^\s+\w+' | wc -l
echo "Bind calls in push_order_insert_binds:"
sed -n '61,107p' src/db/order.rs | rg 'push_bind' | wc -l

Repository: MostroP2P/mostro-core

Length of output: 395


🏁 Script executed:

#!/bin/bash

echo "=== Full ORDER_INSERT_COLUMNS constant ==="
sed -n '11,59p' src/db/order.rs

echo -e "\n=== Full Order struct definition ==="
rg -n 'pub struct Order' -A 200 src/order.rs | head -150

echo -e "\n=== ORDERS_DDL schema definition (full) ==="
rg 'CREATE TABLE orders' -A 60 src/db/test_support.rs

Repository: MostroP2P/mostro-core

Length of output: 10399


Fix database schema or struct definition: dispute_initiator_pubkey column mismatch.

The ORDERS_DDL schema defines dispute_initiator_pubkey as a column (between cancel_initiator_pubkey and buyer_pubkey), but the Order struct has no corresponding field, and ORDER_INSERT_COLUMNS does not include it. This causes a schema-struct mismatch:

  • INSERT statements provide 46 columns but the schema expects 47.
  • SELECT with FromRow will fail when trying to deserialize the extra column.

Either remove dispute_initiator_pubkey from the ORDERS_DDL schema, or add the field to the Order struct and include it in ORDER_INSERT_COLUMNS and both binding functions.

🤖 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/db/order.rs` around lines 61 - 107, The `Order` struct is missing a field
that exists in the `ORDERS_DDL` schema named `dispute_initiator_pubkey`, and the
corresponding binding call is missing from the INSERT statement. Add the
`dispute_initiator_pubkey` field to the `Order` struct with the appropriate
type, include it in the `ORDER_INSERT_COLUMNS` constant between
`cancel_initiator_pubkey` and `buyer_pubkey`, and add a
`.push_bind(&order.dispute_initiator_pubkey)` call in the binding function
between the push_bind calls for `cancel_initiator_pubkey` and `buyer_pubkey` to
match the schema column order.

@mostronatorcoder

Copy link
Copy Markdown

I re-checked the current head after the follow-up changes, and the concerns raised in the strict review now look addressed to me.

In particular:

  • the string-dispatch refactor with the runtime panic!("unmapped order column: ...") is gone, so the compile-time safety regression concern is no longer present
  • the tautological “guard” test is also gone, so there is no longer a test pretending to protect against drift while only comparing constants derived from each other

The current version is more explicit again: ORDER_INSERT_COLUMNS is kept as the shared column list, while the actual bind/update logic stays handwritten in push_order_insert_binds(...) and push_order_update_set(...).

That is less clever, but also more robust, and I think it is the right trade here.

So from my side, the review comments about the reverted last commit now look satisfied.

@grunch grunch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Strict review — chore: drop sqlx-crud from mostro-core

Verdict: APPROVE

This is a clean, well-scoped, behavior-preserving change that removes an unmaintained dependency. It builds, lints, and tests green. The notes below are non-blocking (maintainability / documentation accuracy) and can be addressed in this PR or a follow-up.

What I verified locally (PR branch)

Check Result
cargo fmt --all -- --check ✅ clean
cargo clippy --features sqlx --all-targets -- -D warnings ✅ no warnings
cargo test --features sqlx ✅ 87 tests + 4 doctests, 0 failures
cargo build (default features)
cargo build --no-default-features ❌ fails — pre-existing on main (wasm_bindgen unguarded), NOT a regression from this PR
Residual sqlx_crud / SqlxCrud / external_id references ✅ none, except intentional doc comments in src/db/mod.rs
sqlx-crud in Cargo.lock ✅ removed

Correctness

  • Removing the SqlxCrud derive from Order and Dispute is safe: persistence now goes exclusively through mostro_core::db::Crud (landed in #154), and the db::order / db::dispute round-trip tests exercise create / update / by_id end to end.
  • The four Restored* helpers in message.rs only ever needed FromRow (they are read-only SELECT projections), so dropping SqlxCrud there has no functional impact.
  • The ORDER_INSERT_COLUMNS refactor is behavior-preserving. I diffed the three parallel lists:
    • ORDER_INSERT_COLUMNS (46) — identical sequence to the push_order_insert_binds bind order (46). ✅
    • push_order_update_set (45) — exactly INSERT columns minus id (the WHERE key). ✅

Non-blocking observations

  1. (MEDIUM) The PR description overstates the refactor. It says the change drives "INSERT/UPDATE SQL from a single ORDER_INSERT_COLUMNS list," but:

    • update() / push_order_update_set does not use the constant — it still hardcodes every column name inline.
    • The constant drives only the INSERT column names, not the bind list (push_order_insert_binds).

    So there are still three lists that must be kept in sync (the const, the insert binds, the update set), not one. The net effect is closer to "documented + reusable INSERT column list" than "single source of truth." Suggest softening the description.

  2. (MEDIUM) The "guard test" claim is weaker than stated. The doc comment says "Drift is caught by the roundtrip integration tests." In practice create_by_id_roundtrip mostly asserts fetched == created (self-consistency) rather than against known expected values, so a same-typed column/bind transposition (e.g. two i64 columns swapped) would not necessarily be detected, and nothing asserts ORDER_INSERT_COLUMNS.len() equals the bind count at compile time or in a test. A cheap, high-value guard would be a unit test asserting the column count, and/or asserting distinct sentinel values per field in sample_order. Note this risk is not newly introduced by this PR — it is roughly equal to the prior inline-list approach.

  3. (LOW) Cross-repo invariant in a comment. ORDER_INSERT_COLUMNS documents that it must stay in sync with mostrod migrations. That's a fragile cross-repo coupling to track via a comment, but acceptable given the planned follow-up mostro PR.

Conclusion

The primary goal — eliminating the unmaintained sqlx-crud dependency — is achieved cleanly with no behavioral change and full green CI locally. Approving. Please consider tightening the description (point 1) and adding a small length-assertion guard test (point 2).

@grunch grunch merged commit e221abb into main Jun 24, 2026
11 checks passed
@grunch grunch deleted the chore/remove-sqlx-crud branch June 24, 2026 18:24
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.

2 participants