use sea_orm_migration::prelude::*;
use sea_orm_migration::sea_orm::{ConnectionTrait, Statement};
use toolkit_db::secure::pgq::PropertyGraph as _;
use crate::infra::storage::graph::KnowledgeGraph;
pub const PGQ_MIN_SERVER_VERSION_NUM: i32 = 190_000;
#[derive(DeriveMigrationName)]
pub struct Migration;
async fn server_version_num(manager: &SchemaManager<'_>) -> Result<i32, DbErr> {
let backend = manager.get_database_backend();
let row = manager
.get_connection()
.query_one_raw(Statement::from_string(
backend,
"SELECT current_setting('server_version_num')::int AS v",
))
.await?
.ok_or_else(|| DbErr::Custom("server_version_num returned no row".into()))?;
row.try_get::<i32>("", "v")
}
fn declaration_error(error: &toolkit_db::secure::ScopeError) -> DbErr {
DbErr::Custom(format!(
"property-graph declaration failed to build: {error}"
))
}
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let version = server_version_num(manager).await?;
if version < PGQ_MIN_SERVER_VERSION_NUM {
tracing::warn!(
server_version_num = version,
required = PGQ_MIN_SERVER_VERSION_NUM,
"server does not support SQL/PGQ; skipping property-graph DDL \
(traversal will use the fallback backend)"
);
return Ok(());
}
let declaration =
KnowledgeGraph::declaration().map_err(|error| declaration_error(&error))?;
let drop_ddl = declaration
.drop_statement()
.map_err(|error| declaration_error(&error))?;
let create_ddl = declaration
.create_statement()
.map_err(|error| declaration_error(&error))?;
let connection = manager.get_connection();
connection.execute_unprepared(&drop_ddl).await?;
connection.execute_unprepared(&create_ddl).await?;
Ok(())
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
let version = server_version_num(manager).await?;
if version < PGQ_MIN_SERVER_VERSION_NUM {
return Ok(());
}
let declaration =
KnowledgeGraph::declaration().map_err(|error| declaration_error(&error))?;
let drop_ddl = declaration
.drop_statement()
.map_err(|error| declaration_error(&error))?;
manager
.get_connection()
.execute_unprepared(&drop_ddl)
.await?;
Ok(())
}
}