tag2upload_service_manager/
bsql_rows.rs1
2use crate::prelude::*;
3use crate::bsql_queries::*;
4
5#[derive(Clone, Copy)]
8pub struct SkipRowId;
9
10pub struct AsBSqlColumnData<'r> {
11 pub name: &'r str,
12 pub value: DynToSql<'r>,
13 pub isnt_row_id: Result<(), SkipRowId>,
14}
15
16pub trait AsBSqlRow: Sync {
17 fn as_sql_row_columns(&self) -> impl Iterator<Item=AsBSqlColumnData<'_>>;
18}
19
20#[derive(Clone, Copy)]
21pub struct AsBSqlRowParams<'r, R: AsBSqlRow> {
22 pub row: &'r R,
23 pub include_row_id: Result<(), bsql_rows::SkipRowId>,
24}
25impl<R: AsBSqlRow> AsBSqlRowParams<'_, R> {
26 fn cols(&self) -> impl Iterator<Item = AsBSqlColumnData> {
27 self.row.as_sql_row_columns()
28 .filter(|c| {
29 c.isnt_row_id
30 .or_else(|_: SkipRowId| self.include_row_id)
31 .is_ok()
32 })
33 }
34}
35
36impl<R: AsBSqlRow> IsFragment for AsBSqlRowParams<'_, R> {
37 fn bsql_extend_text(&self, s: &mut String) {
38 *s += "(";
39 extend_texts_sep_commas(s, self.cols().map(|c| c.name));
40 *s += ") VALUES (";
41 extend_texts_sep_commas(s, self.cols().map(|_c| "?"));
42 *s += ")";
43 }
44 fn bsql_extend_params<'v, 'p: 'v>(&'p self, p: &mut Vec<DynToSql<'v>>) {
45 for c in self.cols() {
46 p.push(c.value)
47 }
48 }
49 fn bsql_note_locs(&self, _la: &mut CodeLocationAccumulator) {}
50}
51
52define_derive_deftly! {
53 export AsBSqlRow for struct, expect items:
54
55 impl $crate::bsql_rows::AsBSqlRow for $ttype {
56 fn as_sql_row_columns(&self) -> impl Iterator<
57 Item=$crate::bsql_rows::AsBSqlColumnData<'_>
58 > {
59 use $crate::prelude::*;
60 use bsql_rows::*;
61 chain!(
62 $(
63 ${if fmeta(bsql(flatten)) {
64 AsBSqlRow::as_sql_row_columns(&self.$fname)
65 } else {
66 [AsBSqlColumnData {
67 name: stringify!($fname),
68 value: &self.$fname,
69 isnt_row_id: ${if fmeta(bsql(rowid)) {
70 Err(SkipRowId)
71 } else {
72 Ok(())
73 }},
74 }]
75 }}
76 ,
77 )
78 )
79 }
80 }
81}
82
83pub struct BSqlUpdateColumnData<'u> {
86 pub name: &'u str,
87 pub value: DynToSql<'u>,
88}
89
90pub trait HasUpdateSqlRow {
91 type UpdateSqlRow<'u>: UpdateSqlRow + Default;
92}
93
94pub trait UpdateSqlRow: Sized + Sync {
95 fn bsql(&self) -> Option<impl AsFragment + '_> {
97 let _: BSqlUpdateColumnData = self.bsql_update_row_columns().next()?;
98 Some(Update(self))
99 }
100
101 fn bsql_update_row_columns(
102 &self
103 ) -> impl Iterator<Item=BSqlUpdateColumnData<'_>>;
104}
105
106struct Update<'u, U: UpdateSqlRow>(&'u U);
107
108#[macro_export]
137macro_rules! bsql_update {
138 {
139 let $bind:ident = $tname:ident { $($body:tt)+ } $(;)?
140 } => {
141 let $bind = $crate::bsql_update! { $tname { $($body)+ } };
142 let $bind = $bind.bsql().expect("nonempty by construction");
143 };
144 {
145 $tname:ident { $(
146 $fname:ident $( : $value:expr )?
147 ),* $(,)?
148 }
149 } => { paste!{
150 [< $tname Update >] {
151 $(
152 $fname: $crate::bsql_update!(@ $fname $( : $value )? ),
153 )*
154 ..Default::default()
155 }
156 } };
157 { @ $fname:ident } => { $crate::bsql_update!(@ $fname: $fname ) };
158 { @ $fname:ident: $value:expr } => {
159 std::option::Option::Some(
160 std::convert::From::from(
161 $value
162 )
163 )
164 }
165}
166
167
168impl<'u, U: UpdateSqlRow> AsFragment for Update<'u, U> {
169 type F<'uu> = Self where Self: 'uu;
170 fn as_fragment(&self) -> Self::F<'_> { Update(self.0) }
171}
172
173impl<'u, U: UpdateSqlRow> IsFragment for Update<'u, U> {
174 fn bsql_extend_text(&self, s: &mut String) {
175 for (sep, c) in izip!(
176 chain!([""], iter::repeat(", ")),
177 self.0.bsql_update_row_columns(),
178 ) {
179 write!(s, "{sep}{} = ?", c.name).expect("write to string failed");
180 }
181 }
182 fn bsql_extend_params<'v, 'p: 'v>(&'p self, p: &mut Vec<DynToSql<'v>>) {
183 for c in self.0.bsql_update_row_columns() {
184 p.push(c.value)
185 }
186 }
187 fn bsql_note_locs(&self, _la: &mut CodeLocationAccumulator) {}
188}
189
190define_derive_deftly! {
191 export UpdateSqlRow for struct, expect items:
192
193 #[derive(Clone, Default)]
194 $tvis struct $<$tname Update><'update_sql_row, $tdefgens> { $(
195 ${when not(fmeta(bsql(rowid)))}
196
197 $fvis $fname: std::option::Option<
198 ${if fmeta(bsql(flatten)) {
199 <$ftype as $crate::bsql_rows::HasUpdateSqlRow>
200 ::UpdateSqlRow<'update_sql_row>
201 } else {
202 $crate::prelude::MaybeOwned<'update_sql_row, $ftype>
203 }}
204 >,
205 ) }
206
207 impl<$tgens> $crate::bsql_rows::HasUpdateSqlRow for $ttype {
208 type UpdateSqlRow<'update_sql_row> =
209 $<$tname Update><'update_sql_row, $tgens>;
210 }
211
212 impl<$tgens> $crate::bsql_rows::UpdateSqlRow
213 for $<$tname Update><'_, $tgens>
214 {
215 fn bsql_update_row_columns(
216 &self
217 ) -> impl Iterator<Item=$crate::bsql_rows::BSqlUpdateColumnData<'_>> {
218 #[allow(unused_imports)] use $crate::bsql_rows::*;
220
221 chain!( $(
222 ${when not(fmeta(bsql(rowid)))}
223
224 self.$fname.as_ref().map(|v| {
225 ${if fmeta(bsql(flatten)) {
226 UpdateSqlRow::bsql_update_row_columns(v)
227 } else {
228 [BSqlUpdateColumnData {
229 name: stringify!($fname),
230 value: &**v as _,
231 }]
232 }}
233 }).into_iter().flatten(),
234 ) )
235 }
236 }
237
238 impl<'update_sql_row, $tgens> std::ops::BitOr
239 for $<$tname Update><'update_sql_row, $tgens>
240 {
241 type Output = $<$tname Update><'update_sql_row, $tgens>;
242 fn bitor(self, rhs: Self) -> Self::Output {
243 $<$tname Update> { $(
244 ${when not(fmeta(bsql(rowid)))}
245
246 ${if fmeta(bsql(flatten)) {
247 $fname: Some(
248 self.$fname.unwrap_or_default() |
249 rhs.$fname.unwrap_or_default()
250 )
251 } else {
252 $fname: self.$fname.or(rhs.$fname)
253 }}
254 ,
255 ) }
256 }
257 }
258}
259
260pub trait FromSqlRow: Sized {
263 fn from_sql_row(row: &rusqlite::Row) -> Result<Self, InternalError>;
264}
265
266define_derive_deftly! {
267 export FromSqlRow for struct, expect items:
268
269 impl FromSqlRow for $ttype {
270 fn from_sql_row(row: &rusqlite::Row) -> Result<Self, InternalError> {
271 Ok($ttype {
272 $(
273 $fname:
274 ${if fmeta(bsql(flatten)) {
275 FromSqlRow::from_sql_row(row)?
276 } else {
277 row.get(stringify!($fname))
278 .into_internal(concat!(
279 "failed to convert ",
280 stringify!($fname),
281 ))?
282 }},
283 )
284 })
285 }
286 }
287}