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