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