faucet_core/driver/mod.rs
1//! Family driver traits (RFC 0014, #895).
2//!
3//! A driver is a connector's I/O and nothing else. The engine — this module
4//! for the family-neutral contract, `faucet-common-sql` and
5//! `faucet-common-file` for the SQL and object-store families — drives every
6//! lifecycle from the driver's primitives: overwrite staging, the
7//! exactly-once commit, scoped cleanup, rollback, per-row outcomes and the row
8//! report. A connector built on a driver cannot get one of those contracts
9//! wrong by forgetting a hook, because it does not implement the hook.
10//!
11//! | Layer | Trait | Adapter to [`Sink`](crate::Sink) / [`Source`](crate::Source) |
12//! |---|---|---|
13//! | any sink | [`SinkDriver`] (+ [`StagingDriver`], [`CommitTokenDriver`], [`CleanupDriver`], [`SchemaDriver`], [`RollbackDriver`]) | [`DriverSink`] |
14//! | any source | [`SourceDriver`] | [`DriverSource`] |
15//! | messaging, produce | [`MessageDriver`] (+ [`MessageTransactions`]) | [`MessageSinkDriver`] → [`DriverSink`] |
16//! | messaging, consume | [`MessageConsumer`] | [`MessageSourceDriver`] → [`DriverSource`] |
17//! | HTTP | [`HttpDriver`] | [`HttpSinkDriver`] → [`DriverSink`] |
18//! | SQL | `faucet_common_sql::SqlDriver` | `faucet_common_sql::SqlSinkDriver` → [`DriverSink`] |
19//! | object storage | `faucet_common_file::ObjectStoreDriver` | `faucet_common_file::FileSink` (a [`DriverSink`] inside) |
20//!
21//! The SQL and object-store traits live in their family crates because they
22//! are built on those crates' engines (`SqlSinkEngine` / `SqlDialect`,
23//! `FileWriter` / `StorageBackend`), and `faucet-core` depends on no
24//! connector-family crate.
25//!
26//! **Values.** Drivers exchange JSON [`Value`](crate::Value) records under the
27//! value-fidelity rules (#885); a destination that writes Arrow directly adds
28//! a `ColumnarDriver` (feature `arrow`) and receives the
29//! `RecordBatch` unconverted.
30//!
31//! **Calls.** Every async primitive receives the run's
32//! [`CallSlot`](crate::CallSlot); the adapter installs the run's context into
33//! it. Make each backend request through it.
34//!
35//! **Migrating a connector.** Keep the public type and config; hold the
36//! adapter and forward:
37//!
38//! ```
39//! use faucet_core::driver::{DriverSink, PageWrite, RowPolicy, SinkDriver};
40//! use faucet_core::{CallSlot, FaucetError, Sink, Value, async_trait, forward_sink};
41//!
42//! /// The connector's I/O.
43//! struct AcmeDriver;
44//!
45//! #[async_trait]
46//! impl SinkDriver for AcmeDriver {
47//! fn connector_name(&self) -> &'static str {
48//! "acme"
49//! }
50//! async fn write(
51//! &self,
52//! calls: &CallSlot,
53//! rows: &[Value],
54//! _policy: RowPolicy,
55//! ) -> Result<PageWrite, FaucetError> {
56//! let n = rows.len();
57//! calls
58//! .call_once("insert", async move { Ok::<_, FaucetError>(n) })
59//! .await?;
60//! Ok(PageWrite::accepted(n))
61//! }
62//! }
63//!
64//! /// The public connector type, unchanged for its users.
65//! pub struct AcmeSink {
66//! inner: DriverSink<AcmeDriver>,
67//! }
68//!
69//! #[async_trait]
70//! impl Sink for AcmeSink {
71//! forward_sink!(inner);
72//! }
73//! ```
74//!
75//! See RFC 0014 for the deprecated hooks these traits replace and the
76//! migration guide.
77
78mod http;
79mod message;
80mod sink;
81mod source;
82
83pub use http::{HttpBatching, HttpDriver, HttpSinkDriver};
84pub use message::{
85 AckToken, InboundMessage, MessageConsumer, MessageDriver, MessageSinkDriver,
86 MessageSourceDriver, MessageTransactions, OutboundMessage,
87};
88#[cfg(feature = "arrow")]
89pub use sink::ColumnarDriver;
90pub use sink::{
91 CleanupDriver, CommitTokenDriver, DriverSink, PageWrite, RollbackDriver, RowPolicy,
92 SchemaDriver, SinkDriver, StagingDriver,
93};
94#[cfg(feature = "arrow")]
95pub use source::ColumnarStream;
96pub use source::{DriverSource, NativeStream, PageStream, SourceDriver, pages_of};
97
98#[cfg(test)]
99mod tests;