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
100#[derive(Debug, Clone, SpacetimeType)]
101#[sats(crate = crate)]
102#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
103pub struct RawHttpHandlerDefV10 {
104 pub source_name: RawIdentifier,
105}
106
107#[derive(Debug, Clone, SpacetimeType)]
108#[sats(crate = crate)]
109#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
110pub struct RawHttpRouteDefV10 {
111 pub handler_function: RawIdentifier,
112 pub method: MethodOrAny,
113 pub path: RawIdentifier,
114}
115
116#[derive(Debug, Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
117#[sats(crate = crate)]
118#[non_exhaustive]
119pub enum MethodOrAny {
120 Any,
121 Method(crate::http::Method),
122}
123
124#[derive(Debug, Clone, Copy, Default, SpacetimeType)]
125#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
126#[sats(crate = crate)]
127#[non_exhaustive]
128pub enum CaseConversionPolicy {
129 None,
131 #[default]
133 SnakeCase,
134}
135
136#[derive(Debug, Clone, SpacetimeType)]
137#[sats(crate = crate)]
138#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
139#[non_exhaustive]
140pub struct NameMapping {
141 pub source_name: RawIdentifier,
151
152 pub canonical_name: RawIdentifier,
162}
163
164#[derive(Debug, Clone, SpacetimeType)]
165#[sats(crate = crate)]
166#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
167#[non_exhaustive]
168pub enum ExplicitNameEntry {
169 Table(NameMapping),
170 Function(NameMapping),
171 Index(NameMapping),
172}
173
174#[derive(Debug, Default, Clone, SpacetimeType)]
175#[sats(crate = crate)]
176#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
177#[non_exhaustive]
178pub struct ExplicitNames {
179 entries: Vec<ExplicitNameEntry>,
184}
185
186impl ExplicitNames {
187 fn insert(&mut self, entry: ExplicitNameEntry) {
188 self.entries.push(entry);
189 }
190
191 pub fn insert_table(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
192 self.insert(ExplicitNameEntry::Table(NameMapping {
193 source_name: source_name.into(),
194 canonical_name: canonical_name.into(),
195 }));
196 }
197
198 pub fn insert_function(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
199 self.insert(ExplicitNameEntry::Function(NameMapping {
200 source_name: source_name.into(),
201 canonical_name: canonical_name.into(),
202 }));
203 }
204
205 pub fn insert_index(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
206 self.insert(ExplicitNameEntry::Index(NameMapping {
207 source_name: source_name.into(),
208 canonical_name: canonical_name.into(),
209 }));
210 }
211
212 pub fn merge(&mut self, other: ExplicitNames) {
213 self.entries.extend(other.entries);
214 }
215
216 pub fn into_entries(self) -> Vec<ExplicitNameEntry> {
217 self.entries
218 }
219}
220
221pub type RawRowLevelSecurityDefV10 = crate::db::raw_def::v9::RawRowLevelSecurityDefV9;
222
223#[derive(Debug, Clone, SpacetimeType)]
232#[sats(crate = crate)]
233#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
234pub struct RawTableDefV10 {
235 pub source_name: RawIdentifier,
239
240 pub product_type_ref: AlgebraicTypeRef,
247
248 pub primary_key: ColList,
257
258 pub indexes: Vec<RawIndexDefV10>,
260
261 pub constraints: Vec<RawConstraintDefV10>,
263
264 pub sequences: Vec<RawSequenceDefV10>,
266
267 pub table_type: TableType,
269
270 pub table_access: TableAccess,
272
273 pub default_values: Vec<RawColumnDefaultValueV10>,
275
276 pub is_event: bool,
282}
283
284#[derive(Debug, Clone, SpacetimeType)]
286#[sats(crate = crate)]
287#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
288pub struct RawColumnDefaultValueV10 {
289 pub col_id: ColId,
291
292 pub value: Box<[u8]>,
295}
296
297#[derive(Debug, Clone, SpacetimeType)]
299#[sats(crate = crate)]
300#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
301pub struct RawReducerDefV10 {
302 pub source_name: RawIdentifier,
304
305 pub params: ProductType,
308
309 pub visibility: FunctionVisibility,
311
312 pub ok_return_type: AlgebraicType,
314
315 pub err_return_type: AlgebraicType,
317}
318
319#[derive(Debug, Copy, Clone, SpacetimeType)]
321#[sats(crate = crate)]
322#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
323pub enum FunctionVisibility {
324 Private,
331
332 ClientCallable,
334}
335
336#[derive(Debug, Clone, SpacetimeType)]
338#[sats(crate = crate)]
339#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
340pub struct RawScheduleDefV10 {
341 pub source_name: Option<RawIdentifier>,
345
346 pub table_name: RawIdentifier,
348
349 pub schedule_at_col: ColId,
351
352 pub function_name: RawIdentifier,
354}
355
356#[derive(Debug, Clone, SpacetimeType)]
358#[sats(crate = crate)]
359#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
360pub struct RawLifeCycleReducerDefV10 {
361 pub lifecycle_spec: Lifecycle,
363
364 pub function_name: RawIdentifier,
366}
367
368#[derive(Debug, Clone, SpacetimeType)]
370#[sats(crate = crate)]
371#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
372pub struct RawProcedureDefV10 {
373 pub source_name: RawIdentifier,
375
376 pub params: ProductType,
379
380 pub return_type: AlgebraicType,
385
386 pub visibility: FunctionVisibility,
388}
389
390#[derive(Debug, Clone, SpacetimeType)]
392#[sats(crate = crate)]
393#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
394pub struct RawSequenceDefV10 {
395 pub source_name: Option<RawIdentifier>,
399
400 pub column: ColId,
405
406 pub start: Option<i128>,
410
411 pub min_value: Option<i128>,
414
415 pub max_value: Option<i128>,
418
419 pub increment: i128,
421}
422
423#[derive(Debug, Clone, SpacetimeType)]
425#[sats(crate = crate)]
426#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
427pub struct RawIndexDefV10 {
428 pub source_name: Option<RawIdentifier>,
431
432 pub accessor_name: Option<RawIdentifier>,
435
436 pub algorithm: RawIndexAlgorithm,
438}
439
440#[derive(Debug, Clone, SpacetimeType)]
442#[sats(crate = crate)]
443#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
444pub struct RawConstraintDefV10 {
445 pub source_name: Option<RawIdentifier>,
448
449 pub data: RawConstraintDataV10,
451}
452
453type RawConstraintDataV10 = crate::db::raw_def::v9::RawConstraintDataV9;
454type RawUniqueConstraintDataV10 = crate::db::raw_def::v9::RawUniqueConstraintDataV9;
455
456#[derive(Debug, Clone, SpacetimeType)]
460#[sats(crate = crate)]
461#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
462pub struct RawTypeDefV10 {
463 pub source_name: RawScopedTypeNameV10,
465
466 pub ty: AlgebraicTypeRef,
469
470 pub custom_ordering: bool,
472}
473
474#[derive(Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
479#[sats(crate = crate)]
480pub struct RawScopedTypeNameV10 {
481 pub scope: Box<[RawIdentifier]>,
486
487 pub source_name: RawIdentifier,
491}
492
493impl fmt::Debug for RawScopedTypeNameV10 {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 for module in self.scope.iter() {
496 fmt::Debug::fmt(module, f)?;
497 f.write_str("::")?;
498 }
499 fmt::Debug::fmt(&self.source_name, f)?;
500 Ok(())
501 }
502}
503
504#[derive(Debug, Clone, SpacetimeType)]
506#[sats(crate = crate)]
507#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
508pub struct RawViewDefV10 {
509 pub source_name: RawIdentifier,
511
512 pub index: u32,
514
515 pub is_public: bool,
519
520 pub is_anonymous: bool,
525
526 pub params: ProductType,
529
530 pub return_type: AlgebraicType,
540}
541
542impl RawModuleDefV10 {
543 pub fn types(&self) -> Option<&Vec<RawTypeDefV10>> {
545 self.sections.iter().find_map(|s| match s {
546 RawModuleDefV10Section::Types(types) => Some(types),
547 _ => None,
548 })
549 }
550
551 pub fn tables(&self) -> Option<&Vec<RawTableDefV10>> {
553 self.sections.iter().find_map(|s| match s {
554 RawModuleDefV10Section::Tables(tables) => Some(tables),
555 _ => None,
556 })
557 }
558
559 pub fn typespace(&self) -> Option<&Typespace> {
561 self.sections.iter().find_map(|s| match s {
562 RawModuleDefV10Section::Typespace(ts) => Some(ts),
563 _ => None,
564 })
565 }
566
567 pub fn reducers(&self) -> Option<&Vec<RawReducerDefV10>> {
569 self.sections.iter().find_map(|s| match s {
570 RawModuleDefV10Section::Reducers(reducers) => Some(reducers),
571 _ => None,
572 })
573 }
574
575 pub fn procedures(&self) -> Option<&Vec<RawProcedureDefV10>> {
577 self.sections.iter().find_map(|s| match s {
578 RawModuleDefV10Section::Procedures(procedures) => Some(procedures),
579 _ => None,
580 })
581 }
582
583 pub fn views(&self) -> Option<&Vec<RawViewDefV10>> {
585 self.sections.iter().find_map(|s| match s {
586 RawModuleDefV10Section::Views(views) => Some(views),
587 _ => None,
588 })
589 }
590
591 pub fn schedules(&self) -> Option<&Vec<RawScheduleDefV10>> {
593 self.sections.iter().find_map(|s| match s {
594 RawModuleDefV10Section::Schedules(schedules) => Some(schedules),
595 _ => None,
596 })
597 }
598
599 pub fn lifecycle_reducers(&self) -> Option<&Vec<RawLifeCycleReducerDefV10>> {
601 self.sections.iter().find_map(|s| match s {
602 RawModuleDefV10Section::LifeCycleReducers(lcrs) => Some(lcrs),
603 _ => None,
604 })
605 }
606
607 pub fn tables_mut_for_tests(&mut self) -> &mut Vec<RawTableDefV10> {
608 self.sections
609 .iter_mut()
610 .find_map(|s| match s {
611 RawModuleDefV10Section::Tables(tables) => Some(tables),
612 _ => None,
613 })
614 .expect("Tables section must exist for tests")
615 }
616
617 pub fn row_level_security(&self) -> Option<&Vec<RawRowLevelSecurityDefV10>> {
619 self.sections.iter().find_map(|s| match s {
620 RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls),
621 _ => None,
622 })
623 }
624
625 pub fn case_conversion_policy(&self) -> CaseConversionPolicy {
626 self.sections
627 .iter()
628 .find_map(|s| match s {
629 RawModuleDefV10Section::CaseConversionPolicy(policy) => Some(*policy),
630 _ => None,
631 })
632 .unwrap_or_default()
633 }
634
635 pub fn explicit_names(&self) -> Option<&ExplicitNames> {
636 self.sections.iter().find_map(|s| match s {
637 RawModuleDefV10Section::ExplicitNames(names) => Some(names),
638 _ => None,
639 })
640 }
641
642 pub fn http_handlers(&self) -> Option<&Vec<RawHttpHandlerDefV10>> {
643 self.sections.iter().find_map(|s| match s {
644 RawModuleDefV10Section::HttpHandlers(handlers) => Some(handlers),
645 _ => None,
646 })
647 }
648
649 pub fn http_routes(&self) -> Option<&Vec<RawHttpRouteDefV10>> {
650 self.sections.iter().find_map(|s| match s {
651 RawModuleDefV10Section::HttpRoutes(routes) => Some(routes),
652 _ => None,
653 })
654 }
655}
656
657#[derive(Default)]
659pub struct RawModuleDefV10Builder {
660 module: RawModuleDefV10,
662
663 type_map: BTreeMap<TypeId, AlgebraicTypeRef>,
665}
666
667impl RawModuleDefV10Builder {
668 pub fn new() -> Self {
670 Default::default()
671 }
672
673 fn typespace_mut(&mut self) -> &mut Typespace {
675 let idx = self
676 .module
677 .sections
678 .iter()
679 .position(|s| matches!(s, RawModuleDefV10Section::Typespace(_)))
680 .unwrap_or_else(|| {
681 self.module
682 .sections
683 .push(RawModuleDefV10Section::Typespace(Typespace::EMPTY.clone()));
684 self.module.sections.len() - 1
685 });
686
687 match &mut self.module.sections[idx] {
688 RawModuleDefV10Section::Typespace(ts) => ts,
689 _ => unreachable!("Just ensured Typespace section exists"),
690 }
691 }
692
693 fn reducers_mut(&mut self) -> &mut Vec<RawReducerDefV10> {
695 let idx = self
696 .module
697 .sections
698 .iter()
699 .position(|s| matches!(s, RawModuleDefV10Section::Reducers(_)))
700 .unwrap_or_else(|| {
701 self.module.sections.push(RawModuleDefV10Section::Reducers(Vec::new()));
702 self.module.sections.len() - 1
703 });
704
705 match &mut self.module.sections[idx] {
706 RawModuleDefV10Section::Reducers(reducers) => reducers,
707 _ => unreachable!("Just ensured Reducers section exists"),
708 }
709 }
710
711 fn procedures_mut(&mut self) -> &mut Vec<RawProcedureDefV10> {
713 let idx = self
714 .module
715 .sections
716 .iter()
717 .position(|s| matches!(s, RawModuleDefV10Section::Procedures(_)))
718 .unwrap_or_else(|| {
719 self.module
720 .sections
721 .push(RawModuleDefV10Section::Procedures(Vec::new()));
722 self.module.sections.len() - 1
723 });
724
725 match &mut self.module.sections[idx] {
726 RawModuleDefV10Section::Procedures(procedures) => procedures,
727 _ => unreachable!("Just ensured Procedures section exists"),
728 }
729 }
730
731 fn views_mut(&mut self) -> &mut Vec<RawViewDefV10> {
733 let idx = self
734 .module
735 .sections
736 .iter()
737 .position(|s| matches!(s, RawModuleDefV10Section::Views(_)))
738 .unwrap_or_else(|| {
739 self.module.sections.push(RawModuleDefV10Section::Views(Vec::new()));
740 self.module.sections.len() - 1
741 });
742
743 match &mut self.module.sections[idx] {
744 RawModuleDefV10Section::Views(views) => views,
745 _ => unreachable!("Just ensured Views section exists"),
746 }
747 }
748
749 fn schedules_mut(&mut self) -> &mut Vec<RawScheduleDefV10> {
751 let idx = self
752 .module
753 .sections
754 .iter()
755 .position(|s| matches!(s, RawModuleDefV10Section::Schedules(_)))
756 .unwrap_or_else(|| {
757 self.module.sections.push(RawModuleDefV10Section::Schedules(Vec::new()));
758 self.module.sections.len() - 1
759 });
760
761 match &mut self.module.sections[idx] {
762 RawModuleDefV10Section::Schedules(schedules) => schedules,
763 _ => unreachable!("Just ensured Schedules section exists"),
764 }
765 }
766
767 fn lifecycle_reducers_mut(&mut self) -> &mut Vec<RawLifeCycleReducerDefV10> {
769 let idx = self
770 .module
771 .sections
772 .iter()
773 .position(|s| matches!(s, RawModuleDefV10Section::LifeCycleReducers(_)))
774 .unwrap_or_else(|| {
775 self.module
776 .sections
777 .push(RawModuleDefV10Section::LifeCycleReducers(Vec::new()));
778 self.module.sections.len() - 1
779 });
780
781 match &mut self.module.sections[idx] {
782 RawModuleDefV10Section::LifeCycleReducers(lcrs) => lcrs,
783 _ => unreachable!("Just ensured LifeCycleReducers section exists"),
784 }
785 }
786
787 fn types_mut(&mut self) -> &mut Vec<RawTypeDefV10> {
789 let idx = self
790 .module
791 .sections
792 .iter()
793 .position(|s| matches!(s, RawModuleDefV10Section::Types(_)))
794 .unwrap_or_else(|| {
795 self.module.sections.push(RawModuleDefV10Section::Types(Vec::new()));
796 self.module.sections.len() - 1
797 });
798
799 match &mut self.module.sections[idx] {
800 RawModuleDefV10Section::Types(types) => types,
801 _ => unreachable!("Just ensured Types section exists"),
802 }
803 }
804
805 pub fn add_type<T: SpacetimeType>(&mut self) -> AlgebraicType {
809 TypespaceBuilder::add_type::<T>(self)
810 }
811
812 fn row_level_security_mut(&mut self) -> &mut Vec<RawRowLevelSecurityDefV10> {
814 let idx = self
815 .module
816 .sections
817 .iter()
818 .position(|s| matches!(s, RawModuleDefV10Section::RowLevelSecurity(_)))
819 .unwrap_or_else(|| {
820 self.module
821 .sections
822 .push(RawModuleDefV10Section::RowLevelSecurity(Vec::new()));
823 self.module.sections.len() - 1
824 });
825
826 match &mut self.module.sections[idx] {
827 RawModuleDefV10Section::RowLevelSecurity(rls) => rls,
828 _ => unreachable!("Just ensured RowLevelSecurity section exists"),
829 }
830 }
831
832 fn explicit_names_mut(&mut self) -> &mut ExplicitNames {
834 let idx = self
835 .module
836 .sections
837 .iter()
838 .position(|s| matches!(s, RawModuleDefV10Section::ExplicitNames(_)))
839 .unwrap_or_else(|| {
840 self.module
841 .sections
842 .push(RawModuleDefV10Section::ExplicitNames(ExplicitNames::default()));
843 self.module.sections.len() - 1
844 });
845
846 match &mut self.module.sections[idx] {
847 RawModuleDefV10Section::ExplicitNames(names) => names,
848 _ => unreachable!("Just ensured ExplicitNames section exists"),
849 }
850 }
851
852 fn http_handlers_mut(&mut self) -> &mut Vec<RawHttpHandlerDefV10> {
854 let idx = self
855 .module
856 .sections
857 .iter()
858 .position(|s| matches!(s, RawModuleDefV10Section::HttpHandlers(_)))
859 .unwrap_or_else(|| {
860 self.module
861 .sections
862 .push(RawModuleDefV10Section::HttpHandlers(Vec::new()));
863 self.module.sections.len() - 1
864 });
865
866 match &mut self.module.sections[idx] {
867 RawModuleDefV10Section::HttpHandlers(handlers) => handlers,
868 _ => unreachable!("Just ensured HttpHandlers section exists"),
869 }
870 }
871
872 fn http_routes_mut(&mut self) -> &mut Vec<RawHttpRouteDefV10> {
874 let idx = self
875 .module
876 .sections
877 .iter()
878 .position(|s| matches!(s, RawModuleDefV10Section::HttpRoutes(_)))
879 .unwrap_or_else(|| {
880 self.module
881 .sections
882 .push(RawModuleDefV10Section::HttpRoutes(Vec::new()));
883 self.module.sections.len() - 1
884 });
885
886 match &mut self.module.sections[idx] {
887 RawModuleDefV10Section::HttpRoutes(routes) => routes,
888 _ => unreachable!("Just ensured HttpRoutes section exists"),
889 }
890 }
891
892 pub fn build_table(
896 &mut self,
897 source_name: impl Into<RawIdentifier>,
898 product_type_ref: AlgebraicTypeRef,
899 ) -> RawTableDefBuilderV10<'_> {
900 let source_name = source_name.into();
901 RawTableDefBuilderV10 {
902 module: &mut self.module,
903 table: RawTableDefV10 {
904 source_name,
905 product_type_ref,
906 indexes: vec![],
907 constraints: vec![],
908 sequences: vec![],
909 primary_key: ColList::empty(),
910 table_type: TableType::User,
911 table_access: TableAccess::Public,
912 default_values: vec![],
913 is_event: false,
914 },
915 }
916 }
917
918 pub fn build_table_with_new_type(
921 &mut self,
922 table_name: impl Into<RawIdentifier>,
923 product_type: impl Into<ProductType>,
924 custom_ordering: bool,
925 ) -> RawTableDefBuilderV10<'_> {
926 let table_name = table_name.into();
927
928 let product_type_ref = self.add_algebraic_type(
929 [],
930 table_name.clone(),
931 AlgebraicType::from(product_type.into()),
932 custom_ordering,
933 );
934
935 self.build_table(table_name, product_type_ref)
936 }
937
938 pub fn build_table_with_new_type_for_tests(
941 &mut self,
942 table_name: impl Into<RawIdentifier>,
943 mut product_type: ProductType,
944 custom_ordering: bool,
945 ) -> RawTableDefBuilderV10<'_> {
946 self.add_expand_product_type_for_tests(&mut 0, &mut product_type);
947 self.build_table_with_new_type(table_name, product_type, custom_ordering)
948 }
949
950 fn add_expand_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut AlgebraicType) {
951 if ty.is_valid_for_client_type_use() {
952 return;
953 }
954
955 match ty {
956 AlgebraicType::Product(prod_ty) => self.add_expand_product_type_for_tests(name_gen, prod_ty),
957 AlgebraicType::Sum(sum_type) => {
958 if let Some(wrapped) = sum_type.as_option_mut() {
959 self.add_expand_type_for_tests(name_gen, wrapped);
960 } else {
961 for elem in sum_type.variants.iter_mut() {
962 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
963 }
964 }
965 }
966 AlgebraicType::Array(ty) => {
967 self.add_expand_type_for_tests(name_gen, &mut ty.elem_ty);
968 return;
969 }
970 _ => return,
971 }
972
973 let name = *name_gen;
975 let add_ty = core::mem::replace(ty, AlgebraicType::U8);
976 *ty = AlgebraicType::Ref(self.add_algebraic_type([], RawIdentifier::new(format!("gen_{name}")), add_ty, true));
977 *name_gen += 1;
978 }
979
980 fn add_expand_product_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut ProductType) {
981 for elem in ty.elements.iter_mut() {
982 self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
983 }
984 }
985
986 pub fn add_algebraic_type(
996 &mut self,
997 scope: impl IntoIterator<Item = RawIdentifier>,
998 source_name: impl Into<RawIdentifier>,
999 ty: AlgebraicType,
1000 custom_ordering: bool,
1001 ) -> AlgebraicTypeRef {
1002 let ty_ref = self.typespace_mut().add(ty);
1003 let scope = scope.into_iter().collect();
1004 let source_name = source_name.into();
1005 self.types_mut().push(RawTypeDefV10 {
1006 source_name: RawScopedTypeNameV10 { source_name, scope },
1007 ty: ty_ref,
1008 custom_ordering,
1009 });
1010 ty_ref
1013 }
1014
1015 pub fn add_reducer(&mut self, source_name: impl Into<RawIdentifier>, params: ProductType) {
1030 self.reducers_mut().push(RawReducerDefV10 {
1031 source_name: source_name.into(),
1032 params,
1033 visibility: FunctionVisibility::ClientCallable,
1034 ok_return_type: reducer_default_ok_return_type(),
1035 err_return_type: reducer_default_err_return_type(),
1036 });
1037 }
1038
1039 pub fn add_procedure(
1050 &mut self,
1051 source_name: impl Into<RawIdentifier>,
1052 params: ProductType,
1053 return_type: AlgebraicType,
1054 ) {
1055 self.procedures_mut().push(RawProcedureDefV10 {
1056 source_name: source_name.into(),
1057 params,
1058 return_type,
1059 visibility: FunctionVisibility::ClientCallable,
1060 })
1061 }
1062
1063 pub fn add_view(
1065 &mut self,
1066 source_name: impl Into<RawIdentifier>,
1067 index: usize,
1068 is_public: bool,
1069 is_anonymous: bool,
1070 params: ProductType,
1071 return_type: AlgebraicType,
1072 ) {
1073 self.views_mut().push(RawViewDefV10 {
1074 source_name: source_name.into(),
1075 index: index as u32,
1076 is_public,
1077 is_anonymous,
1078 params,
1079 return_type,
1080 });
1081 }
1082
1083 pub fn add_lifecycle_reducer(
1087 &mut self,
1088 lifecycle_spec: Lifecycle,
1089 function_name: impl Into<RawIdentifier>,
1090 params: ProductType,
1091 ) {
1092 let function_name = function_name.into();
1093 self.lifecycle_reducers_mut().push(RawLifeCycleReducerDefV10 {
1094 lifecycle_spec,
1095 function_name: function_name.clone(),
1096 });
1097
1098 self.reducers_mut().push(RawReducerDefV10 {
1099 source_name: function_name,
1100 params,
1101 visibility: FunctionVisibility::Private,
1102 ok_return_type: reducer_default_ok_return_type(),
1103 err_return_type: reducer_default_err_return_type(),
1104 });
1105 }
1106
1107 pub fn add_schedule(
1114 &mut self,
1115 table: impl Into<RawIdentifier>,
1116 column: impl Into<ColId>,
1117 function: impl Into<RawIdentifier>,
1118 ) {
1119 self.schedules_mut().push(RawScheduleDefV10 {
1120 source_name: None,
1121 table_name: table.into(),
1122 schedule_at_col: column.into(),
1123 function_name: function.into(),
1124 });
1125 }
1126
1127 pub fn add_row_level_security(&mut self, sql: &str) {
1133 self.row_level_security_mut()
1134 .push(RawRowLevelSecurityDefV10 { sql: sql.into() });
1135 }
1136
1137 pub fn add_http_handler(&mut self, source_name: impl Into<RawIdentifier>) {
1139 self.http_handlers_mut().push(RawHttpHandlerDefV10 {
1140 source_name: source_name.into(),
1141 });
1142 }
1143
1144 pub fn add_http_route(
1146 &mut self,
1147 handler_function: impl Into<RawIdentifier>,
1148 method: MethodOrAny,
1149 path: impl Into<RawIdentifier>,
1150 ) {
1151 self.http_routes_mut().push(RawHttpRouteDefV10 {
1152 handler_function: handler_function.into(),
1153 method,
1154 path: path.into(),
1155 });
1156 }
1157
1158 pub fn add_explicit_names(&mut self, names: ExplicitNames) {
1159 self.explicit_names_mut().merge(names);
1160 }
1161
1162 pub fn set_case_conversion_policy(&mut self, policy: CaseConversionPolicy) {
1169 self.module
1171 .sections
1172 .retain(|s| !matches!(s, RawModuleDefV10Section::CaseConversionPolicy(_)));
1173 self.module
1174 .sections
1175 .push(RawModuleDefV10Section::CaseConversionPolicy(policy));
1176 }
1177
1178 pub fn finish(self) -> RawModuleDefV10 {
1181 self.module
1182 }
1183}
1184
1185impl TypespaceBuilder for RawModuleDefV10Builder {
1187 fn add(
1188 &mut self,
1189 typeid: TypeId,
1190 source_name: Option<&'static str>,
1191 make_ty: impl FnOnce(&mut Self) -> AlgebraicType,
1192 ) -> AlgebraicType {
1193 if let btree_map::Entry::Occupied(o) = self.type_map.entry(typeid) {
1194 AlgebraicType::Ref(*o.get())
1195 } else {
1196 let slot_ref = {
1197 let ts = self.typespace_mut();
1198 let slot_ref = ts.add(AlgebraicType::unit());
1200 self.type_map.insert(typeid, slot_ref);
1202
1203 if let Some(sats_name) = source_name {
1205 let source_name = sats_name_to_scoped_name_v10(sats_name);
1206
1207 self.types_mut().push(RawTypeDefV10 {
1208 source_name,
1209 ty: slot_ref,
1210 custom_ordering: true,
1215 });
1216 }
1217 slot_ref
1218 };
1219
1220 let ty = make_ty(self);
1222 self.typespace_mut()[slot_ref] = ty;
1223 AlgebraicType::Ref(slot_ref)
1224 }
1225 }
1226}
1227
1228pub fn reducer_default_ok_return_type() -> AlgebraicType {
1229 AlgebraicType::unit()
1230}
1231
1232pub fn reducer_default_err_return_type() -> AlgebraicType {
1233 AlgebraicType::String
1234}
1235
1236pub fn sats_name_to_scoped_name_v10(sats_name: &str) -> RawScopedTypeNameV10 {
1240 let mut scope: Vec<RawIdentifier> = sats_name
1242 .split("::")
1243 .flat_map(|s| s.split('.'))
1244 .map(RawIdentifier::new)
1245 .collect();
1246 let source_name = scope.pop().unwrap_or_default();
1248 RawScopedTypeNameV10 {
1249 scope: scope.into(),
1250 source_name,
1251 }
1252}
1253
1254pub struct RawTableDefBuilderV10<'a> {
1256 module: &'a mut RawModuleDefV10,
1257 table: RawTableDefV10,
1258}
1259
1260impl RawTableDefBuilderV10<'_> {
1261 pub fn with_type(mut self, table_type: TableType) -> Self {
1266 self.table.table_type = table_type;
1267 self
1268 }
1269
1270 pub fn with_access(mut self, table_access: TableAccess) -> Self {
1272 self.table.table_access = table_access;
1273 self
1274 }
1275
1276 pub fn with_event(mut self, is_event: bool) -> Self {
1278 self.table.is_event = is_event;
1279 self
1280 }
1281
1282 pub fn with_unique_constraint(mut self, columns: impl Into<ColList>) -> Self {
1284 let columns = columns.into();
1285 self.table.constraints.push(RawConstraintDefV10 {
1286 source_name: None,
1287 data: RawConstraintDataV10::Unique(RawUniqueConstraintDataV10 { columns }),
1288 });
1289
1290 self
1291 }
1292
1293 pub fn with_primary_key(mut self, column: impl Into<ColId>) -> Self {
1296 self.table.primary_key = ColList::new(column.into());
1297 self
1298 }
1299
1300 pub fn with_auto_inc_primary_key(self, column: impl Into<ColId>) -> Self {
1303 let column = column.into();
1304 self.with_primary_key(column)
1305 .with_unique_constraint(column)
1306 .with_column_sequence(column)
1307 }
1308
1309 pub fn with_index(
1311 mut self,
1312 algorithm: RawIndexAlgorithm,
1313 source_name: impl Into<RawIdentifier>,
1314 accessor_name: impl Into<RawIdentifier>,
1315 ) -> Self {
1316 self.table.indexes.push(RawIndexDefV10 {
1317 source_name: Some(source_name.into()),
1318 accessor_name: Some(accessor_name.into()),
1319 algorithm,
1320 });
1321 self
1322 }
1323
1324 pub fn with_index_no_accessor_name(
1326 mut self,
1327 algorithm: RawIndexAlgorithm,
1328 source_name: impl Into<RawIdentifier>,
1329 ) -> Self {
1330 self.table.indexes.push(RawIndexDefV10 {
1331 source_name: Some(source_name.into()),
1332 accessor_name: None,
1333 algorithm,
1334 });
1335 self
1336 }
1337
1338 pub fn with_column_sequence(mut self, column: impl Into<ColId>) -> Self {
1340 let column = column.into();
1341 self.table.sequences.push(RawSequenceDefV10 {
1342 source_name: None,
1343 column,
1344 start: None,
1345 min_value: None,
1346 max_value: None,
1347 increment: 1,
1348 });
1349
1350 self
1351 }
1352
1353 pub fn with_default_column_value(mut self, column: impl Into<ColId>, value: AlgebraicValue) -> Self {
1355 let col_id = column.into();
1356 self.table.default_values.push(RawColumnDefaultValueV10 {
1357 col_id,
1358 value: spacetimedb_sats::bsatn::to_vec(&value).unwrap().into(),
1359 });
1360
1361 self
1362 }
1363
1364 pub fn finish(self) -> AlgebraicTypeRef {
1366 let product_type_ref = self.table.product_type_ref;
1367
1368 let tables = match self
1369 .module
1370 .sections
1371 .iter_mut()
1372 .find(|s| matches!(s, RawModuleDefV10Section::Tables(_)))
1373 {
1374 Some(RawModuleDefV10Section::Tables(t)) => t,
1375 _ => {
1376 self.module.sections.push(RawModuleDefV10Section::Tables(Vec::new()));
1377 match self.module.sections.last_mut().expect("Just pushed Tables section") {
1378 RawModuleDefV10Section::Tables(t) => t,
1379 _ => unreachable!(),
1380 }
1381 }
1382 };
1383
1384 tables.push(self.table);
1385 product_type_ref
1386 }
1387
1388 pub fn find_col_pos_by_name(&self, column: impl AsRef<str>) -> Option<ColId> {
1390 let column = column.as_ref();
1391
1392 let typespace = self.module.sections.iter().find_map(|s| {
1393 if let RawModuleDefV10Section::Typespace(ts) = s {
1394 Some(ts)
1395 } else {
1396 None
1397 }
1398 })?;
1399
1400 typespace
1401 .get(self.table.product_type_ref)?
1402 .as_product()?
1403 .elements
1404 .iter()
1405 .position(|x| x.has_name(column.as_ref()))
1406 .map(|i| ColId(i as u16))
1407 }
1408}