1use crate::db::raw_def::v9::{Lifecycle, RawIndexAlgorithm, TableAccess, TableType};
9use core::fmt;
10use spacetimedb_primitives::{ColId, ColList};
11use spacetimedb_sats::raw_identifier::RawIdentifier;
12use spacetimedb_sats::typespace::TypespaceBuilder;
13use spacetimedb_sats::{AlgebraicType, AlgebraicTypeRef, AlgebraicValue, ProductType, SpacetimeType, Typespace};
14use std::any::TypeId;
15use std::collections::{btree_map, BTreeMap};
16
17#[derive(Default, Debug, Clone, SpacetimeType)]
35#[sats(crate = crate)]
36#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
37pub struct RawModuleDefV10 {
38 pub sections: Vec<RawModuleDefV10Section>,
42}
43
44#[derive(Debug, Clone, SpacetimeType)]
48#[sats(crate = crate)]
49#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
50#[non_exhaustive]
51pub enum RawModuleDefV10Section {
52 Typespace(Typespace),
57
58 Types(Vec<RawTypeDefV10>),
60
61 Tables(Vec<RawTableDefV10>),
63
64 Reducers(Vec<RawReducerDefV10>),
66
67 Procedures(Vec<RawProcedureDefV10>),
69
70 Views(Vec<RawViewDefV10>),
72
73 Schedules(Vec<RawScheduleDefV10>),
78
79 LifeCycleReducers(Vec<RawLifeCycleReducerDefV10>),
84
85 RowLevelSecurity(Vec<RawRowLevelSecurityDefV10>), CaseConversionPolicy(CaseConversionPolicy),
89
90 ExplicitNames(ExplicitNames),
92}
93
94#[derive(Debug, Clone, Copy, Default, SpacetimeType)]
95#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
96#[sats(crate = crate)]
97#[non_exhaustive]
98pub enum CaseConversionPolicy {
99 None,
101 #[default]
103 SnakeCase,
104}
105
106#[derive(Debug, Clone, SpacetimeType)]
107#[sats(crate = crate)]
108#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
109#[non_exhaustive]
110pub struct NameMapping {
111 pub source_name: RawIdentifier,
121
122 pub canonical_name: RawIdentifier,
132}
133
134#[derive(Debug, Clone, SpacetimeType)]
135#[sats(crate = crate)]
136#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
137#[non_exhaustive]
138pub enum ExplicitNameEntry {
139 Table(NameMapping),
140 Function(NameMapping),
141 Index(NameMapping),
142}
143
144#[derive(Debug, Default, Clone, SpacetimeType)]
145#[sats(crate = crate)]
146#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
147#[non_exhaustive]
148pub struct ExplicitNames {
149 entries: Vec<ExplicitNameEntry>,
154}
155
156impl ExplicitNames {
157 fn insert(&mut self, entry: ExplicitNameEntry) {
158 self.entries.push(entry);
159 }
160
161 pub fn insert_table(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
162 self.insert(ExplicitNameEntry::Table(NameMapping {
163 source_name: source_name.into(),
164 canonical_name: canonical_name.into(),
165 }));
166 }
167
168 pub fn insert_function(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
169 self.insert(ExplicitNameEntry::Function(NameMapping {
170 source_name: source_name.into(),
171 canonical_name: canonical_name.into(),
172 }));
173 }
174
175 pub fn insert_index(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
176 self.insert(ExplicitNameEntry::Index(NameMapping {
177 source_name: source_name.into(),
178 canonical_name: canonical_name.into(),
179 }));
180 }
181
182 pub fn merge(&mut self, other: ExplicitNames) {
183 self.entries.extend(other.entries);
184 }
185
186 pub fn into_entries(self) -> Vec<ExplicitNameEntry> {
187 self.entries
188 }
189}
190
191pub type RawRowLevelSecurityDefV10 = crate::db::raw_def::v9::RawRowLevelSecurityDefV9;
192
193#[derive(Debug, Clone, SpacetimeType)]
202#[sats(crate = crate)]
203#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
204pub struct RawTableDefV10 {
205 pub source_name: RawIdentifier,
209
210 pub product_type_ref: AlgebraicTypeRef,
217
218 pub primary_key: ColList,
227
228 pub indexes: Vec<RawIndexDefV10>,
230
231 pub constraints: Vec<RawConstraintDefV10>,
233
234 pub sequences: Vec<RawSequenceDefV10>,
236
237 pub table_type: TableType,
239
240 pub table_access: TableAccess,
242
243 pub default_values: Vec<RawColumnDefaultValueV10>,
245
246 pub is_event: bool,
252}
253
254#[derive(Debug, Clone, SpacetimeType)]
256#[sats(crate = crate)]
257#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
258pub struct RawColumnDefaultValueV10 {
259 pub col_id: ColId,
261
262 pub value: Box<[u8]>,
265}
266
267#[derive(Debug, Clone, SpacetimeType)]
269#[sats(crate = crate)]
270#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
271pub struct RawReducerDefV10 {
272 pub source_name: RawIdentifier,
274
275 pub params: ProductType,
278
279 pub visibility: FunctionVisibility,
281
282 pub ok_return_type: AlgebraicType,
284
285 pub err_return_type: AlgebraicType,
287}
288
289#[derive(Debug, Copy, Clone, SpacetimeType)]
291#[sats(crate = crate)]
292#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
293pub enum FunctionVisibility {
294 Private,
301
302 ClientCallable,
304}
305
306#[derive(Debug, Clone, SpacetimeType)]
308#[sats(crate = crate)]
309#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
310pub struct RawScheduleDefV10 {
311 pub source_name: Option<RawIdentifier>,
315
316 pub table_name: RawIdentifier,
318
319 pub schedule_at_col: ColId,
321
322 pub function_name: RawIdentifier,
324}
325
326#[derive(Debug, Clone, SpacetimeType)]
328#[sats(crate = crate)]
329#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
330pub struct RawLifeCycleReducerDefV10 {
331 pub lifecycle_spec: Lifecycle,
333
334 pub function_name: RawIdentifier,
336}
337
338#[derive(Debug, Clone, SpacetimeType)]
340#[sats(crate = crate)]
341#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
342pub struct RawProcedureDefV10 {
343 pub source_name: RawIdentifier,
345
346 pub params: ProductType,
349
350 pub return_type: AlgebraicType,
355
356 pub visibility: FunctionVisibility,
358}
359
360#[derive(Debug, Clone, SpacetimeType)]
362#[sats(crate = crate)]
363#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
364pub struct RawSequenceDefV10 {
365 pub source_name: Option<RawIdentifier>,
369
370 pub column: ColId,
375
376 pub start: Option<i128>,
380
381 pub min_value: Option<i128>,
384
385 pub max_value: Option<i128>,
388
389 pub increment: i128,
391}
392
393#[derive(Debug, Clone, SpacetimeType)]
395#[sats(crate = crate)]
396#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
397pub struct RawIndexDefV10 {
398 pub source_name: Option<RawIdentifier>,
401
402 pub accessor_name: Option<RawIdentifier>,
405
406 pub algorithm: RawIndexAlgorithm,
408}
409
410#[derive(Debug, Clone, SpacetimeType)]
412#[sats(crate = crate)]
413#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
414pub struct RawConstraintDefV10 {
415 pub source_name: Option<RawIdentifier>,
418
419 pub data: RawConstraintDataV10,
421}
422
423type RawConstraintDataV10 = crate::db::raw_def::v9::RawConstraintDataV9;
424type RawUniqueConstraintDataV10 = crate::db::raw_def::v9::RawUniqueConstraintDataV9;
425
426#[derive(Debug, Clone, SpacetimeType)]
430#[sats(crate = crate)]
431#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
432pub struct RawTypeDefV10 {
433 pub source_name: RawScopedTypeNameV10,
435
436 pub ty: AlgebraicTypeRef,
439
440 pub custom_ordering: bool,
442}
443
444#[derive(Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
449#[sats(crate = crate)]
450pub struct RawScopedTypeNameV10 {
451 pub scope: Box<[RawIdentifier]>,
456
457 pub source_name: RawIdentifier,
461}
462
463impl fmt::Debug for RawScopedTypeNameV10 {
464 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
465 for module in self.scope.iter() {
466 fmt::Debug::fmt(module, f)?;
467 f.write_str("::")?;
468 }
469 fmt::Debug::fmt(&self.source_name, f)?;
470 Ok(())
471 }
472}
473
474#[derive(Debug, Clone, SpacetimeType)]
476#[sats(crate = crate)]
477#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
478pub struct RawViewDefV10 {
479 pub source_name: RawIdentifier,
481
482 pub index: u32,
484
485 pub is_public: bool,
489
490 pub is_anonymous: bool,
495
496 pub params: ProductType,
499
500 pub return_type: AlgebraicType,
510}
511
512impl RawModuleDefV10 {
513 pub fn types(&self) -> Option<&Vec<RawTypeDefV10>> {
515 self.sections.iter().find_map(|s| match s {
516 RawModuleDefV10Section::Types(types) => Some(types),
517 _ => None,
518 })
519 }
520
521 pub fn tables(&self) -> Option<&Vec<RawTableDefV10>> {
523 self.sections.iter().find_map(|s| match s {
524 RawModuleDefV10Section::Tables(tables) => Some(tables),
525 _ => None,
526 })
527 }
528
529 pub fn typespace(&self) -> Option<&Typespace> {
531 self.sections.iter().find_map(|s| match s {
532 RawModuleDefV10Section::Typespace(ts) => Some(ts),
533 _ => None,
534 })
535 }
536
537 pub fn reducers(&self) -> Option<&Vec<RawReducerDefV10>> {
539 self.sections.iter().find_map(|s| match s {
540 RawModuleDefV10Section::Reducers(reducers) => Some(reducers),
541 _ => None,
542 })
543 }
544
545 pub fn procedures(&self) -> Option<&Vec<RawProcedureDefV10>> {
547 self.sections.iter().find_map(|s| match s {
548 RawModuleDefV10Section::Procedures(procedures) => Some(procedures),
549 _ => None,
550 })
551 }
552
553 pub fn views(&self) -> Option<&Vec<RawViewDefV10>> {
555 self.sections.iter().find_map(|s| match s {
556 RawModuleDefV10Section::Views(views) => Some(views),
557 _ => None,
558 })
559 }
560
561 pub fn schedules(&self) -> Option<&Vec<RawScheduleDefV10>> {
563 self.sections.iter().find_map(|s| match s {
564 RawModuleDefV10Section::Schedules(schedules) => Some(schedules),
565 _ => None,
566 })
567 }
568
569 pub fn lifecycle_reducers(&self) -> Option<&Vec<RawLifeCycleReducerDefV10>> {
571 self.sections.iter().find_map(|s| match s {
572 RawModuleDefV10Section::LifeCycleReducers(lcrs) => Some(lcrs),
573 _ => None,
574 })
575 }
576
577 pub fn tables_mut_for_tests(&mut self) -> &mut Vec<RawTableDefV10> {
578 self.sections
579 .iter_mut()
580 .find_map(|s| match s {
581 RawModuleDefV10Section::Tables(tables) => Some(tables),
582 _ => None,
583 })
584 .expect("Tables section must exist for tests")
585 }
586
587 pub fn row_level_security(&self) -> Option<&Vec<RawRowLevelSecurityDefV10>> {
589 self.sections.iter().find_map(|s| match s {
590 RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls),
591 _ => None,
592 })
593 }
594
595 pub fn case_conversion_policy(&self) -> CaseConversionPolicy {
596 self.sections
597 .iter()
598 .find_map(|s| match s {
599 RawModuleDefV10Section::CaseConversionPolicy(policy) => Some(*policy),
600 _ => None,
601 })
602 .unwrap_or_default()
603 }
604
605 pub fn explicit_names(&self) -> Option<&ExplicitNames> {
606 self.sections.iter().find_map(|s| match s {
607 RawModuleDefV10Section::ExplicitNames(names) => Some(names),
608 _ => None,
609 })
610 }
611}
612
613#[derive(Default)]
615pub struct RawModuleDefV10Builder {
616 module: RawModuleDefV10,
618
619 type_map: BTreeMap<TypeId, AlgebraicTypeRef>,
621}
622
623impl RawModuleDefV10Builder {
624 pub fn new() -> Self {
626 Default::default()
627 }
628
629 fn typespace_mut(&mut self) -> &mut Typespace {
631 let idx = self
632 .module
633 .sections
634 .iter()
635 .position(|s| matches!(s, RawModuleDefV10Section::Typespace(_)))
636 .unwrap_or_else(|| {
637 self.module
638 .sections
639 .push(RawModuleDefV10Section::Typespace(Typespace::EMPTY.clone()));
640 self.module.sections.len() - 1
641 });
642
643 match &mut self.module.sections[idx] {
644 RawModuleDefV10Section::Typespace(ts) => ts,
645 _ => unreachable!("Just ensured Typespace section exists"),
646 }
647 }
648
649 fn reducers_mut(&mut self) -> &mut Vec<RawReducerDefV10> {
651 let idx = self
652 .module
653 .sections
654 .iter()
655 .position(|s| matches!(s, RawModuleDefV10Section::Reducers(_)))
656 .unwrap_or_else(|| {
657 self.module.sections.push(RawModuleDefV10Section::Reducers(Vec::new()));
658 self.module.sections.len() - 1
659 });
660
661 match &mut self.module.sections[idx] {
662 RawModuleDefV10Section::Reducers(reducers) => reducers,
663 _ => unreachable!("Just ensured Reducers section exists"),
664 }
665 }
666
667 fn procedures_mut(&mut self) -> &mut Vec<RawProcedureDefV10> {
669 let idx = self
670 .module
671 .sections
672 .iter()
673 .position(|s| matches!(s, RawModuleDefV10Section::Procedures(_)))
674 .unwrap_or_else(|| {
675 self.module
676 .sections
677 .push(RawModuleDefV10Section::Procedures(Vec::new()));
678 self.module.sections.len() - 1
679 });
680
681 match &mut self.module.sections[idx] {
682 RawModuleDefV10Section::Procedures(procedures) => procedures,
683 _ => unreachable!("Just ensured Procedures section exists"),
684 }
685 }
686
687 fn views_mut(&mut self) -> &mut Vec<RawViewDefV10> {
689 let idx = self
690 .module
691 .sections
692 .iter()
693 .position(|s| matches!(s, RawModuleDefV10Section::Views(_)))
694 .unwrap_or_else(|| {
695 self.module.sections.push(RawModuleDefV10Section::Views(Vec::new()));
696 self.module.sections.len() - 1
697 });
698
699 match &mut self.module.sections[idx] {
700 RawModuleDefV10Section::Views(views) => views,
701 _ => unreachable!("Just ensured Views section exists"),
702 }
703 }
704
705 fn schedules_mut(&mut self) -> &mut Vec<RawScheduleDefV10> {
707 let idx = self
708 .module
709 .sections
710 .iter()
711 .position(|s| matches!(s, RawModuleDefV10Section::Schedules(_)))
712 .unwrap_or_else(|| {
713 self.module.sections.push(RawModuleDefV10Section::Schedules(Vec::new()));
714 self.module.sections.len() - 1
715 });
716
717 match &mut self.module.sections[idx] {
718 RawModuleDefV10Section::Schedules(schedules) => schedules,
719 _ => unreachable!("Just ensured Schedules section exists"),
720 }
721 }
722
723 fn lifecycle_reducers_mut(&mut self) -> &mut Vec<RawLifeCycleReducerDefV10> {
725 let idx = self
726 .module
727 .sections
728 .iter()
729 .position(|s| matches!(s, RawModuleDefV10Section::LifeCycleReducers(_)))
730 .unwrap_or_else(|| {
731 self.module
732 .sections
733 .push(RawModuleDefV10Section::LifeCycleReducers(Vec::new()));
734 self.module.sections.len() - 1
735 });
736
737 match &mut self.module.sections[idx] {
738 RawModuleDefV10Section::LifeCycleReducers(lcrs) => lcrs,
739 _ => unreachable!("Just ensured LifeCycleReducers section exists"),
740 }
741 }
742
743 fn types_mut(&mut self) -> &mut Vec<RawTypeDefV10> {
745 let idx = self
746 .module
747 .sections
748 .iter()
749 .position(|s| matches!(s, RawModuleDefV10Section::Types(_)))
750 .unwrap_or_else(|| {
751 self.module.sections.push(RawModuleDefV10Section::Types(Vec::new()));
752 self.module.sections.len() - 1
753 });
754
755 match &mut self.module.sections[idx] {
756 RawModuleDefV10Section::Types(types) => types,
757 _ => unreachable!("Just ensured Types section exists"),
758 }
759 }
760
761 pub fn add_type<T: SpacetimeType>(&mut self) -> AlgebraicType {
765 TypespaceBuilder::add_type::<T>(self)
766 }
767
768 fn row_level_security_mut(&mut self) -> &mut Vec<RawRowLevelSecurityDefV10> {
770 let idx = self
771 .module
772 .sections
773 .iter()
774 .position(|s| matches!(s, RawModuleDefV10Section::RowLevelSecurity(_)))
775 .unwrap_or_else(|| {
776 self.module
777 .sections
778 .push(RawModuleDefV10Section::RowLevelSecurity(Vec::new()));
779 self.module.sections.len() - 1
780 });
781
782 match &mut self.module.sections[idx] {
783 RawModuleDefV10Section::RowLevelSecurity(rls) => rls,
784 _ => unreachable!("Just ensured RowLevelSecurity section exists"),
785 }
786 }
787
788 fn explicit_names_mut(&mut self) -> &mut ExplicitNames {
790 let idx = self
791 .module
792 .sections
793 .iter()
794 .position(|s| matches!(s, RawModuleDefV10Section::ExplicitNames(_)))
795 .unwrap_or_else(|| {
796 self.module
797 .sections
798 .push(RawModuleDefV10Section::ExplicitNames(ExplicitNames::default()));
799 self.module.sections.len() - 1
800 });
801
802 match &mut self.module.sections[idx] {
803 RawModuleDefV10Section::ExplicitNames(names) => names,
804 _ => unreachable!("Just ensured ExplicitNames section exists"),
805 }
806 }
807
808 pub fn build_table(
812 &mut self,
813 source_name: impl Into<RawIdentifier>,
814 product_type_ref: AlgebraicTypeRef,
815 ) -> RawTableDefBuilderV10<'_> {
816 let source_name = source_name.into();
817 RawTableDefBuilderV10 {
818 module: &mut self.module,
819 table: RawTableDefV10 {
820 source_name,
821 product_type_ref,
822 indexes: vec![],
823 constraints: vec![],
824 sequences: vec![],
825 primary_key: ColList::empty(),
826 table_type: TableType::User,
827 table_access: TableAccess::Public,
828 default_values: vec![],
829 is_event: false,
830 },
831 }
832 }
833
834 pub fn build_table_with_new_type(
837 &mut self,
838 table_name: impl Into<RawIdentifier>,
839 product_type: impl Into<ProductType>,
840 custom_ordering: bool,
841 ) -> RawTableDefBuilderV10<'_> {
842 let table_name = table_name.into();
843
844 let product_type_ref = self.add_algebraic_type(
845 [],
846 table_name.clone(),
847 AlgebraicType::from(product_type.into()),
848 custom_ordering,
849 );
850
851 self.build_table(table_name, product_type_ref)
852 }
853
854 pub fn build_table_with_new_type_for_tests(
857 &mut self,
858 table_name: impl Into<RawIdentifier>,
859 mut product_type: ProductType,
860 custom_ordering: bool,
861 ) -> RawTableDefBuilderV10<'_> {
862 self.add_expand_product_type_for_tests(&mut 0, &mut product_type);
863 self.build_table_with_new_type(table_name, product_type, custom_ordering)
864 }
865
866 fn add_expand_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut AlgebraicType) {
867 if ty.is_valid_for_client_type_use() {
868 return;
869 }
870
871 match ty {
872 AlgebraicType::Product(prod_ty) => self.add_expand_product_type_for_tests(name_gen, prod_ty),
873 AlgebraicType::Sum(sum_type) => {
874 if let Some(wrapped) = sum_type.as_option_mut() {
875 self.add_expand_type_for_tests(name_gen, wrapped);
876 } else {
877 for elem in sum_type.variants.iter_mut() {
878 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
879 }
880 }
881 }
882 AlgebraicType::Array(ty) => {
883 self.add_expand_type_for_tests(name_gen, &mut ty.elem_ty);
884 return;
885 }
886 _ => return,
887 }
888
889 let name = *name_gen;
891 let add_ty = core::mem::replace(ty, AlgebraicType::U8);
892 *ty = AlgebraicType::Ref(self.add_algebraic_type([], RawIdentifier::new(format!("gen_{name}")), add_ty, true));
893 *name_gen += 1;
894 }
895
896 fn add_expand_product_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut ProductType) {
897 for elem in ty.elements.iter_mut() {
898 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
899 }
900 }
901
902 pub fn add_algebraic_type(
912 &mut self,
913 scope: impl IntoIterator<Item = RawIdentifier>,
914 source_name: impl Into<RawIdentifier>,
915 ty: AlgebraicType,
916 custom_ordering: bool,
917 ) -> AlgebraicTypeRef {
918 let ty_ref = self.typespace_mut().add(ty);
919 let scope = scope.into_iter().collect();
920 let source_name = source_name.into();
921 self.types_mut().push(RawTypeDefV10 {
922 source_name: RawScopedTypeNameV10 { source_name, scope },
923 ty: ty_ref,
924 custom_ordering,
925 });
926 ty_ref
929 }
930
931 pub fn add_reducer(&mut self, source_name: impl Into<RawIdentifier>, params: ProductType) {
946 self.reducers_mut().push(RawReducerDefV10 {
947 source_name: source_name.into(),
948 params,
949 visibility: FunctionVisibility::ClientCallable,
950 ok_return_type: reducer_default_ok_return_type(),
951 err_return_type: reducer_default_err_return_type(),
952 });
953 }
954
955 pub fn add_procedure(
966 &mut self,
967 source_name: impl Into<RawIdentifier>,
968 params: ProductType,
969 return_type: AlgebraicType,
970 ) {
971 self.procedures_mut().push(RawProcedureDefV10 {
972 source_name: source_name.into(),
973 params,
974 return_type,
975 visibility: FunctionVisibility::ClientCallable,
976 })
977 }
978
979 pub fn add_view(
981 &mut self,
982 source_name: impl Into<RawIdentifier>,
983 index: usize,
984 is_public: bool,
985 is_anonymous: bool,
986 params: ProductType,
987 return_type: AlgebraicType,
988 ) {
989 self.views_mut().push(RawViewDefV10 {
990 source_name: source_name.into(),
991 index: index as u32,
992 is_public,
993 is_anonymous,
994 params,
995 return_type,
996 });
997 }
998
999 pub fn add_lifecycle_reducer(
1003 &mut self,
1004 lifecycle_spec: Lifecycle,
1005 function_name: impl Into<RawIdentifier>,
1006 params: ProductType,
1007 ) {
1008 let function_name = function_name.into();
1009 self.lifecycle_reducers_mut().push(RawLifeCycleReducerDefV10 {
1010 lifecycle_spec,
1011 function_name: function_name.clone(),
1012 });
1013
1014 self.reducers_mut().push(RawReducerDefV10 {
1015 source_name: function_name,
1016 params,
1017 visibility: FunctionVisibility::Private,
1018 ok_return_type: reducer_default_ok_return_type(),
1019 err_return_type: reducer_default_err_return_type(),
1020 });
1021 }
1022
1023 pub fn add_schedule(
1030 &mut self,
1031 table: impl Into<RawIdentifier>,
1032 column: impl Into<ColId>,
1033 function: impl Into<RawIdentifier>,
1034 ) {
1035 self.schedules_mut().push(RawScheduleDefV10 {
1036 source_name: None,
1037 table_name: table.into(),
1038 schedule_at_col: column.into(),
1039 function_name: function.into(),
1040 });
1041 }
1042
1043 pub fn add_row_level_security(&mut self, sql: &str) {
1049 self.row_level_security_mut()
1050 .push(RawRowLevelSecurityDefV10 { sql: sql.into() });
1051 }
1052
1053 pub fn add_explicit_names(&mut self, names: ExplicitNames) {
1054 self.explicit_names_mut().merge(names);
1055 }
1056
1057 pub fn set_case_conversion_policy(&mut self, policy: CaseConversionPolicy) {
1064 self.module
1066 .sections
1067 .retain(|s| !matches!(s, RawModuleDefV10Section::CaseConversionPolicy(_)));
1068 self.module
1069 .sections
1070 .push(RawModuleDefV10Section::CaseConversionPolicy(policy));
1071 }
1072
1073 pub fn finish(self) -> RawModuleDefV10 {
1076 self.module
1077 }
1078}
1079
1080impl TypespaceBuilder for RawModuleDefV10Builder {
1082 fn add(
1083 &mut self,
1084 typeid: TypeId,
1085 source_name: Option<&'static str>,
1086 make_ty: impl FnOnce(&mut Self) -> AlgebraicType,
1087 ) -> AlgebraicType {
1088 if let btree_map::Entry::Occupied(o) = self.type_map.entry(typeid) {
1089 AlgebraicType::Ref(*o.get())
1090 } else {
1091 let slot_ref = {
1092 let ts = self.typespace_mut();
1093 let slot_ref = ts.add(AlgebraicType::unit());
1095 self.type_map.insert(typeid, slot_ref);
1097
1098 if let Some(sats_name) = source_name {
1100 let source_name = sats_name_to_scoped_name_v10(sats_name);
1101
1102 self.types_mut().push(RawTypeDefV10 {
1103 source_name,
1104 ty: slot_ref,
1105 custom_ordering: true,
1110 });
1111 }
1112 slot_ref
1113 };
1114
1115 let ty = make_ty(self);
1117 self.typespace_mut()[slot_ref] = ty;
1118 AlgebraicType::Ref(slot_ref)
1119 }
1120 }
1121}
1122
1123pub fn reducer_default_ok_return_type() -> AlgebraicType {
1124 AlgebraicType::unit()
1125}
1126
1127pub fn reducer_default_err_return_type() -> AlgebraicType {
1128 AlgebraicType::String
1129}
1130
1131pub fn sats_name_to_scoped_name_v10(sats_name: &str) -> RawScopedTypeNameV10 {
1135 let mut scope: Vec<RawIdentifier> = sats_name
1137 .split("::")
1138 .flat_map(|s| s.split('.'))
1139 .map(RawIdentifier::new)
1140 .collect();
1141 let source_name = scope.pop().unwrap_or_default();
1143 RawScopedTypeNameV10 {
1144 scope: scope.into(),
1145 source_name,
1146 }
1147}
1148
1149pub struct RawTableDefBuilderV10<'a> {
1151 module: &'a mut RawModuleDefV10,
1152 table: RawTableDefV10,
1153}
1154
1155impl RawTableDefBuilderV10<'_> {
1156 pub fn with_type(mut self, table_type: TableType) -> Self {
1161 self.table.table_type = table_type;
1162 self
1163 }
1164
1165 pub fn with_access(mut self, table_access: TableAccess) -> Self {
1167 self.table.table_access = table_access;
1168 self
1169 }
1170
1171 pub fn with_event(mut self, is_event: bool) -> Self {
1173 self.table.is_event = is_event;
1174 self
1175 }
1176
1177 pub fn with_unique_constraint(mut self, columns: impl Into<ColList>) -> Self {
1179 let columns = columns.into();
1180 self.table.constraints.push(RawConstraintDefV10 {
1181 source_name: None,
1182 data: RawConstraintDataV10::Unique(RawUniqueConstraintDataV10 { columns }),
1183 });
1184
1185 self
1186 }
1187
1188 pub fn with_primary_key(mut self, column: impl Into<ColId>) -> Self {
1191 self.table.primary_key = ColList::new(column.into());
1192 self
1193 }
1194
1195 pub fn with_auto_inc_primary_key(self, column: impl Into<ColId>) -> Self {
1198 let column = column.into();
1199 self.with_primary_key(column)
1200 .with_unique_constraint(column)
1201 .with_column_sequence(column)
1202 }
1203
1204 pub fn with_index(
1206 mut self,
1207 algorithm: RawIndexAlgorithm,
1208 source_name: impl Into<RawIdentifier>,
1209 accessor_name: impl Into<RawIdentifier>,
1210 ) -> Self {
1211 self.table.indexes.push(RawIndexDefV10 {
1212 source_name: Some(source_name.into()),
1213 accessor_name: Some(accessor_name.into()),
1214 algorithm,
1215 });
1216 self
1217 }
1218
1219 pub fn with_index_no_accessor_name(
1221 mut self,
1222 algorithm: RawIndexAlgorithm,
1223 source_name: impl Into<RawIdentifier>,
1224 ) -> Self {
1225 self.table.indexes.push(RawIndexDefV10 {
1226 source_name: Some(source_name.into()),
1227 accessor_name: None,
1228 algorithm,
1229 });
1230 self
1231 }
1232
1233 pub fn with_column_sequence(mut self, column: impl Into<ColId>) -> Self {
1235 let column = column.into();
1236 self.table.sequences.push(RawSequenceDefV10 {
1237 source_name: None,
1238 column,
1239 start: None,
1240 min_value: None,
1241 max_value: None,
1242 increment: 1,
1243 });
1244
1245 self
1246 }
1247
1248 pub fn with_default_column_value(mut self, column: impl Into<ColId>, value: AlgebraicValue) -> Self {
1250 let col_id = column.into();
1251 self.table.default_values.push(RawColumnDefaultValueV10 {
1252 col_id,
1253 value: spacetimedb_sats::bsatn::to_vec(&value).unwrap().into(),
1254 });
1255
1256 self
1257 }
1258
1259 pub fn finish(self) -> AlgebraicTypeRef {
1261 let product_type_ref = self.table.product_type_ref;
1262
1263 let tables = match self
1264 .module
1265 .sections
1266 .iter_mut()
1267 .find(|s| matches!(s, RawModuleDefV10Section::Tables(_)))
1268 {
1269 Some(RawModuleDefV10Section::Tables(t)) => t,
1270 _ => {
1271 self.module.sections.push(RawModuleDefV10Section::Tables(Vec::new()));
1272 match self.module.sections.last_mut().expect("Just pushed Tables section") {
1273 RawModuleDefV10Section::Tables(t) => t,
1274 _ => unreachable!(),
1275 }
1276 }
1277 };
1278
1279 tables.push(self.table);
1280 product_type_ref
1281 }
1282
1283 pub fn find_col_pos_by_name(&self, column: impl AsRef<str>) -> Option<ColId> {
1285 let column = column.as_ref();
1286
1287 let typespace = self.module.sections.iter().find_map(|s| {
1288 if let RawModuleDefV10Section::Typespace(ts) = s {
1289 Some(ts)
1290 } else {
1291 None
1292 }
1293 })?;
1294
1295 typespace
1296 .get(self.table.product_type_ref)?
1297 .as_product()?
1298 .elements
1299 .iter()
1300 .position(|x| x.has_name(column.as_ref()))
1301 .map(|i| ColId(i as u16))
1302 }
1303}