Integrating sqlx::FromRow

⚓ Rust    📅 2025-10-02    👤 surdeus    👁️ 18      

surdeus

Warning

This post was published 109 days ago. The information described in this article may have changed.

Info

This post is auto-generated from RSS feed The Rust Programming Language Forum - Latest topics. Source: Integrating sqlx::FromRow

I 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

Read full topic

🏷️ Rust_feed