use super::traits::{RelationshipFactory, RelationshipType};
use crate::error::OrmResult;
use crate::model::Model;
#[derive(Debug)]
pub struct HasOneFactory<Parent, Related> {
_phantom: std::marker::PhantomData<(Parent, Related)>,
}
impl<Parent, Related> Default for HasOneFactory<Parent, Related> {
fn default() -> Self {
Self::new()
}
}
impl<Parent, Related> HasOneFactory<Parent, Related> {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[async_trait::async_trait]
impl<Parent, Related> RelationshipFactory<Parent, Related> for HasOneFactory<Parent, Related>
where
Parent: Model + Send + Sync,
Related: Model + Send + Sync,
{
async fn create_for_parent(
&self,
_parent: &Parent,
_pool: &sqlx::Pool<sqlx::Postgres>,
) -> OrmResult<Vec<Related>> {
Ok(vec![])
}
async fn make_for_parent(&self, _parent: &Parent) -> OrmResult<Vec<Related>> {
Ok(vec![])
}
fn relationship_type(&self) -> RelationshipType {
RelationshipType::HasOne
}
}
#[derive(Debug)]
pub struct HasManyFactory<Parent, Related> {
count: usize,
_phantom: std::marker::PhantomData<(Parent, Related)>,
}
impl<Parent, Related> HasManyFactory<Parent, Related> {
pub fn new(count: usize) -> Self {
Self {
count,
_phantom: std::marker::PhantomData,
}
}
pub fn count(&self) -> usize {
self.count
}
}
#[async_trait::async_trait]
impl<Parent, Related> RelationshipFactory<Parent, Related> for HasManyFactory<Parent, Related>
where
Parent: Model + Send + Sync,
Related: Model + Send + Sync,
{
async fn create_for_parent(
&self,
_parent: &Parent,
_pool: &sqlx::Pool<sqlx::Postgres>,
) -> OrmResult<Vec<Related>> {
Ok(vec![])
}
async fn make_for_parent(&self, _parent: &Parent) -> OrmResult<Vec<Related>> {
Ok(vec![])
}
fn relationship_type(&self) -> RelationshipType {
RelationshipType::HasMany
}
}
#[derive(Debug)]
pub struct BelongsToFactory<Child, Parent> {
_phantom: std::marker::PhantomData<(Child, Parent)>,
}
impl<Child, Parent> Default for BelongsToFactory<Child, Parent> {
fn default() -> Self {
Self::new()
}
}
impl<Child, Parent> BelongsToFactory<Child, Parent> {
pub fn new() -> Self {
Self {
_phantom: std::marker::PhantomData,
}
}
}
#[async_trait::async_trait]
impl<Child, Parent> RelationshipFactory<Child, Parent> for BelongsToFactory<Child, Parent>
where
Child: Model + Send + Sync,
Parent: Model + Send + Sync,
{
async fn create_for_parent(
&self,
_parent: &Child,
_pool: &sqlx::Pool<sqlx::Postgres>,
) -> OrmResult<Vec<Parent>> {
Ok(vec![])
}
async fn make_for_parent(&self, _parent: &Child) -> OrmResult<Vec<Parent>> {
Ok(vec![])
}
fn relationship_type(&self) -> RelationshipType {
RelationshipType::BelongsTo
}
}
pub struct RelationshipBuilder<Parent, Related> {
factories: Vec<Box<dyn RelationshipFactory<Parent, Related>>>,
_phantom: std::marker::PhantomData<(Parent, Related)>,
}
impl<Parent, Related> Default for RelationshipBuilder<Parent, Related>
where
Parent: crate::model::Model + 'static,
Related: crate::model::Model + 'static,
{
fn default() -> Self {
Self::new()
}
}
impl<Parent, Related> RelationshipBuilder<Parent, Related>
where
Parent: crate::model::Model + 'static,
Related: crate::model::Model + 'static,
{
pub fn new() -> Self {
Self {
factories: Vec::new(),
_phantom: std::marker::PhantomData,
}
}
pub fn has_one(mut self) -> Self {
self.factories.push(Box::new(HasOneFactory::new()));
self
}
pub fn has_many(mut self, count: usize) -> Self {
self.factories.push(Box::new(HasManyFactory::new(count)));
self
}
pub fn belongs_to(self) -> Self {
self
}
pub async fn create_all_for_parent(
&self,
parent: &Parent,
pool: &sqlx::Pool<sqlx::Postgres>,
) -> OrmResult<Vec<Vec<Related>>>
where
Parent: Model + Send + Sync,
Related: Model + Send + Sync,
{
let mut all_related = Vec::new();
for factory in &self.factories {
let related = factory.create_for_parent(parent, pool).await?;
all_related.push(related);
}
Ok(all_related)
}
}
pub trait WithRelationships<Related: crate::model::Model> {
fn with_relationships() -> RelationshipBuilder<Self, Related>
where
Self: crate::model::Model + Sized + 'static,
Related: 'static,
{
RelationshipBuilder::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
struct MockModel;
impl crate::model::Model for MockModel {
type PrimaryKey = i32;
fn table_name() -> &'static str {
"mock_models"
}
fn primary_key(&self) -> Option<Self::PrimaryKey> {
Some(1)
}
fn set_primary_key(&mut self, _key: Self::PrimaryKey) {
}
fn to_fields(&self) -> std::collections::HashMap<String, serde_json::Value> {
std::collections::HashMap::new()
}
fn from_row(_row: &sqlx::postgres::PgRow) -> crate::error::ModelResult<Self> {
Ok(MockModel)
}
}
#[test]
fn test_relationship_factory_creation() {
let has_one_factory: HasOneFactory<MockModel, MockModel> = HasOneFactory::new();
assert_eq!(
has_one_factory.relationship_type(),
RelationshipType::HasOne
);
let has_many_factory: HasManyFactory<MockModel, MockModel> = HasManyFactory::new(5);
assert_eq!(
has_many_factory.relationship_type(),
RelationshipType::HasMany
);
let belongs_to_factory: BelongsToFactory<MockModel, MockModel> = BelongsToFactory::new();
assert_eq!(
belongs_to_factory.relationship_type(),
RelationshipType::BelongsTo
);
}
#[test]
fn test_relationship_builder() {
let builder: RelationshipBuilder<MockModel, MockModel> =
RelationshipBuilder::new().has_one().has_many(3);
assert_eq!(builder.factories.len(), 2);
}
}