use std::marker::PhantomData;
use crate::orm::{DatabaseConnection, QueryRow};
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct ManyToManyConfig<PK> {
pub source_pk: PK,
pub through_table: String,
pub source_field: String,
pub target_field: String,
}
impl<PK> ManyToManyConfig<PK> {
pub fn new(
source_pk: PK,
through_table: String,
source_field: String,
target_field: String,
) -> Self {
Self {
source_pk,
through_table,
source_field,
target_field,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(bound = "")]
pub struct ManyToManyField<Source, Target, S = ()>(PhantomData<(Source, Target, S)>);
impl<Source, Target, S> Default for ManyToManyField<Source, Target, S> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<Source, Target, S> ManyToManyField<Source, Target, S> {
#[inline]
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<Source, Target, S> ManyToManyField<Source, Target, S>
where
Source: std::fmt::Display,
Target: std::fmt::Display,
{
fn get_manager<PK>(
&self,
config: ManyToManyConfig<PK>,
) -> crate::prelude::many_to_many_manager::ManyToManyManager<Source, Target, PK>
where
PK: std::fmt::Display + Clone,
{
crate::prelude::many_to_many_manager::ManyToManyManager::new(
config.source_pk,
config.through_table,
config.source_field,
config.target_field,
)
}
pub async fn add_with_db<PK, TPK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
target_pk: TPK,
) -> reinhardt_core::exception::Result<()>
where
PK: std::fmt::Display + Clone,
TPK: std::fmt::Display,
{
self.get_manager(config).add_with_db(conn, target_pk).await
}
pub async fn remove_with_db<PK, TPK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
target_pk: TPK,
) -> reinhardt_core::exception::Result<()>
where
PK: std::fmt::Display + Clone,
TPK: std::fmt::Display,
{
self.get_manager(config)
.remove_with_db(conn, target_pk)
.await
}
pub async fn contains_with_db<PK, TPK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
target_pk: TPK,
) -> reinhardt_core::exception::Result<bool>
where
PK: std::fmt::Display + Clone,
TPK: std::fmt::Display,
{
self.get_manager(config)
.contains_with_db(conn, target_pk)
.await
}
pub async fn all_with_db<PK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
target_table: &str,
target_pk_field: &str,
) -> reinhardt_core::exception::Result<Vec<QueryRow>>
where
PK: std::fmt::Display + Clone,
{
self.get_manager(config)
.all_with_db(conn, target_table, target_pk_field)
.await
}
pub async fn clear_with_db<PK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
) -> reinhardt_core::exception::Result<()>
where
PK: std::fmt::Display + Clone,
{
self.get_manager(config).clear_with_db(conn).await
}
pub async fn count_with_db<PK>(
&self,
conn: &DatabaseConnection,
config: ManyToManyConfig<PK>,
) -> reinhardt_core::exception::Result<usize>
where
PK: std::fmt::Display + Clone,
{
self.get_manager(config).count_with_db(conn).await
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(bound = "")]
pub struct ForeignKeyField<T>(PhantomData<T>);
impl<T> Default for ForeignKeyField<T> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T> ForeignKeyField<T> {
#[inline]
pub const fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(bound = "")]
pub struct OneToOneField<T>(PhantomData<T>);
impl<T> Default for OneToOneField<T> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T> OneToOneField<T> {
#[inline]
pub const fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct OneToManyField<T, S = ()>(PhantomData<(T, S)>);
impl<T, S> OneToManyField<T, S> {
#[inline]
pub const fn new() -> Self {
Self(PhantomData)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct PolymorphicManyToManyField<K, S = ()>(PhantomData<(K, S)>);
impl<K, S> PolymorphicManyToManyField<K, S> {
#[inline]
pub const fn new() -> Self {
Self(PhantomData)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_many_to_many_field_creation() {
struct User;
struct Group;
let _field: ManyToManyField<User, Group> = ManyToManyField::new();
}
#[test]
fn test_many_to_many_field_self_referential() {
struct User;
let _field: ManyToManyField<User, User> = ManyToManyField::new();
}
#[test]
fn test_one_to_many_field_creation() {
struct Post;
let _field: OneToManyField<Post> = OneToManyField::new();
}
#[test]
fn test_polymorphic_many_to_many_field_creation() {
let _field: PolymorphicManyToManyField<i64> = PolymorphicManyToManyField::new();
}
#[test]
fn test_default_impl() {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
struct Article;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
struct Tag;
let field1: ManyToManyField<Article, Tag> = ManyToManyField::default();
let field2: ManyToManyField<Article, Tag> = ManyToManyField::new();
assert_eq!(field1, field2);
}
#[test]
fn test_many_to_many_field_with_metadata() {
struct User;
struct Tag;
struct OrderedRelation;
let _field1: ManyToManyField<User, Tag> = ManyToManyField::new();
let _field2: ManyToManyField<User, Tag, OrderedRelation> = ManyToManyField::new();
}
#[test]
fn test_foreign_key_field_creation() {
struct User;
let _field: ForeignKeyField<User> = ForeignKeyField::new();
}
#[test]
fn test_foreign_key_field_default() {
#[derive(Debug, PartialEq)]
struct User;
let field1: ForeignKeyField<User> = ForeignKeyField::default();
let field2: ForeignKeyField<User> = ForeignKeyField::new();
assert_eq!(field1, field2);
}
#[test]
fn test_one_to_one_field_creation() {
struct User;
let _field: OneToOneField<User> = OneToOneField::new();
}
#[test]
fn test_one_to_one_field_default() {
#[derive(Debug, PartialEq)]
struct User;
let field1: OneToOneField<User> = OneToOneField::default();
let field2: OneToOneField<User> = OneToOneField::new();
assert_eq!(field1, field2);
}
}