@@ -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 ) ]
16151623struct LockFile {
0 commit comments