@@ -66,27 +66,35 @@ impl InferredTableStructure {
6666 }
6767 }
6868
69- /// Generates a statement of the form `INSERT OR REPLACE INTO $tbl ($cols) VALUES (?, ...)` for
70- /// the sync client.
69+ /// Generates a statement of the form `INSERT INTO $tbl ($cols) VALUES (?, ...) ON CONFLICT (id)
70+ /// DO UPDATE SET ...` for the sync client.
7171 pub fn infer_put_stmt ( & self ) -> PendingStatement {
7272 let mut buffer = SqlBuffer :: new ( ) ;
7373 let mut params = vec ! [ ] ;
7474
75- buffer. push_str ( "INSERT OR REPLACE INTO " ) ;
75+ buffer. push_str ( "INSERT INTO " ) ;
7676 let _ = buffer. identifier ( ) . write_str ( & self . name ) ;
7777 buffer. push_str ( " (id" ) ;
7878 for column in & self . columns {
7979 buffer. comma ( ) ;
8080 let _ = buffer. identifier ( ) . write_str ( column) ;
8181 }
82- buffer. push_str ( ") VALUES (?" ) ;
82+ buffer. push_str ( ") VALUES (?1 " ) ;
8383 params. push ( PendingStatementValue :: Id ) ;
84- for column in & self . columns {
84+ for ( i , column) in self . columns . iter ( ) . enumerate ( ) {
8585 buffer. comma ( ) ;
86- buffer . push_str ( "?" ) ;
86+ let _ = write ! ( & mut buffer , "?{}" , i + 2 ) ;
8787 params. push ( PendingStatementValue :: Column ( column. clone ( ) ) ) ;
8888 }
89- buffer. push_str ( ")" ) ;
89+ buffer. push_str ( ") ON CONFLICT (id) DO UPDATE SET " ) ;
90+ let mut do_update = buffer. comma_separated ( ) ;
91+ // Generated an "x" = ? for all synced columns to update them without affecting local-only
92+ // columns.
93+ for ( i, column) in self . columns . iter ( ) . enumerate ( ) {
94+ let entry = do_update. element ( ) ;
95+ let _ = entry. identifier ( ) . write_str ( column) ;
96+ let _ = write ! ( entry, " = ?{}" , i + 2 ) ;
97+ }
9098
9199 PendingStatement {
92100 sql : buffer. sql ,
@@ -312,3 +320,39 @@ pub fn generate_raw_table_trigger(
312320 buffer. trigger_end ( ) ;
313321 Ok ( buffer. sql )
314322}
323+
324+ #[ cfg( test) ]
325+ mod test {
326+ use alloc:: { string:: ToString , vec} ;
327+
328+ use crate :: schema:: { PendingStatementValue , raw_table:: InferredTableStructure } ;
329+
330+ #[ test]
331+ fn infer_sync_statements ( ) {
332+ let structure = InferredTableStructure {
333+ name : "tbl" . to_string ( ) ,
334+ columns : vec ! [ "foo" . to_string( ) , "bar" . to_string( ) ] ,
335+ } ;
336+
337+ let put = structure. infer_put_stmt ( ) ;
338+ assert_eq ! (
339+ put. sql,
340+ r#"INSERT INTO "tbl" (id, "foo", "bar") VALUES (?1, ?2, ?3) ON CONFLICT (id) DO UPDATE SET "foo" = ?2, "bar" = ?3"#
341+ ) ;
342+ assert_eq ! ( put. params. len( ) , 3 ) ;
343+ assert ! ( matches!( put. params[ 0 ] , PendingStatementValue :: Id ) ) ;
344+ assert ! ( matches!(
345+ put. params[ 1 ] ,
346+ PendingStatementValue :: Column ( ref name) if name == "foo"
347+ ) ) ;
348+ assert ! ( matches!(
349+ put. params[ 2 ] ,
350+ PendingStatementValue :: Column ( ref name) if name == "bar"
351+ ) ) ;
352+
353+ let delete = structure. infer_delete_stmt ( ) ;
354+ assert_eq ! ( delete. sql, r#"DELETE FROM "tbl" WHERE id = ?"# ) ;
355+ assert_eq ! ( delete. params. len( ) , 1 ) ;
356+ assert ! ( matches!( delete. params[ 0 ] , PendingStatementValue :: Id ) ) ;
357+ }
358+ }
0 commit comments