use crate::{prepare::*, types::*, QueryBuilder, QuotedBuilder};
#[derive(Debug)]
pub struct Type;
#[derive(Clone, Debug)]
pub enum TypeRef {
Type(DynIden),
SchemaType(DynIden, DynIden),
DatabaseSchemaType(DynIden, DynIden, DynIden),
}
pub trait IntoTypeRef {
fn into_type_ref(self) -> TypeRef;
}
impl IntoTypeRef for TypeRef {
fn into_type_ref(self) -> TypeRef {
self
}
}
impl<I> IntoTypeRef for I
where
I: IntoIden,
{
fn into_type_ref(self) -> TypeRef {
TypeRef::Type(self.into_iden())
}
}
impl<A, B> IntoTypeRef for (A, B)
where
A: IntoIden,
B: IntoIden,
{
fn into_type_ref(self) -> TypeRef {
TypeRef::SchemaType(self.0.into_iden(), self.1.into_iden())
}
}
impl<A, B, C> IntoTypeRef for (A, B, C)
where
A: IntoIden,
B: IntoIden,
C: IntoIden,
{
fn into_type_ref(self) -> TypeRef {
TypeRef::DatabaseSchemaType(self.0.into_iden(), self.1.into_iden(), self.2.into_iden())
}
}
#[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)]
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)]
pub enum TypeDropOpt {
Cascade,
Restrict,
}
#[derive(Debug, Clone)]
pub enum TypeAlterOpt {
Add(DynIden, Option<TypeAlterAddOpt>),
Rename(DynIden),
RenameValue(DynIden, DynIden),
}
#[derive(Debug, Clone)]
pub enum TypeAlterAddOpt {
Before(DynIden),
After(DynIden),
}
pub trait TypeBuilder: QuotedBuilder {
fn prepare_type_create_statement(&self, create: &TypeCreateStatement, sql: &mut dyn SqlWriter);
fn prepare_type_drop_statement(&self, drop: &TypeDropStatement, sql: &mut dyn SqlWriter);
fn prepare_type_alter_statement(&self, alter: &TypeAlterStatement, sql: &mut dyn SqlWriter);
fn prepare_type_ref(&self, type_ref: &TypeRef, sql: &mut dyn SqlWriter) {
match type_ref {
TypeRef::Type(name) => {
name.prepare(sql.as_writer(), self.quote());
}
TypeRef::SchemaType(schema, name) => {
schema.prepare(sql.as_writer(), self.quote());
write!(sql, ".").unwrap();
name.prepare(sql.as_writer(), self.quote());
}
TypeRef::DatabaseSchemaType(database, schema, name) => {
database.prepare(sql.as_writer(), self.quote());
write!(sql, ".").unwrap();
schema.prepare(sql.as_writer(), self.quote());
write!(sql, ".").unwrap();
name.prepare(sql.as_writer(), self.quote());
}
}
}
}
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.into_iden(), None))
}
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 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(iden, _) => {
Self::Add(iden, Some(TypeAlterAddOpt::Before(value.into_iden())))
}
_ => self,
}
}
pub fn after<T>(self, value: T) -> Self
where
T: IntoIden,
{
match self {
TypeAlterOpt::Add(iden, _) => {
Self::Add(iden, Some(TypeAlterAddOpt::After(value.into_iden())))
}
_ => 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 dyn SqlWriter,
) -> String {
self.build_collect_ref(&type_builder, sql)
}
pub fn build_collect_ref<T: TypeBuilder>(
&self,
type_builder: &T,
sql: &mut dyn 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);