Integrating sqlx::FromRow
⚓ Rust 📅 2025-10-02 👤 surdeus 👁️ 18I am currently building a web framework and CMS using sqlx and sea_query to handle database stuff. I want to provide a simple API (as little boilerplate code as possible) for items that can be stored in the database.
I already have implemented a DatabaseSql trait with methods that return the appropriate sea_query::query::*Statements and a DatabaseItem trait to automatically provide methods for database operations for types that implement DatabaseSql + some trait for constructing that type from database rows.
sqlx provides such a trait (sqlx::FromRow), however there are some issues I have with it:
- Ideally I'd like to provide the option to not deal with sqlx directly
- It's a generic trait that doesn't ensure implementation for every database backend enabled
- The error type is restricted to
sqlx:Error - There's a proc macro however it can't handle more complex types (requiring writing weird boilerplate code) and i prefer to avoid them when it's not obvious what they do internally
I've tried various ways of abstracting over it to no avail, sqlx::Row isn't dyn compatible among other things
Ultimately this is sort of what i want the API to look like (i might even combine these into one trait):
use webcrust::{
assets::{Asset, AssetInstance},
database::{Database, DatabaseItem, DatabaseError}
#[derive(Clone)]
struct Cat {
name: String,
meows: u16
}
impl Cat {
fn meow(&mut self) {
println!("meow!");
self.meows += 1;
}
}
// allows it to be used in AssetInstance, will include more things later on
impl Asset for Cat {}
impl CustomFromRow for Cat {
fn db_from_row(row: CustomRow) -> Result<Self, DatabaseError> {
Self {
name: row.get("name")?,
meows: row.get("meows")?
}
}
}
// Assuming all of the above are implemented, some other traits
// get automatically implemented which the methods in AssetInstance
// rely on:
let db: Database = /* ... */;
let user: User = /* ... */;
let group: Group = /* ... */;
let mut cat = AssetInstance::<Cat>::create(
db.clone(),
Cat {
name: String::from("Beau"),
meows: 21
}
&user,
&group
)?;
cat.edit(|cat| { cat.meows += 21; });
cat.save(db)?;
(even this is a lot of boilerplate stuff, i plan on having at least a few core Asset types, plus User and Group and whatever else goes into the CMS along with whatever plugins)
Is this just generally a bad approach? Is there a database crate that supports mysql, sqlite and postgres and is easier to work with? Should I write my own proc macros?
1 post - 1 participant
🏷️ Rust_feed