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 HttpHandlers(Vec<RawHttpHandlerDefV10>),
95
96 HttpRoutes(Vec<RawHttpRouteDefV10>),
98
99 ViewPrimaryKeys(Vec<RawViewPrimaryKeyDefV10>),
101
102 Submodules(Vec<RawSubmoduleV10>),
104}
105
106#[derive(Debug, Clone, SpacetimeType)]
107#[sats(crate = crate)]
108#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
109pub struct RawHttpHandlerDefV10 {
110 pub source_name: RawIdentifier,
111}
112
113#[derive(Debug, Clone, SpacetimeType)]
114#[sats(crate = crate)]
115#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
116pub struct RawHttpRouteDefV10 {
117 pub handler_function: RawIdentifier,
118 pub method: MethodOrAny,
119 pub path: RawIdentifier,
120}
121
122#[derive(Debug, Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
123#[sats(crate = crate)]
124#[non_exhaustive]
125pub enum MethodOrAny {
126 Any,
127 Method(crate::http::Method),
128}
129
130#[derive(Debug, Clone, SpacetimeType)]
131#[sats(crate = crate)]
132#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
133pub struct RawSubmoduleV10 {
134 pub namespace: String,
135 pub module: RawModuleDefV10,
136}
137
138#[derive(Debug, Clone, Copy, Default, SpacetimeType)]
139#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
140#[sats(crate = crate)]
141#[non_exhaustive]
142pub enum CaseConversionPolicy {
143 None,
145 #[default]
147 SnakeCase,
148}
149
150#[derive(Debug, Clone, SpacetimeType)]
151#[sats(crate = crate)]
152#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
153#[non_exhaustive]
154pub struct NameMapping {
155 pub source_name: RawIdentifier,
165
166 pub canonical_name: RawIdentifier,
176}
177
178#[derive(Debug, Clone, SpacetimeType)]
179#[sats(crate = crate)]
180#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
181#[non_exhaustive]
182pub enum ExplicitNameEntry {
183 Table(NameMapping),
184 Function(NameMapping),
185 Index(NameMapping),
186}
187
188#[derive(Debug, Default, Clone, SpacetimeType)]
189#[sats(crate = crate)]
190#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
191#[non_exhaustive]
192pub struct ExplicitNames {
193 entries: Vec<ExplicitNameEntry>,
198}
199
200impl ExplicitNames {
201 fn insert(&mut self, entry: ExplicitNameEntry) {
202 self.entries.push(entry);
203 }
204
205 pub fn insert_table(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
206 self.insert(ExplicitNameEntry::Table(NameMapping {
207 source_name: source_name.into(),
208 canonical_name: canonical_name.into(),
209 }));
210 }
211
212 pub fn insert_function(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
213 self.insert(ExplicitNameEntry::Function(NameMapping {
214 source_name: source_name.into(),
215 canonical_name: canonical_name.into(),
216 }));
217 }
218
219 pub fn insert_index(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
220 self.insert(ExplicitNameEntry::Index(NameMapping {
221 source_name: source_name.into(),
222 canonical_name: canonical_name.into(),
223 }));
224 }
225
226 pub fn merge(&mut self, other: ExplicitNames) {
227 self.entries.extend(other.entries);
228 }
229
230 pub fn into_entries(self) -> Vec<ExplicitNameEntry> {
231 self.entries
232 }
233}
234
235pub type RawRowLevelSecurityDefV10 = crate::db::raw_def::v9::RawRowLevelSecurityDefV9;
236
237#[derive(Debug, Clone, SpacetimeType)]
246#[sats(crate = crate)]
247#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
248pub struct RawTableDefV10 {
249 pub source_name: RawIdentifier,
253
254 pub product_type_ref: AlgebraicTypeRef,
261
262 pub primary_key: ColList,
271
272 pub indexes: Vec<RawIndexDefV10>,
274
275 pub constraints: Vec<RawConstraintDefV10>,
277
278 pub sequences: Vec<RawSequenceDefV10>,
280
281 pub table_type: TableType,
283
284 pub table_access: TableAccess,
286
287 pub default_values: Vec<RawColumnDefaultValueV10>,
289
290 pub is_event: bool,
296}
297
298#[derive(Debug, Clone, SpacetimeType)]
300#[sats(crate = crate)]
301#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
302pub struct RawColumnDefaultValueV10 {
303 pub col_id: ColId,
305
306 pub value: Box<[u8]>,
309}
310
311#[derive(Debug, Clone, SpacetimeType)]
313#[sats(crate = crate)]
314#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
315pub struct RawReducerDefV10 {
316 pub source_name: RawIdentifier,
318
319 pub params: ProductType,
322
323 pub visibility: FunctionVisibility,
325
326 pub ok_return_type: AlgebraicType,
328
329 pub err_return_type: AlgebraicType,
331}
332
333#[derive(Debug, Copy, Clone, SpacetimeType)]
335#[sats(crate = crate)]
336#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
337pub enum FunctionVisibility {
338 Private,
345
346 ClientCallable,
348}
349
350#[derive(Debug, Clone, SpacetimeType)]
352#[sats(crate = crate)]
353#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
354pub struct RawScheduleDefV10 {
355 pub source_name: Option<RawIdentifier>,
359
360 pub table_name: RawIdentifier,
362
363 pub schedule_at_col: ColId,
365
366 pub function_name: RawIdentifier,
368}
369
370#[derive(Debug, Clone, SpacetimeType)]
372#[sats(crate = crate)]
373#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
374pub struct RawLifeCycleReducerDefV10 {
375 pub lifecycle_spec: Lifecycle,
377
378 pub function_name: RawIdentifier,
380}
381
382#[derive(Debug, Clone, SpacetimeType)]
384#[sats(crate = crate)]
385#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
386pub struct RawProcedureDefV10 {
387 pub source_name: RawIdentifier,
389
390 pub params: ProductType,
393
394 pub return_type: AlgebraicType,
399
400 pub visibility: FunctionVisibility,
402}
403
404#[derive(Debug, Clone, SpacetimeType)]
406#[sats(crate = crate)]
407#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
408pub struct RawSequenceDefV10 {
409 pub source_name: Option<RawIdentifier>,
413
414 pub column: ColId,
419
420 pub start: Option<i128>,
424
425 pub min_value: Option<i128>,
428
429 pub max_value: Option<i128>,
432
433 pub increment: i128,
435}
436
437#[derive(Debug, Clone, SpacetimeType)]
439#[sats(crate = crate)]
440#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
441pub struct RawIndexDefV10 {
442 pub source_name: Option<RawIdentifier>,
445
446 pub accessor_name: Option<RawIdentifier>,
449
450 pub algorithm: RawIndexAlgorithm,
452}
453
454#[derive(Debug, Clone, SpacetimeType)]
456#[sats(crate = crate)]
457#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
458pub struct RawConstraintDefV10 {
459 pub source_name: Option<RawIdentifier>,
462
463 pub data: RawConstraintDataV10,
465}
466
467type RawConstraintDataV10 = crate::db::raw_def::v9::RawConstraintDataV9;
468type RawUniqueConstraintDataV10 = crate::db::raw_def::v9::RawUniqueConstraintDataV9;
469
470#[derive(Debug, Clone, SpacetimeType)]
474#[sats(crate = crate)]
475#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
476pub struct RawTypeDefV10 {
477 pub source_name: RawScopedTypeNameV10,
479
480 pub ty: AlgebraicTypeRef,
483
484 pub custom_ordering: bool,
486}
487
488#[derive(Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
493#[sats(crate = crate)]
494pub struct RawScopedTypeNameV10 {
495 pub scope: Box<[RawIdentifier]>,
500
501 pub source_name: RawIdentifier,
505}
506
507impl fmt::Debug for RawScopedTypeNameV10 {
508 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509 for module in self.scope.iter() {
510 fmt::Debug::fmt(module, f)?;
511 f.write_str("::")?;
512 }
513 fmt::Debug::fmt(&self.source_name, f)?;
514 Ok(())
515 }
516}
517
518#[derive(Debug, Clone, SpacetimeType)]
520#[sats(crate = crate)]
521#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
522pub struct RawViewDefV10 {
523 pub source_name: RawIdentifier,
525
526 pub index: u32,
528
529 pub is_public: bool,
533
534 pub is_anonymous: bool,
539
540 pub params: ProductType,
543
544 pub return_type: AlgebraicType,
554}
555
556#[derive(Debug, Clone, SpacetimeType)]
558#[sats(crate = crate)]
559#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
560pub struct RawViewPrimaryKeyDefV10 {
561 pub view_source_name: RawIdentifier,
563
564 pub columns: Vec<RawIdentifier>,
569}
570
571impl RawModuleDefV10 {
572 pub fn submodules(&self) -> Option<&Vec<RawSubmoduleV10>> {
574 self.sections.iter().find_map(|s| match s {
575 RawModuleDefV10Section::Submodules(submodules) => Some(submodules),
576 _ => None,
577 })
578 }
579
580 pub fn types(&self) -> Option<&Vec<RawTypeDefV10>> {
582 self.sections.iter().find_map(|s| match s {
583 RawModuleDefV10Section::Types(types) => Some(types),
584 _ => None,
585 })
586 }
587
588 pub fn tables(&self) -> Option<&Vec<RawTableDefV10>> {
590 self.sections.iter().find_map(|s| match s {
591 RawModuleDefV10Section::Tables(tables) => Some(tables),
592 _ => None,
593 })
594 }
595
596 pub fn typespace(&self) -> Option<&Typespace> {
598 self.sections.iter().find_map(|s| match s {
599 RawModuleDefV10Section::Typespace(ts) => Some(ts),
600 _ => None,
601 })
602 }
603
604 pub fn reducers(&self) -> Option<&Vec<RawReducerDefV10>> {
606 self.sections.iter().find_map(|s| match s {
607 RawModuleDefV10Section::Reducers(reducers) => Some(reducers),
608 _ => None,
609 })
610 }
611
612 pub fn procedures(&self) -> Option<&Vec<RawProcedureDefV10>> {
614 self.sections.iter().find_map(|s| match s {
615 RawModuleDefV10Section::Procedures(procedures) => Some(procedures),
616 _ => None,
617 })
618 }
619
620 pub fn views(&self) -> Option<&Vec<RawViewDefV10>> {
622 self.sections.iter().find_map(|s| match s {
623 RawModuleDefV10Section::Views(views) => Some(views),
624 _ => None,
625 })
626 }
627
628 pub fn view_primary_keys(&self) -> Option<&Vec<RawViewPrimaryKeyDefV10>> {
630 self.sections.iter().find_map(|s| match s {
631 RawModuleDefV10Section::ViewPrimaryKeys(primary_keys) => Some(primary_keys),
632 _ => None,
633 })
634 }
635
636 pub fn schedules(&self) -> Option<&Vec<RawScheduleDefV10>> {
638 self.sections.iter().find_map(|s| match s {
639 RawModuleDefV10Section::Schedules(schedules) => Some(schedules),
640 _ => None,
641 })
642 }
643
644 pub fn lifecycle_reducers(&self) -> Option<&Vec<RawLifeCycleReducerDefV10>> {
646 self.sections.iter().find_map(|s| match s {
647 RawModuleDefV10Section::LifeCycleReducers(lcrs) => Some(lcrs),
648 _ => None,
649 })
650 }
651
652 pub fn tables_mut_for_tests(&mut self) -> &mut Vec<RawTableDefV10> {
653 self.sections
654 .iter_mut()
655 .find_map(|s| match s {
656 RawModuleDefV10Section::Tables(tables) => Some(tables),
657 _ => None,
658 })
659 .expect("Tables section must exist for tests")
660 }
661
662 pub fn row_level_security(&self) -> Option<&Vec<RawRowLevelSecurityDefV10>> {
664 self.sections.iter().find_map(|s| match s {
665 RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls),
666 _ => None,
667 })
668 }
669
670 pub fn case_conversion_policy(&self) -> CaseConversionPolicy {
671 self.sections
672 .iter()
673 .find_map(|s| match s {
674 RawModuleDefV10Section::CaseConversionPolicy(policy) => Some(*policy),
675 _ => None,
676 })
677 .unwrap_or_default()
678 }
679
680 pub fn explicit_names(&self) -> Option<&ExplicitNames> {
681 self.sections.iter().find_map(|s| match s {
682 RawModuleDefV10Section::ExplicitNames(names) => Some(names),
683 _ => None,
684 })
685 }
686
687 pub fn http_handlers(&self) -> Option<&Vec<RawHttpHandlerDefV10>> {
688 self.sections.iter().find_map(|s| match s {
689 RawModuleDefV10Section::HttpHandlers(handlers) => Some(handlers),
690 _ => None,
691 })
692 }
693
694 pub fn http_routes(&self) -> Option<&Vec<RawHttpRouteDefV10>> {
695 self.sections.iter().find_map(|s| match s {
696 RawModuleDefV10Section::HttpRoutes(routes) => Some(routes),
697 _ => None,
698 })
699 }
700}
701
702#[derive(Default)]
704pub struct RawModuleDefV10Builder {
705 module: RawModuleDefV10,
707
708 type_map: BTreeMap<TypeId, AlgebraicTypeRef>,
710}
711
712impl RawModuleDefV10Builder {
713 pub fn new() -> Self {
715 Default::default()
716 }
717
718 fn typespace_mut(&mut self) -> &mut Typespace {
720 let idx = self
721 .module
722 .sections
723 .iter()
724 .position(|s| matches!(s, RawModuleDefV10Section::Typespace(_)))
725 .unwrap_or_else(|| {
726 self.module
727 .sections
728 .push(RawModuleDefV10Section::Typespace(Typespace::EMPTY.clone()));
729 self.module.sections.len() - 1
730 });
731
732 match &mut self.module.sections[idx] {
733 RawModuleDefV10Section::Typespace(ts) => ts,
734 _ => unreachable!("Just ensured Typespace section exists"),
735 }
736 }
737
738 fn reducers_mut(&mut self) -> &mut Vec<RawReducerDefV10> {
740 let idx = self
741 .module
742 .sections
743 .iter()
744 .position(|s| matches!(s, RawModuleDefV10Section::Reducers(_)))
745 .unwrap_or_else(|| {
746 self.module.sections.push(RawModuleDefV10Section::Reducers(Vec::new()));
747 self.module.sections.len() - 1
748 });
749
750 match &mut self.module.sections[idx] {
751 RawModuleDefV10Section::Reducers(reducers) => reducers,
752 _ => unreachable!("Just ensured Reducers section exists"),
753 }
754 }
755
756 fn procedures_mut(&mut self) -> &mut Vec<RawProcedureDefV10> {
758 let idx = self
759 .module
760 .sections
761 .iter()
762 .position(|s| matches!(s, RawModuleDefV10Section::Procedures(_)))
763 .unwrap_or_else(|| {
764 self.module
765 .sections
766 .push(RawModuleDefV10Section::Procedures(Vec::new()));
767 self.module.sections.len() - 1
768 });
769
770 match &mut self.module.sections[idx] {
771 RawModuleDefV10Section::Procedures(procedures) => procedures,
772 _ => unreachable!("Just ensured Procedures section exists"),
773 }
774 }
775
776 fn views_mut(&mut self) -> &mut Vec<RawViewDefV10> {
778 let idx = self
779 .module
780 .sections
781 .iter()
782 .position(|s| matches!(s, RawModuleDefV10Section::Views(_)))
783 .unwrap_or_else(|| {
784 self.module.sections.push(RawModuleDefV10Section::Views(Vec::new()));
785 self.module.sections.len() - 1
786 });
787
788 match &mut self.module.sections[idx] {
789 RawModuleDefV10Section::Views(views) => views,
790 _ => unreachable!("Just ensured Views section exists"),
791 }
792 }
793
794 fn view_primary_keys_mut(&mut self) -> &mut Vec<RawViewPrimaryKeyDefV10> {
796 let idx = self
797 .module
798 .sections
799 .iter()
800 .position(|s| matches!(s, RawModuleDefV10Section::ViewPrimaryKeys(_)))
801 .unwrap_or_else(|| {
802 self.module
803 .sections
804 .push(RawModuleDefV10Section::ViewPrimaryKeys(Vec::new()));
805 self.module.sections.len() - 1
806 });
807
808 match &mut self.module.sections[idx] {
809 RawModuleDefV10Section::ViewPrimaryKeys(primary_keys) => primary_keys,
810 _ => unreachable!("Just ensured ViewPrimaryKeys section exists"),
811 }
812 }
813
814 fn schedules_mut(&mut self) -> &mut Vec<RawScheduleDefV10> {
816 let idx = self
817 .module
818 .sections
819 .iter()
820 .position(|s| matches!(s, RawModuleDefV10Section::Schedules(_)))
821 .unwrap_or_else(|| {
822 self.module.sections.push(RawModuleDefV10Section::Schedules(Vec::new()));
823 self.module.sections.len() - 1
824 });
825
826 match &mut self.module.sections[idx] {
827 RawModuleDefV10Section::Schedules(schedules) => schedules,
828 _ => unreachable!("Just ensured Schedules section exists"),
829 }
830 }
831
832 fn lifecycle_reducers_mut(&mut self) -> &mut Vec<RawLifeCycleReducerDefV10> {
834 let idx = self
835 .module
836 .sections
837 .iter()
838 .position(|s| matches!(s, RawModuleDefV10Section::LifeCycleReducers(_)))
839 .unwrap_or_else(|| {
840 self.module
841 .sections
842 .push(RawModuleDefV10Section::LifeCycleReducers(Vec::new()));
843 self.module.sections.len() - 1
844 });
845
846 match &mut self.module.sections[idx] {
847 RawModuleDefV10Section::LifeCycleReducers(lcrs) => lcrs,
848 _ => unreachable!("Just ensured LifeCycleReducers section exists"),
849 }
850 }
851
852 fn types_mut(&mut self) -> &mut Vec<RawTypeDefV10> {
854 let idx = self
855 .module
856 .sections
857 .iter()
858 .position(|s| matches!(s, RawModuleDefV10Section::Types(_)))
859 .unwrap_or_else(|| {
860 self.module.sections.push(RawModuleDefV10Section::Types(Vec::new()));
861 self.module.sections.len() - 1
862 });
863
864 match &mut self.module.sections[idx] {
865 RawModuleDefV10Section::Types(types) => types,
866 _ => unreachable!("Just ensured Types section exists"),
867 }
868 }
869
870 pub fn add_type<T: SpacetimeType>(&mut self) -> AlgebraicType {
874 TypespaceBuilder::add_type::<T>(self)
875 }
876
877 fn row_level_security_mut(&mut self) -> &mut Vec<RawRowLevelSecurityDefV10> {
879 let idx = self
880 .module
881 .sections
882 .iter()
883 .position(|s| matches!(s, RawModuleDefV10Section::RowLevelSecurity(_)))
884 .unwrap_or_else(|| {
885 self.module
886 .sections
887 .push(RawModuleDefV10Section::RowLevelSecurity(Vec::new()));
888 self.module.sections.len() - 1
889 });
890
891 match &mut self.module.sections[idx] {
892 RawModuleDefV10Section::RowLevelSecurity(rls) => rls,
893 _ => unreachable!("Just ensured RowLevelSecurity section exists"),
894 }
895 }
896
897 fn explicit_names_mut(&mut self) -> &mut ExplicitNames {
899 let idx = self
900 .module
901 .sections
902 .iter()
903 .position(|s| matches!(s, RawModuleDefV10Section::ExplicitNames(_)))
904 .unwrap_or_else(|| {
905 self.module
906 .sections
907 .push(RawModuleDefV10Section::ExplicitNames(ExplicitNames::default()));
908 self.module.sections.len() - 1
909 });
910
911 match &mut self.module.sections[idx] {
912 RawModuleDefV10Section::ExplicitNames(names) => names,
913 _ => unreachable!("Just ensured ExplicitNames section exists"),
914 }
915 }
916
917 fn http_handlers_mut(&mut self) -> &mut Vec<RawHttpHandlerDefV10> {
919 let idx = self
920 .module
921 .sections
922 .iter()
923 .position(|s| matches!(s, RawModuleDefV10Section::HttpHandlers(_)))
924 .unwrap_or_else(|| {
925 self.module
926 .sections
927 .push(RawModuleDefV10Section::HttpHandlers(Vec::new()));
928 self.module.sections.len() - 1
929 });
930
931 match &mut self.module.sections[idx] {
932 RawModuleDefV10Section::HttpHandlers(handlers) => handlers,
933 _ => unreachable!("Just ensured HttpHandlers section exists"),
934 }
935 }
936
937 fn http_routes_mut(&mut self) -> &mut Vec<RawHttpRouteDefV10> {
939 let idx = self
940 .module
941 .sections
942 .iter()
943 .position(|s| matches!(s, RawModuleDefV10Section::HttpRoutes(_)))
944 .unwrap_or_else(|| {
945 self.module
946 .sections
947 .push(RawModuleDefV10Section::HttpRoutes(Vec::new()));
948 self.module.sections.len() - 1
949 });
950
951 match &mut self.module.sections[idx] {
952 RawModuleDefV10Section::HttpRoutes(routes) => routes,
953 _ => unreachable!("Just ensured HttpRoutes section exists"),
954 }
955 }
956
957 pub fn build_table(
961 &mut self,
962 source_name: impl Into<RawIdentifier>,
963 product_type_ref: AlgebraicTypeRef,
964 ) -> RawTableDefBuilderV10<'_> {
965 let source_name = source_name.into();
966 RawTableDefBuilderV10 {
967 module: &mut self.module,
968 table: RawTableDefV10 {
969 source_name,
970 product_type_ref,
971 indexes: vec![],
972 constraints: vec![],
973 sequences: vec![],
974 primary_key: ColList::empty(),
975 table_type: TableType::User,
976 table_access: TableAccess::Public,
977 default_values: vec![],
978 is_event: false,
979 },
980 }
981 }
982
983 pub fn build_table_with_new_type(
986 &mut self,
987 table_name: impl Into<RawIdentifier>,
988 product_type: impl Into<ProductType>,
989 custom_ordering: bool,
990 ) -> RawTableDefBuilderV10<'_> {
991 let table_name = table_name.into();
992
993 let product_type_ref = self.add_algebraic_type(
994 [],
995 table_name.clone(),
996 AlgebraicType::from(product_type.into()),
997 custom_ordering,
998 );
999
1000 self.build_table(table_name, product_type_ref)
1001 }
1002
1003 pub fn build_table_with_new_type_for_tests(
1006 &mut self,
1007 table_name: impl Into<RawIdentifier>,
1008 mut product_type: ProductType,
1009 custom_ordering: bool,
1010 ) -> RawTableDefBuilderV10<'_> {
1011 self.add_expand_product_type_for_tests(&mut 0, &mut product_type);
1012 self.build_table_with_new_type(table_name, product_type, custom_ordering)
1013 }
1014
1015 fn add_expand_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut AlgebraicType) {
1016 if ty.is_valid_for_client_type_use() {
1017 return;
1018 }
1019
1020 match ty {
1021 AlgebraicType::Product(prod_ty) => self.add_expand_product_type_for_tests(name_gen, prod_ty),
1022 AlgebraicType::Sum(sum_type) => {
1023 if let Some(wrapped) = sum_type.as_option_mut() {
1024 self.add_expand_type_for_tests(name_gen, wrapped);
1025 } else {
1026 for elem in sum_type.variants.iter_mut() {
1027 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
1028 }
1029 }
1030 }
1031 AlgebraicType::Array(ty) => {
1032 self.add_expand_type_for_tests(name_gen, &mut ty.elem_ty);
1033 return;
1034 }
1035 _ => return,
1036 }
1037
1038 let name = *name_gen;
1040 let add_ty = core::mem::replace(ty, AlgebraicType::U8);
1041 *ty = AlgebraicType::Ref(self.add_algebraic_type([], RawIdentifier::new(format!("gen_{name}")), add_ty, true));
1042 *name_gen += 1;
1043 }
1044
1045 fn add_expand_product_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut ProductType) {
1046 for elem in ty.elements.iter_mut() {
1047 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
1048 }
1049 }
1050
1051 pub fn add_algebraic_type(
1061 &mut self,
1062 scope: impl IntoIterator<Item = RawIdentifier>,
1063 source_name: impl Into<RawIdentifier>,
1064 ty: AlgebraicType,
1065 custom_ordering: bool,
1066 ) -> AlgebraicTypeRef {
1067 let ty_ref = self.typespace_mut().add(ty);
1068 let scope = scope.into_iter().collect();
1069 let source_name = source_name.into();
1070 self.types_mut().push(RawTypeDefV10 {
1071 source_name: RawScopedTypeNameV10 { source_name, scope },
1072 ty: ty_ref,
1073 custom_ordering,
1074 });
1075 ty_ref
1078 }
1079
1080 pub fn add_reducer(&mut self, source_name: impl Into<RawIdentifier>, params: ProductType) {
1095 self.reducers_mut().push(RawReducerDefV10 {
1096 source_name: source_name.into(),
1097 params,
1098 visibility: FunctionVisibility::ClientCallable,
1099 ok_return_type: reducer_default_ok_return_type(),
1100 err_return_type: reducer_default_err_return_type(),
1101 });
1102 }
1103
1104 pub fn add_procedure(
1115 &mut self,
1116 source_name: impl Into<RawIdentifier>,
1117 params: ProductType,
1118 return_type: AlgebraicType,
1119 ) {
1120 self.procedures_mut().push(RawProcedureDefV10 {
1121 source_name: source_name.into(),
1122 params,
1123 return_type,
1124 visibility: FunctionVisibility::ClientCallable,
1125 })
1126 }
1127
1128 pub fn add_view(
1130 &mut self,
1131 source_name: impl Into<RawIdentifier>,
1132 index: usize,
1133 is_public: bool,
1134 is_anonymous: bool,
1135 params: ProductType,
1136 return_type: AlgebraicType,
1137 ) {
1138 self.views_mut().push(RawViewDefV10 {
1139 source_name: source_name.into(),
1140 index: index as u32,
1141 is_public,
1142 is_anonymous,
1143 params,
1144 return_type,
1145 });
1146 }
1147
1148 pub fn add_view_primary_key<C, I>(&mut self, view_source_name: impl Into<RawIdentifier>, columns: I)
1150 where
1151 C: Into<RawIdentifier>,
1152 I: IntoIterator<Item = C>,
1153 {
1154 self.view_primary_keys_mut().push(RawViewPrimaryKeyDefV10 {
1155 view_source_name: view_source_name.into(),
1156 columns: columns.into_iter().map(Into::into).collect(),
1157 });
1158 }
1159
1160 pub fn add_lifecycle_reducer(
1164 &mut self,
1165 lifecycle_spec: Lifecycle,
1166 function_name: impl Into<RawIdentifier>,
1167 params: ProductType,
1168 ) {
1169 let function_name = function_name.into();
1170 self.lifecycle_reducers_mut().push(RawLifeCycleReducerDefV10 {
1171 lifecycle_spec,
1172 function_name: function_name.clone(),
1173 });
1174
1175 self.reducers_mut().push(RawReducerDefV10 {
1176 source_name: function_name,
1177 params,
1178 visibility: FunctionVisibility::Private,
1179 ok_return_type: reducer_default_ok_return_type(),
1180 err_return_type: reducer_default_err_return_type(),
1181 });
1182 }
1183
1184 pub fn add_schedule(
1191 &mut self,
1192 table: impl Into<RawIdentifier>,
1193 column: impl Into<ColId>,
1194 function: impl Into<RawIdentifier>,
1195 ) {
1196 self.schedules_mut().push(RawScheduleDefV10 {
1197 source_name: None,
1198 table_name: table.into(),
1199 schedule_at_col: column.into(),
1200 function_name: function.into(),
1201 });
1202 }
1203
1204 pub fn add_row_level_security(&mut self, sql: &str) {
1210 self.row_level_security_mut()
1211 .push(RawRowLevelSecurityDefV10 { sql: sql.into() });
1212 }
1213
1214 pub fn add_http_handler(&mut self, source_name: impl Into<RawIdentifier>) {
1216 self.http_handlers_mut().push(RawHttpHandlerDefV10 {
1217 source_name: source_name.into(),
1218 });
1219 }
1220
1221 pub fn add_http_route(
1223 &mut self,
1224 handler_function: impl Into<RawIdentifier>,
1225 method: MethodOrAny,
1226 path: impl Into<RawIdentifier>,
1227 ) {
1228 self.http_routes_mut().push(RawHttpRouteDefV10 {
1229 handler_function: handler_function.into(),
1230 method,
1231 path: path.into(),
1232 });
1233 }
1234
1235 pub fn add_explicit_names(&mut self, names: ExplicitNames) {
1236 self.explicit_names_mut().merge(names);
1237 }
1238
1239 pub fn set_case_conversion_policy(&mut self, policy: CaseConversionPolicy) {
1246 self.module
1248 .sections
1249 .retain(|s| !matches!(s, RawModuleDefV10Section::CaseConversionPolicy(_)));
1250 self.module
1251 .sections
1252 .push(RawModuleDefV10Section::CaseConversionPolicy(policy));
1253 }
1254
1255 pub fn finish(self) -> RawModuleDefV10 {
1258 self.module
1259 }
1260}
1261
1262impl TypespaceBuilder for RawModuleDefV10Builder {
1264 fn add(
1265 &mut self,
1266 typeid: TypeId,
1267 source_name: Option<&'static str>,
1268 make_ty: impl FnOnce(&mut Self) -> AlgebraicType,
1269 ) -> AlgebraicType {
1270 if let btree_map::Entry::Occupied(o) = self.type_map.entry(typeid) {
1271 AlgebraicType::Ref(*o.get())
1272 } else {
1273 let slot_ref = {
1274 let ts = self.typespace_mut();
1275 let slot_ref = ts.add(AlgebraicType::unit());
1277 self.type_map.insert(typeid, slot_ref);
1279
1280 if let Some(sats_name) = source_name {
1282 let source_name = sats_name_to_scoped_name_v10(sats_name);
1283
1284 self.types_mut().push(RawTypeDefV10 {
1285 source_name,
1286 ty: slot_ref,
1287 custom_ordering: true,
1292 });
1293 }
1294 slot_ref
1295 };
1296
1297 let ty = make_ty(self);
1299 self.typespace_mut()[slot_ref] = ty;
1300 AlgebraicType::Ref(slot_ref)
1301 }
1302 }
1303}
1304
1305pub fn reducer_default_ok_return_type() -> AlgebraicType {
1306 AlgebraicType::unit()
1307}
1308
1309pub fn reducer_default_err_return_type() -> AlgebraicType {
1310 AlgebraicType::String
1311}
1312
1313pub fn sats_name_to_scoped_name_v10(sats_name: &str) -> RawScopedTypeNameV10 {
1317 let mut scope: Vec<RawIdentifier> = sats_name
1319 .split("::")
1320 .flat_map(|s| s.split('.'))
1321 .map(RawIdentifier::new)
1322 .collect();
1323 let source_name = scope.pop().unwrap_or_default();
1325 RawScopedTypeNameV10 {
1326 scope: scope.into(),
1327 source_name,
1328 }
1329}
1330
1331pub struct RawTableDefBuilderV10<'a> {
1333 module: &'a mut RawModuleDefV10,
1334 table: RawTableDefV10,
1335}
1336
1337impl RawTableDefBuilderV10<'_> {
1338 pub fn with_type(mut self, table_type: TableType) -> Self {
1343 self.table.table_type = table_type;
1344 self
1345 }
1346
1347 pub fn with_access(mut self, table_access: TableAccess) -> Self {
1349 self.table.table_access = table_access;
1350 self
1351 }
1352
1353 pub fn with_event(mut self, is_event: bool) -> Self {
1355 self.table.is_event = is_event;
1356 self
1357 }
1358
1359 pub fn with_unique_constraint(mut self, columns: impl Into<ColList>) -> Self {
1361 let columns = columns.into();
1362 self.table.constraints.push(RawConstraintDefV10 {
1363 source_name: None,
1364 data: RawConstraintDataV10::Unique(RawUniqueConstraintDataV10 { columns }),
1365 });
1366
1367 self
1368 }
1369
1370 pub fn with_primary_key(mut self, column: impl Into<ColId>) -> Self {
1373 self.table.primary_key = ColList::new(column.into());
1374 self
1375 }
1376
1377 pub fn with_auto_inc_primary_key(self, column: impl Into<ColId>) -> Self {
1380 let column = column.into();
1381 self.with_primary_key(column)
1382 .with_unique_constraint(column)
1383 .with_column_sequence(column)
1384 }
1385
1386 pub fn with_index(
1388 mut self,
1389 algorithm: RawIndexAlgorithm,
1390 source_name: impl Into<RawIdentifier>,
1391 accessor_name: impl Into<RawIdentifier>,
1392 ) -> Self {
1393 self.table.indexes.push(RawIndexDefV10 {
1394 source_name: Some(source_name.into()),
1395 accessor_name: Some(accessor_name.into()),
1396 algorithm,
1397 });
1398 self
1399 }
1400
1401 pub fn with_index_no_accessor_name(
1403 mut self,
1404 algorithm: RawIndexAlgorithm,
1405 source_name: impl Into<RawIdentifier>,
1406 ) -> Self {
1407 self.table.indexes.push(RawIndexDefV10 {
1408 source_name: Some(source_name.into()),
1409 accessor_name: None,
1410 algorithm,
1411 });
1412 self
1413 }
1414
1415 pub fn with_column_sequence(mut self, column: impl Into<ColId>) -> Self {
1417 let column = column.into();
1418 self.table.sequences.push(RawSequenceDefV10 {
1419 source_name: None,
1420 column,
1421 start: None,
1422 min_value: None,
1423 max_value: None,
1424 increment: 1,
1425 });
1426
1427 self
1428 }
1429
1430 pub fn with_default_column_value(mut self, column: impl Into<ColId>, value: AlgebraicValue) -> Self {
1432 let col_id = column.into();
1433 self.table.default_values.push(RawColumnDefaultValueV10 {
1434 col_id,
1435 value: spacetimedb_sats::bsatn::to_vec(&value).unwrap().into(),
1436 });
1437
1438 self
1439 }
1440
1441 pub fn finish(self) -> AlgebraicTypeRef {
1443 let product_type_ref = self.table.product_type_ref;
1444
1445 let tables = match self
1446 .module
1447 .sections
1448 .iter_mut()
1449 .find(|s| matches!(s, RawModuleDefV10Section::Tables(_)))
1450 {
1451 Some(RawModuleDefV10Section::Tables(t)) => t,
1452 _ => {
1453 self.module.sections.push(RawModuleDefV10Section::Tables(Vec::new()));
1454 match self.module.sections.last_mut().expect("Just pushed Tables section") {
1455 RawModuleDefV10Section::Tables(t) => t,
1456 _ => unreachable!(),
1457 }
1458 }
1459 };
1460
1461 tables.push(self.table);
1462 product_type_ref
1463 }
1464
1465 pub fn find_col_pos_by_name(&self, column: impl AsRef<str>) -> Option<ColId> {
1467 let column = column.as_ref();
1468
1469 let typespace = self.module.sections.iter().find_map(|s| {
1470 if let RawModuleDefV10Section::Typespace(ts) = s {
1471 Some(ts)
1472 } else {
1473 None
1474 }
1475 })?;
1476
1477 typespace
1478 .get(self.table.product_type_ref)?
1479 .as_product()?
1480 .elements
1481 .iter()
1482 .position(|x| x.has_name(column.as_ref()))
1483 .map(|i| ColId(i as u16))
1484 }
1485}