use crate::{QueryBuilder, QuotedBuilder, prepare::*, types::*};
#[derive(Debug)]
pub struct Type;
pub use crate::TypeRef;
pub use crate::IntoTypeRef;
#[derive(Debug, Clone, Default)]
pub struct TypeCreateStatement {
pub(crate) name: Option<TypeRef>,
pub(crate) as_type: Option<TypeAs>,
pub(crate) values: Vec<DynIden>,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeAs {
Enum,
}
#[derive(Debug, Clone, Default)]
pub struct TypeDropStatement {
pub(crate) names: Vec<TypeRef>,
pub(crate) option: Option<TypeDropOpt>,
pub(crate) if_exists: bool,
}
#[derive(Debug, Clone, Default)]
pub struct TypeAlterStatement {
pub(crate) name: Option<TypeRef>,
pub(crate) option: Option<TypeAlterOpt>,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeDropOpt {
Cascade,
Restrict,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeAlterOpt {
Add {
value: DynIden,
placement: Option<TypeAlterAddOpt>,
if_not_exists: bool,
},
Rename(DynIden),
RenameValue(DynIden, DynIden),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeAlterAddOpt {
Before(DynIden),
After(DynIden),
}
pub trait TypeBuilder: QuotedBuilder {
fn prepare_type_create_statement(&self, create: &TypeCreateStatement, sql: &mut impl SqlWriter);
fn prepare_type_drop_statement(&self, drop: &TypeDropStatement, sql: &mut impl SqlWriter);
fn prepare_type_alter_statement(&self, alter: &TypeAlterStatement, sql: &mut impl SqlWriter);
}
impl Type {
pub fn create() -> TypeCreateStatement {
TypeCreateStatement::new()
}
pub fn drop() -> TypeDropStatement {
TypeDropStatement::new()
}
pub fn alter() -> TypeAlterStatement {
TypeAlterStatement::new()
}
}
impl TypeCreateStatement {
pub fn new() -> Self {
Self::default()
}
pub fn as_enum<T>(&mut self, name: T) -> &mut Self
where
T: IntoTypeRef,
{
self.name = Some(name.into_type_ref());
self.as_type = Some(TypeAs::Enum);
self
}
pub fn values<T, I>(&mut self, values: I) -> &mut Self
where
T: IntoIden,
I: IntoIterator<Item = T>,
{
for v in values.into_iter() {
self.values.push(v.into_iden());
}
self
}
}
impl TypeDropStatement {
pub fn new() -> Self {
Self::default()
}
pub fn name<T>(&mut self, name: T) -> &mut Self
where
T: IntoTypeRef,
{
self.names.push(name.into_type_ref());
self
}
pub fn names<T, I>(&mut self, names: I) -> &mut Self
where
T: IntoTypeRef,
I: IntoIterator<Item = T>,
{
for n in names.into_iter() {
self.names.push(n.into_type_ref());
}
self
}
pub fn if_exists(&mut self) -> &mut Self {
self.if_exists = true;
self
}
pub fn cascade(&mut self) -> &mut Self {
self.option = Some(TypeDropOpt::Cascade);
self
}
pub fn restrict(&mut self) -> &mut Self {
self.option = Some(TypeDropOpt::Restrict);
self
}
}
impl TypeAlterStatement {
pub fn new() -> Self {
Self::default()
}
pub fn name<T>(mut self, name: T) -> Self
where
T: IntoTypeRef,
{
self.name = Some(name.into_type_ref());
self
}
pub fn add_value<T>(self, value: T) -> Self
where
T: IntoIden,
{
self.alter_option(TypeAlterOpt::Add {
value: value.into_iden(),
placement: None,
if_not_exists: false,
})
}
pub fn before<T>(mut self, value: T) -> Self
where
T: IntoIden,
{
if let Some(option) = self.option {
self.option = Some(option.before(value));
}
self
}
pub fn after<T>(mut self, value: T) -> Self
where
T: IntoIden,
{
if let Some(option) = self.option {
self.option = Some(option.after(value));
}
self
}
pub fn if_not_exists(mut self) -> Self {
if let Some(option) = self.option {
self.option = Some(option.if_not_exists());
}
self
}
pub fn rename_to<T>(self, name: T) -> Self
where
T: IntoIden,
{
self.alter_option(TypeAlterOpt::Rename(name.into_iden()))
}
pub fn rename_value<T, V>(self, existing: T, new_name: V) -> Self
where
T: IntoIden,
V: IntoIden,
{
self.alter_option(TypeAlterOpt::RenameValue(
existing.into_iden(),
new_name.into_iden(),
))
}
fn alter_option(mut self, option: TypeAlterOpt) -> Self {
self.option = Some(option);
self
}
}
impl TypeAlterOpt {
pub fn before<T>(self, value: T) -> Self
where
T: IntoIden,
{
match self {
TypeAlterOpt::Add {
value: iden,
if_not_exists,
..
} => Self::Add {
value: iden,
if_not_exists,
placement: Some(TypeAlterAddOpt::Before(value.into_iden())),
},
_ => self,
}
}
pub fn after<T>(self, value: T) -> Self
where
T: IntoIden,
{
match self {
TypeAlterOpt::Add {
value: iden,
if_not_exists,
..
} => Self::Add {
value: iden,
if_not_exists,
placement: Some(TypeAlterAddOpt::After(value.into_iden())),
},
_ => self,
}
}
pub fn if_not_exists(self) -> Self {
match self {
TypeAlterOpt::Add {
value, placement, ..
} => Self::Add {
value,
placement,
if_not_exists: true,
},
_ => self,
}
}
}
macro_rules! impl_type_statement_builder {
( $struct_name: ident, $func_name: ident ) => {
impl $struct_name {
pub fn build_ref<T: TypeBuilder>(&self, type_builder: &T) -> String {
let mut sql = String::with_capacity(256);
self.build_collect_ref(type_builder, &mut sql)
}
pub fn build_collect<T: TypeBuilder>(
&self,
type_builder: T,
sql: &mut impl SqlWriter,
) -> String {
self.build_collect_ref(&type_builder, sql)
}
pub fn build_collect_ref<T: TypeBuilder>(
&self,
type_builder: &T,
sql: &mut impl SqlWriter,
) -> String {
type_builder.$func_name(self, sql);
sql.to_string()
}
pub fn to_string<T>(&self, type_builder: T) -> String
where
T: TypeBuilder + QueryBuilder,
{
self.build_ref(&type_builder)
}
}
};
}
impl_type_statement_builder!(TypeCreateStatement, prepare_type_create_statement);
impl_type_statement_builder!(TypeAlterStatement, prepare_type_alter_statement);
impl_type_statement_builder!(TypeDropStatement, prepare_type_drop_statement);