1use crate::delete::DeleteBuilder;
7use crate::escape_all;
8use crate::field_mapper::{FieldMapperFunc, default_field_mapper};
9use crate::flavor::Flavor;
10use crate::insert::InsertBuilder;
11use crate::select::SelectBuilder;
12use crate::select_cols;
13use crate::update::UpdateBuilder;
14use std::any::Any;
15use std::collections::HashSet;
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum FieldOpt {
19 WithQuote,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct FieldMeta {
24 pub rust: &'static str,
26 pub orig: &'static str,
31 pub db: &'static str,
33 pub as_: Option<&'static str>,
35 pub tags: &'static [&'static str],
37 pub omitempty_tags: &'static [&'static str],
39 pub with_quote: bool,
40}
41
42impl FieldMeta {
43 pub fn name_for_select(&self, flavor: Flavor, alias: &str) -> String {
44 let base = if self.with_quote {
45 flavor.quote(alias)
46 } else {
47 alias.to_string()
48 };
49 if let Some(as_) = self.as_ {
50 format!("{base} AS {as_}")
51 } else {
52 base
53 }
54 }
55}
56
57fn is_ignored(fm: &FieldMeta) -> bool {
58 fm.db == "-"
60}
61
62pub trait SqlStruct: Sized {
64 const FIELDS: &'static [FieldMeta];
65
66 fn values(&self) -> Vec<crate::modifiers::Arg>;
68
69 fn is_empty_field(&self, rust_field: &'static str) -> bool;
71
72 fn addr_cells<'a>(
77 &'a mut self,
78 rust_fields: &[&'static str],
79 ) -> Option<Vec<crate::scan::ScanCell<'a>>>;
80}
81
82pub trait IsEmpty {
84 fn is_empty_value(&self) -> bool;
85}
86
87impl IsEmpty for String {
88 fn is_empty_value(&self) -> bool {
89 self.is_empty()
90 }
91}
92
93impl IsEmpty for &str {
94 fn is_empty_value(&self) -> bool {
95 self.is_empty()
96 }
97}
98
99impl IsEmpty for bool {
100 fn is_empty_value(&self) -> bool {
101 !*self
102 }
103}
104
105macro_rules! empty_num {
106 ($($t:ty),+ $(,)?) => {
107 $(impl IsEmpty for $t {
108 fn is_empty_value(&self) -> bool {
109 *self == 0 as $t
110 }
111 })+
112 };
113}
114
115empty_num!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
116
117impl IsEmpty for f64 {
118 fn is_empty_value(&self) -> bool {
119 self.to_bits() == 0
121 }
122}
123
124impl<T: IsEmpty> IsEmpty for Option<T> {
125 fn is_empty_value(&self) -> bool {
126 match self {
127 None => true,
128 Some(v) => v.is_empty_value(),
129 }
130 }
131}
132
133impl<T> IsEmpty for Vec<T> {
134 fn is_empty_value(&self) -> bool {
135 self.is_empty()
136 }
137}
138
139impl IsEmpty for Box<dyn crate::valuer::SqlValuer> {
140 fn is_empty_value(&self) -> bool {
141 false
143 }
144}
145
146pub struct Struct<T: SqlStruct> {
147 pub flavor: Flavor,
148 mapper: FieldMapperFunc,
149 with_tags: Vec<&'static str>,
150 without_tags: Vec<&'static str>,
151 _phantom: std::marker::PhantomData<T>,
152}
153
154impl<T: SqlStruct> Clone for Struct<T> {
155 fn clone(&self) -> Self {
156 Self {
157 flavor: self.flavor,
158 mapper: self.mapper.clone(),
159 with_tags: self.with_tags.clone(),
160 without_tags: self.without_tags.clone(),
161 _phantom: std::marker::PhantomData,
162 }
163 }
164}
165
166impl<T: SqlStruct> std::fmt::Debug for Struct<T> {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 f.debug_struct("Struct")
170 .field("flavor", &self.flavor)
171 .field("with_tags", &self.with_tags)
172 .field("without_tags", &self.without_tags)
173 .finish()
174 }
175}
176
177impl<T: SqlStruct> Default for Struct<T> {
178 fn default() -> Self {
179 Self {
180 flavor: crate::default_flavor(),
181 mapper: default_field_mapper(),
182 with_tags: Vec::new(),
183 without_tags: Vec::new(),
184 _phantom: std::marker::PhantomData,
185 }
186 }
187}
188
189impl<T: SqlStruct> Struct<T> {
190 pub fn new() -> Self {
191 Self::default()
192 }
193
194 pub fn with_field_mapper(&self, mapper: FieldMapperFunc) -> Self {
198 let mut c = self.clone();
199 c.mapper = mapper;
200 c
201 }
202
203 fn has_defined_tag(tag: &str) -> bool {
204 if tag.is_empty() {
205 return false;
206 }
207 T::FIELDS
208 .iter()
209 .any(|f| !is_ignored(f) && f.tags.contains(&tag))
210 }
211
212 pub fn for_flavor(&self, flavor: Flavor) -> Self {
214 let mut c = self.clone();
215 c.flavor = flavor;
216 c
217 }
218
219 pub fn with_tag(&self, tags: impl IntoIterator<Item = &'static str>) -> Self {
221 let mut c = self.clone();
222 for t in tags {
223 if t.is_empty() {
224 continue;
225 }
226 if !c.with_tags.contains(&t) {
227 c.with_tags.push(t);
228 }
229 }
230 c.with_tags.sort_unstable();
231 c.with_tags.dedup();
232 c
233 }
234
235 pub fn without_tag(&self, tags: impl IntoIterator<Item = &'static str>) -> Self {
237 let mut c = self.clone();
238 for t in tags {
239 if t.is_empty() {
240 continue;
241 }
242 if !c.without_tags.contains(&t) {
243 c.without_tags.push(t);
244 }
245 }
246 c.without_tags.sort_unstable();
247 c.without_tags.dedup();
248 c.with_tags.retain(|t| !c.without_tags.contains(t));
250 c
251 }
252
253 fn should_omit_empty(&self, fm: &FieldMeta) -> bool {
254 let omit = fm.omitempty_tags;
258 if omit.is_empty() {
259 return false;
260 }
261 if omit.contains(&"") {
262 return true;
263 }
264 self.with_tags.iter().any(|t| omit.contains(t))
265 }
266
267 fn excluded_by_without(&self, fm: &FieldMeta) -> bool {
268 self.without_tags.iter().any(|t| fm.tags.contains(t))
269 }
270
271 fn alias_of(&self, fm: &FieldMeta) -> String {
272 if is_ignored(fm) {
273 return String::new();
274 }
275
276 if !fm.db.is_empty() {
277 return fm.db.to_string();
278 }
279
280 let mapped = (self.mapper)(fm.orig);
281 if mapped.is_empty() {
282 fm.orig.to_string()
283 } else {
284 mapped
285 }
286 }
287
288 fn read_key_of(&self, fm: &FieldMeta) -> String {
289 if let Some(as_) = fm.as_ {
291 return as_.to_string();
292 }
293 let a = self.alias_of(fm);
294 if a.is_empty() { fm.rust.to_string() } else { a }
295 }
296
297 fn write_key_of(&self, fm: &FieldMeta) -> String {
298 let a = self.alias_of(fm);
300 if a.is_empty() { fm.rust.to_string() } else { a }
301 }
302
303 fn fields_for_read(&self) -> Vec<&'static FieldMeta> {
304 self.fields_filtered(true)
305 }
306
307 fn fields_for_write(&self) -> Vec<&'static FieldMeta> {
308 self.fields_filtered(false)
309 }
310
311 fn fields_filtered(&self, for_read: bool) -> Vec<&'static FieldMeta> {
312 let mut out = Vec::new();
313 let mut seen = HashSet::<String>::new();
314
315 let push_field = |out: &mut Vec<&'static FieldMeta>,
316 seen: &mut HashSet<String>,
317 fm: &'static FieldMeta,
318 for_read: bool| {
319 if is_ignored(fm) {
320 return;
321 }
322 if self.excluded_by_without(fm) {
323 return;
324 }
325 let key = if for_read {
326 self.read_key_of(fm)
327 } else {
328 self.write_key_of(fm)
329 };
330 if seen.insert(key) {
331 out.push(fm);
332 }
333 };
334
335 if self.with_tags.is_empty() {
336 for fm in T::FIELDS {
337 push_field(&mut out, &mut seen, fm, for_read);
338 }
339 return out;
340 }
341
342 for tag in &self.with_tags {
344 for fm in T::FIELDS {
345 if fm.tags.contains(tag) {
346 push_field(&mut out, &mut seen, fm, for_read);
347 }
348 }
349 }
350
351 out
352 }
353
354 fn parse_table_alias(table: &str) -> &str {
355 table.rsplit_once(' ').map(|(_, a)| a).unwrap_or(table)
357 }
358
359 pub fn columns(&self) -> Vec<String> {
361 self.fields_for_write()
362 .into_iter()
363 .map(|f| self.alias_of(f))
364 .collect()
365 }
366
367 pub fn columns_for_tag(&self, tag: &str) -> Option<Vec<String>> {
371 if !Self::has_defined_tag(tag) {
372 return None;
373 }
374 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
377 Some(self.with_tag([tag]).columns())
378 }
379
380 pub fn values(&self, v: &T) -> Vec<crate::modifiers::Arg> {
382 let all = v.values();
383 let mut out = Vec::new();
384 for (fm, arg) in T::FIELDS.iter().zip(all) {
385 if is_ignored(fm) || self.excluded_by_without(fm) {
386 continue;
387 }
388 if self.with_tags.is_empty() || self.with_tags.iter().any(|t| fm.tags.contains(t)) {
389 out.push(arg);
390 }
391 }
392 let mut map = std::collections::HashMap::<&'static str, crate::modifiers::Arg>::new();
395 for (fm, arg) in T::FIELDS.iter().zip(v.values()) {
396 map.insert(fm.rust, arg);
397 }
398 self.fields_for_write()
399 .into_iter()
400 .filter_map(|fm| map.get(fm.rust).cloned())
401 .collect()
402 }
403
404 pub fn values_for_tag(&self, tag: &str, v: &T) -> Option<Vec<crate::modifiers::Arg>> {
408 if !Self::has_defined_tag(tag) {
409 return None;
410 }
411 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
412 Some(self.with_tag([tag]).values(v))
413 }
414
415 pub fn foreach_read(&self, mut trans: impl FnMut(&str, bool, &FieldMeta)) {
421 for fm in self.fields_for_read() {
422 trans(fm.db, fm.with_quote, fm);
423 }
424 }
425
426 pub fn foreach_write(&self, mut trans: impl FnMut(&str, bool, &FieldMeta)) {
428 for fm in self.fields_for_write() {
429 trans(fm.db, fm.with_quote, fm);
430 }
431 }
432
433 pub fn addr<'a>(&self, st: &'a mut T) -> Vec<crate::scan::ScanCell<'a>> {
435 let rust_fields: Vec<&'static str> = self
436 .fields_for_read()
437 .into_iter()
438 .map(|fm| fm.rust)
439 .collect();
440 st.addr_cells(&rust_fields).unwrap_or_default()
441 }
442
443 pub fn addr_for_tag<'a>(
446 &self,
447 tag: &str,
448 st: &'a mut T,
449 ) -> Option<Vec<crate::scan::ScanCell<'a>>> {
450 if !Self::has_defined_tag(tag) {
451 return None;
452 }
453 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
454 Some(self.with_tag([tag]).addr(st))
455 }
456
457 pub fn addr_with_cols<'a>(
460 &self,
461 cols: &[&str],
462 st: &'a mut T,
463 ) -> Option<Vec<crate::scan::ScanCell<'a>>> {
464 let fields = self.fields_for_read();
465 let mut map = std::collections::HashMap::<String, &'static str>::new();
466 for fm in fields {
467 let key = self.read_key_of(fm);
468 map.insert(key, fm.rust);
469 }
470
471 let mut rust_fields = Vec::with_capacity(cols.len());
472 for &c in cols {
473 rust_fields.push(*map.get(c)?);
474 }
475 st.addr_cells(&rust_fields)
476 }
477
478 pub fn select_from(&self, table: &str) -> SelectBuilder {
479 let mut sb = SelectBuilder::new();
480 sb.set_flavor(self.flavor);
481 sb.from([table.to_string()]);
482
483 let alias = Self::parse_table_alias(table);
484 let cols: Vec<String> = self
485 .fields_for_read()
486 .into_iter()
487 .map(|f| {
488 let field_alias = self.alias_of(f);
489 let mut c = String::new();
490 if self.flavor != Flavor::CQL && !field_alias.contains('.') {
492 c.push_str(alias);
493 c.push('.');
494 }
495 c.push_str(&f.name_for_select(self.flavor, &field_alias));
496 c
497 })
498 .collect();
499
500 if cols.is_empty() {
501 select_cols!(sb, "*");
502 } else {
503 sb.select(cols);
504 }
505 sb
506 }
507
508 pub fn select_from_for_tag(&self, table: &str, tag: &str) -> SelectBuilder {
510 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
512 self.with_tag([tag]).select_from(table)
513 }
514
515 pub fn update(&self, table: &str, value: &T) -> UpdateBuilder {
516 let mut ub = UpdateBuilder::new();
517 ub.set_flavor(self.flavor);
518 ub.update([table.to_string()]);
519
520 let mut assigns = Vec::new();
521
522 let mut map = std::collections::HashMap::<&'static str, crate::modifiers::Arg>::new();
523 for (fm, arg) in T::FIELDS.iter().zip(value.values()) {
524 map.insert(fm.rust, arg);
525 }
526
527 for fm in self.fields_for_write() {
528 if self.should_omit_empty(fm) && value.is_empty_field(fm.rust) {
529 continue;
530 }
531 let field_alias = self.alias_of(fm);
533 let col = if fm.with_quote {
534 self.flavor.quote(&field_alias)
535 } else {
536 field_alias
537 };
538 if let Some(v) = map.get(fm.rust).cloned() {
539 assigns.push(ub.assign(&col, v));
540 }
541 }
542
543 ub.set(assigns);
544 ub
545 }
546
547 pub fn update_for_tag(&self, table: &str, tag: &str, value: &T) -> UpdateBuilder {
549 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
550 self.with_tag([tag]).update(table, value)
551 }
552
553 pub fn delete_from(&self, table: &str) -> DeleteBuilder {
554 let mut db = DeleteBuilder::new();
555 db.set_flavor(self.flavor);
556 db.delete_from([table.to_string()]);
557 db
558 }
559
560 pub fn insert_into<'a>(
561 &self,
562 table: &str,
563 rows: impl IntoIterator<Item = &'a T>,
564 ) -> InsertBuilder
565 where
566 T: 'a,
567 {
568 self.insert_internal(table, rows, InsertVerb::Insert)
569 }
570
571 pub fn insert_into_for_tag<'a>(
573 &self,
574 table: &str,
575 tag: &str,
576 rows: impl IntoIterator<Item = &'a T>,
577 ) -> InsertBuilder
578 where
579 T: 'a,
580 {
581 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
582 self.with_tag([tag]).insert_into(table, rows)
583 }
584
585 pub fn insert_ignore_into_for_tag<'a>(
586 &self,
587 table: &str,
588 tag: &str,
589 rows: impl IntoIterator<Item = &'a T>,
590 ) -> InsertBuilder
591 where
592 T: 'a,
593 {
594 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
595 self.with_tag([tag]).insert_ignore_into(table, rows)
596 }
597
598 pub fn replace_into_for_tag<'a>(
599 &self,
600 table: &str,
601 tag: &str,
602 rows: impl IntoIterator<Item = &'a T>,
603 ) -> InsertBuilder
604 where
605 T: 'a,
606 {
607 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
608 self.with_tag([tag]).replace_into(table, rows)
609 }
610
611 fn filter_rows_any<'a>(values: impl IntoIterator<Item = &'a dyn Any>) -> Vec<&'a T>
612 where
613 T: 'static,
614 {
615 values
616 .into_iter()
617 .filter_map(|v| v.downcast_ref::<T>())
618 .collect()
619 }
620
621 pub fn insert_into_any<'a>(
623 &self,
624 table: &str,
625 values: impl IntoIterator<Item = &'a dyn Any>,
626 ) -> InsertBuilder
627 where
628 T: 'static,
629 {
630 let rows = Self::filter_rows_any(values);
631 self.insert_into(table, rows)
632 }
633
634 pub fn insert_ignore_into_any<'a>(
635 &self,
636 table: &str,
637 values: impl IntoIterator<Item = &'a dyn Any>,
638 ) -> InsertBuilder
639 where
640 T: 'static,
641 {
642 let rows = Self::filter_rows_any(values);
643 self.insert_ignore_into(table, rows)
644 }
645
646 pub fn replace_into_any<'a>(
647 &self,
648 table: &str,
649 values: impl IntoIterator<Item = &'a dyn Any>,
650 ) -> InsertBuilder
651 where
652 T: 'static,
653 {
654 let rows = Self::filter_rows_any(values);
655 self.replace_into(table, rows)
656 }
657
658 pub fn insert_into_for_tag_any<'a>(
659 &self,
660 table: &str,
661 tag: &str,
662 values: impl IntoIterator<Item = &'a dyn Any>,
663 ) -> InsertBuilder
664 where
665 T: 'static,
666 {
667 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
668 let rows = Self::filter_rows_any(values);
669 self.with_tag([tag]).insert_into(table, rows)
670 }
671
672 pub fn insert_ignore_into_for_tag_any<'a>(
673 &self,
674 table: &str,
675 tag: &str,
676 values: impl IntoIterator<Item = &'a dyn Any>,
677 ) -> InsertBuilder
678 where
679 T: 'static,
680 {
681 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
682 let rows = Self::filter_rows_any(values);
683 self.with_tag([tag]).insert_ignore_into(table, rows)
684 }
685
686 pub fn replace_into_for_tag_any<'a>(
687 &self,
688 table: &str,
689 tag: &str,
690 values: impl IntoIterator<Item = &'a dyn Any>,
691 ) -> InsertBuilder
692 where
693 T: 'static,
694 {
695 let tag: &'static str = Box::leak(tag.to_string().into_boxed_str());
696 let rows = Self::filter_rows_any(values);
697 self.with_tag([tag]).replace_into(table, rows)
698 }
699
700 pub fn insert_ignore_into<'a>(
701 &self,
702 table: &str,
703 rows: impl IntoIterator<Item = &'a T>,
704 ) -> InsertBuilder
705 where
706 T: 'a,
707 {
708 self.insert_internal(table, rows, InsertVerb::InsertIgnore)
709 }
710
711 pub fn replace_into<'a>(
712 &self,
713 table: &str,
714 rows: impl IntoIterator<Item = &'a T>,
715 ) -> InsertBuilder
716 where
717 T: 'a,
718 {
719 self.insert_internal(table, rows, InsertVerb::Replace)
720 }
721
722 fn insert_internal<'a>(
723 &self,
724 table: &str,
725 rows: impl IntoIterator<Item = &'a T>,
726 verb: InsertVerb,
727 ) -> InsertBuilder
728 where
729 T: 'a,
730 {
731 let mut ib = InsertBuilder::new();
732 ib.set_flavor(self.flavor);
733 match verb {
734 InsertVerb::Insert => {
735 ib.insert_into(table);
736 }
737 InsertVerb::InsertIgnore => {
738 ib.insert_ignore_into(table);
739 }
740 InsertVerb::Replace => {
741 ib.replace_into(table);
742 }
743 }
744
745 let rows: Vec<&T> = rows.into_iter().collect();
746 if rows.is_empty() {
747 return ib;
749 }
750
751 let fields = self.fields_for_write();
752
753 let mut nil_cnt = vec![0_usize; fields.len()];
755 for (fi, fm) in fields.iter().enumerate() {
756 let should_omit = self.should_omit_empty(fm);
757 if !should_omit {
758 continue;
759 }
760 for r in &rows {
761 if r.is_empty_field(fm.rust) {
762 nil_cnt[fi] += 1;
763 }
764 }
765 }
766
767 let mut kept = Vec::<usize>::new();
768 for (i, cnt) in nil_cnt.into_iter().enumerate() {
769 if cnt == rows.len() {
770 continue;
771 }
772 kept.push(i);
773 }
774
775 let cols: Vec<String> = kept
776 .iter()
777 .map(|&i| {
778 let fm = fields[i];
779 let field_alias = self.alias_of(fm);
780 if fm.with_quote {
781 self.flavor.quote(&field_alias)
782 } else {
783 field_alias
784 }
785 })
786 .collect();
787 ib.cols(escape_all(cols));
788
789 for r in rows {
790 let mut map = std::collections::HashMap::<&'static str, crate::modifiers::Arg>::new();
791 for (fm, arg) in T::FIELDS.iter().zip(r.values()) {
792 map.insert(fm.rust, arg);
793 }
794 let mut row_args = Vec::new();
795 for &i in &kept {
796 let fm = fields[i];
797 row_args.push(
798 map.get(fm.rust)
799 .cloned()
800 .unwrap_or_else(|| crate::SqlValue::Null.into()),
801 );
802 }
803 ib.values(row_args);
804 }
805
806 ib
807 }
808}
809
810#[derive(Debug, Clone, Copy)]
811enum InsertVerb {
812 Insert,
813 InsertIgnore,
814 Replace,
815}
816
817#[macro_export]
833macro_rules! sql_struct {
834 (
835 impl $ty:ty {
836 $(
837 $field:ident : { db: $db:literal, $(orig: $orig:literal,)? tags: [ $($tag:literal),* $(,)? ], omitempty: [ $($omit:literal),* $(,)? ], quote: $quote:literal, as: $as:expr }
838 ),* $(,)?
839 }
840 ) => {
841 impl $crate::structs::SqlStruct for $ty {
842 const FIELDS: &'static [$crate::structs::FieldMeta] = &[
843 $(
844 $crate::structs::FieldMeta{
845 rust: stringify!($field),
846 orig: $crate::__sql_struct_orig!(stringify!($field) $(, $orig)?),
847 db: $db,
848 as_: $as,
849 tags: &[ $($tag),* ],
850 omitempty_tags: &[ $($omit),* ],
851 with_quote: $quote,
852 }
853 ),*
854 ];
855
856 fn values(&self) -> Vec<$crate::modifiers::Arg> {
857 vec![
858 $(
859 $crate::modifiers::Arg::from(self.$field.clone())
860 ),*
861 ]
862 }
863
864 fn is_empty_field(&self, rust_field: &'static str) -> bool {
865 match rust_field {
866 $(
867 stringify!($field) => $crate::structs::IsEmpty::is_empty_value(&self.$field),
868 )*
869 _ => false,
870 }
871 }
872
873 fn addr_cells<'a>(
874 &'a mut self,
875 rust_fields: &[&'static str],
876 ) -> Option<Vec<$crate::scan::ScanCell<'a>>> {
877 let mut out = Vec::with_capacity(rust_fields.len());
878 for &rf in rust_fields {
879 match rf {
880 $(
881 stringify!($field) => {
882 out.push($crate::scan::ScanCell::from_ptr(std::ptr::addr_of_mut!(self.$field)));
883 }
884 )*
885 _ => return None,
886 }
887 }
888 Some(out)
889 }
890 }
891 };
892}
893
894#[doc(hidden)]
896#[macro_export]
897macro_rules! __sql_struct_orig {
898 ($default:expr) => {
899 $default
900 };
901 ($default:expr, $custom:expr) => {
902 $custom
903 };
904}