siderite_orm/
relations.rs1use crate::db::Db;
12use crate::error::OrmError;
13use crate::model::{ManyToManyMeta, Model};
14use crate::types::{DbType, SqlType};
15use crate::value::Value;
16use serde::{Deserialize, Deserializer, Serialize, Serializer};
17use serde_json::Value as JsonValue;
18use siderite_validation::{
19 Dump, Schema, SchemaObject, SchemaRegistry, Validate, ValidationContext,
20};
21use std::sync::Arc;
22
23pub struct ForeignKey<T: Model> {
29 id: T::Pk,
30 cached: Option<Arc<T>>,
31}
32
33pub type OneToOne<T> = ForeignKey<T>;
35
36impl<T: Model> ForeignKey<T> {
37 pub fn new(id: T::Pk) -> Self {
39 Self { id, cached: None }
40 }
41
42 pub fn to(object: T) -> Self {
44 Self {
45 id: object.pk(),
46 cached: Some(Arc::new(object)),
47 }
48 }
49
50 pub fn id(&self) -> &T::Pk {
52 &self.id
53 }
54
55 pub fn cached(&self) -> Option<&T> {
57 self.cached.as_deref()
58 }
59
60 pub async fn get(&self, db: &Db) -> Result<Arc<T>, OrmError> {
67 if let Some(object) = &self.cached {
68 return Ok(Arc::clone(object));
69 }
70 let pk = T::META.pk().ok_or_else(|| {
71 crate::QueryError::Model(format!("{} has no primary key", T::META.name))
72 })?;
73 T::objects(db)
74 .get(crate::Expr::col(pk.column).eq(self.id.to_value()))
75 .await
76 .map(Arc::new)
77 }
78
79 pub fn set_cached(&mut self, object: Arc<T>) {
82 if object.pk() == self.id {
83 self.cached = Some(object);
84 }
85 }
86}
87
88impl<T: Model> Clone for ForeignKey<T> {
89 fn clone(&self) -> Self {
90 Self {
91 id: self.id.clone(),
92 cached: self.cached.clone(),
93 }
94 }
95}
96
97impl<T: Model> std::fmt::Debug for ForeignKey<T> {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.debug_struct("ForeignKey")
100 .field("model", &T::META.name)
101 .field("id", &self.id)
102 .field("loaded", &self.cached.is_some())
103 .finish()
104 }
105}
106
107impl<T: Model> PartialEq for ForeignKey<T> {
109 fn eq(&self, other: &Self) -> bool {
110 self.id == other.id
111 }
112}
113
114impl<T: Model> DbType for ForeignKey<T> {
115 const SQL_TYPE: SqlType = <T::Pk as DbType>::SQL_TYPE;
116 fn to_value(&self) -> Value {
117 self.id.to_value()
118 }
119 fn from_value(value: Value) -> Result<Self, String> {
120 T::Pk::from_value(value).map(Self::new)
121 }
122}
123
124impl<T: Model> Serialize for ForeignKey<T>
125where
126 T::Pk: Serialize,
127{
128 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
129 self.id.serialize(serializer)
130 }
131}
132
133impl<'de, T: Model> Deserialize<'de> for ForeignKey<T>
134where
135 T::Pk: Deserialize<'de>,
136{
137 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
138 T::Pk::deserialize(deserializer).map(Self::new)
139 }
140}
141
142impl<T: Model> Validate for ForeignKey<T>
143where
144 T::Pk: Validate,
145{
146 fn prepare(input: &mut JsonValue, ctx: &mut ValidationContext) {
147 T::Pk::prepare(input, ctx);
148 }
149
150 fn validate(&self, ctx: &mut ValidationContext) {
151 self.id.validate(ctx);
152 }
153}
154
155impl<T: Model + 'static> Schema for ForeignKey<T>
156where
157 T::Pk: Schema + 'static,
158{
159 fn schema(registry: &mut SchemaRegistry) -> SchemaObject {
160 registry.subschema::<T::Pk>()
161 }
162}
163
164impl<T: Model> Dump for ForeignKey<T> where T::Pk: Serialize {}
165
166pub struct ManyToManyManager<S: Model, T: Model> {
170 db: Db,
171 meta: &'static ManyToManyMeta,
172 source_pk: Value,
173 _models: std::marker::PhantomData<fn() -> (S, T)>,
174}
175
176impl<S: Model, T: Model> ManyToManyManager<S, T> {
177 pub fn new(db: &Db, meta: &'static ManyToManyMeta, source_pk: Value) -> Self {
179 Self {
180 db: db.clone(),
181 meta,
182 source_pk,
183 _models: std::marker::PhantomData,
184 }
185 }
186
187 pub fn db(&self) -> &Db {
189 &self.db
190 }
191
192 pub fn meta(&self) -> &'static ManyToManyMeta {
194 self.meta
195 }
196
197 pub fn source_pk(&self) -> &Value {
199 &self.source_pk
200 }
201}