diff --git a/crates/bindings-csharp/Runtime/Internal/Autogen/RawModuleDefV10Section.g.cs b/crates/bindings-csharp/Runtime/Internal/Autogen/RawModuleDefV10Section.g.cs index 49328bc9766..7df8b83d3ac 100644 --- a/crates/bindings-csharp/Runtime/Internal/Autogen/RawModuleDefV10Section.g.cs +++ b/crates/bindings-csharp/Runtime/Internal/Autogen/RawModuleDefV10Section.g.cs @@ -16,6 +16,7 @@ public partial record RawModuleDefV10Section : SpacetimeDB.TaggedEnum<( System.Collections.Generic.List Procedures, System.Collections.Generic.List Views, System.Collections.Generic.List Schedules, - System.Collections.Generic.List LifeCycleReducers + System.Collections.Generic.List LifeCycleReducers, + System.Collections.Generic.List RowLevelSecurity )>; } diff --git a/crates/lib/src/db/raw_def/v10.rs b/crates/lib/src/db/raw_def/v10.rs index e1e95c7f0c0..e36461f8990 100644 --- a/crates/lib/src/db/raw_def/v10.rs +++ b/crates/lib/src/db/raw_def/v10.rs @@ -83,9 +83,12 @@ pub enum RawModuleDefV10Section { /// Unlike V9 where lifecycle was a field on reducers, /// V10 stores lifecycle-to-reducer mappings separately. LifeCycleReducers(Vec), - //TODO: Add section for Event tables, and Case conversion before exposing this from module + + RowLevelSecurity(Vec), //TODO: Add section for Event tables, and Case conversion before exposing this from module } +pub type RawRowLevelSecurityDefV10 = crate::db::raw_def::v9::RawRowLevelSecurityDefV9; + /// The definition of a database table. /// /// This struct holds information about the table, including its name, columns, indexes, @@ -476,6 +479,14 @@ impl RawModuleDefV10 { }) .expect("Tables section must exist for tests") } + + // Get the row-level security section, if present. + pub fn row_level_security(&self) -> Option<&Vec> { + self.sections.iter().find_map(|s| match s { + RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls), + _ => None, + }) + } } /// A builder for a [`RawModuleDefV10`]. @@ -633,6 +644,26 @@ impl RawModuleDefV10Builder { TypespaceBuilder::add_type::(self) } + /// Get mutable access to the row-level security section, creating it if missing. + fn row_level_security_mut(&mut self) -> &mut Vec { + 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"), + } + } + /// Create a table builder. /// /// Does not validate that the product_type_ref is valid; this is left to the module validation code. @@ -867,6 +898,16 @@ impl RawModuleDefV10Builder { }); } + /// Add a row-level security policy to the module. + /// + /// The `sql` expression should be a valid SQL expression that will be used to filter rows. + /// + /// **NOTE**: The `sql` expression must be unique within the module. + pub fn add_row_level_security(&mut self, sql: &str) { + self.row_level_security_mut() + .push(RawRowLevelSecurityDefV10 { sql: sql.into() }); + } + /// Finish building, consuming the builder and returning the module. /// The module should be validated before use. /// diff --git a/crates/schema/src/def/validate/v10.rs b/crates/schema/src/def/validate/v10.rs index af0ea1d6673..b0d8d132d13 100644 --- a/crates/schema/src/def/validate/v10.rs +++ b/crates/schema/src/def/validate/v10.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; -use spacetimedb_data_structures::map::HashCollectionExt; use spacetimedb_lib::bsatn::Deserializer; use spacetimedb_lib::db::raw_def::v10::*; use spacetimedb_lib::de::DeserializeSeed as _; @@ -180,6 +179,13 @@ pub fn validate(def: RawModuleDefV10) -> Result { .. } = validator.core; + let row_level_security_raw = def + .row_level_security() + .into_iter() + .flatten() + .map(|rls| (rls.sql.clone(), rls.to_owned())) + .collect(); + let (tables, types, reducers, procedures, views) = (tables_types_reducers_procedures_views).map_err(|errors| errors.sort_deduplicate())?; @@ -194,7 +200,7 @@ pub fn validate(def: RawModuleDefV10) -> Result { typespace_for_generate, stored_in_table_def, refmap, - row_level_security_raw: HashMap::new(), + row_level_security_raw, lifecycle_reducers, procedures, raw_module_def_version: RawModuleDefVersion::V10,