1use std::collections::BTreeMap;
19use std::fmt::{self, Debug, Write};
20use std::hash::Hash;
21
22use crate::error::{IdentifierError, ValidationErrors};
23use crate::identifier::Identifier;
24use crate::reducer_name::ReducerName;
25use crate::schema::{Schema, TableSchema};
26use crate::type_for_generate::{AlgebraicTypeUse, ProductTypeDef, TypespaceForGenerate};
27use deserialize::ArgsSeed;
28use enum_map::EnumMap;
29use indexmap::IndexMap;
30use itertools::Itertools;
31use spacetimedb_data_structures::error_stream::{CollectAllErrors, CombineErrors, ErrorStream};
32use spacetimedb_data_structures::map::{Equivalent, HashMap};
33use spacetimedb_lib::db::raw_def;
34use spacetimedb_lib::db::raw_def::v10::{
35 ExplicitNames, RawConstraintDefV10, RawIndexDefV10, RawLifeCycleReducerDefV10, RawModuleDefV10,
36 RawModuleDefV10Section, RawProcedureDefV10, RawReducerDefV10, RawRowLevelSecurityDefV10, RawScheduleDefV10,
37 RawScopedTypeNameV10, RawSequenceDefV10, RawTableDefV10, RawTypeDefV10, RawViewDefV10,
38};
39use spacetimedb_lib::db::raw_def::v9::{
40 Lifecycle, RawColumnDefaultValueV9, RawConstraintDataV9, RawConstraintDefV9, RawIndexAlgorithm, RawIndexDefV9,
41 RawMiscModuleExportV9, RawModuleDefV9, RawProcedureDefV9, RawReducerDefV9, RawRowLevelSecurityDefV9,
42 RawScheduleDefV9, RawScopedTypeNameV9, RawSequenceDefV9, RawSql, RawTableDefV9, RawTypeDefV9,
43 RawUniqueConstraintDataV9, RawViewDefV9, TableAccess, TableType,
44};
45use spacetimedb_lib::{ProductType, RawModuleDef};
46use spacetimedb_primitives::{ColId, ColList, ColOrCols, ColSet, ProcedureId, ReducerId, TableId, ViewFnPtr};
47use spacetimedb_sats::raw_identifier::RawIdentifier;
48use spacetimedb_sats::{AlgebraicType, AlgebraicTypeRef, AlgebraicValue, Typespace};
49
50pub mod deserialize;
51pub mod error;
52pub mod validate;
53
54pub type IdentifierMap<T> = HashMap<Identifier, T>;
56
57pub type StrMap<T> = HashMap<RawIdentifier, T>;
59
60#[derive(Debug, Clone)]
102#[non_exhaustive]
103pub struct ModuleDef {
104 tables: IdentifierMap<TableDef>,
106
107 reducers: IndexMap<Identifier, ReducerDef>,
111
112 procedures: IndexMap<Identifier, ProcedureDef>,
117
118 views: IndexMap<Identifier, ViewDef>,
123
124 lifecycle_reducers: EnumMap<Lifecycle, Option<ReducerId>>,
126
127 types: HashMap<ScopedTypeName, TypeDef>,
129
130 typespace: Typespace,
132
133 typespace_for_generate: TypespaceForGenerate,
135
136 stored_in_table_def: StrMap<Identifier>,
141
142 refmap: HashMap<AlgebraicTypeRef, ScopedTypeName>,
144
145 row_level_security_raw: HashMap<RawSql, RawRowLevelSecurityDefV9>,
149
150 #[allow(unused)]
153 raw_module_def_version: RawModuleDefVersion,
154}
155
156#[derive(Debug, Clone, Copy, Eq, PartialEq)]
157pub enum RawModuleDefVersion {
158 V9OrEarlier,
160 V10,
162}
163
164impl ModuleDef {
165 pub fn raw_module_def_version(&self) -> RawModuleDefVersion {
167 self.raw_module_def_version
168 }
169
170 pub fn tables(&self) -> impl Iterator<Item = &TableDef> {
172 self.tables.values()
173 }
174
175 pub fn indexes(&self) -> impl Iterator<Item = &IndexDef> {
177 self.tables().flat_map(|table| table.indexes.values())
178 }
179
180 pub fn constraints(&self) -> impl Iterator<Item = &ConstraintDef> {
182 self.tables().flat_map(|table| table.constraints.values())
183 }
184
185 pub fn sequences(&self) -> impl Iterator<Item = &SequenceDef> {
187 self.tables().flat_map(|table| table.sequences.values())
188 }
189
190 pub fn schedules(&self) -> impl Iterator<Item = &ScheduleDef> {
192 self.tables().filter_map(|table| table.schedule.as_ref())
193 }
194
195 pub fn reducers(&self) -> impl Iterator<Item = &ReducerDef> {
197 self.reducers.values()
198 }
199
200 pub fn reducer_ids_and_defs(&self) -> impl ExactSizeIterator<Item = (ReducerId, &ReducerDef)> {
202 self.reducers.values().enumerate().map(|(idx, def)| (idx.into(), def))
203 }
204
205 pub fn procedures(&self) -> impl Iterator<Item = &ProcedureDef> {
207 self.procedures.values()
208 }
209
210 pub fn views(&self) -> impl Iterator<Item = &ViewDef> {
212 self.views.values()
213 }
214
215 pub fn types(&self) -> impl Iterator<Item = &TypeDef> {
217 self.types.values()
218 }
219
220 pub fn row_level_security(&self) -> impl Iterator<Item = &RawRowLevelSecurityDefV9> {
222 self.row_level_security_raw.values()
223 }
224
225 pub fn typespace(&self) -> &Typespace {
238 &self.typespace
239 }
240
241 pub fn typespace_for_generate(&self) -> &TypespaceForGenerate {
243 &self.typespace_for_generate
244 }
245
246 pub fn stored_in_table_def(&self, name: &RawIdentifier) -> Option<&TableDef> {
250 self.stored_in_table_def
251 .get(name)
252 .and_then(|table_name| self.tables.get(table_name))
253 }
254
255 pub fn lookup<T: ModuleDefLookup>(&self, key: T::Key<'_>) -> Option<&T> {
257 T::lookup(self, key)
258 }
259
260 pub fn lookup_expect<T: ModuleDefLookup>(&self, key: T::Key<'_>) -> &T {
263 T::lookup(self, key).expect("expected ModuleDef to contain key, but it does not")
264 }
265
266 pub fn table<K: ?Sized + Hash + Equivalent<Identifier>>(&self, name: &K) -> Option<&TableDef> {
268 self.tables.get(name)
270 }
271
272 pub fn view<K: ?Sized + Hash + Equivalent<Identifier>>(&self, name: &K) -> Option<&ViewDef> {
274 self.views.get(name)
276 }
277
278 pub fn view_full<K: ?Sized + Hash + Equivalent<Identifier>>(&self, name: &K) -> Option<(ViewFnPtr, &ViewDef)> {
280 self.views.get(name).map(|def| (def.fn_ptr, def))
282 }
283
284 pub fn reducer<K: ?Sized + Hash + Equivalent<Identifier>>(&self, name: &K) -> Option<&ReducerDef> {
286 self.reducers.get(name)
288 }
289
290 pub fn reducer_full<K: ?Sized + Hash + Equivalent<Identifier>>(
292 &self,
293 name: &K,
294 ) -> Option<(ReducerId, &ReducerDef)> {
295 self.reducers.get_full(name).map(|(idx, _, def)| (idx.into(), def))
297 }
298
299 pub fn reducer_by_id(&self, id: ReducerId) -> &ReducerDef {
301 &self.reducers[id.idx()]
302 }
303
304 pub fn get_reducer_by_id(&self, id: ReducerId) -> Option<&ReducerDef> {
306 self.reducers.get_index(id.idx()).map(|(_, def)| def)
307 }
308
309 pub fn get_view_by_id(&self, id: ViewFnPtr, is_anonymous: bool) -> Option<&ViewDef> {
311 self.views
312 .iter()
313 .find(|(_, def)| def.fn_ptr == id && def.is_anonymous == is_anonymous)
314 .map(|(_, def)| def)
315 }
316
317 pub fn procedure<K: ?Sized + Hash + Equivalent<Identifier>>(&self, name: &K) -> Option<&ProcedureDef> {
319 self.procedures.get(name)
321 }
322
323 pub fn procedure_full<K: ?Sized + Hash + Equivalent<Identifier>>(
325 &self,
326 name: &K,
327 ) -> Option<(ProcedureId, &ProcedureDef)> {
328 self.procedures.get_full(name).map(|(idx, _, def)| (idx.into(), def))
330 }
331
332 pub fn procedure_by_id(&self, id: ProcedureId) -> &ProcedureDef {
334 &self.procedures[id.idx()]
335 }
336
337 pub fn get_procedure_by_id(&self, id: ProcedureId) -> Option<&ProcedureDef> {
339 self.procedures.get_index(id.idx()).map(|(_, def)| def)
340 }
341
342 pub fn lifecycle_reducer(&self, lifecycle: Lifecycle) -> Option<(ReducerId, &ReducerDef)> {
344 self.lifecycle_reducers[lifecycle].map(|i| (i, &self.reducers[i.idx()]))
345 }
346
347 pub fn arg_seed_for<'a, T>(&'a self, def: &'a T) -> ArgsSeed<'a, T> {
349 ArgsSeed(self.typespace.with_type(def))
350 }
351
352 pub fn type_def_from_ref(&self, r: AlgebraicTypeRef) -> Option<(&ScopedTypeName, &TypeDef)> {
354 let name = self.refmap.get(&r)?;
355 let def = self
356 .types
357 .get(name)
358 .expect("if it was in refmap, it should be in types");
359
360 Some((name, def))
361 }
362
363 pub fn table_schema<K: ?Sized + Hash + Equivalent<Identifier>>(
366 &self,
367 name: &K,
368 table_id: TableId,
369 ) -> Option<TableSchema> {
370 let table_def = self.tables.get(name)?;
372 Some(TableSchema::from_module_def(self, table_def, (), table_id))
373 }
374
375 pub fn expect_lookup<T: ModuleDefLookup>(&self, key: T::Key<'_>) -> &T {
377 if let Some(result) = T::lookup(self, key) {
378 result
379 } else {
380 panic!("expected ModuleDef to contain {key:?}, but it does not");
381 }
382 }
383
384 pub fn expect_contains<Def: ModuleDefLookup>(&self, def: &Def) {
386 if let Some(my_def) = self.lookup(def.key()) {
387 assert_eq!(
388 def as *const Def, my_def as *const Def,
389 "expected ModuleDef to contain {def:?}, but it contained {my_def:?}"
390 );
391 } else {
392 panic!("expected ModuleDef to contain {:?}, but it does not", def.key());
393 }
394 }
395}
396
397impl TryFrom<RawModuleDef> for ModuleDef {
398 type Error = ValidationErrors;
399
400 fn try_from(raw: RawModuleDef) -> Result<Self, Self::Error> {
401 match raw {
402 RawModuleDef::V8BackCompat(v8_mod) => Self::try_from(v8_mod),
403 RawModuleDef::V9(v9_mod) => Self::try_from(v9_mod),
404 RawModuleDef::V10(v10_mod) => Self::try_from(v10_mod),
405 _ => unimplemented!(),
406 }
407 }
408}
409impl TryFrom<raw_def::v8::RawModuleDefV8> for ModuleDef {
410 type Error = ValidationErrors;
411
412 fn try_from(v8_mod: raw_def::v8::RawModuleDefV8) -> Result<Self, Self::Error> {
413 validate::v8::validate(v8_mod)
416 }
417}
418impl TryFrom<raw_def::v9::RawModuleDefV9> for ModuleDef {
419 type Error = ValidationErrors;
420
421 fn try_from(v9_mod: raw_def::v9::RawModuleDefV9) -> Result<Self, Self::Error> {
422 validate::v9::validate(v9_mod)
423 }
424}
425impl From<ModuleDef> for RawModuleDefV9 {
426 fn from(val: ModuleDef) -> Self {
427 let ModuleDef {
428 tables,
429 views,
430 reducers,
431 lifecycle_reducers: _,
432 types,
433 typespace,
434 stored_in_table_def: _,
435 typespace_for_generate: _,
436 refmap: _,
437 row_level_security_raw,
438 procedures,
439 raw_module_def_version: _,
440 } = val;
441
442 let column_defaults: Vec<_> = tables
444 .iter()
445 .flat_map(|(table_name, table_def)| {
446 table_def.columns.iter().enumerate().filter_map(|(col_id, col)| {
447 col.default_value.as_ref().map(|default_val| {
448 RawMiscModuleExportV9::ColumnDefaultValue(RawColumnDefaultValueV9 {
449 table: table_name.clone().into(),
450 col_id: ColId(col_id as u16),
451 value: spacetimedb_sats::bsatn::to_vec(default_val).unwrap().into(),
452 })
453 })
454 })
455 })
456 .collect();
457
458 RawModuleDefV9 {
459 tables: to_raw(tables),
460 reducers: reducers.into_iter().map(|(_, def)| def.into()).collect(),
461 types: to_raw(types),
462 misc_exports: column_defaults
463 .into_iter()
464 .chain(procedures.into_iter().map(|(_, def)| def.into()))
465 .chain(views.into_iter().map(|(_, def)| def.into()))
466 .collect(),
467 typespace,
468 row_level_security: row_level_security_raw.into_iter().map(|(_, def)| def).collect(),
469 }
470 }
471}
472
473impl TryFrom<raw_def::v10::RawModuleDefV10> for ModuleDef {
474 type Error = ValidationErrors;
475
476 fn try_from(v10_mod: raw_def::v10::RawModuleDefV10) -> Result<Self, Self::Error> {
477 validate::v10::validate(v10_mod)
478 }
479}
480
481impl From<ModuleDef> for RawModuleDefV10 {
482 fn from(val: ModuleDef) -> Self {
483 let ModuleDef {
484 tables,
485 views,
486 reducers,
487 lifecycle_reducers,
488 types,
489 typespace,
490 stored_in_table_def: _,
491 typespace_for_generate: _,
492 refmap: _,
493 row_level_security_raw,
494 procedures,
495 raw_module_def_version: _,
496 } = val;
497
498 let mut sections = Vec::new();
499 let mut explicit_names = ExplicitNames::default();
500
501 sections.push(RawModuleDefV10Section::Typespace(typespace));
502
503 let raw_lifecycle: Vec<RawLifeCycleReducerDefV10> = lifecycle_reducers
505 .into_iter()
506 .filter_map(|(lifecycle, reducer_id)| {
507 let id = reducer_id?;
508 let (name, _) = reducers.get_index(id.idx())?;
509 Some(RawLifeCycleReducerDefV10 {
510 lifecycle_spec: lifecycle,
511 function_name: name.clone().into(),
512 })
513 })
514 .collect();
515
516 let raw_types: Vec<RawTypeDefV10> = types.into_values().map(Into::into).collect();
517 if !raw_types.is_empty() {
518 sections.push(RawModuleDefV10Section::Types(raw_types));
519 }
520
521 let mut schedules = Vec::new();
524 let raw_tables: Vec<RawTableDefV10> = tables
525 .into_values()
526 .map(|td| {
527 explicit_names.insert_table(
529 RawIdentifier::from(td.accessor_name.clone()),
530 RawIdentifier::from(td.name.clone()),
531 );
532 if let Some(sched) = td.schedule.clone() {
533 schedules.push(RawScheduleDefV10 {
534 source_name: Some(sched.name.into()),
535 table_name: td.name.clone().into(),
536 schedule_at_col: sched.at_column,
537 function_name: sched.function_name.into(),
538 });
539 }
540 td.into()
541 })
542 .collect();
543 if !raw_tables.is_empty() {
544 sections.push(RawModuleDefV10Section::Tables(raw_tables));
545 }
546
547 let raw_reducers: Vec<RawReducerDefV10> = reducers
549 .into_values()
550 .map(|rd| {
551 explicit_names.insert_function(
552 RawIdentifier::from(rd.accessor_name.clone()),
553 RawIdentifier::from(rd.name.clone()),
554 );
555 rd.into()
556 })
557 .collect();
558 if !raw_reducers.is_empty() {
559 sections.push(RawModuleDefV10Section::Reducers(raw_reducers));
560 }
561
562 let raw_procedures: Vec<RawProcedureDefV10> = procedures
564 .into_values()
565 .map(|pd| {
566 explicit_names.insert_function(
567 RawIdentifier::from(pd.accessor_name.clone()),
568 RawIdentifier::from(pd.name.clone()),
569 );
570 pd.into()
571 })
572 .collect();
573 if !raw_procedures.is_empty() {
574 sections.push(RawModuleDefV10Section::Procedures(raw_procedures));
575 }
576
577 let raw_views: Vec<RawViewDefV10> = views
579 .into_values()
580 .map(|vd| {
581 explicit_names.insert_function(
582 RawIdentifier::from(vd.accessor_name.clone()),
583 RawIdentifier::from(vd.name.clone()),
584 );
585 vd.into()
586 })
587 .collect();
588 if !raw_views.is_empty() {
589 sections.push(RawModuleDefV10Section::Views(raw_views));
590 }
591
592 if !schedules.is_empty() {
593 sections.push(RawModuleDefV10Section::Schedules(schedules));
594 }
595
596 if !raw_lifecycle.is_empty() {
597 sections.push(RawModuleDefV10Section::LifeCycleReducers(raw_lifecycle));
598 }
599
600 let raw_rls: Vec<RawRowLevelSecurityDefV10> = row_level_security_raw.into_values().collect();
601 if !raw_rls.is_empty() {
602 sections.push(RawModuleDefV10Section::RowLevelSecurity(raw_rls));
603 }
604
605 sections.push(RawModuleDefV10Section::ExplicitNames(explicit_names));
607
608 RawModuleDefV10 { sections }
609 }
610}
611
612pub trait ModuleDefLookup: Sized + Debug + 'static {
616 type Key<'a>: Debug + Copy;
618
619 fn key(&self) -> Self::Key<'_>;
621
622 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self>;
624}
625#[derive(Debug, Clone, Eq, PartialEq)]
640#[non_exhaustive]
641pub struct TableDef {
642 pub name: Identifier,
646 pub accessor_name: Identifier,
653 pub product_type_ref: AlgebraicTypeRef,
659
660 pub primary_key: Option<ColId>,
667
668 pub columns: Vec<ColumnDef>,
671
672 pub indexes: StrMap<IndexDef>,
674
675 pub constraints: StrMap<ConstraintDef>,
677
678 pub sequences: StrMap<SequenceDef>,
680
681 pub schedule: Option<ScheduleDef>,
683
684 pub table_type: TableType,
686
687 pub table_access: TableAccess,
689
690 pub is_event: bool,
695}
696
697impl TableDef {
698 pub fn get_column(&self, id: ColId) -> Option<&ColumnDef> {
700 self.columns.get(id.idx())
701 }
702 pub fn get_column_by_name(&self, name: &Identifier) -> Option<&ColumnDef> {
704 self.columns.iter().find(|c| &c.name == name)
705 }
706}
707
708impl From<TableDef> for RawTableDefV9 {
709 fn from(val: TableDef) -> Self {
710 let TableDef {
711 name,
712 product_type_ref,
713 primary_key,
714 columns: _, indexes,
716 constraints,
717 sequences,
718 schedule,
719 table_type,
720 table_access,
721 is_event: _, ..
723 } = val;
724
725 RawTableDefV9 {
726 name: name.into(),
727 product_type_ref,
728 primary_key: ColList::from_iter(primary_key),
729 indexes: to_raw(indexes),
730 constraints: to_raw(constraints),
731 sequences: to_raw(sequences),
732 schedule: schedule.map(Into::into),
733 table_type,
734 table_access,
735 }
736 }
737}
738
739impl From<TableDef> for RawTableDefV10 {
740 fn from(val: TableDef) -> Self {
741 let TableDef {
742 name: _,
743 product_type_ref,
744 primary_key,
745 columns: _, indexes,
747 constraints,
748 sequences,
749 schedule: _, table_type,
751 table_access,
752 is_event,
753 accessor_name,
754 } = val;
755
756 RawTableDefV10 {
757 source_name: accessor_name.into(),
758 product_type_ref,
759 primary_key: ColList::from_iter(primary_key),
760 indexes: indexes.into_values().map(Into::into).collect(),
761 constraints: constraints.into_values().map(Into::into).collect(),
762 sequences: sequences.into_values().map(Into::into).collect(),
763 table_type,
764 table_access,
765 default_values: Vec::new(),
766 is_event,
767 }
768 }
769}
770
771impl From<ViewDef> for TableDef {
772 fn from(def: ViewDef) -> Self {
773 use TableAccess::*;
774 let ViewDef {
775 name,
776 is_public,
777 product_type_ref,
778 primary_key,
779 return_columns,
780 accessor_name,
781 ..
782 } = def;
783 Self {
784 name,
785 product_type_ref,
786 primary_key,
787 columns: return_columns.into_iter().map(ColumnDef::from).collect(),
788 indexes: <_>::default(),
789 constraints: <_>::default(),
790 sequences: <_>::default(),
791 schedule: None,
792 table_type: TableType::User,
793 table_access: if is_public { Public } else { Private },
794 is_event: false,
795 accessor_name,
796 }
797 }
798}
799
800#[derive(Debug, Clone, Eq, PartialEq)]
802pub struct SequenceDef {
803 pub name: RawIdentifier,
805
806 pub column: ColId,
811
812 pub start: Option<i128>,
816
817 pub min_value: Option<i128>,
820
821 pub max_value: Option<i128>,
824
825 pub increment: i128,
827}
828
829impl From<SequenceDef> for RawSequenceDefV9 {
830 fn from(val: SequenceDef) -> Self {
831 RawSequenceDefV9 {
832 name: Some(val.name),
833 column: val.column,
834 start: val.start,
835 min_value: val.min_value,
836 max_value: val.max_value,
837 increment: val.increment,
838 }
839 }
840}
841
842impl From<SequenceDef> for RawSequenceDefV10 {
843 fn from(val: SequenceDef) -> Self {
844 RawSequenceDefV10 {
845 source_name: Some(val.name),
846 column: val.column,
847 start: val.start,
848 min_value: val.min_value,
849 max_value: val.max_value,
850 increment: val.increment,
851 }
852 }
853}
854
855#[derive(Debug, Clone, Eq, PartialEq)]
860#[non_exhaustive]
861pub struct IndexDef {
862 pub name: RawIdentifier,
868
869 pub source_name: RawIdentifier,
877
878 pub accessor_name: Option<Identifier>,
885 pub algorithm: IndexAlgorithm,
887}
888
889impl IndexDef {
890 pub fn generated(&self) -> bool {
892 self.accessor_name.is_none()
893 }
894}
895
896impl From<IndexDef> for RawIndexDefV9 {
897 fn from(val: IndexDef) -> Self {
898 RawIndexDefV9 {
899 name: Some(val.name),
900 algorithm: match val.algorithm {
901 IndexAlgorithm::BTree(BTreeAlgorithm { columns }) => RawIndexAlgorithm::BTree { columns },
902 IndexAlgorithm::Hash(HashAlgorithm { columns }) => RawIndexAlgorithm::Hash { columns },
903 IndexAlgorithm::Direct(DirectAlgorithm { column }) => RawIndexAlgorithm::Direct { column },
904 },
905 accessor_name: val.accessor_name.map(Into::into),
906 }
907 }
908}
909
910impl From<IndexDef> for RawIndexDefV10 {
911 fn from(val: IndexDef) -> Self {
912 RawIndexDefV10 {
913 source_name: Some(val.source_name),
914 accessor_name: val.accessor_name.map(Into::into),
915 algorithm: val.algorithm.into(),
916 }
917 }
918}
919
920#[non_exhaustive]
922#[derive(Debug, Clone, Eq, PartialEq)]
923pub enum IndexAlgorithm {
924 BTree(BTreeAlgorithm),
926 Hash(HashAlgorithm),
928 Direct(DirectAlgorithm),
930}
931
932impl spacetimedb_memory_usage::MemoryUsage for IndexAlgorithm {
933 fn heap_usage(&self) -> usize {
934 match self {
935 Self::BTree(a) => a.heap_usage(),
936 Self::Direct(a) => a.heap_usage(),
937 Self::Hash(a) => a.heap_usage(),
938 }
939 }
940}
941
942impl IndexAlgorithm {
943 pub fn columns(&self) -> ColOrCols<'_> {
945 match self {
946 Self::BTree(btree) => ColOrCols::ColList(&btree.columns),
947 Self::Hash(hash) => ColOrCols::ColList(&hash.columns),
948 Self::Direct(direct) => ColOrCols::Col(direct.column),
949 }
950 }
951 pub fn find_col_index(&self, pos: usize) -> Option<ColId> {
955 self.columns().iter().find(|col_id| col_id.idx() == pos)
956 }
957}
958
959impl From<IndexAlgorithm> for RawIndexAlgorithm {
960 fn from(val: IndexAlgorithm) -> Self {
961 match val {
962 IndexAlgorithm::BTree(BTreeAlgorithm { columns }) => Self::BTree { columns },
963 IndexAlgorithm::Hash(HashAlgorithm { columns }) => Self::Hash { columns },
964 IndexAlgorithm::Direct(DirectAlgorithm { column }) => Self::Direct { column },
965 }
966 }
967}
968
969#[derive(Debug, Clone, Eq, PartialEq)]
971pub struct BTreeAlgorithm {
972 pub columns: ColList,
974}
975
976impl spacetimedb_memory_usage::MemoryUsage for BTreeAlgorithm {
977 fn heap_usage(&self) -> usize {
978 self.columns.heap_usage()
979 }
980}
981
982impl<CL: Into<ColList>> From<CL> for BTreeAlgorithm {
983 fn from(columns: CL) -> Self {
984 let columns = columns.into();
985 Self { columns }
986 }
987}
988
989impl From<BTreeAlgorithm> for IndexAlgorithm {
990 fn from(val: BTreeAlgorithm) -> Self {
991 IndexAlgorithm::BTree(val)
992 }
993}
994
995#[derive(Debug, Clone, Eq, PartialEq)]
997pub struct HashAlgorithm {
998 pub columns: ColList,
1000}
1001
1002impl spacetimedb_memory_usage::MemoryUsage for HashAlgorithm {
1003 fn heap_usage(&self) -> usize {
1004 self.columns.heap_usage()
1005 }
1006}
1007
1008impl<CL: Into<ColList>> From<CL> for HashAlgorithm {
1009 fn from(columns: CL) -> Self {
1010 let columns = columns.into();
1011 Self { columns }
1012 }
1013}
1014
1015impl From<HashAlgorithm> for IndexAlgorithm {
1016 fn from(val: HashAlgorithm) -> Self {
1017 IndexAlgorithm::Hash(val)
1018 }
1019}
1020
1021#[derive(Debug, Clone, Eq, PartialEq)]
1023pub struct DirectAlgorithm {
1024 pub column: ColId,
1026}
1027
1028impl spacetimedb_memory_usage::MemoryUsage for DirectAlgorithm {
1029 fn heap_usage(&self) -> usize {
1030 self.column.heap_usage()
1031 }
1032}
1033
1034impl<C: Into<ColId>> From<C> for DirectAlgorithm {
1035 fn from(column: C) -> Self {
1036 let column = column.into();
1037 Self { column }
1038 }
1039}
1040
1041impl From<DirectAlgorithm> for IndexAlgorithm {
1042 fn from(val: DirectAlgorithm) -> Self {
1043 IndexAlgorithm::Direct(val)
1044 }
1045}
1046
1047#[derive(Debug, Clone, Eq, PartialEq)]
1052#[non_exhaustive]
1053pub struct ColumnDef {
1054 pub name: Identifier,
1058
1059 pub accessor_name: Identifier,
1063
1064 pub col_id: ColId,
1066
1067 pub ty: AlgebraicType,
1074
1075 pub ty_for_generate: AlgebraicTypeUse,
1077
1078 pub table_name: Identifier,
1080
1081 pub default_value: Option<AlgebraicValue>,
1083}
1084
1085impl From<ViewColumnDef> for ColumnDef {
1086 fn from(def: ViewColumnDef) -> Self {
1087 let ViewColumnDef {
1088 name,
1089 col_id,
1090 ty,
1091 ty_for_generate,
1092 view_name: table_name,
1093 accessor_name,
1094 } = def;
1095 Self {
1096 name,
1097 col_id,
1098 ty,
1099 ty_for_generate,
1100 table_name,
1101 default_value: None,
1102 accessor_name,
1103 }
1104 }
1105}
1106
1107#[derive(Debug, Clone, Eq, PartialEq)]
1109#[non_exhaustive]
1110pub struct ViewColumnDef {
1111 pub name: Identifier,
1113
1114 pub accessor_name: Identifier,
1115
1116 pub col_id: ColId,
1118
1119 pub ty: AlgebraicType,
1121
1122 pub ty_for_generate: AlgebraicTypeUse,
1124
1125 pub view_name: Identifier,
1127}
1128
1129impl From<ColumnDef> for ViewColumnDef {
1130 fn from(
1131 ColumnDef {
1132 name,
1133 col_id,
1134 ty,
1135 ty_for_generate,
1136 table_name: view_name,
1137 accessor_name,
1138 ..
1139 }: ColumnDef,
1140 ) -> Self {
1141 Self {
1142 name,
1143 col_id,
1144 ty,
1145 ty_for_generate,
1146 view_name,
1147 accessor_name,
1148 }
1149 }
1150}
1151
1152#[derive(Debug, Clone, Eq, PartialEq)]
1154#[non_exhaustive]
1155pub struct ViewParamDef {
1156 pub name: Identifier,
1158
1159 pub col_id: ColId,
1161
1162 pub ty: AlgebraicType,
1164
1165 pub ty_for_generate: AlgebraicTypeUse,
1167
1168 pub view_name: Identifier,
1170}
1171
1172#[derive(Debug, Clone, Eq, PartialEq)]
1174pub struct ConstraintDef {
1175 pub name: RawIdentifier,
1177
1178 pub data: ConstraintData,
1180}
1181
1182impl From<ConstraintDef> for RawConstraintDefV9 {
1183 fn from(val: ConstraintDef) -> Self {
1184 RawConstraintDefV9 {
1185 name: Some(val.name),
1186 data: val.data.into(),
1187 }
1188 }
1189}
1190
1191impl From<ConstraintDef> for RawConstraintDefV10 {
1192 fn from(val: ConstraintDef) -> Self {
1193 RawConstraintDefV10 {
1194 source_name: Some(val.name),
1195 data: val.data.into(),
1196 }
1197 }
1198}
1199
1200#[derive(Debug, Clone, Eq, PartialEq)]
1202#[non_exhaustive]
1203pub enum ConstraintData {
1204 Unique(UniqueConstraintData),
1205}
1206
1207impl spacetimedb_memory_usage::MemoryUsage for ConstraintData {
1208 fn heap_usage(&self) -> usize {
1209 match self {
1210 ConstraintData::Unique(d) => d.heap_usage(),
1211 }
1212 }
1213}
1214
1215impl ConstraintData {
1216 pub fn unique_columns(&self) -> Option<&ColSet> {
1219 match &self {
1220 ConstraintData::Unique(UniqueConstraintData { columns }) => Some(columns),
1221 }
1222 }
1223}
1224
1225impl From<ConstraintData> for RawConstraintDataV9 {
1226 fn from(val: ConstraintData) -> Self {
1227 match val {
1228 ConstraintData::Unique(unique) => RawConstraintDataV9::Unique(unique.into()),
1229 }
1230 }
1231}
1232
1233#[derive(Debug, Clone, Eq, PartialEq)]
1237pub struct UniqueConstraintData {
1238 pub columns: ColSet,
1240}
1241
1242impl spacetimedb_memory_usage::MemoryUsage for UniqueConstraintData {
1243 fn heap_usage(&self) -> usize {
1244 self.columns.heap_usage()
1245 }
1246}
1247
1248impl From<UniqueConstraintData> for RawUniqueConstraintDataV9 {
1249 fn from(val: UniqueConstraintData) -> Self {
1250 RawUniqueConstraintDataV9 {
1251 columns: val.columns.into(),
1252 }
1253 }
1254}
1255
1256impl From<UniqueConstraintData> for ConstraintData {
1257 fn from(val: UniqueConstraintData) -> Self {
1258 ConstraintData::Unique(val)
1259 }
1260}
1261
1262#[derive(Debug, Clone, Eq, PartialEq)]
1264pub struct RowLevelSecurityDef {
1265 pub sql: RawSql,
1267}
1268
1269impl From<RowLevelSecurityDef> for RawRowLevelSecurityDefV9 {
1270 fn from(val: RowLevelSecurityDef) -> Self {
1271 RawRowLevelSecurityDefV9 { sql: val.sql }
1272 }
1273}
1274
1275#[derive(Copy, Clone, Eq, PartialEq, Debug, Ord, PartialOrd)]
1276pub enum FunctionKind {
1277 Unknown,
1284 Reducer,
1285 Procedure,
1286}
1287
1288impl fmt::Display for FunctionKind {
1289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1290 f.write_str(match self {
1291 FunctionKind::Unknown => "exported function",
1292 FunctionKind::Reducer => "reducer",
1293 FunctionKind::Procedure => "procedure",
1294 })
1295 }
1296}
1297
1298#[derive(Debug, Clone, Eq, PartialEq)]
1300#[non_exhaustive]
1301pub struct ScheduleDef {
1302 pub name: Identifier,
1304
1305 pub at_column: ColId,
1309
1310 pub id_column: ColId,
1314
1315 pub function_name: Identifier,
1317
1318 pub function_kind: FunctionKind,
1320}
1321
1322impl From<ScheduleDef> for RawScheduleDefV9 {
1323 fn from(val: ScheduleDef) -> Self {
1324 RawScheduleDefV9 {
1325 name: Some(val.name.into()),
1326 reducer_name: val.function_name.into(),
1327 scheduled_at_column: val.at_column,
1328 }
1329 }
1330}
1331
1332#[derive(Debug, Clone, Eq, PartialEq)]
1334#[non_exhaustive]
1335pub struct TypeDef {
1336 pub accessor_name: ScopedTypeName,
1338
1339 pub ty: AlgebraicTypeRef,
1343
1344 pub custom_ordering: bool,
1346}
1347impl From<TypeDef> for RawTypeDefV9 {
1348 fn from(val: TypeDef) -> Self {
1349 RawTypeDefV9 {
1350 name: val.accessor_name.into(),
1351 ty: val.ty,
1352 custom_ordering: val.custom_ordering,
1353 }
1354 }
1355}
1356
1357impl From<TypeDef> for RawTypeDefV10 {
1358 fn from(val: TypeDef) -> Self {
1359 RawTypeDefV10 {
1360 source_name: val.accessor_name.into(),
1361 ty: val.ty,
1362 custom_ordering: val.custom_ordering,
1363 }
1364 }
1365}
1366
1367#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1372pub struct ScopedTypeName {
1373 scope: Box<[Identifier]>,
1378
1379 name: Identifier,
1383}
1384impl ScopedTypeName {
1385 pub fn new(scope: Box<[Identifier]>, name: Identifier) -> Self {
1387 ScopedTypeName { scope, name }
1388 }
1389
1390 pub fn try_new(
1393 scope: impl IntoIterator<Item = RawIdentifier>,
1394 name: impl Into<RawIdentifier>,
1395 ) -> Result<Self, ErrorStream<IdentifierError>> {
1396 let scope = scope
1397 .into_iter()
1398 .map(|chunk| Identifier::new(chunk).map_err(ErrorStream::from))
1399 .collect_all_errors();
1400 let name = Identifier::new(name.into()).map_err(ErrorStream::from);
1401 let (scope, name) = (scope, name).combine_errors()?;
1402 Ok(ScopedTypeName { scope, name })
1403 }
1404
1405 pub fn from_name(name: Identifier) -> Self {
1407 ScopedTypeName {
1408 scope: Box::new([]),
1409 name,
1410 }
1411 }
1412
1413 pub fn name(&self) -> &Identifier {
1415 &self.name
1416 }
1417
1418 pub fn as_identifier(&self) -> Option<&Identifier> {
1420 self.scope.is_empty().then_some(&self.name)
1421 }
1422
1423 pub fn name_segments(&self) -> impl Iterator<Item = &Identifier> {
1425 self.scope.iter().chain(std::iter::once(&self.name))
1426 }
1427}
1428impl fmt::Debug for ScopedTypeName {
1429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1430 f.write_char('"')?;
1433 for scope in &*self.scope {
1434 write!(f, "{scope}::")?;
1435 }
1436 write!(f, "{}\"", self.name)
1437 }
1438}
1439impl fmt::Display for ScopedTypeName {
1440 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1441 for scope in &*self.scope {
1442 write!(f, "{scope}::")?;
1443 }
1444 fmt::Display::fmt(&self.name, f)
1445 }
1446}
1447impl TryFrom<RawScopedTypeNameV9> for ScopedTypeName {
1448 type Error = ErrorStream<IdentifierError>;
1449
1450 fn try_from(value: RawScopedTypeNameV9) -> Result<Self, Self::Error> {
1451 Self::try_new(value.scope.into_vec(), value.name)
1452 }
1453}
1454impl From<ScopedTypeName> for RawScopedTypeNameV9 {
1455 fn from(val: ScopedTypeName) -> Self {
1456 RawScopedTypeNameV9 {
1457 scope: val.scope.into_vec().into_iter().map(|id| id.into()).collect(),
1458 name: val.name.into(),
1459 }
1460 }
1461}
1462
1463impl From<ScopedTypeName> for RawScopedTypeNameV10 {
1464 fn from(val: ScopedTypeName) -> Self {
1465 RawScopedTypeNameV10 {
1466 scope: val.scope.into_vec().into_iter().map(|id| id.into()).collect(),
1467 source_name: val.name.into(),
1468 }
1469 }
1470}
1471
1472#[derive(Debug, Clone, Eq, PartialEq)]
1474#[non_exhaustive]
1475pub struct ViewDef {
1476 pub name: Identifier,
1478
1479 pub accessor_name: Identifier,
1483
1484 pub is_public: bool,
1488
1489 pub is_anonymous: bool,
1494
1495 pub fn_ptr: ViewFnPtr,
1499
1500 pub params: ProductType,
1504
1505 pub params_for_generate: ProductTypeDef,
1509
1510 pub return_type: AlgebraicType,
1519
1520 pub return_type_for_generate: AlgebraicTypeUse,
1522
1523 pub product_type_ref: AlgebraicTypeRef,
1529
1530 pub primary_key: Option<ColId>,
1535
1536 pub return_columns: Vec<ViewColumnDef>,
1540
1541 pub param_columns: Vec<ViewParamDef>,
1545}
1546
1547impl ViewDef {
1548 pub fn get_column_by_name(&self, name: &Identifier) -> Option<&ViewColumnDef> {
1550 self.return_columns.iter().find(|c| &c.name == name)
1551 }
1552
1553 pub fn get_param_by_name(&self, name: &Identifier) -> Option<&ViewParamDef> {
1555 self.param_columns.iter().find(|c| &c.name == name)
1556 }
1557}
1558
1559impl From<ViewDef> for RawViewDefV9 {
1560 fn from(val: ViewDef) -> Self {
1561 let ViewDef {
1562 name,
1563 is_anonymous,
1564 is_public,
1565 params,
1566 return_type,
1567 fn_ptr: index,
1568 ..
1569 } = val;
1570 RawViewDefV9 {
1571 name: name.into(),
1572 index: index.into(),
1573 is_anonymous,
1574 is_public,
1575 params,
1576 return_type,
1577 }
1578 }
1579}
1580
1581impl From<ViewDef> for RawViewDefV10 {
1582 fn from(val: ViewDef) -> Self {
1583 let ViewDef {
1584 accessor_name,
1585 is_anonymous,
1586 is_public,
1587 params,
1588 return_type,
1589 fn_ptr,
1590 ..
1591 } = val;
1592 RawViewDefV10 {
1593 source_name: accessor_name.into(),
1594 index: fn_ptr.into(),
1595 is_public,
1596 is_anonymous,
1597 params,
1598 return_type,
1599 }
1600 }
1601}
1602
1603impl From<ViewDef> for RawMiscModuleExportV9 {
1604 fn from(def: ViewDef) -> Self {
1605 Self::View(def.into())
1606 }
1607}
1608
1609#[derive(Debug, Clone, Eq, PartialEq)]
1611pub enum FunctionVisibility {
1612 Private,
1617
1618 ClientCallable,
1620}
1621
1622impl FunctionVisibility {
1623 pub fn is_private(&self) -> bool {
1624 matches!(self, FunctionVisibility::Private)
1625 }
1626}
1627
1628use spacetimedb_lib::db::raw_def::v10::FunctionVisibility as RawFunctionVisibility;
1629impl From<RawFunctionVisibility> for FunctionVisibility {
1630 fn from(val: RawFunctionVisibility) -> Self {
1631 match val {
1632 RawFunctionVisibility::Private => FunctionVisibility::Private,
1633 RawFunctionVisibility::ClientCallable => FunctionVisibility::ClientCallable,
1634 }
1635 }
1636}
1637
1638impl From<FunctionVisibility> for RawFunctionVisibility {
1639 fn from(val: FunctionVisibility) -> Self {
1640 match val {
1641 FunctionVisibility::Private => RawFunctionVisibility::Private,
1642 FunctionVisibility::ClientCallable => RawFunctionVisibility::ClientCallable,
1643 }
1644 }
1645}
1646
1647#[derive(Debug, Clone, Eq, PartialEq)]
1649#[non_exhaustive]
1650pub struct ReducerDef {
1651 pub name: ReducerName,
1653
1654 pub accessor_name: ReducerName,
1661
1662 pub params: ProductType,
1666
1667 pub params_for_generate: ProductTypeDef,
1671
1672 pub lifecycle: Option<Lifecycle>,
1674
1675 pub visibility: FunctionVisibility,
1677
1678 pub ok_return_type: AlgebraicType,
1680
1681 pub err_return_type: AlgebraicType,
1683}
1684
1685impl From<ReducerDef> for RawReducerDefV9 {
1686 fn from(val: ReducerDef) -> Self {
1687 RawReducerDefV9 {
1688 name: val.name.into(),
1689 params: val.params,
1690 lifecycle: val.lifecycle,
1691 }
1692 }
1693}
1694
1695impl From<ReducerDef> for RawReducerDefV10 {
1696 fn from(val: ReducerDef) -> Self {
1697 RawReducerDefV10 {
1698 source_name: val.accessor_name.into(),
1699 params: val.params,
1700 visibility: val.visibility.into(),
1701 ok_return_type: val.ok_return_type,
1702 err_return_type: val.err_return_type,
1703 }
1704 }
1705}
1706
1707#[derive(Debug, Clone, Eq, PartialEq)]
1708#[non_exhaustive]
1709pub struct ProcedureDef {
1710 pub name: Identifier,
1714
1715 pub accessor_name: Identifier,
1719 pub params: ProductType,
1723
1724 pub params_for_generate: ProductTypeDef,
1728
1729 pub return_type: AlgebraicType,
1734
1735 pub return_type_for_generate: AlgebraicTypeUse,
1740
1741 pub visibility: FunctionVisibility,
1743}
1744
1745impl From<ProcedureDef> for RawProcedureDefV9 {
1746 fn from(val: ProcedureDef) -> Self {
1747 RawProcedureDefV9 {
1748 name: val.name.into(),
1749 params: val.params,
1750 return_type: val.return_type,
1751 }
1752 }
1753}
1754
1755impl From<ProcedureDef> for RawProcedureDefV10 {
1756 fn from(val: ProcedureDef) -> Self {
1757 RawProcedureDefV10 {
1758 source_name: val.accessor_name.into(),
1759 params: val.params,
1760 return_type: val.return_type,
1761 visibility: val.visibility.into(),
1762 }
1763 }
1764}
1765
1766impl From<ProcedureDef> for RawMiscModuleExportV9 {
1767 fn from(def: ProcedureDef) -> Self {
1768 Self::Procedure(def.into())
1769 }
1770}
1771
1772impl ModuleDefLookup for TableDef {
1773 type Key<'a> = &'a Identifier;
1774
1775 fn key(&self) -> Self::Key<'_> {
1776 &self.name
1777 }
1778
1779 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1780 module_def.tables.get(key)
1781 }
1782}
1783
1784impl ModuleDefLookup for SequenceDef {
1785 type Key<'a> = &'a RawIdentifier;
1786
1787 fn key(&self) -> Self::Key<'_> {
1788 &self.name
1789 }
1790
1791 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1792 module_def.stored_in_table_def(key)?.sequences.get(key)
1793 }
1794}
1795
1796impl ModuleDefLookup for IndexDef {
1797 type Key<'a> = &'a RawIdentifier;
1798
1799 fn key(&self) -> Self::Key<'_> {
1800 &self.name
1801 }
1802
1803 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1804 module_def.stored_in_table_def(key)?.indexes.get(key)
1805 }
1806}
1807
1808impl ModuleDefLookup for ColumnDef {
1809 type Key<'a> = (&'a Identifier, &'a Identifier);
1813
1814 fn key(&self) -> Self::Key<'_> {
1815 (&self.table_name, &self.name)
1816 }
1817
1818 fn lookup<'a>(module_def: &'a ModuleDef, (table_name, name): Self::Key<'_>) -> Option<&'a Self> {
1819 module_def
1820 .tables
1821 .get(table_name)
1822 .and_then(|table| table.get_column_by_name(name))
1823 }
1824}
1825
1826impl ModuleDefLookup for ViewColumnDef {
1827 type Key<'a> = (&'a Identifier, &'a Identifier);
1830
1831 fn key(&self) -> Self::Key<'_> {
1832 (&self.view_name, &self.name)
1833 }
1834
1835 fn lookup<'a>(module_def: &'a ModuleDef, (view_name, name): Self::Key<'_>) -> Option<&'a Self> {
1836 module_def
1837 .views
1838 .get(view_name)
1839 .and_then(|view| view.get_column_by_name(name))
1840 }
1841}
1842
1843impl ModuleDefLookup for ViewParamDef {
1844 type Key<'a> = (&'a Identifier, &'a Identifier);
1847
1848 fn key(&self) -> Self::Key<'_> {
1849 (&self.view_name, &self.name)
1850 }
1851
1852 fn lookup<'a>(module_def: &'a ModuleDef, (view_name, name): Self::Key<'_>) -> Option<&'a Self> {
1853 module_def
1854 .views
1855 .get(view_name)
1856 .and_then(|view| view.get_param_by_name(name))
1857 }
1858}
1859
1860impl ModuleDefLookup for ConstraintDef {
1861 type Key<'a> = &'a RawIdentifier;
1862
1863 fn key(&self) -> Self::Key<'_> {
1864 &self.name
1865 }
1866
1867 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1868 module_def.stored_in_table_def(key)?.constraints.get(key)
1869 }
1870}
1871
1872impl ModuleDefLookup for RawRowLevelSecurityDefV9 {
1873 type Key<'a> = &'a RawSql;
1874
1875 fn key(&self) -> Self::Key<'_> {
1876 &self.sql
1877 }
1878
1879 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1880 module_def.row_level_security_raw.get(key)
1881 }
1882}
1883
1884impl ModuleDefLookup for ScheduleDef {
1885 type Key<'a> = &'a Identifier;
1886
1887 fn key(&self) -> Self::Key<'_> {
1888 &self.name
1889 }
1890
1891 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1892 let schedule = module_def.stored_in_table_def(key.as_raw())?.schedule.as_ref()?;
1893 if &schedule.name == key {
1894 Some(schedule)
1895 } else {
1896 None
1897 }
1898 }
1899}
1900
1901impl ModuleDefLookup for TypeDef {
1902 type Key<'a> = &'a ScopedTypeName;
1903
1904 fn key(&self) -> Self::Key<'_> {
1905 &self.accessor_name
1906 }
1907
1908 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1909 module_def.types.get(key)
1910 }
1911}
1912
1913impl ModuleDefLookup for ReducerDef {
1914 type Key<'a> = &'a ReducerName;
1915
1916 fn key(&self) -> Self::Key<'_> {
1917 &self.name
1918 }
1919
1920 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1921 let key = &**key;
1922 module_def.reducers.get(key)
1923 }
1924}
1925
1926impl ModuleDefLookup for ProcedureDef {
1927 type Key<'a> = &'a Identifier;
1928
1929 fn key(&self) -> Self::Key<'_> {
1930 &self.name
1931 }
1932
1933 fn lookup<'a>(module_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1934 let key = &**key;
1935 module_def.procedures.get(key)
1936 }
1937}
1938
1939impl ModuleDefLookup for ViewDef {
1940 type Key<'a> = &'a Identifier;
1941
1942 fn key(&self) -> Self::Key<'_> {
1943 &self.name
1944 }
1945
1946 fn lookup<'a>(view_def: &'a ModuleDef, key: Self::Key<'_>) -> Option<&'a Self> {
1947 view_def.views.get(key)
1948 }
1949}
1950
1951fn to_raw<Def, RawDef, Name>(data: HashMap<Name, Def>) -> Vec<RawDef>
1952where
1953 Def: ModuleDefLookup + Into<RawDef>,
1954 Name: Eq + Ord + 'static,
1955{
1956 let sorted: BTreeMap<Name, Def> = data.into_iter().collect();
1957 sorted.into_values().map_into().collect()
1958}
1959
1960#[cfg(test)]
1961mod tests {
1962 use crate::{def::validate::tests::expect_identifier, error::ValidationError};
1963
1964 use super::*;
1965 use proptest::prelude::*;
1966 use spacetimedb_data_structures::{expect_error_matching, map::HashCollectionExt as _};
1967 use spacetimedb_lib::db::raw_def::v9::RawModuleDefV9Builder;
1968
1969 proptest! {
1970 #[test]
1971 fn to_raw_deterministic(vec in prop::collection::vec(any::<u32>(), 0..5)) {
1972 let mut map = HashMap::new();
1973 let name = ScopedTypeName::try_new([], "fake_name").unwrap();
1974 for k in vec {
1975 let def = TypeDef { accessor_name: name.clone(), ty: AlgebraicTypeRef(k), custom_ordering: false };
1976 map.insert(k, def);
1977 }
1978 let raw: Vec<RawTypeDefV9> = to_raw(map.clone());
1979 let raw2: Vec<RawTypeDefV9> = to_raw(map);
1980 prop_assert_eq!(raw, raw2);
1981 }
1982 }
1983
1984 #[test]
1985 fn validate_new_column_with_multiple_values() {
1986 let mut old_builder = RawModuleDefV9Builder::new();
1987 old_builder
1988 .build_table_with_new_type(
1989 "Apples",
1990 ProductType::from([("id", AlgebraicType::U64), ("count", AlgebraicType::U16)]),
1991 true,
1992 )
1993 .with_default_column_value(1, AlgebraicValue::U16(12))
1994 .with_default_column_value(1, AlgebraicValue::U16(10))
1995 .finish();
1996
1997 let result: Result<ModuleDef, ValidationErrors> = old_builder.finish().try_into();
1998 let apples = expect_identifier("Apples");
1999
2000 expect_error_matching!(
2001 result,
2002 ValidationError::MultipleColumnDefaultValues {
2003 table,
2004 ..
2005 } => *table == apples.clone().into()
2006 );
2007 }
2008
2009 #[test]
2010 fn validate_new_column_with_malformed_value() {
2011 let mut old_builder = RawModuleDefV9Builder::new();
2012 old_builder
2013 .build_table_with_new_type(
2014 "Apples",
2015 ProductType::from([("id", AlgebraicType::U64), ("count", AlgebraicType::U16)]),
2016 true,
2017 )
2018 .with_default_column_value(1, AlgebraicValue::Bool(false))
2019 .with_default_column_value(1, AlgebraicValue::unit())
2020 .finish();
2021
2022 let result: Result<ModuleDef, ValidationErrors> = old_builder.finish().try_into();
2023 let apples = expect_identifier("Apples");
2024
2025 expect_error_matching!(
2026 result,
2027 ValidationError::ColumnDefaultValueMalformed { table, col_id, .. } => *table == apples.clone().into() && *col_id == ColId(1)
2028 );
2029 assert!(result.is_err_and(|e| e
2030 .into_iter()
2031 .filter(|e| matches!(e, ValidationError::ColumnDefaultValueMalformed { .. }))
2032 .count()
2033 == 2))
2034 }
2035}