use std::marker::PhantomData;
use sea_orm::EntityTrait;
#[derive(Debug, Clone)]
pub struct ForwardManyToOneDescriptor<Source: EntityTrait, Target: EntityTrait> {
pub field_name: String,
pub related_model: String,
_source: PhantomData<Source>,
_target: PhantomData<Target>,
}
impl<S: EntityTrait, T: EntityTrait> ForwardManyToOneDescriptor<S, T> {
#[must_use]
pub fn new(field_name: impl Into<String>, related_model: impl Into<String>) -> Self {
Self {
field_name: field_name.into(),
related_model: related_model.into(),
_source: PhantomData,
_target: PhantomData,
}
}
#[must_use]
pub fn field_name(&self) -> &str {
&self.field_name
}
#[must_use]
pub fn related_model(&self) -> &str {
&self.related_model
}
#[must_use]
pub fn describe(&self) -> String {
format!(
"ForwardManyToOne({} -> {})",
self.field_name, self.related_model
)
}
}
#[derive(Debug, Clone)]
pub struct ForwardOneToOneDescriptor<Source: EntityTrait, Target: EntityTrait> {
pub field_name: String,
pub related_model: String,
_source: PhantomData<Source>,
_target: PhantomData<Target>,
}
impl<S: EntityTrait, T: EntityTrait> ForwardOneToOneDescriptor<S, T> {
#[must_use]
pub fn new(field_name: impl Into<String>, related_model: impl Into<String>) -> Self {
Self {
field_name: field_name.into(),
related_model: related_model.into(),
_source: PhantomData,
_target: PhantomData,
}
}
#[must_use]
pub fn field_name(&self) -> &str {
&self.field_name
}
#[must_use]
pub fn related_model(&self) -> &str {
&self.related_model
}
#[must_use]
pub fn describe(&self) -> String {
format!(
"ForwardOneToOne({} -> {})",
self.field_name, self.related_model
)
}
}
#[derive(Debug, Clone)]
pub struct ReverseOneToOneDescriptor<Source: EntityTrait, Target: EntityTrait> {
pub related_name: String,
pub related_model: String,
_source: PhantomData<Source>,
_target: PhantomData<Target>,
}
impl<S: EntityTrait, T: EntityTrait> ReverseOneToOneDescriptor<S, T> {
#[must_use]
pub fn new(related_name: impl Into<String>, related_model: impl Into<String>) -> Self {
Self {
related_name: related_name.into(),
related_model: related_model.into(),
_source: PhantomData,
_target: PhantomData,
}
}
#[must_use]
pub fn related_name(&self) -> &str {
&self.related_name
}
#[must_use]
pub fn related_model(&self) -> &str {
&self.related_model
}
#[must_use]
pub fn describe(&self) -> String {
format!(
"ReverseOneToOne({} <- {})",
self.related_name, self.related_model
)
}
}
#[derive(Debug, Clone)]
pub struct ReverseManyToOneDescriptor<Source: EntityTrait, Target: EntityTrait> {
pub related_name: String,
pub related_model: String,
_source: PhantomData<Source>,
_target: PhantomData<Target>,
}
impl<S: EntityTrait, T: EntityTrait> ReverseManyToOneDescriptor<S, T> {
#[must_use]
pub fn new(related_name: impl Into<String>, related_model: impl Into<String>) -> Self {
Self {
related_name: related_name.into(),
related_model: related_model.into(),
_source: PhantomData,
_target: PhantomData,
}
}
#[must_use]
pub fn related_name(&self) -> &str {
&self.related_name
}
#[must_use]
pub fn related_model(&self) -> &str {
&self.related_model
}
#[must_use]
pub fn describe(&self) -> String {
format!(
"ReverseManyToOne({} <- {})",
self.related_name, self.related_model
)
}
}
#[derive(Debug, Clone)]
pub struct ManyToManyDescriptor<Source: EntityTrait, Target: EntityTrait> {
pub field_name: String,
pub related_model: String,
pub through_model: Option<String>,
pub symmetrical: bool,
_source: PhantomData<Source>,
_target: PhantomData<Target>,
}
impl<S: EntityTrait, T: EntityTrait> ManyToManyDescriptor<S, T> {
#[must_use]
pub fn new(
field_name: impl Into<String>,
related_model: impl Into<String>,
through_model: Option<String>,
symmetrical: bool,
) -> Self {
Self {
field_name: field_name.into(),
related_model: related_model.into(),
through_model,
symmetrical,
_source: PhantomData,
_target: PhantomData,
}
}
#[must_use]
pub fn field_name(&self) -> &str {
&self.field_name
}
#[must_use]
pub fn related_model(&self) -> &str {
&self.related_model
}
#[must_use]
pub fn through_model(&self) -> Option<&str> {
self.through_model.as_deref()
}
#[must_use]
pub fn symmetrical(&self) -> bool {
self.symmetrical
}
#[must_use]
pub fn describe(&self) -> String {
match self.through_model.as_deref() {
Some(through_model) => format!(
"ManyToMany({} <-> {} through={} symmetrical={})",
self.field_name, self.related_model, through_model, self.symmetrical
),
None => format!(
"ManyToMany({} <-> {} symmetrical={})",
self.field_name, self.related_model, self.symmetrical
),
}
}
}
#[cfg(test)]
mod tests {
use super::{
ForwardManyToOneDescriptor, ForwardOneToOneDescriptor, ManyToManyDescriptor,
ReverseManyToOneDescriptor, ReverseOneToOneDescriptor,
};
mod source_entity {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "books")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
}
impl ActiveModelBehavior for ActiveModel {}
}
mod target_entity {
use sea_orm::entity::prelude::*;
#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "authors")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
}
impl ActiveModelBehavior for ActiveModel {}
}
type ForwardMany = ForwardManyToOneDescriptor<source_entity::Entity, target_entity::Entity>;
type ForwardOne = ForwardOneToOneDescriptor<source_entity::Entity, target_entity::Entity>;
type ReverseOne = ReverseOneToOneDescriptor<source_entity::Entity, target_entity::Entity>;
type ReverseMany = ReverseManyToOneDescriptor<source_entity::Entity, target_entity::Entity>;
type ManyToMany = ManyToManyDescriptor<source_entity::Entity, target_entity::Entity>;
#[test]
fn forward_many_to_one_new_stores_field_name() {
let descriptor = ForwardMany::new("author", "Author");
assert_eq!(descriptor.field_name, "author");
}
#[test]
fn forward_many_to_one_new_stores_related_model() {
let descriptor = ForwardMany::new("author", "Author");
assert_eq!(descriptor.related_model, "Author");
}
#[test]
fn forward_many_to_one_field_name_getter() {
let descriptor = ForwardMany::new("author", "Author");
assert_eq!(descriptor.field_name(), "author");
}
#[test]
fn forward_many_to_one_related_model_getter() {
let descriptor = ForwardMany::new("author", "Author");
assert_eq!(descriptor.related_model(), "Author");
}
#[test]
fn forward_many_to_one_describe_mentions_relation() {
let descriptor = ForwardMany::new("author", "Author");
assert_eq!(descriptor.describe(), "ForwardManyToOne(author -> Author)");
}
#[test]
fn forward_one_to_one_new_stores_field_name() {
let descriptor = ForwardOne::new("profile", "Profile");
assert_eq!(descriptor.field_name, "profile");
}
#[test]
fn forward_one_to_one_new_stores_related_model() {
let descriptor = ForwardOne::new("profile", "Profile");
assert_eq!(descriptor.related_model, "Profile");
}
#[test]
fn forward_one_to_one_field_name_getter() {
let descriptor = ForwardOne::new("profile", "Profile");
assert_eq!(descriptor.field_name(), "profile");
}
#[test]
fn forward_one_to_one_related_model_getter() {
let descriptor = ForwardOne::new("profile", "Profile");
assert_eq!(descriptor.related_model(), "Profile");
}
#[test]
fn forward_one_to_one_describe_mentions_relation() {
let descriptor = ForwardOne::new("profile", "Profile");
assert_eq!(descriptor.describe(), "ForwardOneToOne(profile -> Profile)");
}
#[test]
fn reverse_one_to_one_new_stores_related_name() {
let descriptor = ReverseOne::new("user", "User");
assert_eq!(descriptor.related_name, "user");
}
#[test]
fn reverse_one_to_one_new_stores_related_model() {
let descriptor = ReverseOne::new("user", "User");
assert_eq!(descriptor.related_model, "User");
}
#[test]
fn reverse_one_to_one_related_name_getter() {
let descriptor = ReverseOne::new("user", "User");
assert_eq!(descriptor.related_name(), "user");
}
#[test]
fn reverse_one_to_one_related_model_getter() {
let descriptor = ReverseOne::new("user", "User");
assert_eq!(descriptor.related_model(), "User");
}
#[test]
fn reverse_one_to_one_describe_mentions_relation() {
let descriptor = ReverseOne::new("user", "User");
assert_eq!(descriptor.describe(), "ReverseOneToOne(user <- User)");
}
#[test]
fn reverse_many_to_one_new_stores_related_name() {
let descriptor = ReverseMany::new("books", "Book");
assert_eq!(descriptor.related_name, "books");
}
#[test]
fn reverse_many_to_one_new_stores_related_model() {
let descriptor = ReverseMany::new("books", "Book");
assert_eq!(descriptor.related_model, "Book");
}
#[test]
fn reverse_many_to_one_related_name_getter() {
let descriptor = ReverseMany::new("books", "Book");
assert_eq!(descriptor.related_name(), "books");
}
#[test]
fn reverse_many_to_one_related_model_getter() {
let descriptor = ReverseMany::new("books", "Book");
assert_eq!(descriptor.related_model(), "Book");
}
#[test]
fn reverse_many_to_one_describe_mentions_relation() {
let descriptor = ReverseMany::new("books", "Book");
assert_eq!(descriptor.describe(), "ReverseManyToOne(books <- Book)");
}
#[test]
fn many_to_many_new_stores_field_name() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(descriptor.field_name, "tags");
}
#[test]
fn many_to_many_new_stores_related_model() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(descriptor.related_model, "Tag");
}
#[test]
fn many_to_many_field_name_getter() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(descriptor.field_name(), "tags");
}
#[test]
fn many_to_many_related_model_getter() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(descriptor.related_model(), "Tag");
}
#[test]
fn many_to_many_through_model_getter_returns_value() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(descriptor.through_model(), Some("book_tags"));
}
#[test]
fn many_to_many_through_model_getter_handles_missing_value() {
let descriptor = ManyToMany::new("followers", "User", None, true);
assert_eq!(descriptor.through_model(), None);
}
#[test]
fn many_to_many_symmetrical_getter_reflects_flag() {
let descriptor = ManyToMany::new("followers", "User", None, true);
assert!(descriptor.symmetrical());
}
#[test]
fn many_to_many_describe_mentions_through_and_symmetry() {
let descriptor = ManyToMany::new("tags", "Tag", Some("book_tags".into()), false);
assert_eq!(
descriptor.describe(),
"ManyToMany(tags <-> Tag through=book_tags symmetrical=false)"
);
}
}