diff --git a/crates/bench/benches/subscription.rs b/crates/bench/benches/subscription.rs index f23406a10f..a24a686447 100644 --- a/crates/bench/benches/subscription.rs +++ b/crates/bench/benches/subscription.rs @@ -110,7 +110,7 @@ fn eval(c: &mut Criterion) { &raw.db, &tx, None, - Compression::Brotli, + Compression::None, ))) }) }); diff --git a/crates/core/src/db/relational_db.rs b/crates/core/src/db/relational_db.rs index 801bd63976..b429bc0eb3 100644 --- a/crates/core/src/db/relational_db.rs +++ b/crates/core/src/db/relational_db.rs @@ -841,8 +841,9 @@ impl RelationalDB { access: StAccess, ) -> Result { let mut module_def_builder = RawModuleDefV9Builder::new(); + let mut table_builder = module_def_builder - .build_table_with_new_type(name, ProductType::from_iter(schema.iter().cloned()), true) + .build_table_with_new_type_for_tests(name, ProductType::from_iter(schema.iter().cloned()), true) .with_access(access.into()); for columns in indexes { diff --git a/crates/lib/src/db/raw_def/v9.rs b/crates/lib/src/db/raw_def/v9.rs index cb7b0e4401..8b5d041631 100644 --- a/crates/lib/src/db/raw_def/v9.rs +++ b/crates/lib/src/db/raw_def/v9.rs @@ -479,11 +479,61 @@ impl RawModuleDefV9Builder { custom_ordering: bool, ) -> RawTableDefBuilder { let table_name = table_name.into(); + let product_type_ref = self.add_algebraic_type([], table_name.clone(), product_type.into(), custom_ordering); self.build_table(table_name, product_type_ref) } + /// Build a new table with a product type, for testing. + /// Adds the type to the module. + pub fn build_table_with_new_type_for_tests( + &mut self, + table_name: impl Into, + mut product_type: spacetimedb_sats::ProductType, + custom_ordering: bool, + ) -> RawTableDefBuilder { + 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, + } + + // Make the type into a ref. + let name = *name_gen; + let add_ty = core::mem::replace(ty, AlgebraicType::U8); + *ty = AlgebraicType::Ref(self.add_algebraic_type([], 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); + } + } + /// Add a type to the typespace, along with a type alias declaring its name. /// This method should only be use for `AlgebraicType`s not corresponding to a Rust /// type that implements `SpacetimeType`. diff --git a/crates/sats/src/sum_type.rs b/crates/sats/src/sum_type.rs index b035f9dc25..378bae8588 100644 --- a/crates/sats/src/sum_type.rs +++ b/crates/sats/src/sum_type.rs @@ -68,17 +68,32 @@ impl SumType { /// If the type does look like a structural option type, returns the type `T`. pub fn as_option(&self) -> Option<&AlgebraicType> { match &*self.variants { - [first, second] - if second.is_unit() // Done first to avoid pointer indirection when it doesn't matter. - && first.has_name(OPTION_SOME_TAG) - && second.has_name(OPTION_NONE_TAG) => - { - Some(&first.algebraic_type) - } + [first, second] if Self::are_variants_option(first, second) => Some(&first.algebraic_type), _ => None, } } + /// Check whether this sum type is a structural option type. + /// + /// A structural option type has `some(T)` as its first variant and `none` as its second. + /// That is, `{ some(T), none }` or `some: T | none` depending on your notation. + /// Note that `some` and `none` are lowercase, unlike Rust's `Option`. + /// Order matters, and an option type with these variants in the opposite order will not be recognized. + /// + /// If the type does look like a structural option type, returns the type `T`. + pub fn as_option_mut(&mut self) -> Option<&mut AlgebraicType> { + match &mut *self.variants { + [first, second] if Self::are_variants_option(first, second) => Some(&mut first.algebraic_type), + _ => None, + } + } + + fn are_variants_option(first: &SumTypeVariant, second: &SumTypeVariant) -> bool { + second.is_unit() // Done first to avoid pointer indirection when it doesn't matter. + && first.has_name(OPTION_SOME_TAG) + && second.has_name(OPTION_NONE_TAG) + } + /// Check whether this sum type is a structural option type. /// /// A structural option type has `some(T)` as its first variant and `none` as its second.