use crate::db::raw_def::v9::{Lifecycle, RawIndexAlgorithm, TableAccess, TableType};
use core::fmt;
use spacetimedb_primitives::{ColId, ColList};
use spacetimedb_sats::raw_identifier::RawIdentifier;
use spacetimedb_sats::typespace::TypespaceBuilder;
use spacetimedb_sats::{AlgebraicType, AlgebraicTypeRef, AlgebraicValue, ProductType, SpacetimeType, Typespace};
use std::any::TypeId;
use std::collections::{btree_map, BTreeMap};
#[derive(Default, Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawModuleDefV10 {
pub sections: Vec<RawModuleDefV10Section>,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
#[non_exhaustive]
pub enum RawModuleDefV10Section {
Typespace(Typespace),
Types(Vec<RawTypeDefV10>),
Tables(Vec<RawTableDefV10>),
Reducers(Vec<RawReducerDefV10>),
Procedures(Vec<RawProcedureDefV10>),
Views(Vec<RawViewDefV10>),
Schedules(Vec<RawScheduleDefV10>),
LifeCycleReducers(Vec<RawLifeCycleReducerDefV10>),
RowLevelSecurity(Vec<RawRowLevelSecurityDefV10>),
CaseConversionPolicy(CaseConversionPolicy),
ExplicitNames(ExplicitNames),
}
#[derive(Debug, Clone, Copy, Default, SpacetimeType)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
#[sats(crate = crate)]
#[non_exhaustive]
pub enum CaseConversionPolicy {
None,
#[default]
SnakeCase,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
#[non_exhaustive]
pub struct NameMapping {
pub source_name: RawIdentifier,
pub canonical_name: RawIdentifier,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
#[non_exhaustive]
pub enum ExplicitNameEntry {
Table(NameMapping),
Function(NameMapping),
Index(NameMapping),
}
#[derive(Debug, Default, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, Ord, PartialOrd))]
#[non_exhaustive]
pub struct ExplicitNames {
entries: Vec<ExplicitNameEntry>,
}
impl ExplicitNames {
fn insert(&mut self, entry: ExplicitNameEntry) {
self.entries.push(entry);
}
pub fn insert_table(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
self.insert(ExplicitNameEntry::Table(NameMapping {
source_name: source_name.into(),
canonical_name: canonical_name.into(),
}));
}
pub fn insert_function(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
self.insert(ExplicitNameEntry::Function(NameMapping {
source_name: source_name.into(),
canonical_name: canonical_name.into(),
}));
}
pub fn insert_index(&mut self, source_name: impl Into<RawIdentifier>, canonical_name: impl Into<RawIdentifier>) {
self.insert(ExplicitNameEntry::Index(NameMapping {
source_name: source_name.into(),
canonical_name: canonical_name.into(),
}));
}
pub fn merge(&mut self, other: ExplicitNames) {
self.entries.extend(other.entries);
}
pub fn into_entries(self) -> Vec<ExplicitNameEntry> {
self.entries
}
}
pub type RawRowLevelSecurityDefV10 = crate::db::raw_def::v9::RawRowLevelSecurityDefV9;
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawTableDefV10 {
pub source_name: RawIdentifier,
pub product_type_ref: AlgebraicTypeRef,
pub primary_key: ColList,
pub indexes: Vec<RawIndexDefV10>,
pub constraints: Vec<RawConstraintDefV10>,
pub sequences: Vec<RawSequenceDefV10>,
pub table_type: TableType,
pub table_access: TableAccess,
pub default_values: Vec<RawColumnDefaultValueV10>,
pub is_event: bool,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawColumnDefaultValueV10 {
pub col_id: ColId,
pub value: Box<[u8]>,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawReducerDefV10 {
pub source_name: RawIdentifier,
pub params: ProductType,
pub visibility: FunctionVisibility,
pub ok_return_type: AlgebraicType,
pub err_return_type: AlgebraicType,
}
#[derive(Debug, Copy, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub enum FunctionVisibility {
Private,
ClientCallable,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawScheduleDefV10 {
pub source_name: Option<RawIdentifier>,
pub table_name: RawIdentifier,
pub schedule_at_col: ColId,
pub function_name: RawIdentifier,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawLifeCycleReducerDefV10 {
pub lifecycle_spec: Lifecycle,
pub function_name: RawIdentifier,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawProcedureDefV10 {
pub source_name: RawIdentifier,
pub params: ProductType,
pub return_type: AlgebraicType,
pub visibility: FunctionVisibility,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawSequenceDefV10 {
pub source_name: Option<RawIdentifier>,
pub column: ColId,
pub start: Option<i128>,
pub min_value: Option<i128>,
pub max_value: Option<i128>,
pub increment: i128,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawIndexDefV10 {
pub source_name: Option<RawIdentifier>,
pub accessor_name: Option<RawIdentifier>,
pub algorithm: RawIndexAlgorithm,
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawConstraintDefV10 {
pub source_name: Option<RawIdentifier>,
pub data: RawConstraintDataV10,
}
type RawConstraintDataV10 = crate::db::raw_def::v9::RawConstraintDataV9;
type RawUniqueConstraintDataV10 = crate::db::raw_def::v9::RawUniqueConstraintDataV9;
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawTypeDefV10 {
pub source_name: RawScopedTypeNameV10,
pub ty: AlgebraicTypeRef,
pub custom_ordering: bool,
}
#[derive(Clone, SpacetimeType, PartialEq, Eq, PartialOrd, Ord)]
#[sats(crate = crate)]
pub struct RawScopedTypeNameV10 {
pub scope: Box<[RawIdentifier]>,
pub source_name: RawIdentifier,
}
impl fmt::Debug for RawScopedTypeNameV10 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for module in self.scope.iter() {
fmt::Debug::fmt(module, f)?;
f.write_str("::")?;
}
fmt::Debug::fmt(&self.source_name, f)?;
Ok(())
}
}
#[derive(Debug, Clone, SpacetimeType)]
#[sats(crate = crate)]
#[cfg_attr(feature = "test", derive(PartialEq, Eq, PartialOrd, Ord))]
pub struct RawViewDefV10 {
pub source_name: RawIdentifier,
pub index: u32,
pub is_public: bool,
pub is_anonymous: bool,
pub params: ProductType,
pub return_type: AlgebraicType,
}
impl RawModuleDefV10 {
pub fn types(&self) -> Option<&Vec<RawTypeDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Types(types) => Some(types),
_ => None,
})
}
pub fn tables(&self) -> Option<&Vec<RawTableDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Tables(tables) => Some(tables),
_ => None,
})
}
pub fn typespace(&self) -> Option<&Typespace> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Typespace(ts) => Some(ts),
_ => None,
})
}
pub fn reducers(&self) -> Option<&Vec<RawReducerDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Reducers(reducers) => Some(reducers),
_ => None,
})
}
pub fn procedures(&self) -> Option<&Vec<RawProcedureDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Procedures(procedures) => Some(procedures),
_ => None,
})
}
pub fn views(&self) -> Option<&Vec<RawViewDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Views(views) => Some(views),
_ => None,
})
}
pub fn schedules(&self) -> Option<&Vec<RawScheduleDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::Schedules(schedules) => Some(schedules),
_ => None,
})
}
pub fn lifecycle_reducers(&self) -> Option<&Vec<RawLifeCycleReducerDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::LifeCycleReducers(lcrs) => Some(lcrs),
_ => None,
})
}
pub fn tables_mut_for_tests(&mut self) -> &mut Vec<RawTableDefV10> {
self.sections
.iter_mut()
.find_map(|s| match s {
RawModuleDefV10Section::Tables(tables) => Some(tables),
_ => None,
})
.expect("Tables section must exist for tests")
}
pub fn row_level_security(&self) -> Option<&Vec<RawRowLevelSecurityDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls),
_ => None,
})
}
pub fn case_conversion_policy(&self) -> CaseConversionPolicy {
self.sections
.iter()
.find_map(|s| match s {
RawModuleDefV10Section::CaseConversionPolicy(policy) => Some(*policy),
_ => None,
})
.unwrap_or_default()
}
pub fn explicit_names(&self) -> Option<&ExplicitNames> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::ExplicitNames(names) => Some(names),
_ => None,
})
}
}
#[derive(Default)]
pub struct RawModuleDefV10Builder {
module: RawModuleDefV10,
type_map: BTreeMap<TypeId, AlgebraicTypeRef>,
}
impl RawModuleDefV10Builder {
pub fn new() -> Self {
Default::default()
}
fn typespace_mut(&mut self) -> &mut Typespace {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Typespace(_)))
.unwrap_or_else(|| {
self.module
.sections
.push(RawModuleDefV10Section::Typespace(Typespace::EMPTY.clone()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Typespace(ts) => ts,
_ => unreachable!("Just ensured Typespace section exists"),
}
}
fn reducers_mut(&mut self) -> &mut Vec<RawReducerDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Reducers(_)))
.unwrap_or_else(|| {
self.module.sections.push(RawModuleDefV10Section::Reducers(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Reducers(reducers) => reducers,
_ => unreachable!("Just ensured Reducers section exists"),
}
}
fn procedures_mut(&mut self) -> &mut Vec<RawProcedureDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Procedures(_)))
.unwrap_or_else(|| {
self.module
.sections
.push(RawModuleDefV10Section::Procedures(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Procedures(procedures) => procedures,
_ => unreachable!("Just ensured Procedures section exists"),
}
}
fn views_mut(&mut self) -> &mut Vec<RawViewDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Views(_)))
.unwrap_or_else(|| {
self.module.sections.push(RawModuleDefV10Section::Views(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Views(views) => views,
_ => unreachable!("Just ensured Views section exists"),
}
}
fn schedules_mut(&mut self) -> &mut Vec<RawScheduleDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Schedules(_)))
.unwrap_or_else(|| {
self.module.sections.push(RawModuleDefV10Section::Schedules(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Schedules(schedules) => schedules,
_ => unreachable!("Just ensured Schedules section exists"),
}
}
fn lifecycle_reducers_mut(&mut self) -> &mut Vec<RawLifeCycleReducerDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::LifeCycleReducers(_)))
.unwrap_or_else(|| {
self.module
.sections
.push(RawModuleDefV10Section::LifeCycleReducers(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::LifeCycleReducers(lcrs) => lcrs,
_ => unreachable!("Just ensured LifeCycleReducers section exists"),
}
}
fn types_mut(&mut self) -> &mut Vec<RawTypeDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::Types(_)))
.unwrap_or_else(|| {
self.module.sections.push(RawModuleDefV10Section::Types(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::Types(types) => types,
_ => unreachable!("Just ensured Types section exists"),
}
}
pub fn add_type<T: SpacetimeType>(&mut self) -> AlgebraicType {
TypespaceBuilder::add_type::<T>(self)
}
fn row_level_security_mut(&mut self) -> &mut Vec<RawRowLevelSecurityDefV10> {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::RowLevelSecurity(_)))
.unwrap_or_else(|| {
self.module
.sections
.push(RawModuleDefV10Section::RowLevelSecurity(Vec::new()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::RowLevelSecurity(rls) => rls,
_ => unreachable!("Just ensured RowLevelSecurity section exists"),
}
}
fn explicit_names_mut(&mut self) -> &mut ExplicitNames {
let idx = self
.module
.sections
.iter()
.position(|s| matches!(s, RawModuleDefV10Section::ExplicitNames(_)))
.unwrap_or_else(|| {
self.module
.sections
.push(RawModuleDefV10Section::ExplicitNames(ExplicitNames::default()));
self.module.sections.len() - 1
});
match &mut self.module.sections[idx] {
RawModuleDefV10Section::ExplicitNames(names) => names,
_ => unreachable!("Just ensured ExplicitNames section exists"),
}
}
pub fn build_table(
&mut self,
source_name: impl Into<RawIdentifier>,
product_type_ref: AlgebraicTypeRef,
) -> RawTableDefBuilderV10<'_> {
let source_name = source_name.into();
RawTableDefBuilderV10 {
module: &mut self.module,
table: RawTableDefV10 {
source_name,
product_type_ref,
indexes: vec![],
constraints: vec![],
sequences: vec![],
primary_key: ColList::empty(),
table_type: TableType::User,
table_access: TableAccess::Public,
default_values: vec![],
is_event: false,
},
}
}
pub fn build_table_with_new_type(
&mut self,
table_name: impl Into<RawIdentifier>,
product_type: impl Into<ProductType>,
custom_ordering: bool,
) -> RawTableDefBuilderV10<'_> {
let table_name = table_name.into();
let product_type_ref = self.add_algebraic_type(
[],
table_name.clone(),
AlgebraicType::from(product_type.into()),
custom_ordering,
);
self.build_table(table_name, product_type_ref)
}
pub fn build_table_with_new_type_for_tests(
&mut self,
table_name: impl Into<RawIdentifier>,
mut product_type: ProductType,
custom_ordering: bool,
) -> RawTableDefBuilderV10<'_> {
self.add_expand_product_type_for_tests(&mut 0, &mut product_type);
self.build_table_with_new_type(table_name, product_type, custom_ordering)
}
fn add_expand_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut AlgebraicType) {
if ty.is_valid_for_client_type_use() {
return;
}
match ty {
AlgebraicType::Product(prod_ty) => self.add_expand_product_type_for_tests(name_gen, prod_ty),
AlgebraicType::Sum(sum_type) => {
if let Some(wrapped) = sum_type.as_option_mut() {
self.add_expand_type_for_tests(name_gen, wrapped);
} else {
for elem in sum_type.variants.iter_mut() {
self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
}
}
}
AlgebraicType::Array(ty) => {
self.add_expand_type_for_tests(name_gen, &mut ty.elem_ty);
return;
}
_ => return,
}
let name = *name_gen;
let add_ty = core::mem::replace(ty, AlgebraicType::U8);
*ty = AlgebraicType::Ref(self.add_algebraic_type([], RawIdentifier::new(format!("gen_{name}")), add_ty, true));
*name_gen += 1;
}
fn add_expand_product_type_for_tests(&mut self, name_gen: &mut usize, ty: &mut ProductType) {
for elem in ty.elements.iter_mut() {
self.add_expand_type_for_tests(name_gen, &mut elem.algebraic_type);
}
}
pub fn add_algebraic_type(
&mut self,
scope: impl IntoIterator<Item = RawIdentifier>,
source_name: impl Into<RawIdentifier>,
ty: AlgebraicType,
custom_ordering: bool,
) -> AlgebraicTypeRef {
let ty_ref = self.typespace_mut().add(ty);
let scope = scope.into_iter().collect();
let source_name = source_name.into();
self.types_mut().push(RawTypeDefV10 {
source_name: RawScopedTypeNameV10 { source_name, scope },
ty: ty_ref,
custom_ordering,
});
ty_ref
}
pub fn add_reducer(&mut self, source_name: impl Into<RawIdentifier>, params: ProductType) {
self.reducers_mut().push(RawReducerDefV10 {
source_name: source_name.into(),
params,
visibility: FunctionVisibility::ClientCallable,
ok_return_type: reducer_default_ok_return_type(),
err_return_type: reducer_default_err_return_type(),
});
}
pub fn add_procedure(
&mut self,
source_name: impl Into<RawIdentifier>,
params: ProductType,
return_type: AlgebraicType,
) {
self.procedures_mut().push(RawProcedureDefV10 {
source_name: source_name.into(),
params,
return_type,
visibility: FunctionVisibility::ClientCallable,
})
}
pub fn add_view(
&mut self,
source_name: impl Into<RawIdentifier>,
index: usize,
is_public: bool,
is_anonymous: bool,
params: ProductType,
return_type: AlgebraicType,
) {
self.views_mut().push(RawViewDefV10 {
source_name: source_name.into(),
index: index as u32,
is_public,
is_anonymous,
params,
return_type,
});
}
pub fn add_lifecycle_reducer(
&mut self,
lifecycle_spec: Lifecycle,
function_name: impl Into<RawIdentifier>,
params: ProductType,
) {
let function_name = function_name.into();
self.lifecycle_reducers_mut().push(RawLifeCycleReducerDefV10 {
lifecycle_spec,
function_name: function_name.clone(),
});
self.reducers_mut().push(RawReducerDefV10 {
source_name: function_name,
params,
visibility: FunctionVisibility::Private,
ok_return_type: reducer_default_ok_return_type(),
err_return_type: reducer_default_err_return_type(),
});
}
pub fn add_schedule(
&mut self,
table: impl Into<RawIdentifier>,
column: impl Into<ColId>,
function: impl Into<RawIdentifier>,
) {
self.schedules_mut().push(RawScheduleDefV10 {
source_name: None,
table_name: table.into(),
schedule_at_col: column.into(),
function_name: function.into(),
});
}
pub fn add_row_level_security(&mut self, sql: &str) {
self.row_level_security_mut()
.push(RawRowLevelSecurityDefV10 { sql: sql.into() });
}
pub fn add_explicit_names(&mut self, names: ExplicitNames) {
self.explicit_names_mut().merge(names);
}
pub fn set_case_conversion_policy(&mut self, policy: CaseConversionPolicy) {
self.module
.sections
.retain(|s| !matches!(s, RawModuleDefV10Section::CaseConversionPolicy(_)));
self.module
.sections
.push(RawModuleDefV10Section::CaseConversionPolicy(policy));
}
pub fn finish(self) -> RawModuleDefV10 {
self.module
}
}
impl TypespaceBuilder for RawModuleDefV10Builder {
fn add(
&mut self,
typeid: TypeId,
source_name: Option<&'static str>,
make_ty: impl FnOnce(&mut Self) -> AlgebraicType,
) -> AlgebraicType {
if let btree_map::Entry::Occupied(o) = self.type_map.entry(typeid) {
AlgebraicType::Ref(*o.get())
} else {
let slot_ref = {
let ts = self.typespace_mut();
let slot_ref = ts.add(AlgebraicType::unit());
self.type_map.insert(typeid, slot_ref);
if let Some(sats_name) = source_name {
let source_name = sats_name_to_scoped_name_v10(sats_name);
self.types_mut().push(RawTypeDefV10 {
source_name,
ty: slot_ref,
custom_ordering: true,
});
}
slot_ref
};
let ty = make_ty(self);
self.typespace_mut()[slot_ref] = ty;
AlgebraicType::Ref(slot_ref)
}
}
}
pub fn reducer_default_ok_return_type() -> AlgebraicType {
AlgebraicType::unit()
}
pub fn reducer_default_err_return_type() -> AlgebraicType {
AlgebraicType::String
}
pub fn sats_name_to_scoped_name_v10(sats_name: &str) -> RawScopedTypeNameV10 {
let mut scope: Vec<RawIdentifier> = sats_name
.split("::")
.flat_map(|s| s.split('.'))
.map(RawIdentifier::new)
.collect();
let source_name = scope.pop().unwrap_or_default();
RawScopedTypeNameV10 {
scope: scope.into(),
source_name,
}
}
pub struct RawTableDefBuilderV10<'a> {
module: &'a mut RawModuleDefV10,
table: RawTableDefV10,
}
impl RawTableDefBuilderV10<'_> {
pub fn with_type(mut self, table_type: TableType) -> Self {
self.table.table_type = table_type;
self
}
pub fn with_access(mut self, table_access: TableAccess) -> Self {
self.table.table_access = table_access;
self
}
pub fn with_event(mut self, is_event: bool) -> Self {
self.table.is_event = is_event;
self
}
pub fn with_unique_constraint(mut self, columns: impl Into<ColList>) -> Self {
let columns = columns.into();
self.table.constraints.push(RawConstraintDefV10 {
source_name: None,
data: RawConstraintDataV10::Unique(RawUniqueConstraintDataV10 { columns }),
});
self
}
pub fn with_primary_key(mut self, column: impl Into<ColId>) -> Self {
self.table.primary_key = ColList::new(column.into());
self
}
pub fn with_auto_inc_primary_key(self, column: impl Into<ColId>) -> Self {
let column = column.into();
self.with_primary_key(column)
.with_unique_constraint(column)
.with_column_sequence(column)
}
pub fn with_index(
mut self,
algorithm: RawIndexAlgorithm,
source_name: impl Into<RawIdentifier>,
accessor_name: impl Into<RawIdentifier>,
) -> Self {
self.table.indexes.push(RawIndexDefV10 {
source_name: Some(source_name.into()),
accessor_name: Some(accessor_name.into()),
algorithm,
});
self
}
pub fn with_index_no_accessor_name(
mut self,
algorithm: RawIndexAlgorithm,
source_name: impl Into<RawIdentifier>,
) -> Self {
self.table.indexes.push(RawIndexDefV10 {
source_name: Some(source_name.into()),
accessor_name: None,
algorithm,
});
self
}
pub fn with_column_sequence(mut self, column: impl Into<ColId>) -> Self {
let column = column.into();
self.table.sequences.push(RawSequenceDefV10 {
source_name: None,
column,
start: None,
min_value: None,
max_value: None,
increment: 1,
});
self
}
pub fn with_default_column_value(mut self, column: impl Into<ColId>, value: AlgebraicValue) -> Self {
let col_id = column.into();
self.table.default_values.push(RawColumnDefaultValueV10 {
col_id,
value: spacetimedb_sats::bsatn::to_vec(&value).unwrap().into(),
});
self
}
pub fn finish(self) -> AlgebraicTypeRef {
let product_type_ref = self.table.product_type_ref;
let tables = match self
.module
.sections
.iter_mut()
.find(|s| matches!(s, RawModuleDefV10Section::Tables(_)))
{
Some(RawModuleDefV10Section::Tables(t)) => t,
_ => {
self.module.sections.push(RawModuleDefV10Section::Tables(Vec::new()));
match self.module.sections.last_mut().expect("Just pushed Tables section") {
RawModuleDefV10Section::Tables(t) => t,
_ => unreachable!(),
}
}
};
tables.push(self.table);
product_type_ref
}
pub fn find_col_pos_by_name(&self, column: impl AsRef<str>) -> Option<ColId> {
let column = column.as_ref();
let typespace = self.module.sections.iter().find_map(|s| {
if let RawModuleDefV10Section::Typespace(ts) = s {
Some(ts)
} else {
None
}
})?;
typespace
.get(self.table.product_type_ref)?
.as_product()?
.elements
.iter()
.position(|x| x.has_name(column.as_ref()))
.map(|i| ColId(i as u16))
}
}