use std::{fmt, marker::PhantomData};
use crate::common::*;
use crate::separator::Separator;
pub(crate) trait EnumSetExt<T: EnumSetType> {
fn display(self) -> DisplayEnumSet<T>;
}
impl<T: EnumSetType> EnumSetExt<T> for EnumSet<T> {
fn display(self) -> DisplayEnumSet<T> {
DisplayEnumSet(self)
}
}
pub(crate) struct DisplayEnumSet<T: EnumSetType>(pub EnumSet<T>);
pub trait ArgumentState: Clone {}
#[derive(Clone)]
pub enum Unverified {}
impl ArgumentState for Unverified {}
#[derive(Clone)]
pub enum Verified {}
impl ArgumentState for Verified {}
#[derive(Clone, Debug)]
pub struct SharedArguments<S: ArgumentState> {
schema: Table,
temporary_storage: TemporaryStorage,
_phantom: PhantomData<S>,
}
impl SharedArguments<Unverified> {
pub fn new(schema: Table, temporary_storage: TemporaryStorage) -> Self {
Self {
schema,
temporary_storage,
_phantom: PhantomData,
}
}
pub fn verify(self, _features: Features) -> Result<SharedArguments<Verified>> {
Ok(SharedArguments {
schema: self.schema,
temporary_storage: self.temporary_storage,
_phantom: PhantomData,
})
}
}
impl SharedArguments<Verified> {
pub fn schema(&self) -> &Table {
&self.schema
}
pub fn temporary_storage(&self) -> &TemporaryStorage {
&self.temporary_storage
}
}
#[derive(Debug, EnumSetType)]
pub enum SourceArgumentsFeatures {
DriverArgs,
WhereClause,
}
impl fmt::Display for DisplayEnumSet<SourceArgumentsFeatures> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut sep = Separator::new(" ");
if self.0.contains(SourceArgumentsFeatures::DriverArgs) {
write!(f, "{}--from-arg=$NAME=$VALUE", sep.display())?;
}
if self.0.contains(SourceArgumentsFeatures::WhereClause) {
write!(f, "{}--where=$SQL_EXPR", sep.display())?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default)]
pub struct SourceArguments<ArgumentState> {
driver_args: DriverArguments,
where_clause: Option<String>,
_phantom: PhantomData<ArgumentState>,
}
impl SourceArguments<Unverified> {
pub fn new(driver_args: DriverArguments, where_clause: Option<String>) -> Self {
Self {
driver_args,
where_clause,
_phantom: PhantomData,
}
}
pub fn for_temporary() -> Self {
Self::new(DriverArguments::default(), None)
}
pub fn verify(self, features: Features) -> Result<SourceArguments<Verified>> {
if !features
.source_args
.contains(SourceArgumentsFeatures::DriverArgs)
&& !self.driver_args.is_empty()
{
return Err(format_err!("this data source does not support --from-args"));
}
if !features
.source_args
.contains(SourceArgumentsFeatures::WhereClause)
&& self.where_clause.is_some()
{
return Err(format_err!("this data source does not support --where"));
}
Ok(SourceArguments {
driver_args: self.driver_args,
where_clause: self.where_clause,
_phantom: PhantomData,
})
}
}
impl SourceArguments<Verified> {
pub fn driver_args(&self) -> &DriverArguments {
&self.driver_args
}
pub fn where_clause(&self) -> Option<&str> {
self.where_clause.as_ref().map(|s| &s[..])
}
}
#[derive(Debug, EnumSetType)]
pub enum DestinationArgumentsFeatures {
DriverArgs,
}
impl fmt::Display for DisplayEnumSet<DestinationArgumentsFeatures> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut sep = Separator::new(" ");
if self.0.contains(DestinationArgumentsFeatures::DriverArgs) {
write!(f, "{}--to-arg=$NAME=$VALUE", sep.display())?;
}
Ok(())
}
}
#[derive(Clone, Debug, Default)]
pub struct DestinationArguments<ArgumentState> {
driver_args: DriverArguments,
if_exists: IfExists,
_phantom: PhantomData<ArgumentState>,
}
impl DestinationArguments<Unverified> {
pub fn new(driver_args: DriverArguments, if_exists: IfExists) -> Self {
DestinationArguments {
driver_args,
if_exists,
_phantom: PhantomData,
}
}
pub fn for_temporary() -> Self {
Self::new(DriverArguments::default(), IfExists::Overwrite)
}
pub fn verify(self, features: Features) -> Result<DestinationArguments<Verified>> {
if !features
.dest_args
.contains(DestinationArgumentsFeatures::DriverArgs)
&& !self.driver_args.is_empty()
{
return Err(format_err!(
"this data destination does not support --to-args"
));
}
self.if_exists.verify(features.dest_if_exists)?;
Ok(DestinationArguments {
driver_args: self.driver_args,
if_exists: self.if_exists,
_phantom: PhantomData,
})
}
}
impl DestinationArguments<Verified> {
pub fn driver_args(&self) -> &DriverArguments {
&self.driver_args
}
pub fn if_exists(&self) -> &IfExists {
&self.if_exists
}
}