1#![deny(missing_docs)]
3use std::borrow::Cow;
4use std::fmt::Debug;
5use std::sync::OnceLock;
6
7#[cfg(feature = "fake")]
8use fake::{Dummy, Faker};
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11use crate::util::get_or_init_once_lock;
12#[cfg(feature = "async")]
13use crate::{util::get_or_init_once_lock_async, ConnectionMethodsAsync};
14use crate::{
15 AsPrimaryKey, ConnectionMethods, DataObject, Error, FieldType, FromSql, Result, SqlType,
16 SqlVal, SqlValRef, ToSql,
17};
18
19#[derive(Clone, Debug)]
37pub struct ForeignKey<T>
38where
39 T: DataObject,
40{
41 val: OnceLock<Box<T>>,
45 valpk: OnceLock<SqlVal>,
46}
47impl<T: DataObject> ForeignKey<T> {
48 pub fn from_pk(pk: T::PKType) -> Self {
50 let ret = Self::new_raw();
51 ret.valpk.set(pk.into_sql()).unwrap();
52 ret
53 }
54 pub fn get(&self) -> Result<&T> {
56 self.val
57 .get()
58 .map(|v| v.as_ref())
59 .ok_or(Error::ValueNotLoaded)
60 }
61
62 pub fn pk(&self) -> T::PKType {
64 match self.val.get() {
65 Some(v) => v.pk().clone(),
66 None => match self.valpk.get() {
67 Some(pk) => T::PKType::from_sql_ref(pk.as_ref()).unwrap(),
68 None => panic!("Invalid foreign key state"),
69 },
70 }
71 }
72
73 fn new_raw() -> Self {
74 ForeignKey {
75 val: OnceLock::new(),
76 valpk: OnceLock::new(),
77 }
78 }
79
80 fn ensure_valpk(&self) -> &SqlVal {
81 match self.valpk.get() {
82 Some(sqlval) => return sqlval,
83 None => match self.val.get() {
84 Some(val) => self.valpk.set(val.pk().to_sql()).unwrap(),
85 None => panic!("Invalid foreign key state"),
86 },
87 }
88 self.valpk.get().unwrap()
89 }
90}
91
92#[allow(async_fn_in_trait)] #[maybe_async_cfg::maybe(
95 idents(ConnectionMethods(sync = "ConnectionMethods"),),
96 sync(),
97 async(feature = "async")
98)]
99pub trait ForeignKeyOps<T: DataObject> {
100 async fn load<'a>(&'a self, conn: &impl ConnectionMethods) -> Result<&'a T>
103 where
104 T: 'a;
105}
106
107#[cfg(feature = "async")]
108impl<T: DataObject> ForeignKeyOpsAsync<T> for ForeignKey<T> {
109 async fn load<'a>(&'a self, conn: &impl ConnectionMethodsAsync) -> Result<&'a T>
110 where
111 T: 'a,
112 {
113 use crate::DataObjectOpsAsync;
114 get_or_init_once_lock_async(&self.val, || async {
115 let pk = self.valpk.get().unwrap();
116 T::get(conn, T::PKType::from_sql_ref(pk.as_ref())?)
117 .await
118 .map(Box::new)
119 })
120 .await
121 .map(|v| v.as_ref())
122 }
123}
124
125impl<T: DataObject> ForeignKeyOpsSync<T> for ForeignKey<T> {
126 fn load<'a>(&'a self, conn: &impl ConnectionMethods) -> Result<&'a T>
127 where
128 T: 'a,
129 {
130 use crate::DataObjectOpsSync;
131 get_or_init_once_lock(&self.val, || {
132 let pk = self.valpk.get().unwrap();
133 T::get(conn, T::PKType::from_sql_ref(pk.as_ref())?).map(Box::new)
134 })
135 .map(|v| v.as_ref())
136 }
137}
138
139impl<T: DataObject> From<T> for ForeignKey<T> {
140 fn from(obj: T) -> Self {
141 let ret = Self::new_raw();
142 ret.val.set(Box::new(obj)).ok();
143 ret
144 }
145}
146impl<T: DataObject> From<&T> for ForeignKey<T> {
147 fn from(obj: &T) -> Self {
148 Self::from_pk(obj.pk().clone())
149 }
150}
151
152impl<T> AsPrimaryKey<T> for ForeignKey<T>
153where
154 T: DataObject,
155{
156 fn as_pk(&self) -> Cow<T::PKType> {
157 Cow::Owned(self.pk())
158 }
159}
160
161impl<T: DataObject> Eq for ForeignKey<T> {}
162
163impl<T> ToSql for ForeignKey<T>
164where
165 T: DataObject,
166{
167 fn to_sql(&self) -> SqlVal {
168 self.ensure_valpk().clone()
169 }
170 fn to_sql_ref(&self) -> SqlValRef<'_> {
171 self.ensure_valpk().as_ref()
172 }
173 fn into_sql(self) -> SqlVal {
174 self.ensure_valpk();
175 self.valpk.into_inner().unwrap()
176 }
177}
178impl<T> FieldType for ForeignKey<T>
179where
180 T: DataObject,
181{
182 const SQLTYPE: SqlType = <T as DataObject>::PKType::SQLTYPE;
183 type RefType = <<T as DataObject>::PKType as FieldType>::RefType;
184}
185impl<T> FromSql for ForeignKey<T>
186where
187 T: DataObject,
188{
189 fn from_sql_ref(valref: SqlValRef) -> Result<Self> {
190 Ok(ForeignKey {
191 valpk: SqlVal::from(valref).into(),
192 val: OnceLock::new(),
193 })
194 }
195}
196impl<T, U> PartialEq<U> for ForeignKey<T>
197where
198 U: AsPrimaryKey<T>,
199 T: DataObject,
200{
201 fn eq(&self, other: &U) -> bool {
202 match self.val.get() {
203 Some(t) => t.pk().eq(&other.as_pk()),
204 None => match self.valpk.get() {
205 Some(valpk) => valpk.eq(&other.as_pk().to_sql()),
206 None => panic!("Invalid foreign key state"),
207 },
208 }
209 }
210}
211
212impl<T> Serialize for ForeignKey<T>
213where
214 T: DataObject,
215 T::PKType: Serialize,
216{
217 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
218 where
219 S: Serializer,
220 {
221 self.pk().serialize(serializer)
222 }
223}
224
225impl<'de, T> Deserialize<'de> for ForeignKey<T>
226where
227 T: DataObject,
228 T::PKType: Deserialize<'de>,
229{
230 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
231 where
232 D: Deserializer<'de>,
233 {
234 Ok(Self::from_pk(T::PKType::deserialize(deserializer)?))
235 }
236}
237
238#[cfg(feature = "fake")]
239impl<T: DataObject> Dummy<Faker> for ForeignKey<T> {
241 fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &Faker, _rng: &mut R) -> Self {
242 Self::new_raw()
243 }
244}