use crate::i18n::Translator;
use crate::sql::{Auto, ExecError, Pool};
use crate::Model;
#[derive(Model, Debug, Clone, serde::Serialize)]
#[rustango(table = "rustango_translations", managed = false)]
pub struct Translation {
#[rustango(primary_key)]
pub id: Auto<i64>,
#[rustango(max_length = 16)]
pub locale: String,
#[rustango(max_length = 200)]
pub key: String,
pub value: String,
#[rustango(max_length = 200, default = "")]
pub updated_by: String,
}
const DDL_PG: &str = r#"
CREATE TABLE IF NOT EXISTS "rustango_translations" (
"id" BIGSERIAL PRIMARY KEY,
"locale" VARCHAR(16) NOT NULL,
"key" VARCHAR(200) NOT NULL,
"value" TEXT NOT NULL,
"updated_by" VARCHAR(200) NOT NULL DEFAULT '',
"created_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
"updated_at" TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT "rustango_translations_locale_key_uq" UNIQUE ("locale", "key")
);
"#;
const DDL_SQLITE: &str = r#"
CREATE TABLE IF NOT EXISTS "rustango_translations" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"locale" TEXT NOT NULL,
"key" TEXT NOT NULL,
"value" TEXT NOT NULL,
"updated_by" TEXT NOT NULL DEFAULT '',
"created_at" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "rustango_translations_locale_key_uq" UNIQUE ("locale", "key")
);
"#;
const DDL_MYSQL: &str = r"
CREATE TABLE IF NOT EXISTS `rustango_translations` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`locale` VARCHAR(16) NOT NULL,
`key` VARCHAR(200) NOT NULL,
`value` TEXT NOT NULL,
`updated_by` VARCHAR(200) NOT NULL DEFAULT '',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT `rustango_translations_locale_key_uq` UNIQUE (`locale`, `key`)
);
";
pub async fn ensure_table_pool(pool: &Pool) -> Result<(), sqlx::Error> {
let ddl = match pool.dialect().name() {
"mysql" => DDL_MYSQL,
"sqlite" => DDL_SQLITE,
_ => DDL_PG,
};
crate::sql::run_ddl_idempotent(pool, ddl).await
}
pub async fn all_pool(pool: &Pool) -> Result<Vec<Translation>, ExecError> {
use crate::sql::FetcherPool as _;
Translation::objects().fetch_pool(pool).await
}
pub async fn upsert_pool(
pool: &Pool,
locale: &str,
key: &str,
value: &str,
updated_by: &str,
) -> Result<(), ExecError> {
let row = Translation {
id: Auto::Unset,
locale: locale.to_owned(),
key: key.to_owned(),
value: value.to_owned(),
updated_by: updated_by.to_owned(),
};
Translation::bulk_upsert_pool(&[row], &["locale", "key"], &["value", "updated_by"], pool).await
}
pub async fn seed_from_translator_pool(
pool: &Pool,
translator: &Translator,
) -> Result<usize, ExecError> {
let rows: Vec<Translation> = translator
.entries()
.into_iter()
.map(|(locale, key, value)| Translation {
id: Auto::Unset,
locale,
key,
value,
updated_by: String::new(),
})
.collect();
let n = rows.len();
if n > 0 {
Translation::bulk_insert_or_ignore_pool(&rows, pool).await?;
}
Ok(n)
}
pub async fn delete_key_pool(pool: &Pool, key: &str) -> Result<u64, ExecError> {
use crate::core::Model as _; use crate::core::{DeleteQuery, Filter, Op, SqlValue, WhereExpr};
crate::sql::delete_pool(
pool,
&DeleteQuery {
model: Translation::SCHEMA,
where_clause: WhereExpr::and_predicates(vec![Filter {
column: "key",
op: Op::Eq,
value: SqlValue::from(key),
}]),
},
)
.await
}
pub async fn refresh_overrides_pool(
translator: &Translator,
pool: &Pool,
) -> Result<usize, ExecError> {
let rows = all_pool(pool).await?;
let n = rows.len();
translator.load_overrides(rows.into_iter().map(|t| (t.locale, t.key, t.value)));
Ok(n)
}