fix: fix migrations

This commit is contained in:
2025-07-03 04:25:50 +08:00
parent 1d0aa8d7f1
commit b5b3c77ba3
14 changed files with 343 additions and 99 deletions

View File

@@ -17,8 +17,8 @@ fn skip_columns_for_entity_input(context: &mut BuilderContext) {
for column in cron::Column::iter() {
if matches!(
column,
cron::Column::SubscriberTask
| cron::Column::SystemTask
cron::Column::SubscriberTaskCron
| cron::Column::SystemTaskCron
| cron::Column::CronExpr
| cron::Column::Enabled
| cron::Column::TimeoutMs
@@ -45,8 +45,11 @@ fn skip_columns_for_entity_input(context: &mut BuilderContext) {
pub fn register_cron_to_schema_context(context: &mut BuilderContext) {
restrict_subscriber_for_entity::<cron::Entity>(context, &cron::Column::SubscriberId);
restrict_subscriber_tasks_for_entity::<cron::Entity>(context, &cron::Column::SubscriberTask);
restrict_system_tasks_for_entity::<cron::Entity>(context, &cron::Column::SystemTask);
restrict_subscriber_tasks_for_entity::<cron::Entity>(
context,
&cron::Column::SubscriberTaskCron,
);
restrict_system_tasks_for_entity::<cron::Entity>(context, &cron::Column::SystemTaskCron);
skip_columns_for_entity_input(context);
}

View File

@@ -7,7 +7,8 @@ use sea_orm::{
QuerySelect, QueryTrait, prelude::Expr, sea_query::Query,
};
use seaography::{
Builder as SeaographyBuilder, BuilderContext, SeaographyError, prepare_active_model,
Builder as SeaographyBuilder, BuilderContext, GuardAction, SeaographyError,
prepare_active_model,
};
use ts_rs::TS;
@@ -59,6 +60,14 @@ where
restrict_jsonb_filter_input_for_entity::<T>(context, column);
convert_jsonb_output_for_entity::<T>(context, column, Some(Case::Camel));
let entity_column_name = get_entity_and_column_name::<T>(context, column);
context.guards.field_guards.insert(
entity_column_name.clone(),
Box::new(|_resolver_ctx| {
GuardAction::Block(Some(
"SystemTask can not be created by subscribers now".to_string(),
))
}),
);
context.types.input_type_overwrites.insert(
entity_column_name.clone(),
@@ -112,6 +121,7 @@ pub fn register_system_tasks_to_schema_builder(
.description(system_tasks::SystemTask::decl()),
);
builder.register_enumeration::<system_tasks::SystemTaskType>();
builder.register_enumeration::<system_tasks::SystemTaskStatus>();
builder = register_entity_default_readonly!(builder, system_tasks);
let builder_context = builder.context;

View File

@@ -189,8 +189,8 @@ pub enum Cron {
MaxAttempts,
Priority,
Status,
SubscriberTask,
SystemTask,
SubscriberTaskCron,
SystemTaskCron,
}
#[derive(sea_query::Iden)]
@@ -317,6 +317,26 @@ pub trait CustomSchemaManagerExt {
Ok(())
}
async fn create_foreign_key_if_not_exists<
T: IntoIden + 'static + Send,
S: IntoIden + 'static + Send,
>(
&self,
from_tbl: T,
foreign_key: S,
stmt: ForeignKeyCreateStatement,
) -> Result<(), DbErr>;
async fn drop_foreign_key_if_exists<
T: IntoIden + 'static + Send,
S: IntoIden + 'static + Send,
>(
&self,
from_tbl: T,
foreign_key: S,
stmt: ForeignKeyDropStatement,
) -> Result<(), DbErr>;
async fn create_postgres_enum_for_active_enum<
E: IntoTypeRef + IntoIden + Send + Clone,
I: IntoIterator<Item = String> + Send,
@@ -403,6 +423,71 @@ impl CustomSchemaManagerExt for SchemaManager<'_> {
Ok(())
}
async fn create_foreign_key_if_not_exists<
T: IntoIden + 'static + Send,
S: IntoIden + 'static + Send,
>(
&self,
from_tbl: T,
foreign_key: S,
stmt: ForeignKeyCreateStatement,
) -> Result<(), DbErr> {
let from_tbl = from_tbl.into_iden().to_string();
let foreign_key = foreign_key.into_iden().to_string();
let db = self
.get_connection()
.query_one(Statement::from_string(
self.get_database_backend(),
format!(
"
SELECT CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_NAME = '{from_tbl}' AND CONSTRAINT_NAME = '{foreign_key}'
"
),
))
.await?;
if db.is_some() {
return Ok(());
}
self.create_foreign_key(stmt).await?;
Ok(())
}
async fn drop_foreign_key_if_exists<
T: IntoIden + 'static + Send,
S: IntoIden + 'static + Send,
>(
&self,
from_tbl: T,
foreign_key: S,
stmt: ForeignKeyDropStatement,
) -> Result<(), DbErr> {
let from_tbl = from_tbl.into_iden().to_string();
let foreign_key = foreign_key.into_iden().to_string();
let db = self
.get_connection()
.query_one(Statement::from_string(
self.get_database_backend(),
format!(
"
SELECT CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_NAME = '{from_tbl}' AND CONSTRAINT_NAME = '{foreign_key}'
"
),
))
.await?;
if db.is_some() {
self.drop_foreign_key(stmt).await?;
}
Ok(())
}
async fn create_postgres_enum_for_active_enum<
E: IntoTypeRef + IntoIden + Send + Clone,
I: IntoIterator<Item = String> + Send,

View File

@@ -90,6 +90,11 @@ impl MigrationTrait for Migration {
SimpleExpr::from(AuthType::Basic).as_enum(AuthTypeEnum),
seed_subscriber_id.into(),
])
.on_conflict(
OnConflict::columns([Auth::Pid, Auth::AuthType])
.do_nothing()
.to_owned(),
)
.to_owned(),
)
.await?;

View File

@@ -72,16 +72,22 @@ impl MigrationTrait for Migration {
Table::alter()
.table(Subscriptions::Table)
.add_column_if_not_exists(integer_null(Subscriptions::CredentialId))
.add_foreign_key(
TableForeignKey::new()
.name("fk_subscriptions_credential_id")
.from_tbl(Subscriptions::Table)
.from_col(Subscriptions::CredentialId)
.to_tbl(Credential3rd::Table)
.to_col(Credential3rd::Id)
.on_update(ForeignKeyAction::Cascade)
.on_delete(ForeignKeyAction::SetNull),
)
.to_owned(),
)
.await?;
manager
.create_foreign_key_if_not_exists(
Subscriptions::Table,
"fk_subscriptions_credential_id",
ForeignKeyCreateStatement::new()
.name("fk_subscriptions_credential_id")
.from_tbl(Subscriptions::Table)
.from_col(Subscriptions::CredentialId)
.to_tbl(Credential3rd::Table)
.to_col(Credential3rd::Id)
.on_update(ForeignKeyAction::Cascade)
.on_delete(ForeignKeyAction::SetNull)
.to_owned(),
)
.await?;

View File

@@ -23,7 +23,7 @@ impl MigrationTrait for Migration {
.table((ApalisSchema::Schema, ApalisJobs::Table))
.add_column_if_not_exists(integer_null(ApalisJobs::SubscriberId))
.add_column_if_not_exists(integer_null(ApalisJobs::SubscriptionId))
.add_column_if_not_exists(string_null(ApalisJobs::TaskType))
.add_column_if_not_exists(text_null(ApalisJobs::TaskType))
.add_foreign_key(
TableForeignKey::new()
.name("fk_apalis_jobs_subscriber_id")

View File

@@ -56,8 +56,8 @@ impl MigrationTrait for Migration {
CronStatusEnum,
CronStatus::iden_values(),
))
.col(json_binary_null(Cron::SubscriberTask))
.col(json_binary_null(Cron::SystemTask))
.col(json_binary_null(Cron::SubscriberTaskCron))
.col(json_binary_null(Cron::SystemTaskCron))
.foreign_key(
ForeignKey::create()
.name("fk_cron_subscriber_id")
@@ -102,25 +102,25 @@ impl MigrationTrait for Migration {
new_subscriber_task_subscription_id integer;
new_system_task_subscriber_id integer;
BEGIN
new_subscriber_task_subscriber_id = (NEW.{subscriber_task} ->> 'subscriber_id')::integer;
new_subscriber_task_subscription_id = (NEW.{subscriber_task} ->> 'subscription_id')::integer;
new_system_task_subscriber_id = (NEW.{system_task} ->> 'subscriber_id')::integer;
IF new_subscriber_task_subscriber_id != (OLD.{subscriber_task} ->> 'subscriber_id')::integer AND new_subscriber_task_subscriber_id != NEW.{subscriber_id} THEN
new_subscriber_task_subscriber_id = (NEW.{subscriber_task_cron} ->> 'subscriber_id')::integer;
new_subscriber_task_subscription_id = (NEW.{subscriber_task_cron} ->> 'subscription_id')::integer;
new_system_task_subscriber_id = (NEW.{system_task_cron} ->> 'subscriber_id')::integer;
IF new_subscriber_task_subscriber_id != (OLD.{subscriber_task_cron} ->> 'subscriber_id')::integer AND new_subscriber_task_subscriber_id != NEW.{subscriber_id} THEN
NEW.{subscriber_id} = new_subscriber_task_subscriber_id;
END IF;
IF new_subscriber_task_subscription_id != (OLD.{subscriber_task} ->> 'subscription_id')::integer AND new_subscriber_task_subscription_id != NEW.{subscription_id} THEN
IF new_subscriber_task_subscription_id != (OLD.{subscriber_task_cron} ->> 'subscription_id')::integer AND new_subscriber_task_subscription_id != NEW.{subscription_id} THEN
NEW.{subscription_id} = new_subscriber_task_subscription_id;
END IF;
IF new_system_task_subscriber_id != (OLD.{system_task} ->> 'subscriber_id')::integer AND new_system_task_subscriber_id != NEW.{subscriber_id} THEN
IF new_system_task_subscriber_id != (OLD.{system_task_cron} ->> 'subscriber_id')::integer AND new_system_task_subscriber_id != NEW.{subscriber_id} THEN
NEW.{subscriber_id} = new_system_task_subscriber_id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;"#,
subscriber_task = &Cron::SubscriberTask.to_string(),
subscriber_task_cron = &Cron::SubscriberTaskCron.to_string(),
subscriber_id = &Cron::SubscriberId.to_string(),
subscription_id = &Cron::SubscriptionId.to_string(),
system_task = &Cron::SystemTask.to_string(),
system_task_cron = &Cron::SystemTaskCron.to_string(),
)).await?;
db.execute_unprepared(&format!(

View File

@@ -1,5 +1,4 @@
mod core;
mod registry;
pub use core::{
CHECK_AND_TRIGGER_DUE_CRONS_FUNCTION_NAME, CRON_DUE_EVENT,
@@ -71,8 +70,8 @@ pub struct Model {
pub status: CronStatus,
#[sea_orm(default_expr = "true")]
pub enabled: bool,
pub subscriber_task: Option<subscriber_tasks::SubscriberTask>,
pub system_task: Option<system_tasks::SystemTask>,
pub subscriber_task_cron: Option<subscriber_tasks::SubscriberTask>,
pub system_task_cron: Option<system_tasks::SystemTask>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
@@ -152,19 +151,19 @@ impl ActiveModelBehavior for ActiveModel {
self.next_run = Set(Some(next_run));
}
if let ActiveValue::Set(Some(subscriber_id)) = self.subscriber_id
&& let ActiveValue::Set(Some(ref subscriber_task)) = self.subscriber_task
&& let ActiveValue::Set(Some(ref subscriber_task)) = self.subscriber_task_cron
&& subscriber_task.get_subscriber_id() != subscriber_id
{
return Err(DbErr::Custom(
"Cron subscriber_id does not match subscriber_task.subscriber_id".to_string(),
"Cron subscriber_id does not match subscriber_task_cron.subscriber_id".to_string(),
));
}
if let ActiveValue::Set(Some(subscriber_id)) = self.subscriber_id
&& let ActiveValue::Set(Some(ref system_task)) = self.system_task
&& let ActiveValue::Set(Some(ref system_task)) = self.system_task_cron
&& system_task.get_subscriber_id() != Some(subscriber_id)
{
return Err(DbErr::Custom(
"Cron subscriber_id does not match system_task.subscriber_id".to_string(),
"Cron subscriber_id does not match system_task_cron.subscriber_id".to_string(),
));
}
@@ -248,14 +247,14 @@ impl Model {
}
async fn exec_cron(&self, ctx: &dyn AppContextTrait) -> RecorderResult<()> {
if let Some(subscriber_task) = self.subscriber_task.as_ref() {
if let Some(subscriber_task) = self.subscriber_task_cron.as_ref() {
let task_service = ctx.task();
let mut new_subscriber_task = subscriber_task.clone();
new_subscriber_task.set_cron_id(Some(self.id));
task_service
.add_subscriber_task(new_subscriber_task)
.await?;
} else if let Some(system_task) = self.system_task.as_ref() {
} else if let Some(system_task) = self.system_task_cron.as_ref() {
let task_service = ctx.task();
let mut new_system_task = system_task.clone();
new_system_task.set_cron_id(Some(self.id));

View File

@@ -1 +0,0 @@

View File

@@ -302,7 +302,10 @@ mod tests {
use tracing::Level;
use super::*;
use crate::test_utils::{app::TestingPreset, tracing::try_init_testing_tracing};
use crate::test_utils::{
// app::TestingPreset,
tracing::try_init_testing_tracing,
};
#[fixture]
fn before_each() {
@@ -312,13 +315,6 @@ mod tests {
#[rstest]
#[tokio::test]
async fn test_cron_due_listening(before_each: ()) -> RecorderResult<()> {
let mut preset = TestingPreset::default().await?;
let app_ctx = preset.app_ctx.clone();
let db = app_ctx.db();
todo!();
Ok(())
todo!()
}
}