diff options
Diffstat (limited to 'development/libs/barrel/src/backend/pg.rs')
-rw-r--r-- | development/libs/barrel/src/backend/pg.rs | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/development/libs/barrel/src/backend/pg.rs b/development/libs/barrel/src/backend/pg.rs new file mode 100644 index 000000000000..1bea666efa1a --- /dev/null +++ b/development/libs/barrel/src/backend/pg.rs @@ -0,0 +1,164 @@ +//! Postgres implementation of a generator +//! +//! This module generates strings that are specific to Postgres +//! databases. They should be thoroughly tested via unit testing + +use super::SqlGenerator; +use crate::types::{BaseType, Type}; + +/// A simple macro that will generate a schema prefix if it exists +macro_rules! prefix { + ($schema:expr) => { + $schema + .map(|s| format!("\"{}\".", s)) + .unwrap_or_else(|| String::new()) + }; +} + +/// Postgres SQL generator backend +pub struct Pg; +impl SqlGenerator for Pg { + fn create_table(name: &str, schema: Option<&str>) -> String { + format!("CREATE TABLE {}\"{}\"", prefix!(schema), name) + } + + fn create_table_if_not_exists(name: &str, schema: Option<&str>) -> String { + format!("CREATE TABLE IF NOT EXISTS {}\"{}\"", prefix!(schema), name) + } + + fn drop_table(name: &str, schema: Option<&str>) -> String { + format!("DROP TABLE {}\"{}\"", prefix!(schema), name) + } + + fn drop_table_if_exists(name: &str, schema: Option<&str>) -> String { + format!("DROP TABLE IF EXISTS {}\"{}\"", prefix!(schema), name) + } + + fn rename_table(old: &str, new: &str, schema: Option<&str>) -> String { + let schema = prefix!(schema); + format!( + "ALTER TABLE {}\"{}\" RENAME TO {}\"{}\"", + schema, old, schema, new + ) + } + + fn alter_table(name: &str, schema: Option<&str>) -> String { + format!("ALTER TABLE {}\"{}\"", prefix!(schema), name) + } + + fn add_column(ex: bool, schema: Option<&str>, name: &str, tt: &Type) -> String { + let bt: BaseType = tt.get_inner(); + use self::BaseType::*; + + #[cfg_attr(rustfmt, rustfmt_skip)] /* This shouldn't be formatted. It's too long */ + format!( + "{}{}{}{}{}", + match bt { + Text => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Varchar(_) => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Primary => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Integer => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Float => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Double => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + UUID => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Json => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Boolean => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Date => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Binary => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Foreign(_, _, _) => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Custom(_) => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(bt, schema)), + Array(it) => format!("{}\"{}\" {}", Pg::prefix(ex), name, Pg::print_type(Array(Box::new(*it)), schema)), + Index(_) => unreachable!(), // Indices are handled via custom builder + }, + match tt.primary { + true => " PRIMARY KEY", + false => "", + }, + match (&tt.default).as_ref() { + Some(ref m) => format!(" DEFAULT '{}'", m), + _ => format!(""), + }, + match tt.nullable { + true => "", + false => " NOT NULL", + }, + match tt.unique { + true => " UNIQUE", + false => "", + }, + ) + } + + fn drop_column(name: &str) -> String { + format!("DROP COLUMN \"{}\"", name) + } + + fn rename_column(old: &str, new: &str) -> String { + format!("ALTER COLUMN \"{}\" RENAME TO \"{}\"", old, new) + } + + fn create_index(table: &str, schema: Option<&str>, name: &str, _type: &Type) -> String { + // FIXME: Implement PG specific index builder here + format!( + "CREATE {} INDEX \"{}\" ON {}\"{}\" ({})", + match _type.unique { + true => "UNIQUE", + false => "", + }, + name, + prefix!(schema), + table, + match _type.inner { + BaseType::Index(ref cols) => cols + .iter() + .map(|col| format!("\"{}\"", col)) + .collect::<Vec<_>>() + .join(", "), + _ => unreachable!(), + } + ) + } + + fn drop_index(name: &str) -> String { + format!("DROP INDEX \"{}\"", name) + } +} + +impl Pg { + fn prefix(ex: bool) -> String { + match ex { + true => format!("ADD COLUMN "), + false => format!(""), + } + } + + fn print_type(t: BaseType, schema: Option<&str>) -> String { + use self::BaseType::*; + match t { + Text => format!("TEXT"), + Varchar(l) => match l { + 0 => format!("VARCHAR"), // For "0" remove the limit + _ => format!("VARCHAR({})", l), + }, + /* "NOT NULL" is added here because normally primary keys are implicitly not-null */ + Primary => format!("SERIAL PRIMARY KEY NOT NULL"), + Integer => format!("INTEGER"), + Float => format!("FLOAT"), + Double => format!("DOUBLE PRECISION"), + UUID => format!("UUID"), + Boolean => format!("BOOLEAN"), + Date => format!("DATE"), + Json => format!("JSON"), + Binary => format!("BYTEA"), + Foreign(s, t, refs) => format!( + "INTEGER REFERENCES {}\"{}\"({})", + prefix!(s.or(schema.map(|s| s.into()))), + t, + refs.0.join(",") + ), + Custom(t) => format!("{}", t), + Array(meh) => format!("{}[]", Pg::print_type(*meh, schema)), + Index(_) => unreachable!(), // Indices are handled via custom builder + } + } +} |