#![allow(clippy::print_stdout, clippy::print_stderr)]
use spate::backpressure::InflightBudget;
use spate::checkpoint::Checkpointer;
use spate::deser::Owned;
use spate::error::ErrorPolicy;
use spate::ops::{ChunkConfig, PushOutcome, chain_owned};
use spate::record::PartitionId;
use spate::sink::{KeyHashRouter, shard_queues};
use spate::source::{LaneId, Source, SourceCtx, SourceEvent, SourceLane};
use spate_test::{TestDeserializer, TestEncoder, memory_source};
use std::collections::HashSet;
use std::sync::Arc;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
spate::telemetry::init(spate::telemetry::LogFormat::Pretty, "info");
let (queues, mut receivers) = shard_queues(1, 16);
let budget = Arc::new(InflightBudget::new());
let mut seen: HashSet<Vec<u8>> = HashSet::new();
let mut chain = chain_owned::<Vec<u8>, _>(TestDeserializer::passthrough())
.flat_map::<Owned<Vec<u8>>, _>(move |word, out| {
if seen.insert(word.clone()) {
out.emit(word);
}
})
.try_map(
|word: Vec<u8>| {
if word.iter().all(u8::is_ascii_alphabetic) {
Ok(word)
} else {
Err("non-alphabetic word")
}
},
ErrorPolicy::Skip,
)
.map(|word: Vec<u8>| word.to_ascii_uppercase())
.sink(
TestEncoder,
KeyHashRouter,
ChunkConfig::default(),
queues,
budget,
)
.build();
let mut cp = Checkpointer::new();
let (mut source, handle) = memory_source();
source.open(SourceCtx::new(cp.handle()))?;
let p0 = PartitionId(0);
cp.begin_epoch(&[p0], 1);
handle.assign_lanes(&[(LaneId(0), p0)]);
let SourceEvent::LanesAssigned(mut lanes) = source.poll_events(Duration::from_millis(100))?
else {
panic!("expected assignment");
};
for word in ["hello", "world", "hello", "rust", "n0pe", "world"] {
handle.push(p0, None, word.as_bytes());
}
let mut batch = lanes[0]
.poll(64, Duration::from_millis(200))?
.expect("records queued");
assert!(matches!(chain.push_batch(&mut batch, 0), PushOutcome::Done));
drop(batch);
assert!(matches!(chain.flush(), PushOutcome::Done));
let mut rows = Vec::new();
while let Ok(chunk) = receivers[0].try_recv() {
rows.extend(
spate_test::decode_rows(&chunk.frame)
.into_iter()
.map(|r| String::from_utf8_lossy(&r).into_owned()),
);
}
println!("deduped + validated + uppercased: {rows:?}");
assert_eq!(rows, ["HELLO", "WORLD", "RUST"]);
drop(chain); cp.drain();
println!("committable watermarks: {:?}", cp.take_watermarks());
Ok(())
}