-
-
Notifications
You must be signed in to change notification settings - Fork 195
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'type_enum' into master
- Loading branch information
Showing
9 changed files
with
371 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use super::*; | ||
use crate::extension::postgres::types::*; | ||
|
||
impl TypeBuilder for PostgresQueryBuilder { | ||
fn prepare_type_create_statement(&self, create: &TypeCreateStatement, sql: &mut SqlWriter, collector: &mut dyn FnMut(Value)) { | ||
write!(sql, "CREATE TYPE ").unwrap(); | ||
|
||
if let Some(name) = &create.name { | ||
name.prepare(sql, '"'); | ||
} | ||
|
||
if let Some(as_type) = &create.as_type { | ||
write!(sql, " AS ").unwrap(); | ||
self.prepare_create_as_type(&as_type, sql); | ||
} | ||
|
||
if !create.values.is_empty() { | ||
write!(sql, " (").unwrap(); | ||
|
||
for (count, val) in create.values.iter().enumerate() { | ||
if count > 0 { | ||
write!(sql, ", ").unwrap(); | ||
} | ||
self.prepare_value(&val.to_string().into(), sql, collector); | ||
} | ||
|
||
write!(sql, ")").unwrap(); | ||
} | ||
} | ||
|
||
fn prepare_type_drop_statement(&self, drop: &TypeDropStatement, sql: &mut SqlWriter, _collector: &mut dyn FnMut(Value)) { | ||
write!(sql, "DROP TYPE ").unwrap(); | ||
|
||
if drop.if_exists { | ||
write!(sql, "IF EXISTS ").unwrap(); | ||
} | ||
|
||
for name in drop.names.iter() { | ||
name.prepare(sql, '"'); | ||
} | ||
|
||
if let Some(option) = &drop.option { | ||
write!(sql, " ").unwrap(); | ||
self.prepare_drop_type_opt(&option, sql); | ||
} | ||
} | ||
} | ||
|
||
impl PostgresQueryBuilder { | ||
fn prepare_create_as_type(&self, as_type: &TypeAs, sql: &mut SqlWriter) { | ||
write!(sql, "{}", match as_type { | ||
TypeAs::Enum => "ENUM", | ||
}).unwrap() | ||
} | ||
|
||
fn prepare_drop_type_opt(&self, opt: &TypeDropOpt, sql: &mut SqlWriter) { | ||
write!(sql, "{}", match opt { | ||
TypeDropOpt::Cascade => "CASCADE", | ||
TypeDropOpt::Restrict => "RESTRICT", | ||
}).unwrap() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// mod mysql; | ||
// mod sqlite; | ||
pub mod postgres; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub(crate) mod types; | ||
|
||
pub use types::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,236 @@ | ||
use std::rc::Rc; | ||
use crate::{backend::QueryBuilder, prepare::*, types::*, value::*}; | ||
|
||
/// Helper for constructing any type statement | ||
pub struct Type; | ||
|
||
#[derive(Clone, Default)] | ||
pub struct TypeCreateStatement { | ||
pub(crate) name: Option<Rc<dyn Iden>>, | ||
pub(crate) as_type: Option<TypeAs>, | ||
pub(crate) values: Vec<Rc<dyn Iden>>, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub enum TypeAs { | ||
// Composite, | ||
Enum, | ||
// Range, | ||
// Base, | ||
// Array, | ||
} | ||
|
||
#[derive(Clone, Default)] | ||
pub struct TypeDropStatement { | ||
pub(crate) names: Vec<Rc<dyn Iden>>, | ||
pub(crate) option: Option<TypeDropOpt>, | ||
pub(crate) if_exists: bool, | ||
} | ||
|
||
#[derive(Clone)] | ||
pub enum TypeDropOpt { | ||
Cascade, | ||
Restrict, | ||
} | ||
|
||
pub trait TypeBuilder { | ||
/// Translate [`TypeCreateStatement`] into database specific SQL statement. | ||
fn prepare_type_create_statement(&self, create: &TypeCreateStatement, sql: &mut SqlWriter, collector: &mut dyn FnMut(Value)); | ||
|
||
/// Translate [`TypeDropStatement`] into database specific SQL statement. | ||
fn prepare_type_drop_statement(&self, create: &TypeDropStatement, sql: &mut SqlWriter, collector: &mut dyn FnMut(Value)); | ||
} | ||
|
||
impl Type { | ||
/// Construct type [`TypeCreateStatement`] | ||
pub fn create() -> TypeCreateStatement { | ||
TypeCreateStatement::new() | ||
} | ||
|
||
/// Construct type [`TypeDropStatement`] | ||
pub fn drop() -> TypeDropStatement { | ||
TypeDropStatement::new() | ||
} | ||
} | ||
|
||
impl TypeCreateStatement { | ||
|
||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Create enum as custom type | ||
/// | ||
/// ``` | ||
/// use sea_query::{*, extension::postgres::Type}; | ||
/// | ||
/// enum FontFamily { | ||
/// Type, | ||
/// Serif, | ||
/// Sans, | ||
/// Monospace, | ||
/// } | ||
/// | ||
/// impl Iden for FontFamily { | ||
/// fn unquoted(&self, s: &mut dyn std::fmt::Write) { | ||
/// write!(s, "{}", match self { | ||
/// Self::Type => "font_family", | ||
/// Self::Serif => "serif", | ||
/// Self::Sans => "sans", | ||
/// Self::Monospace => "monospace", | ||
/// }).unwrap(); | ||
/// } | ||
/// } | ||
/// | ||
/// assert_eq!( | ||
/// Type::create() | ||
/// .as_enum(FontFamily::Type) | ||
/// .values(vec![FontFamily::Serif, FontFamily::Sans, FontFamily::Monospace]) | ||
/// .to_string(PostgresQueryBuilder), | ||
/// r#"CREATE TYPE "font_family" AS ENUM ('serif', 'sans', 'monospace')"# | ||
/// ); | ||
/// ``` | ||
pub fn as_enum<T: 'static>(&mut self, name: T) -> &mut Self | ||
where T: Iden { | ||
self.name = Some(Rc::new(name)); | ||
self.as_type = Some(TypeAs::Enum); | ||
self | ||
} | ||
|
||
pub fn values<T: 'static>(&mut self, values: Vec<T>) -> &mut Self | ||
where T: Iden { | ||
self.values_dyn(values.into_iter().map(|c| Rc::new(c) as Rc<dyn Iden>).collect()) | ||
} | ||
|
||
pub fn values_dyn(&mut self, mut values: Vec<Rc<dyn Iden>>) -> &mut Self { | ||
self.values.append(&mut values); | ||
self | ||
} | ||
|
||
// below are boiler plates | ||
|
||
pub fn build<T: TypeBuilder>(&self, type_builder: T) -> (String, Vec<Value>) { | ||
self.build_ref(&type_builder) | ||
} | ||
|
||
pub fn build_ref<T: TypeBuilder>(&self, type_builder: &T) -> (String, Vec<Value>) { | ||
let mut params = Vec::new(); | ||
let mut collector = |v| params.push(v); | ||
let sql = self.build_collect_ref(type_builder, &mut collector); | ||
(sql, params) | ||
} | ||
|
||
pub fn build_collect<T: TypeBuilder>(&self, type_builder: T, collector: &mut dyn FnMut(Value)) -> String { | ||
self.build_collect_ref(&type_builder, collector) | ||
} | ||
|
||
pub fn build_collect_ref<T: TypeBuilder>(&self, type_builder: &T, collector: &mut dyn FnMut(Value)) -> String { | ||
let mut sql = SqlWriter::new(); | ||
type_builder.prepare_type_create_statement(self, &mut sql, collector); | ||
sql.result() | ||
} | ||
|
||
/// Build corresponding SQL statement and return SQL string | ||
pub fn to_string<T>(&self, type_builder: T) -> String | ||
where T: TypeBuilder + QueryBuilder { | ||
let (sql, values) = self.build_ref(&type_builder); | ||
inject_parameters(&sql, values, &type_builder) | ||
} | ||
} | ||
|
||
impl TypeDropStatement { | ||
|
||
pub fn new() -> Self { | ||
Self::default() | ||
} | ||
|
||
/// Drop a type | ||
/// | ||
/// ``` | ||
/// use sea_query::{*, extension::postgres::Type}; | ||
/// | ||
/// struct FontFamily; | ||
/// | ||
/// impl Iden for FontFamily { | ||
/// fn unquoted(&self, s: &mut dyn std::fmt::Write) { | ||
/// write!(s, "{}", "font_family").unwrap(); | ||
/// } | ||
/// } | ||
/// | ||
/// assert_eq!( | ||
/// Type::drop() | ||
/// .if_exists() | ||
/// .name(FontFamily) | ||
/// .restrict() | ||
/// .to_string(PostgresQueryBuilder), | ||
/// r#"DROP TYPE IF EXISTS "font_family" RESTRICT"# | ||
/// ); | ||
/// ``` | ||
pub fn name<T: 'static>(&mut self, name: T) -> &mut Self | ||
where T: Iden { | ||
self.name_dyn(Rc::new(name)) | ||
} | ||
|
||
pub fn name_dyn(&mut self, name: Rc<dyn Iden>) -> &mut Self { | ||
self.names.push(name); | ||
self | ||
} | ||
|
||
pub fn names<T: 'static>(&mut self, names: Vec<T>) -> &mut Self | ||
where T: Iden { | ||
self.names_dyn(names.into_iter().map(|c| Rc::new(c) as Rc<dyn Iden>).collect()) | ||
} | ||
|
||
pub fn names_dyn(&mut self, mut names: Vec<Rc<dyn Iden>>) -> &mut Self { | ||
self.names.append(&mut names); | ||
self | ||
} | ||
|
||
/// Set `IF EXISTS` | ||
pub fn if_exists(&mut self) -> &mut Self { | ||
self.if_exists = true; | ||
self | ||
} | ||
|
||
/// Set `CASCADE` | ||
pub fn cascade(&mut self) -> &mut Self { | ||
self.option = Some(TypeDropOpt::Cascade); | ||
self | ||
} | ||
|
||
/// Set `RESTRICT` | ||
pub fn restrict(&mut self) -> &mut Self { | ||
self.option = Some(TypeDropOpt::Restrict); | ||
self | ||
} | ||
|
||
// below are boiler plates | ||
|
||
pub fn build<T: TypeBuilder>(&self, type_builder: T) -> (String, Vec<Value>) { | ||
self.build_ref(&type_builder) | ||
} | ||
|
||
pub fn build_ref<T: TypeBuilder>(&self, type_builder: &T) -> (String, Vec<Value>) { | ||
let mut params = Vec::new(); | ||
let mut collector = |v| params.push(v); | ||
let sql = self.build_collect_ref(type_builder, &mut collector); | ||
(sql, params) | ||
} | ||
|
||
pub fn build_collect<T: TypeBuilder>(&self, type_builder: T, collector: &mut dyn FnMut(Value)) -> String { | ||
self.build_collect_ref(&type_builder, collector) | ||
} | ||
|
||
pub fn build_collect_ref<T: TypeBuilder>(&self, type_builder: &T, collector: &mut dyn FnMut(Value)) -> String { | ||
let mut sql = SqlWriter::new(); | ||
type_builder.prepare_type_drop_statement(self, &mut sql, collector); | ||
sql.result() | ||
} | ||
|
||
/// Build corresponding SQL statement and return SQL string | ||
pub fn to_string<T>(&self, type_builder: T) -> String | ||
where T: TypeBuilder + QueryBuilder { | ||
let (sql, values) = self.build_ref(&type_builder); | ||
inject_parameters(&sql, values, &type_builder) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.