@@ -27,12 +27,12 @@ use anyhow::{anyhow, Context};
27
27
use core:: { cell:: RefCell , ops:: RangeBounds } ;
28
28
use parking_lot:: { Mutex , RwLock } ;
29
29
use spacetimedb_commitlog:: payload:: { txdata, Txdata } ;
30
- use spacetimedb_data_structures:: map:: { HashCollectionExt , HashMap } ;
30
+ use spacetimedb_data_structures:: map:: { HashCollectionExt , HashMap , IntMap } ;
31
31
use spacetimedb_durability:: TxOffset ;
32
32
use spacetimedb_lib:: { db:: auth:: StAccess , metrics:: ExecutionMetrics } ;
33
33
use spacetimedb_lib:: { ConnectionId , Identity } ;
34
34
use spacetimedb_paths:: server:: SnapshotDirPath ;
35
- use spacetimedb_primitives:: { ColList , ConstraintId , IndexId , SequenceId , TableId } ;
35
+ use spacetimedb_primitives:: { ColId , ColList , ConstraintId , IndexId , SequenceId , TableId } ;
36
36
use spacetimedb_sats:: memory_usage:: MemoryUsage ;
37
37
use spacetimedb_sats:: { bsatn, buffer:: BufReader , AlgebraicValue , ProductValue } ;
38
38
use spacetimedb_schema:: schema:: { ColumnSchema , IndexSchema , SequenceSchema , TableSchema } ;
@@ -313,6 +313,16 @@ impl Locking {
313
313
) -> Result < ( ) > {
314
314
tx. alter_table_row_type ( table_id, column_schemas)
315
315
}
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
+ }
316
326
}
317
327
318
328
impl DataRow for Locking {
@@ -1159,6 +1169,8 @@ mod tests {
1159
1169
use core:: { fmt, mem} ;
1160
1170
use itertools:: Itertools ;
1161
1171
use pretty_assertions:: { assert_eq, assert_matches} ;
1172
+ use spacetimedb_data_structures:: map:: IntMap ;
1173
+ use spacetimedb_execution:: dml:: MutDatastore as _;
1162
1174
use spacetimedb_execution:: Datastore ;
1163
1175
use spacetimedb_lib:: db:: auth:: { StAccess , StTableType } ;
1164
1176
use spacetimedb_lib:: error:: ResultTest ;
@@ -3320,8 +3332,138 @@ mod tests {
3320
3332
3321
3333
Ok ( ( ) )
3322
3334
}
3323
-
3324
3335
// TODO: Add the following tests
3325
3336
// - Create a tx that inserts 2000 rows with an auto_inc column
3326
3337
// - 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
+ }
3327
3469
}
0 commit comments