Skip to content

Commit 655ab83

Browse files
committed
evaluate_view -> materialize_view
1 parent 131fdba commit 655ab83

File tree

2 files changed

+52
-44
lines changed

2 files changed

+52
-44
lines changed

crates/core/src/db/relational_db.rs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,43 +1519,42 @@ impl RelationalDB {
15191519
})
15201520
}
15211521

1522-
/// Evaluate and update View.
1523-
/// This involves:
1524-
/// 1. Serializing the view arguments into `ST_VIEW_ARG_ID`
1525-
/// 2. Deleting all rows in the view table matching the view arguments
1526-
/// 3. Deserializing the return value from the view execution
1527-
/// 4. Inserting all rows from the return value into the view table, with the arg_id
1528-
/// set to the inserted view argument's id.
1529-
/// The `typespace` is needed for deserializing the return value.
1522+
/// Materialize View backing table.
1523+
///
1524+
/// # Process
1525+
/// 1. Serializes view arguments into `ST_VIEW_ARG_ID`
1526+
/// 2. Deletes stale rows matching the view arguments
1527+
/// 3. Deserializes the new view execution results
1528+
/// 4. Inserts fresh rows with the corresponding arg_id
1529+
///
1530+
/// # Arguments
1531+
/// * `tx` - Mutable transaction context
1532+
/// * `view` - Name of the view to update
1533+
/// * `args` - Arguments passed to the view call
1534+
/// * `return_type` - Expected return type of the view
1535+
/// * `bytes` - Serialized (bsatn encoded) return value from view execution
1536+
/// * `typespace` - Type information for deserialization
1537+
/// * `caller_identity` - Identity of the caller (for non-anonymous views)
15301538
#[allow(clippy::too_many_arguments)]
1531-
pub fn evaluate_view(
1539+
pub fn materialize_view(
15321540
&self,
15331541
tx: &mut MutTxId,
1534-
// Name of the view to update
15351542
view: &str,
1536-
// Arguments passed to the view call
15371543
args: ArgsTuple,
1538-
// Return type of the view call
15391544
return_type: AlgebraicType,
1540-
// Serialized bytes of the return value from the view call
1541-
//TODO: pass arg_id; do the insertion during starting of invoking view
15421545
bytes: Bytes,
15431546
typespace: &Typespace,
1544-
// Identity of the caller (for non-anonymous views)
15451547
caller_identity: Identity,
15461548
) -> Result<(), DBError> {
1549+
// Fetch view metadata
15471550
let st_view_row = tx.lookup_st_view_by_name(view)?;
1548-
1549-
let (table_id, is_anonymous) = (
1550-
st_view_row
1551-
.table_id
1552-
.expect("Tables are always created for views upon view creation"),
1553-
st_view_row.is_anonymous,
1554-
);
1551+
let table_id = st_view_row.table_id.expect("View table must exist for materialization");
1552+
let is_anonymous = st_view_row.is_anonymous;
15551553

15561554
let arg_id = tx.get_or_insert_st_view_arg(args.get_bsatn())?;
15571555

1558-
let input_rows = product![
1556+
// Build the filter key for identifying rows to update
1557+
let input_args = product![
15591558
if is_anonymous {
15601559
AlgebraicValue::OptionNone()
15611560
} else {
@@ -1564,52 +1563,61 @@ impl RelationalDB {
15641563
AlgebraicValue::U64(arg_id)
15651564
];
15661565

1567-
// Delete all existing rows in the view table matching the view arguments
1566+
// Remove stale View entries
15681567
let rows_to_delete: Vec<_> = self
1569-
.iter_by_col_eq_mut(tx, table_id, [0, 1], &input_rows.clone().into())?
1568+
.iter_by_col_eq_mut(tx, table_id, [0, 1], &input_args.clone().into())?
15701569
.map(|res| res.pointer())
15711570
.collect();
15721571

1573-
let count = self.delete(tx, table_id, rows_to_delete);
1574-
trace!("Deleted {count} rows from view table {table_id} for arg_id {arg_id}");
1572+
let deleted_count = self.delete(tx, table_id, rows_to_delete);
1573+
trace!("Deleted {deleted_count} stale rows from view table {table_id} for arg_id {arg_id}");
15751574

15761575
// Deserialize the return value
15771576
let seed = spacetimedb_sats::WithTypespace::new(typespace, &return_type);
15781577
let return_val = seed
15791578
.deserialize(bsatn::Deserializer::new(&mut &bytes[..]))
15801579
.map_err(|e| DatastoreError::from(ViewError::DeserializeReturn(e.to_string())))?;
15811580

1581+
// Extract products from return value (must be array or option)
15821582
let products: Vec<ProductValue> = if return_type.is_array() {
1583-
let arr = return_val.into_array().expect("return type is array");
1584-
Ok(arr.into_iter().map(|v| v.into_product().unwrap()).collect())
1583+
let arr = return_val
1584+
.into_array()
1585+
.expect("return_type.is_array() ensures this is an array");
1586+
1587+
arr.into_iter().map(|v| v.into_product().unwrap()).collect()
15851588
} else if return_type.is_option() {
1586-
let opt = return_val.into_option().expect("return type is option");
1587-
Ok(opt.into_iter().map(|v| v.into_product().unwrap()).collect())
1589+
let opt = return_val
1590+
.into_option()
1591+
.expect("return_type.is_option() ensures this is an option");
1592+
opt.into_iter().map(|v| v.into_product().unwrap()).collect()
15881593
} else {
1589-
Err(DatastoreError::from(ViewError::InvalidReturnType(return_type.clone())))
1590-
}?;
1594+
return Err(DatastoreError::from(ViewError::InvalidReturnType(return_type)).into());
1595+
};
15911596

1592-
// Insert all rows from the return value into the view table
1597+
// Insert fresh results into the view table
1598+
let mut elements: Vec<AlgebraicValue> =
1599+
Vec::with_capacity(input_args.elements.len() + products.first().map_or(0, |p| p.elements.len()));
15931600
for product in products {
1594-
let row = {
1595-
let mut elements = Vec::with_capacity(2 + product.elements.len());
1596-
elements.extend_from_slice(&input_rows.elements);
1597-
elements.append(&mut product.elements.to_vec());
1598-
1599-
ProductValue {
1600-
elements: elements.into_boxed_slice(),
1601-
}
1601+
elements.clear();
1602+
// Build complete row by prepending filter key to product data
1603+
let mut elements = Vec::with_capacity(input_args.elements.len() + product.elements.len());
1604+
elements.extend_from_slice(&input_args.elements);
1605+
elements.extend_from_slice(&product.elements);
1606+
1607+
let row = ProductValue {
1608+
elements: elements.into_boxed_slice(),
16021609
};
1610+
16031611
let row_bytes = row
16041612
.to_bsatn_vec()
16051613
.map_err(|_| DatastoreError::from(ViewError::SerializeRow))?;
1614+
16061615
self.insert(tx, table_id, &row_bytes)?;
16071616
}
16081617

16091618
Ok(())
16101619
}
16111620
}
1612-
16131621
#[allow(unused)]
16141622
#[derive(Clone)]
16151623
struct LockFile {

crates/core/src/host/wasm_common/module_host_actor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ impl InstanceCommon {
817817
}
818818
Ok(res) => {
819819
let db = &replica_ctx.relational_db.clone();
820-
db.evaluate_view(
820+
db.materialize_view(
821821
&mut tx,
822822
view_name,
823823
args,

0 commit comments

Comments
 (0)