feat: one-to-many relation helper
Allow one to specify that a field of a model is a foreign key. It will generate a bunch of helper methods to query related entities from one entity.
This commit is contained in:
parent
32ef1f7b33
commit
5f45671b74
25 changed files with 764 additions and 140 deletions
20
lib/sqlxgentools_misc/Cargo.toml
Normal file
20
lib/sqlxgentools_misc/Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
[package]
|
||||
name = "sqlxgentools_misc"
|
||||
description = "Various misc class to use in applications that use sqlxgentools"
|
||||
publish = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
sqlx-core = { version = "=0.8.6" }
|
||||
sqlx-sqlite = { version = "=0.8.6", features = ["offline"] }
|
||||
fully_pub = "0.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[lib]
|
||||
|
||||
[lints.clippy]
|
||||
uninlined_format_args = "allow"
|
||||
92
lib/sqlxgentools_misc/src/lib.rs
Normal file
92
lib/sqlxgentools_misc/src/lib.rs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
use std::error::Error;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use fully_pub::fully_pub;
|
||||
|
||||
use serde::{Serialize, Serializer};
|
||||
use sqlx_core::any::{Any, AnyArgumentBuffer};
|
||||
use sqlx_core::database::Database;
|
||||
use sqlx_core::decode::Decode;
|
||||
use sqlx_core::encode::{Encode, IsNull};
|
||||
use sqlx_core::error::BoxDynError;
|
||||
use sqlx_core::types::Type;
|
||||
use sqlx_sqlite::{Sqlite, SqliteArgumentValue};
|
||||
|
||||
|
||||
#[fully_pub]
|
||||
trait DatabaseLine {
|
||||
fn id(&self) -> String;
|
||||
}
|
||||
|
||||
|
||||
/// Wrapper to mark a model field as foreign
|
||||
/// You can use a generic argument inside ForeignRef to point to the target model
|
||||
#[derive(Clone, Debug)]
|
||||
#[fully_pub]
|
||||
struct ForeignRef<T: Sized + DatabaseLine> {
|
||||
pub target_type: PhantomData<T>,
|
||||
pub target_id: String
|
||||
}
|
||||
|
||||
|
||||
// Implement serde Serialize for ForeignRef
|
||||
impl<T: Sized + DatabaseLine> Serialize for ForeignRef<T> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
// Serialize only the target_id as a string
|
||||
serializer.serialize_str(&self.target_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: Sized + DatabaseLine> ForeignRef<T> {
|
||||
pub fn new(entity: &T) -> ForeignRef<T> {
|
||||
ForeignRef {
|
||||
target_type: PhantomData,
|
||||
target_id: entity.id()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'r, DB: Database, T: Sized + DatabaseLine> Decode<'r, DB> for ForeignRef<T>
|
||||
where
|
||||
// we want to delegate some of the work to string decoding so let's make sure strings
|
||||
// are supported by the database
|
||||
&'r str: Decode<'r, DB>
|
||||
{
|
||||
fn decode(
|
||||
value: <DB as Database>::ValueRef<'r>,
|
||||
) -> Result<ForeignRef<T>, Box<dyn Error + 'static + Send + Sync>> {
|
||||
let value = <&str as Decode<DB>>::decode(value)?;
|
||||
|
||||
let ref_val: String = value.parse()?;
|
||||
|
||||
Ok(ForeignRef::<T> {
|
||||
target_type: PhantomData,
|
||||
target_id: ref_val
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DatabaseLine + Sized> Encode<'_, Any> for ForeignRef<T> {
|
||||
fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {
|
||||
<String as Encode<'_, Any>>::encode_by_ref(&self.target_id.to_string(), buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DatabaseLine + Sized> Type<Sqlite> for ForeignRef<T> {
|
||||
fn type_info() -> <Sqlite as Database>::TypeInfo {
|
||||
<String as Type<Sqlite>>::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: DatabaseLine + Sized> Encode<'_, Sqlite> for ForeignRef<T> {
|
||||
fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
|
||||
args.push(SqliteArgumentValue::Text(self.target_id.clone().into()));
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue