#[rustfmt::skip] /* diesel master support on_conflict on sqlite but not 1.4.7 version. Workaround for this match dsl::workspace_table .filter(workspace_table::id.eq(table.id.clone())) .count() .get_result(conn) .unwrap_or(0) { 0 => diesel::insert_into(workspace_table::table).values(table) .on_conflict(workspace_table::id) .do_update() .set(WorkspaceTableChangeset::from_table(workspace_table)) .execute(conn)?, _ => { let changeset = WorkspaceTableChangeset::from_table(table); let filter = dsl::workspace_table.filter(workspace_table::id.eq(changeset.id.clone())); diesel::update(filter).set(changeset).execute(conn)?; }, } is equivalent to: match diesel_record_count!(workspace_table, &table.id, conn) { 0 => diesel_insert_table!(workspace_table, table, conn), _ => diesel_update_table!(workspace_table, WorkspaceTableChangeset::from_table(table), &*conn), } */ #[macro_export] macro_rules! diesel_insert_table { ( $table_name:ident, $table:expr, $connection:expr ) => { { let _ = diesel::insert_into($table_name::table) .values($table.clone()) // .on_conflict($table_name::dsl::id) // .do_update() // .set(WorkspaceTableChangeset::from_table(workspace_table)) .execute($connection)?; } }; } #[macro_export] macro_rules! diesel_record_count { ( $table_name:ident, $id:expr, $connection:expr ) => { $table_name::dsl::$table_name .filter($table_name::dsl::id.eq($id.clone())) .count() .get_result($connection) .unwrap_or(0); }; } #[macro_export] macro_rules! diesel_update_table { ( $table_name:ident, $changeset:expr, $connection:expr ) => {{ let filter = $table_name::dsl::$table_name.filter($table_name::dsl::id.eq($changeset.id.clone())); let affected_row = diesel::update(filter).set($changeset).execute($connection)?; debug_assert_eq!(affected_row, 1); }}; } #[macro_export] macro_rules! diesel_delete_table { ( $table_name:ident, $id:ident, $connection:ident ) => { let filter = $table_name::dsl::$table_name.filter($table_name::dsl::id.eq($id)); let affected_row = diesel::delete(filter).execute(&*$connection)?; debug_assert_eq!(affected_row, 1); }; } #[macro_export] macro_rules! impl_sql_binary_expression { ($target:ident) => { impl diesel::serialize::ToSql for $target { fn to_sql( &self, out: &mut diesel::serialize::Output, ) -> diesel::serialize::Result { let bytes: Vec = self.try_into().map_err(|e| format!("{:?}", e))?; diesel::serialize::ToSql::::to_sql(&bytes, out) } } // https://docs.diesel.rs/src/diesel/sqlite/types/mod.rs.html#30-33 // impl FromSql for *const [u8] { // fn from_sql(bytes: Option<&SqliteValue>) -> deserialize::Result { // let bytes = not_none!(bytes).read_blob(); // Ok(bytes as *const _) // } // } impl diesel::deserialize::FromSql for $target where DB: diesel::backend::Backend, *const [u8]: diesel::deserialize::FromSql, { fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result { let slice_ptr = <*const [u8] as diesel::deserialize::FromSql>::from_sql(bytes)?; let bytes = unsafe { &*slice_ptr }; match $target::try_from(bytes) { Ok(object) => Ok(object), Err(e) => { log::error!( "{:?} deserialize from bytes fail. {:?}", std::any::type_name::<$target>(), e ); panic!(); } } } } }; } #[macro_export] macro_rules! impl_sql_integer_expression { ($target:ident) => { impl diesel::serialize::ToSql for $target where DB: diesel::backend::Backend, i32: diesel::serialize::ToSql, { fn to_sql( &self, out: &mut diesel::serialize::Output, ) -> diesel::serialize::Result { (*self as i32).to_sql(out) } } impl diesel::deserialize::FromSql for $target where DB: diesel::backend::Backend, i32: diesel::deserialize::FromSql, { fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result { let smaill_int = i32::from_sql(bytes)?; Ok($target::from(smaill_int)) } } }; } #[macro_export] macro_rules! impl_rev_state_map { ($target:ident) => { impl std::convert::From for $target { fn from(value: i32) -> Self { match value { 0 => $target::Sync, 1 => $target::Ack, o => { tracing::error!("Unsupported rev state {}, fallback to RevState::Local", o); $target::Sync } } } } impl std::convert::From<$target> for RevisionState { fn from(s: $target) -> Self { match s { $target::Sync => RevisionState::Sync, $target::Ack => RevisionState::Ack, } } } impl std::convert::From for $target { fn from(s: RevisionState) -> Self { match s { RevisionState::Sync => $target::Sync, RevisionState::Ack => $target::Ack, } } } }; }