@@ -27,12 +27,12 @@ use anyhow::{anyhow, Context};
2727use core:: { cell:: RefCell , ops:: RangeBounds } ;
2828use parking_lot:: { Mutex , RwLock } ;
2929use spacetimedb_commitlog:: payload:: { txdata, Txdata } ;
30- use spacetimedb_data_structures:: map:: { HashCollectionExt , HashMap } ;
30+ use spacetimedb_data_structures:: map:: { HashCollectionExt , HashMap , IntMap } ;
3131use spacetimedb_durability:: TxOffset ;
3232use spacetimedb_lib:: { db:: auth:: StAccess , metrics:: ExecutionMetrics } ;
3333use spacetimedb_lib:: { ConnectionId , Identity } ;
3434use spacetimedb_paths:: server:: SnapshotDirPath ;
35- use spacetimedb_primitives:: { ColList , ConstraintId , IndexId , SequenceId , TableId } ;
35+ use spacetimedb_primitives:: { ColId , ColList , ConstraintId , IndexId , SequenceId , TableId } ;
3636use spacetimedb_sats:: memory_usage:: MemoryUsage ;
3737use spacetimedb_sats:: { bsatn, buffer:: BufReader , AlgebraicValue , ProductValue } ;
3838use spacetimedb_schema:: schema:: { ColumnSchema , IndexSchema , SequenceSchema , TableSchema } ;
@@ -313,6 +313,16 @@ impl Locking {
313313 ) -> Result < ( ) > {
314314 tx. alter_table_row_type ( table_id, column_schemas)
315315 }
316+
317+ pub fn add_columns_to_table_mut_tx (
318+ & self ,
319+ tx : & mut MutTxId ,
320+ table_id : TableId ,
321+ column_schemas : Vec < ColumnSchema > ,
322+ defaults : IntMap < ColId , AlgebraicValue > ,
323+ ) -> Result < TableId > {
324+ tx. add_columns_to_table ( table_id, column_schemas, defaults)
325+ }
316326}
317327
318328impl DataRow for Locking {
@@ -1159,6 +1169,8 @@ mod tests {
11591169 use core:: { fmt, mem} ;
11601170 use itertools:: Itertools ;
11611171 use pretty_assertions:: { assert_eq, assert_matches} ;
1172+ use spacetimedb_data_structures:: map:: IntMap ;
1173+ use spacetimedb_execution:: dml:: MutDatastore as _;
11621174 use spacetimedb_execution:: Datastore ;
11631175 use spacetimedb_lib:: db:: auth:: { StAccess , StTableType } ;
11641176 use spacetimedb_lib:: error:: ResultTest ;
@@ -3320,8 +3332,138 @@ mod tests {
33203332
33213333 Ok ( ( ) )
33223334 }
3323-
33243335 // TODO: Add the following tests
33253336 // - Create a tx that inserts 2000 rows with an auto_inc column
33263337 // - Create a tx that inserts 2000 rows with an auto_inc column and then rolls back
3338+
3339+ #[ test]
3340+ fn test_add_columns_to_table ( ) -> ResultTest < ( ) > {
3341+ let datastore = get_datastore ( ) ?;
3342+
3343+ let mut tx = begin_mut_tx ( & datastore) ;
3344+
3345+ let initial_sum_type = AlgebraicType :: sum ( [ ( "ba" , AlgebraicType :: U16 ) ] ) ;
3346+ let initial_columns = [
3347+ ColumnSchema :: for_test ( 0 , "a" , AlgebraicType :: U64 ) ,
3348+ ColumnSchema :: for_test ( 1 , "b" , initial_sum_type. clone ( ) ) ,
3349+ ] ;
3350+
3351+ let initial_indices = [
3352+ IndexSchema :: for_test ( "index_a" , BTreeAlgorithm :: from ( 0 ) ) ,
3353+ IndexSchema :: for_test ( "index_b" , BTreeAlgorithm :: from ( 1 ) ) ,
3354+ ] ;
3355+
3356+ let sequence = SequenceRow {
3357+ id : SequenceId :: SENTINEL . into ( ) ,
3358+ table : 0 ,
3359+ col_pos : 0 ,
3360+ name : "Foo_id_seq" ,
3361+ start : 5 ,
3362+ } ;
3363+
3364+ let schema = user_public_table (
3365+ initial_columns,
3366+ initial_indices. clone ( ) ,
3367+ [ ] ,
3368+ map_array ( [ sequence] ) ,
3369+ None ,
3370+ None ,
3371+ ) ;
3372+
3373+ let table_id = datastore. create_table_mut_tx ( & mut tx, schema) ?;
3374+
3375+ let columns_original = tx. get_schema ( table_id) . unwrap ( ) . columns . to_vec ( ) ;
3376+
3377+ // Insert initial rows
3378+ let initial_row = ProductValue {
3379+ elements : [ AlgebraicValue :: U64 ( 0 ) , AlgebraicValue :: sum ( 0 , AlgebraicValue :: U16 ( 1 ) ) ] . into ( ) ,
3380+ } ;
3381+ tx. insert_product_value ( table_id, & initial_row) . unwrap ( ) ;
3382+ tx. insert_product_value ( table_id, & initial_row) . unwrap ( ) ;
3383+
3384+ commit ( & datastore, tx) ?;
3385+
3386+ // Alter Table: Add Variant and Column
3387+ let mut new_columns = columns_original. clone ( ) ;
3388+ new_columns. push ( ColumnSchema :: for_test ( 2 , "c" , AlgebraicType :: U8 ) ) ;
3389+ let defaults = IntMap :: from_iter ( [ ( 2 . into ( ) , AlgebraicValue :: U8 ( 42 ) ) ] ) ;
3390+
3391+ let mut tx = begin_mut_tx ( & datastore) ;
3392+ let new_table_id = datastore. add_columns_to_table_mut_tx ( & mut tx, table_id, new_columns. clone ( ) , defaults) ?;
3393+ let tx_data = commit ( & datastore, tx) ?;
3394+
3395+ assert_ne ! (
3396+ new_table_id, table_id,
3397+ "New table ID after migration should differ from old one"
3398+ ) ;
3399+
3400+ // Validate Commitlog Changes
3401+ let ( _, deletes) = tx_data
3402+ . deletes ( )
3403+ . find ( |( id, _) | * * id == table_id)
3404+ . expect ( "Expected delete log for original table" ) ;
3405+
3406+ let deleted_rows = [
3407+ product ! [ AlgebraicValue :: U64 ( 5 ) , AlgebraicValue :: sum( 0 , AlgebraicValue :: U16 ( 1 ) ) ] ,
3408+ product ! [ AlgebraicValue :: U64 ( 6 ) , AlgebraicValue :: sum( 0 , AlgebraicValue :: U16 ( 1 ) ) ] ,
3409+ ] ;
3410+
3411+ assert_eq ! (
3412+ & * * deletes, & deleted_rows,
3413+ "Unexpected delete entries after altering the table"
3414+ ) ;
3415+
3416+ let inserted_rows = [
3417+ product ! [
3418+ AlgebraicValue :: U64 ( 5 ) ,
3419+ AlgebraicValue :: sum( 0 , AlgebraicValue :: U16 ( 1 ) ) ,
3420+ AlgebraicValue :: U8 ( 42 )
3421+ ] ,
3422+ product ! [
3423+ AlgebraicValue :: U64 ( 6 ) ,
3424+ AlgebraicValue :: sum( 0 , AlgebraicValue :: U16 ( 1 ) ) ,
3425+ AlgebraicValue :: U8 ( 42 )
3426+ ] ,
3427+ ] ;
3428+
3429+ let ( _, inserts) = tx_data
3430+ . inserts ( )
3431+ . find ( |( id, _) | * * id == new_table_id)
3432+ . expect ( "Expected insert log for new table" ) ;
3433+
3434+ assert_eq ! (
3435+ & * * inserts, & inserted_rows,
3436+ "Unexpected insert entries after altering the table"
3437+ ) ;
3438+
3439+ // Insert Rows into Altered Table
3440+ let mut tx = begin_mut_tx ( & datastore) ;
3441+
3442+ let new_row = ProductValue {
3443+ elements : [
3444+ AlgebraicValue :: U64 ( 0 ) ,
3445+ AlgebraicValue :: sum ( 0 , AlgebraicValue :: U16 ( 1 ) ) ,
3446+ AlgebraicValue :: U8 ( 0 ) ,
3447+ ]
3448+ . into ( ) ,
3449+ } ;
3450+
3451+ tx. insert_product_value ( new_table_id, & new_row) . unwrap ( ) ;
3452+ commit ( & datastore, tx) ?;
3453+
3454+ // test for auto_inc feields
3455+ let tx = begin_mut_tx ( & datastore) ;
3456+ let rows = tx. table_scan ( new_table_id) . unwrap ( ) . map ( |row| row. to_product_value ( ) ) ;
3457+
3458+ let mut last_row_auto_inc = 0 ;
3459+ for row in rows {
3460+ let auto_inc_col = row. get_field ( 0 , None ) ?;
3461+ if let AlgebraicValue :: U64 ( val) = auto_inc_col {
3462+ assert ! ( val > & last_row_auto_inc, "Auto-increment value did not increase" ) ;
3463+ last_row_auto_inc = * val;
3464+ }
3465+ }
3466+
3467+ Ok ( ( ) )
3468+ }
33273469}
0 commit comments