#![allow(dead_code)]
use orbit_orm::{Database, Driver};
pub fn url() -> Option<String> {
std::env::var("ORBIT_DATABASE_URL").ok()
}
pub fn on_mysql(driver: Driver) -> bool {
#[cfg(feature = "mysql")]
{
driver == Driver::MySql
}
#[cfg(not(feature = "mysql"))]
{
let _ = driver;
false
}
}
pub fn on_postgres(driver: Driver) -> bool {
#[cfg(feature = "postgres")]
{
driver == Driver::Postgres
}
#[cfg(not(feature = "postgres"))]
{
let _ = driver;
false
}
}
pub fn on_sqlite(driver: Driver) -> bool {
#[cfg(feature = "sqlite")]
{
driver == Driver::Sqlite
}
#[cfg(not(feature = "sqlite"))]
{
let _ = driver;
false
}
}
pub fn text_type(driver: Driver) -> &'static str {
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => "CHAR",
#[cfg(any(feature = "postgres", feature = "sqlite"))]
_ => "TEXT",
}
}
pub fn bigint_type(driver: Driver) -> &'static str {
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => "SIGNED",
#[cfg(feature = "postgres")]
Driver::Postgres => "BIGINT",
#[cfg(feature = "sqlite")]
Driver::Sqlite => "INTEGER",
}
}
fn unique_keys(input: &str) -> String {
let mut out = String::new();
let mut rest = input;
while let Some(at) = rest.find("UNIQUE KEY `") {
out.push_str(&rest[..at]);
let after = &rest[at + "UNIQUE KEY `".len()..];
let end = after
.find('`')
.expect("a closing backtick after UNIQUE KEY");
let name = &after[..end];
out.push_str(&format!("CONSTRAINT \"{name}\" UNIQUE"));
rest = &after[end + 1..];
}
out.push_str(rest);
out
}
pub fn sql(driver: Driver, mysql: &str) -> String {
let unique = unique_keys(mysql);
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => {
let _ = &unique;
mysql.to_owned()
}
#[cfg(feature = "postgres")]
Driver::Postgres => unique
.replace('`', "\"")
.replace(
"BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY",
"BIGSERIAL PRIMARY KEY",
)
.replace("BIGINT AUTO_INCREMENT PRIMARY KEY", "BIGSERIAL PRIMARY KEY")
.replace("DATETIME(6)", "TIMESTAMP(6)")
.replace("TINYINT(1)", "BOOLEAN")
.replace("MEDIUMBLOB", "BYTEA")
.replace(" ENGINE=InnoDB", ""),
#[cfg(feature = "sqlite")]
Driver::Sqlite => unique
.replace('`', "\"")
.replace(
"BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY",
"INTEGER PRIMARY KEY AUTOINCREMENT",
)
.replace(
"BIGINT AUTO_INCREMENT PRIMARY KEY",
"INTEGER PRIMARY KEY AUTOINCREMENT",
)
.replace("DATETIME(6)", "TEXT")
.replace("TINYINT(1)", "INTEGER")
.replace("MEDIUMBLOB", "BLOB")
.replace(" ENGINE=InnoDB", ""),
}
}
pub fn statements(script: &str) -> Vec<String> {
let mut out = Vec::new();
let mut current = String::new();
let mut quote: Option<char> = None;
for c in script.chars() {
match quote {
Some(q) => {
if c == q {
quote = None;
}
current.push(c);
}
None => match c {
'\'' | '"' => {
quote = Some(c);
current.push(c);
}
';' => {
let s = current.trim().to_owned();
if !s.is_empty() {
out.push(s);
}
current.clear();
}
_ => current.push(c),
},
}
}
let s = current.trim().to_owned();
if !s.is_empty() {
out.push(s);
}
out
}
pub async fn exec(db: &Database, mysql: &str) {
for statement in statements(mysql) {
let statement = sql(db.driver(), &statement);
orbit_orm::raw::execute(db, &statement, &[])
.await
.unwrap_or_else(|e| panic!("`{statement}` failed: {e}"));
}
}
pub async fn drop_tables(db: &Database, tables: &[&str]) {
for table in tables {
exec(db, &format!("DROP TABLE IF EXISTS `{table}`")).await;
}
}
pub fn columns_sql(driver: Driver) -> String {
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => "SELECT CAST(column_name AS CHAR) FROM information_schema.columns \
WHERE table_schema = DATABASE() AND table_name = ? ORDER BY ordinal_position"
.to_owned(),
#[cfg(feature = "postgres")]
Driver::Postgres => "SELECT CAST(column_name AS TEXT) FROM information_schema.columns \
WHERE table_schema = current_schema() AND table_name = ? ORDER BY ordinal_position"
.to_owned(),
#[cfg(feature = "sqlite")]
Driver::Sqlite => "SELECT name FROM pragma_table_info(?) ORDER BY cid".to_owned(),
}
}
pub fn table_count_sql(driver: Driver) -> &'static str {
match driver {
#[cfg(feature = "mysql")]
Driver::MySql => {
"SELECT COUNT(*) FROM information_schema.tables \
WHERE table_schema = DATABASE() AND table_name = ?"
}
#[cfg(feature = "postgres")]
Driver::Postgres => {
"SELECT COUNT(*) FROM information_schema.tables \
WHERE table_schema = current_schema() AND table_name = ?"
}
#[cfg(feature = "sqlite")]
Driver::Sqlite => "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = ?",
}
}