pub mod foreign_key;
pub mod joined_row;
pub mod many_to_many;
pub mod on_delete;
pub mod one_to_one;
pub mod path;
pub mod prefetch;
pub mod registry;
pub mod select_related;
pub use foreign_key::{ForeignKey, ForeignKeyResolved};
pub use joined_row::JoinedRow;
pub use many_to_many::ManyToMany;
pub use on_delete::OnDelete;
pub use one_to_one::{OneToOneField, OneToOneFieldResolved};
pub use path::{RelationKind, RelationPath};
pub use prefetch::PrefetchedRow;
#[doc(hidden)]
pub mod __macro_support {
use super::path::{RelationKind, RelationPath};
use crate::ident::assert_plain_ident;
use crate::model::Model;
#[doc(hidden)]
pub fn __make_relation_path<Source: Model, Target: Model>(
source_column: &'static str,
target_table: &'static str,
kind: RelationKind,
) -> RelationPath<Source, Target> {
assert_plain_ident(source_column, "source_column");
assert_plain_ident(target_table, "target_table");
RelationPath::new(source_column, target_table, kind)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::DjogiError;
use crate::descriptor::ModelDescriptor;
use std::future::Future;
struct Src;
struct Dst;
macro_rules! dummy_model {
($ty:ty, $table:literal) => {
impl crate::model::__sealed::Sealed for $ty {}
impl Model for $ty {
type Pk = crate::types::HeerId;
type Fields = ();
fn table_name() -> &'static str {
$table
}
fn pk_value(&self) -> &Self::Pk {
unreachable!()
}
fn descriptor() -> &'static ModelDescriptor {
unreachable!()
}
fn get(
_ctx: &mut crate::context::DjogiContext,
_id: Self::Pk,
) -> impl Future<Output = Result<Self, DjogiError>> + Send {
async { unreachable!() }
}
fn create(
_ctx: &mut crate::context::DjogiContext,
_v: Self,
) -> impl Future<Output = Result<Self, DjogiError>> + Send {
async { unreachable!() }
}
fn save<'ctx>(
&'ctx mut self,
_ctx: &'ctx mut crate::context::DjogiContext,
) -> impl Future<Output = Result<(), DjogiError>> + Send + 'ctx {
async { unreachable!() }
}
fn delete(
self,
_ctx: &mut crate::context::DjogiContext,
) -> impl Future<Output = Result<(), DjogiError>> + Send {
async { unreachable!() }
}
fn refresh_from_db<'ctx>(
&'ctx self,
_ctx: &'ctx mut crate::context::DjogiContext,
) -> impl Future<Output = Result<Self, DjogiError>> + Send + 'ctx {
async { unreachable!() }
}
}
};
}
dummy_model!(Src, "srcs");
dummy_model!(Dst, "dsts");
fn try_make(
source_column: &'static str,
target_table: &'static str,
) -> std::thread::Result<RelationPath<Src, Dst>> {
std::panic::catch_unwind(|| {
__make_relation_path::<Src, Dst>(
source_column,
target_table,
RelationKind::ForeignKey,
)
})
}
#[test]
fn accepts_plain_identifiers() {
assert!(try_make("owner_id", "owners").is_ok());
}
#[test]
fn validates_source_column() {
assert!(try_make("123", "owners").is_err());
}
#[test]
fn validates_target_table() {
assert!(try_make("owner_id", "select").is_err());
}
}
}