@@ -2,6 +2,7 @@ extern crate alloc;
22
33use alloc:: boxed:: Box ;
44use alloc:: string:: String ;
5+ use const_format:: formatcp;
56use core:: ffi:: { c_char, c_int, c_void} ;
67
78use sqlite:: { Connection , ResultCode , Value } ;
@@ -11,10 +12,11 @@ use sqlite_nostd::ResultCode::NULL;
1112
1213use crate :: error:: SQLiteError ;
1314use crate :: ext:: SafeManagedStmt ;
15+ use crate :: schema:: TableInfoFlags ;
1416use crate :: vtab_util:: * ;
1517
1618// Structure:
17- // CREATE TABLE powersync_crud_(data TEXT);
19+ // CREATE TABLE powersync_crud_(data TEXT, options INT HIDDEN );
1820//
1921// This is a insert-only virtual table. It generates transaction ids in ps_tx, and inserts data in
2022// ps_crud(tx_id, data).
@@ -39,7 +41,10 @@ extern "C" fn connect(
3941 vtab : * mut * mut sqlite:: vtab ,
4042 _err : * mut * mut c_char ,
4143) -> c_int {
42- if let Err ( rc) = sqlite:: declare_vtab ( db, "CREATE TABLE powersync_crud_(data TEXT);" ) {
44+ if let Err ( rc) = sqlite:: declare_vtab (
45+ db,
46+ "CREATE TABLE powersync_crud_(data TEXT, options INT HIDDEN);" ,
47+ ) {
4348 return rc as c_int ;
4449 }
4550
@@ -70,7 +75,16 @@ extern "C" fn disconnect(vtab: *mut sqlite::vtab) -> c_int {
7075fn begin_impl ( tab : & mut VirtualTable ) -> Result < ( ) , SQLiteError > {
7176 let db = tab. db ;
7277
73- let insert_statement = db. prepare_v3 ( "INSERT INTO ps_crud(tx_id, data) VALUES (?1, ?2)" , 0 ) ?;
78+ const SQL : & str = formatcp ! (
79+ "\
80+ WITH insertion (tx_id, data) AS (VALUES (?1, ?2))
81+ INSERT INTO ps_crud(tx_id, data)
82+ SELECT * FROM insertion WHERE (NOT (?3 & {})) OR data->>'op' != 'PATCH' OR data->'data' != '{{}}';
83+ " ,
84+ TableInfoFlags :: IGNORE_EMPTY_UPDATE
85+ ) ;
86+
87+ let insert_statement = db. prepare_v3 ( SQL , 0 ) ?;
7488 tab. insert_statement = Some ( insert_statement) ;
7589
7690 // language=SQLite
@@ -107,7 +121,11 @@ extern "C" fn rollback(vtab: *mut sqlite::vtab) -> c_int {
107121 ResultCode :: OK as c_int
108122}
109123
110- fn insert_operation ( vtab : * mut sqlite:: vtab , data : & str ) -> Result < ( ) , SQLiteError > {
124+ fn insert_operation (
125+ vtab : * mut sqlite:: vtab ,
126+ data : & str ,
127+ flags : TableInfoFlags ,
128+ ) -> Result < ( ) , SQLiteError > {
111129 let tab = unsafe { & mut * ( vtab. cast :: < VirtualTable > ( ) ) } ;
112130 if tab. current_tx . is_none ( ) {
113131 return Err ( SQLiteError (
@@ -123,6 +141,7 @@ fn insert_operation(vtab: *mut sqlite::vtab, data: &str) -> Result<(), SQLiteErr
123141 . ok_or ( SQLiteError :: from ( NULL ) ) ?;
124142 statement. bind_int64 ( 1 , current_tx) ?;
125143 statement. bind_text ( 2 , data, sqlite:: Destructor :: STATIC ) ?;
144+ statement. bind_int ( 3 , flags. 0 as i32 ) ?;
126145 statement. exec ( ) ?;
127146
128147 Ok ( ( ) )
@@ -144,7 +163,11 @@ extern "C" fn update(
144163 } else if rowid. value_type ( ) == sqlite:: ColumnType :: Null {
145164 // INSERT
146165 let data = args[ 2 ] . text ( ) ;
147- let result = insert_operation ( vtab, data) ;
166+ let flags = match args[ 3 ] . value_type ( ) {
167+ sqlite_nostd:: ColumnType :: Null => TableInfoFlags :: default ( ) ,
168+ _ => TableInfoFlags ( args[ 3 ] . int ( ) as u32 ) ,
169+ } ;
170+ let result = insert_operation ( vtab, data, flags) ;
148171 vtab_result ( vtab, result)
149172 } else {
150173 // UPDATE - not supported
0 commit comments