Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 42 additions & 1 deletion crates/lib/src/db/raw_def/v10.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<RawLifeCycleReducerDefV10>),
//TODO: Add section for Event tables, and Case conversion before exposing this from module

RowLevelSecurity(Vec<RawRowLevelSecurityDefV10>), //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,
Expand Down Expand Up @@ -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<RawRowLevelSecurityDefV10>> {
self.sections.iter().find_map(|s| match s {
RawModuleDefV10Section::RowLevelSecurity(rls) => Some(rls),
_ => None,
})
}
}

/// A builder for a [`RawModuleDefV10`].
Expand Down Expand Up @@ -633,6 +644,26 @@ impl RawModuleDefV10Builder {
TypespaceBuilder::add_type::<T>(self)
}

/// Get mutable access to the row-level security section, creating it if missing.
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"),
}
}

/// Create a table builder.
///
/// Does not validate that the product_type_ref is valid; this is left to the module validation code.
Expand Down Expand Up @@ -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.
///
Expand Down
10 changes: 8 additions & 2 deletions crates/schema/src/def/validate/v10.rs
Original file line number Diff line number Diff line change
@@ -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 _;
Expand Down Expand Up @@ -180,6 +179,13 @@ pub fn validate(def: RawModuleDefV10) -> Result<ModuleDef> {
..
} = 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())?;

Expand All @@ -194,7 +200,7 @@ pub fn validate(def: RawModuleDefV10) -> Result<ModuleDef> {
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,
Expand Down
Loading