1- use core:: fmt:: { self , Formatter , from_fn} ;
1+ use core:: fmt:: { self , Formatter , Write , from_fn} ;
22
33use alloc:: {
44 format,
@@ -10,7 +10,7 @@ use powersync_sqlite_nostd::{Connection, Destructor, ResultCode};
1010
1111use crate :: {
1212 error:: PowerSyncError ,
13- schema:: { RawTable , SchemaTable } ,
13+ schema:: { ColumnFilter , RawTable , SchemaTable } ,
1414 utils:: { InsertIntoCrud , SqlBuffer , WriteType } ,
1515 views:: table_columns_to_json_object,
1616} ;
@@ -23,6 +23,7 @@ impl InferredTableStructure {
2323 pub fn read_from_database (
2424 table_name : & str ,
2525 db : impl Connection ,
26+ ignored_local_columns : & ColumnFilter ,
2627 ) -> Result < Option < Self > , PowerSyncError > {
2728 let stmt = db. prepare_v2 ( "select name from pragma_table_info(?)" ) ?;
2829 stmt. bind_text ( 1 , table_name, Destructor :: STATIC ) ?;
@@ -34,7 +35,7 @@ impl InferredTableStructure {
3435 let name = stmt. column_text ( 0 ) ?;
3536 if name == "id" {
3637 has_id_column = true ;
37- } else {
38+ } else if !ignored_local_columns . matches ( name ) {
3839 columns. push ( name. to_string ( ) ) ;
3940 }
4041 }
@@ -63,7 +64,9 @@ pub fn generate_raw_table_trigger(
6364 return Err ( PowerSyncError :: argument_error ( "Table has no local name" ) ) ;
6465 } ;
6566
66- let Some ( resolved_table) = InferredTableStructure :: read_from_database ( local_table_name, db) ?
67+ let local_only_columns = & table. schema . local_only_columns ;
68+ let Some ( resolved_table) =
69+ InferredTableStructure :: read_from_database ( local_table_name, db, local_only_columns) ?
6770 else {
6871 return Err ( PowerSyncError :: argument_error ( format ! (
6972 "Could not find {} in local schema" ,
@@ -80,7 +83,27 @@ pub fn generate_raw_table_trigger(
8083 buffer. create_trigger ( "" , trigger_name) ;
8184 buffer. trigger_after ( write, local_table_name) ;
8285 // Skip the trigger for writes during sync_local, these aren't crud writes.
83- buffer. push_str ( "WHEN NOT powersync_in_sync_operation() BEGIN\n " ) ;
86+ buffer. push_str ( "WHEN NOT powersync_in_sync_operation()" ) ;
87+
88+ if write == WriteType :: Update && !local_only_columns. as_ref ( ) . is_empty ( ) {
89+ buffer. push_str ( " AND\n (" ) ;
90+ // If we have local-only columns, we want to add additional WHEN clauses to ensure the
91+ // trigger runs for updates on synced columns.
92+ for ( i, name) in as_schema_table. column_names ( ) . enumerate ( ) {
93+ if i != 0 {
94+ buffer. push_str ( " OR " ) ;
95+ }
96+
97+ // Generate OLD."column" IS NOT NEW."column"
98+ buffer. push_str ( "OLD." ) ;
99+ let _ = buffer. identifier ( ) . write_str ( name) ;
100+ buffer. push_str ( " IS NOT NEW." ) ;
101+ let _ = buffer. identifier ( ) . write_str ( name) ;
102+ }
103+ buffer. push_str ( ")" ) ;
104+ }
105+
106+ buffer. push_str ( " BEGIN\n " ) ;
84107
85108 if table. schema . options . flags . insert_only ( ) {
86109 if write != WriteType :: Insert {
0 commit comments