@@ -4,16 +4,19 @@ use alloc::format;
44use alloc:: string:: { String , ToString } ;
55use alloc:: vec:: Vec ;
66
7- use powersync_sqlite_nostd as sqlite;
7+ use powersync_sqlite_nostd:: { self as sqlite, Destructor } ;
88use powersync_sqlite_nostd:: { Connection , Context } ;
9+ use serde:: Serialize ;
10+ use serde_json:: json;
911use sqlite:: ResultCode ;
1012
1113use crate :: error:: { PSResult , PowerSyncError } ;
14+ use crate :: ext:: SafeManagedStmt ;
1215use crate :: fix_data:: apply_v035_fix;
1316use crate :: schema:: inspection:: ExistingView ;
1417use crate :: sync:: BucketPriority ;
1518
16- pub const LATEST_VERSION : i32 = 12 ;
19+ pub const LATEST_VERSION : i32 = 13 ;
1720
1821pub fn powersync_migrate (
1922 ctx : * mut sqlite:: context ,
@@ -424,5 +427,53 @@ json_object('sql', 'DELETE FROM ps_migration WHERE id >= 12')
424427 local_db. exec_safe ( stmt) . into_db_result ( local_db) ?;
425428 }
426429
430+ if current_version < 13 && target_version >= 13 {
431+ let up = "\
432+ UPDATE ps_stream_subscriptions SET expires_at = expires_at * 1000000, last_synced_at = last_synced_at * 1000000;
433+ ALTER TABLE ps_sync_state RENAME TO ps_sync_state_old;
434+ CREATE TABLE ps_sync_state (
435+ priority INTEGER NOT NULL PRIMARY KEY,
436+ last_synced_at INTEGER NOT NULL
437+ ) STRICT;
438+ INSERT INTO ps_sync_state (priority, last_synced_at)
439+ SELECT priority, unixepoch(last_synced_at) * 1000000 FROM ps_sync_state_old;
440+ DROP TABLE ps_sync_state_old;
441+ " ;
442+ local_db. exec_safe ( up) . into_db_result ( local_db) ?;
443+
444+ const DOWN_STATEMENTS : & [ & str ] = & [
445+ "UPDATE ps_stream_subscriptions SET expires_at = expires_at / 1000000, last_synced_at = last_synced_at / 1000000" ,
446+ "ALTER TABLE ps_sync_state RENAME TO ps_sync_state_new" ,
447+ "CREATE TABLE ps_sync_state (
448+ priority INTEGER NOT NULL PRIMARY KEY,
449+ last_synced_at TEXT NOT NULL
450+ ) STRICT;" ,
451+ "INSERT INTO ps_sync_state (priority, last_synced_at) SELECT priority, datetime(last_synced_at / 1000000, 'unixepoch') FROM ps_sync_state_new" ,
452+ "DROP TABLE ps_sync_state_new" ,
453+ "DELETE FROM ps_migration WHERE id >= 13" ,
454+ ] ;
455+ let down = serialize_down_statements ( DOWN_STATEMENTS ) ?;
456+ let track_migration =
457+ local_db. prepare_v2 ( "INSERT INTO ps_migration(id, down_migrations) VALUES (?, ?)" ) ?;
458+ track_migration. bind_int ( 1 , 13 ) ?;
459+ track_migration. bind_text ( 2 , & down, Destructor :: STATIC ) ?;
460+ track_migration. exec ( ) ?;
461+ }
462+
427463 Ok ( ( ) )
428464}
465+
466+ fn serialize_down_statements ( statements : & [ & ' static str ] ) -> Result < String , PowerSyncError > {
467+ struct DownStatements < ' a > ( & ' a [ & ' static str ] ) ;
468+
469+ impl < ' a > Serialize for DownStatements < ' a > {
470+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
471+ where
472+ S : serde:: Serializer ,
473+ {
474+ serializer. collect_seq ( self . 0 . iter ( ) . map ( |s| json ! ( { "sql" : s} ) ) . into_iter ( ) )
475+ }
476+ }
477+
478+ serde_json:: to_string ( & DownStatements ( statements) ) . map_err ( PowerSyncError :: internal)
479+ }
0 commit comments