You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
6.1 KiB
164 lines
6.1 KiB
//! 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
|
|
}
|
|
}
|
|
}
|
|
|