use async_trait::async_trait;
use crate::error::ConnectError;
use crate::record::ConnectRecord;
#[async_trait]
pub trait Sink<K, V>: Send + Sync + 'static {
async fn put(&mut self, records: Vec<ConnectRecord<K, V>>) -> Result<(), ConnectError>;
async fn flush(&mut self) -> Result<(), ConnectError>;
fn supports_transactions(&self) -> bool {
false
}
async fn begin(&mut self) -> Result<(), ConnectError> {
Ok(())
}
async fn commit(&mut self) -> Result<(), ConnectError> {
self.flush().await
}
async fn abort(&mut self) -> Result<(), ConnectError> {
Ok(())
}
async fn close(&mut self) -> Result<(), ConnectError> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use assert2::check;
use async_trait::async_trait;
use bytes::Bytes;
use super::*;
#[derive(Default)]
struct DefaultSink {
durable: usize,
buffered: usize,
}
#[async_trait]
impl Sink<Bytes, Bytes> for DefaultSink {
async fn put(
&mut self,
records: Vec<ConnectRecord<Bytes, Bytes>>,
) -> Result<(), ConnectError> {
self.buffered += records.len();
Ok(())
}
async fn flush(&mut self) -> Result<(), ConnectError> {
self.durable += self.buffered;
self.buffered = 0;
Ok(())
}
}
#[test]
fn default_sink_is_not_transactional() {
check!(!DefaultSink::default().supports_transactions());
}
#[tokio::test]
async fn default_commit_makes_buffered_records_durable() {
let mut sink = DefaultSink::default();
sink.put(vec![ConnectRecord::new(
None,
Some(Bytes::from_static(b"x")),
)])
.await
.unwrap();
sink.commit().await.unwrap();
check!(sink.durable == 1);
check!(sink.buffered == 0);
}
#[tokio::test]
async fn default_begin_abort_and_close_are_noops() {
let mut sink = DefaultSink::default();
check!(sink.begin().await.is_ok());
check!(sink.abort().await.is_ok());
check!(sink.close().await.is_ok());
}
}