use crate::backends::drivers::postgresql::schema::PostgreSQLSchemaEditor;
use crate::backends::schema::{BaseDatabaseSchemaEditor, SchemaEditorResult};
fn quote_ident(ident: &str) -> String {
format!("\"{}\"", ident.replace("\"", "\"\""))
}
pub struct CockroachDBSchemaEditor {
pub pg_editor: PostgreSQLSchemaEditor,
}
impl CockroachDBSchemaEditor {
pub fn new(pg_editor: PostgreSQLSchemaEditor) -> Self {
Self { pg_editor }
}
pub fn create_table_with_locality_sql(
&self,
table: &str,
columns: &[(&str, &str)],
locality: &str,
) -> String {
let quoted_table = quote_ident(table);
let column_defs: Vec<String> = columns
.iter()
.map(|(name, def)| format!("{} {}", quote_ident(name), def))
.collect();
format!(
"CREATE TABLE {} ({}) LOCALITY {}",
quoted_table,
column_defs.join(", "),
locality
)
}
pub fn alter_table_locality_sql(&self, table: &str, locality: &str) -> String {
format!(
"ALTER TABLE {} SET LOCALITY {}",
quote_ident(table),
locality
)
}
pub fn create_partitioned_table_sql(
&self,
table: &str,
columns: &[(&str, &str)],
partition_column: &str,
partitions: &[(&str, &str)],
) -> String {
let quoted_table = quote_ident(table);
let column_defs: Vec<String> = columns
.iter()
.map(|(name, def)| format!("{} {}", quote_ident(name), def))
.collect();
let partition_defs: Vec<String> = partitions
.iter()
.map(|(name, values)| format!("PARTITION {} VALUES IN ({})", quote_ident(name), values))
.collect();
format!(
"CREATE TABLE {} ({}) PARTITION BY LIST ({}) ({})",
quoted_table,
column_defs.join(", "),
quote_ident(partition_column),
partition_defs.join(", ")
)
}
pub fn create_index_with_storing_sql(
&self,
name: &str,
table: &str,
columns: &[&str],
storing: &[&str],
unique: bool,
condition: Option<&str>,
) -> String {
let unique_keyword = if unique { "UNIQUE " } else { "" };
let quoted_columns: Vec<String> = columns.iter().map(|c| quote_ident(c)).collect();
let mut sql = format!(
"CREATE {}INDEX {} ON {} ({})",
unique_keyword,
quote_ident(name),
quote_ident(table),
quoted_columns.join(", ")
);
if !storing.is_empty() {
let storing_cols: Vec<String> = storing.iter().map(|c| quote_ident(c)).collect();
sql.push_str(&format!(" STORING ({})", storing_cols.join(", ")));
}
if let Some(cond) = condition {
sql.push_str(&format!(" WHERE {}", cond));
}
sql
}
pub fn as_of_system_time_sql(&self, query: &str, timestamp: &str) -> String {
format!("{} AS OF SYSTEM TIME {}", query, timestamp)
}
pub fn show_regions_sql(&self) -> String {
"SHOW REGIONS".to_string()
}
pub fn show_survival_goal_sql(&self) -> String {
"SHOW SURVIVAL GOAL".to_string()
}
pub fn set_primary_region_sql(&self, database: &str, region: &str) -> String {
format!(
"ALTER DATABASE {} SET PRIMARY REGION {}",
quote_ident(database),
quote_ident(region)
)
}
}
#[async_trait::async_trait]
impl BaseDatabaseSchemaEditor for CockroachDBSchemaEditor {
fn database_type(&self) -> crate::backends::types::DatabaseType {
crate::backends::types::DatabaseType::Postgres
}
async fn execute(&mut self, sql: &str) -> SchemaEditorResult<()> {
self.pg_editor.execute(sql).await
}
}