#![allow(unreachable_pub, dead_code)]
pub mod create_table;
mod state;
pub mod update_table;
use std::sync::Arc;
pub(super) use self::state::TransactionBuilderState;
use crate::actions::DomainMetadata;
use crate::schema::SchemaRef;
use crate::transaction::commit_info::collect_operation_metadata;
use crate::transaction::{CreateTable, UpdateTable};
use crate::EngineData;
pub trait TransactionType: private::Sealed {
#[doc(hidden)]
type BuilderState: Send;
}
pub struct TransactionBuilder<T: TransactionType = UpdateTable> {
common_state: TransactionBuilderState,
local_state: T::BuilderState,
}
impl<T: TransactionType> TransactionBuilder<T> {
pub fn with_transaction_id(mut self, app_id: impl Into<String>, version: i64) -> Self {
self.common_state
.transaction_ids
.push((app_id.into(), version));
self
}
pub fn with_domain_metadata(
mut self,
domain: impl Into<String>,
configuration: impl Into<String>,
) -> Self {
self.common_state
.domain_metadata_additions
.push(DomainMetadata::new(domain.into(), configuration.into()));
self
}
pub fn with_correlation_id(mut self, correlation_id: impl Into<Arc<str>>) -> Self {
self.common_state.correlation_id = Some(correlation_id.into()).filter(|id| !id.is_empty());
self
}
pub fn with_operation_parameters<I, K, V>(mut self, parameters: I) -> Self
where
I: IntoIterator<Item = (K, Option<V>)>,
K: Into<String>,
V: Into<String>,
{
self.common_state.operation_parameters = Some(collect_operation_metadata(parameters));
self
}
pub fn with_operation_metrics<I, K, V>(mut self, metrics: I) -> Self
where
I: IntoIterator<Item = (K, Option<V>)>,
K: Into<String>,
V: Into<String>,
{
self.common_state.operation_metrics = Some(collect_operation_metadata(metrics));
self
}
pub fn with_commit_info(
mut self,
commit_info: Box<dyn EngineData>,
commit_info_schema: SchemaRef,
) -> Self {
self.common_state.engine_commit_info = Some((commit_info, commit_info_schema));
self
}
}
impl TransactionType for CreateTable {
type BuilderState = create_table::CreateTableBuilderState;
}
impl TransactionType for UpdateTable {
type BuilderState = update_table::UpdateTableBuilderState;
}
impl private::Sealed for CreateTable {}
impl private::Sealed for UpdateTable {}
mod private {
pub trait Sealed {}
}
#[cfg(test)]
mod tests {
use super::{private, TransactionBuilder, TransactionBuilderState, TransactionType};
use crate::arrow::array::StringArray;
use crate::schema::schema_ref;
use crate::unit_test_utils::string_array_to_engine_data;
struct CustomType;
impl private::Sealed for CustomType {}
impl TransactionType for CustomType {
type BuilderState = ();
}
impl TransactionBuilder<CustomType> {
fn new(engine_info: &str) -> Self {
Self {
common_state: TransactionBuilderState::new(engine_info.into(), false),
local_state: (),
}
}
}
fn configure_shared_setters<T: TransactionType>(
builder: TransactionBuilder<T>,
) -> TransactionBuilder<T> {
builder
.with_correlation_id("correlation")
.with_operation_parameters([("mode", Some("Append"))])
.with_operation_metrics([("numFiles", Some("3"))])
.with_transaction_id("app", 7)
.with_domain_metadata("app.domain", "{}")
.with_commit_info(
string_array_to_engine_data(StringArray::from(vec!["tag"])),
schema_ref! { nullable "a": STRING },
)
}
#[test]
fn custom_type_supports_shared_setters_without_custom_state() {
let builder = TransactionBuilder::<CustomType>::new("test-engine");
let builder = configure_shared_setters(builder);
assert_eq!(builder.common_state.engine_info, "test-engine");
assert_eq!(
builder.common_state.correlation_id.as_deref(),
Some("correlation")
);
assert_eq!(
builder.common_state.operation_parameters.as_ref().unwrap()["mode"].as_deref(),
Some("Append")
);
assert_eq!(
builder.common_state.operation_metrics.as_ref().unwrap()["numFiles"].as_deref(),
Some("3")
);
assert_eq!(builder.common_state.transaction_ids, [("app".into(), 7)]);
assert_eq!(
builder.common_state.domain_metadata_additions[0].domain(),
"app.domain"
);
assert!(!builder.common_state.data_change);
let (commit_info, schema) = builder.common_state.engine_commit_info.as_ref().unwrap();
assert_eq!(commit_info.len(), 1);
assert_eq!(
schema.as_ref(),
schema_ref! { nullable "a": STRING }.as_ref()
);
builder.common_state.validate().unwrap();
}
}