1pub use crate::models::{
2 BaseModel, ByUuid, CreatableModel, CreateListenerList, DeletableModel, DeleteHandlerList,
3 DuplicableModel, DuplicateHandlerList, EventEmittingModel, Fetchable, IntoAdminApiObject,
4 IntoApiObject, ListenerPriority, ModelHandlerList, OrderedJson, UpdatableModel,
5 UpdateHandlerList,
6};
7use futures_util::{StreamExt, TryStreamExt};
8pub use schema_extension_core::finish_extendible;
9use std::borrow::Cow;
10
11pub trait IteratorExt<R, E>: Iterator<Item = Result<R, E>> {
12 fn try_collect_vec(self) -> Result<Vec<R>, E>
13 where
14 Self: Sized,
15 {
16 let mut vec = Vec::new();
17
18 let (hint_min, hint_max) = self.size_hint();
19 if let Some(hint_max) = hint_max
20 && hint_min == hint_max
21 {
22 vec.reserve_exact(hint_max);
23 }
24
25 for item in self {
26 vec.push(item?);
27 }
28
29 Ok(vec)
30 }
31
32 fn try_collect_vecdeque(self) -> Result<std::collections::VecDeque<R>, E>
33 where
34 Self: Sized,
35 {
36 let mut deque = std::collections::VecDeque::new();
37
38 let (hint_min, hint_max) = self.size_hint();
39 if let Some(hint_max) = hint_max
40 && hint_min == hint_max
41 {
42 deque.reserve_exact(hint_max);
43 }
44
45 for item in self {
46 deque.push_back(item?);
47 }
48
49 Ok(deque)
50 }
51
52 fn try_collect_set(self) -> Result<std::collections::HashSet<R>, E>
53 where
54 Self: Sized,
55 R: std::hash::Hash + Eq,
56 {
57 let mut set = std::collections::HashSet::new();
58
59 for item in self {
60 set.insert(item?);
61 }
62
63 Ok(set)
64 }
65}
66
67impl<R, E, T: Iterator<Item = Result<R, E>>> IteratorExt<R, E> for T {}
68
69#[async_trait::async_trait]
70pub trait AsyncIteratorExt<R: Send, E: Send, F: Future<Output = Result<R, E>> + Send>:
71 Iterator<Item = F> + Sized + Send
72{
73 async fn try_collect_async_vec(self) -> Result<Vec<R>, E>
74 where
75 Self: Sized,
76 {
77 let mut vec = Vec::new();
78
79 let (hint_min, hint_max) = self.size_hint();
80 if let Some(hint_max) = hint_max
81 && hint_min == hint_max
82 {
83 vec.reserve_exact(hint_max);
84 }
85
86 let mut result_stream = futures_util::stream::iter(self).buffered(25);
87
88 while let Some(result) = result_stream.try_next().await? {
89 vec.push(result);
90 }
91
92 Ok(vec)
93 }
94}
95
96impl<
97 R: Send,
98 E: Send,
99 F: Future<Output = Result<R, E>> + Send,
100 T: Iterator<Item = F> + Sized + Send,
101> AsyncIteratorExt<R, E, F> for T
102{
103}
104
105pub trait OptionExt<T> {
106 fn try_map<R, E, F: FnMut(T) -> Result<R, E>>(self, f: F) -> Result<Option<R>, E>;
107}
108
109impl<T> OptionExt<T> for Option<T> {
110 #[inline]
111 fn try_map<R, E, F: FnMut(T) -> Result<R, E>>(self, mut f: F) -> Result<Option<R>, E> {
112 match self {
113 Some(item) => Ok(Some(f(item)?)),
114 None => Ok(None),
115 }
116 }
117}
118
119#[async_trait::async_trait]
120pub trait AsyncOptionExt<T, Fut: Future<Output = T>> {
121 async fn awaited(self) -> Option<T>;
122}
123
124#[async_trait::async_trait]
125impl<T, Fut: Future<Output = T> + Send> AsyncOptionExt<T, Fut> for Option<Fut> {
126 #[inline]
127 async fn awaited(self) -> Option<T> {
128 match self {
129 Some(item) => Some(item.await),
130 None => None,
131 }
132 }
133}
134
135pub trait SqlxErrorExt {
136 fn is_unique_violation(&self) -> bool;
137 fn is_foreign_key_violation(&self) -> bool;
138 fn is_check_violation(&self) -> bool;
139
140 fn code(&self) -> Option<Cow<'_, str>>;
141 fn message(&self) -> Option<&str>;
142}
143
144impl SqlxErrorExt for sqlx::Error {
145 #[inline]
146 fn is_unique_violation(&self) -> bool {
147 self.as_database_error()
148 .is_some_and(|e| e.is_unique_violation())
149 }
150
151 #[inline]
152 fn is_foreign_key_violation(&self) -> bool {
153 self.as_database_error()
154 .is_some_and(|e| e.is_foreign_key_violation())
155 }
156
157 #[inline]
158 fn is_check_violation(&self) -> bool {
159 self.as_database_error()
160 .is_some_and(|e| e.is_check_violation())
161 }
162
163 #[inline]
164 fn code(&self) -> Option<Cow<'_, str>> {
165 self.as_database_error().and_then(|e| e.code())
166 }
167
168 #[inline]
169 fn message(&self) -> Option<&str> {
170 self.as_database_error().map(|e| e.message())
171 }
172}
173
174pub trait StringExt: Sized {
175 fn optional(&self) -> Option<&Self>;
177
178 fn into_optional(self) -> Option<Self>;
180}
181
182impl StringExt for String {
183 #[inline]
184 fn optional(&self) -> Option<&Self> {
185 if self.is_empty() { None } else { Some(self) }
186 }
187
188 #[inline]
189 fn into_optional(self) -> Option<Self> {
190 if self.is_empty() { None } else { Some(self) }
191 }
192}
193
194impl StringExt for compact_str::CompactString {
195 #[inline]
196 fn optional(&self) -> Option<&Self> {
197 if self.is_empty() { None } else { Some(self) }
198 }
199
200 #[inline]
201 fn into_optional(self) -> Option<Self> {
202 if self.is_empty() { None } else { Some(self) }
203 }
204}
205
206impl StringExt for &str {
207 #[inline]
208 fn optional(&self) -> Option<&Self> {
209 if self.is_empty() { None } else { Some(self) }
210 }
211
212 #[inline]
213 fn into_optional(self) -> Option<Self> {
214 if self.is_empty() { None } else { Some(self) }
215 }
216}