fix: fix migrations

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

12
Cargo.lock generated
View File

@ -356,9 +356,9 @@ dependencies = [
[[package]] [[package]]
name = "async-channel" name = "async-channel"
version = "2.3.1" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" checksum = "16c74e56284d2188cabb6ad99603d1ace887a5d7e7b695d01b728155ed9ed427"
dependencies = [ dependencies = [
"concurrent-queue", "concurrent-queue",
"event-listener-strategy", "event-listener-strategy",
@ -4169,9 +4169,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
version = "0.4.9" version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"cc", "cc",
@ -10426,9 +10426,9 @@ dependencies = [
[[package]] [[package]]
name = "zune-jpeg" name = "zune-jpeg"
version = "0.4.18" version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7384255a918371b5af158218d131530f694de9ad3815ebdd0453a940485cb0fa" checksum = "2c9e525af0a6a658e031e95f14b7f889976b74a11ba0eca5a5fc9ac8a1c43a6a"
dependencies = [ dependencies = [
"zune-core", "zune-core",
] ]

View File

@ -13,9 +13,6 @@ members = [
resolver = "2" resolver = "2"
[profile.dev] [profile.dev]
debug = 0
# https://github.com/rust-lang/rust/issues/141540
incremental = true # Then only change rust-analyzer incremental
# [simd not supported by cranelift](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171) # [simd not supported by cranelift](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171)
# codegen-backend = "cranelift" # codegen-backend = "cranelift"

View File

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

View File

@ -7,7 +7,8 @@ use sea_orm::{
QuerySelect, QueryTrait, prelude::Expr, sea_query::Query, QuerySelect, QueryTrait, prelude::Expr, sea_query::Query,
}; };
use seaography::{ use seaography::{
Builder as SeaographyBuilder, BuilderContext, SeaographyError, prepare_active_model, Builder as SeaographyBuilder, BuilderContext, GuardAction, SeaographyError,
prepare_active_model,
}; };
use ts_rs::TS; use ts_rs::TS;
@ -59,6 +60,14 @@ where
restrict_jsonb_filter_input_for_entity::<T>(context, column); restrict_jsonb_filter_input_for_entity::<T>(context, column);
convert_jsonb_output_for_entity::<T>(context, column, Some(Case::Camel)); convert_jsonb_output_for_entity::<T>(context, column, Some(Case::Camel));
let entity_column_name = get_entity_and_column_name::<T>(context, column); 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( context.types.input_type_overwrites.insert(
entity_column_name.clone(), entity_column_name.clone(),
@ -112,6 +121,7 @@ pub fn register_system_tasks_to_schema_builder(
.description(system_tasks::SystemTask::decl()), .description(system_tasks::SystemTask::decl()),
); );
builder.register_enumeration::<system_tasks::SystemTaskType>(); builder.register_enumeration::<system_tasks::SystemTaskType>();
builder.register_enumeration::<system_tasks::SystemTaskStatus>();
builder = register_entity_default_readonly!(builder, system_tasks); builder = register_entity_default_readonly!(builder, system_tasks);
let builder_context = builder.context; let builder_context = builder.context;

View File

@ -189,8 +189,8 @@ pub enum Cron {
MaxAttempts, MaxAttempts,
Priority, Priority,
Status, Status,
SubscriberTask, SubscriberTaskCron,
SystemTask, SystemTaskCron,
} }
#[derive(sea_query::Iden)] #[derive(sea_query::Iden)]
@ -317,6 +317,26 @@ pub trait CustomSchemaManagerExt {
Ok(()) 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< async fn create_postgres_enum_for_active_enum<
E: IntoTypeRef + IntoIden + Send + Clone, E: IntoTypeRef + IntoIden + Send + Clone,
I: IntoIterator<Item = String> + Send, I: IntoIterator<Item = String> + Send,
@ -403,6 +423,71 @@ impl CustomSchemaManagerExt for SchemaManager<'_> {
Ok(()) 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< async fn create_postgres_enum_for_active_enum<
E: IntoTypeRef + IntoIden + Send + Clone, E: IntoTypeRef + IntoIden + Send + Clone,
I: IntoIterator<Item = String> + Send, I: IntoIterator<Item = String> + Send,

View File

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

View File

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

View File

@ -23,7 +23,7 @@ impl MigrationTrait for Migration {
.table((ApalisSchema::Schema, ApalisJobs::Table)) .table((ApalisSchema::Schema, ApalisJobs::Table))
.add_column_if_not_exists(integer_null(ApalisJobs::SubscriberId)) .add_column_if_not_exists(integer_null(ApalisJobs::SubscriberId))
.add_column_if_not_exists(integer_null(ApalisJobs::SubscriptionId)) .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( .add_foreign_key(
TableForeignKey::new() TableForeignKey::new()
.name("fk_apalis_jobs_subscriber_id") .name("fk_apalis_jobs_subscriber_id")

View File

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

View File

@ -1,5 +1,4 @@
mod core; mod core;
mod registry;
pub use core::{ pub use core::{
CHECK_AND_TRIGGER_DUE_CRONS_FUNCTION_NAME, CRON_DUE_EVENT, CHECK_AND_TRIGGER_DUE_CRONS_FUNCTION_NAME, CRON_DUE_EVENT,
@ -71,8 +70,8 @@ pub struct Model {
pub status: CronStatus, pub status: CronStatus,
#[sea_orm(default_expr = "true")] #[sea_orm(default_expr = "true")]
pub enabled: bool, pub enabled: bool,
pub subscriber_task: Option<subscriber_tasks::SubscriberTask>, pub subscriber_task_cron: Option<subscriber_tasks::SubscriberTask>,
pub system_task: Option<system_tasks::SystemTask>, pub system_task_cron: Option<system_tasks::SystemTask>,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
@ -152,19 +151,19 @@ impl ActiveModelBehavior for ActiveModel {
self.next_run = Set(Some(next_run)); self.next_run = Set(Some(next_run));
} }
if let ActiveValue::Set(Some(subscriber_id)) = self.subscriber_id 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 && subscriber_task.get_subscriber_id() != subscriber_id
{ {
return Err(DbErr::Custom( 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 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) && system_task.get_subscriber_id() != Some(subscriber_id)
{ {
return Err(DbErr::Custom( 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<()> { 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 task_service = ctx.task();
let mut new_subscriber_task = subscriber_task.clone(); let mut new_subscriber_task = subscriber_task.clone();
new_subscriber_task.set_cron_id(Some(self.id)); new_subscriber_task.set_cron_id(Some(self.id));
task_service task_service
.add_subscriber_task(new_subscriber_task) .add_subscriber_task(new_subscriber_task)
.await?; .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 task_service = ctx.task();
let mut new_system_task = system_task.clone(); let mut new_system_task = system_task.clone();
new_system_task.set_cron_id(Some(self.id)); 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 tracing::Level;
use super::*; 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] #[fixture]
fn before_each() { fn before_each() {
@ -312,13 +315,6 @@ mod tests {
#[rstest] #[rstest]
#[tokio::test] #[tokio::test]
async fn test_cron_due_listening(before_each: ()) -> RecorderResult<()> { async fn test_cron_due_listening(before_each: ()) -> RecorderResult<()> {
let mut preset = TestingPreset::default().await?; todo!()
let app_ctx = preset.app_ctx.clone();
let db = app_ctx.db();
todo!();
Ok(())
} }
} }

View File

@ -21,6 +21,8 @@ export type Scalars = {
JsonbFilterInput: { input: any; output: any; } JsonbFilterInput: { input: any; output: any; }
/** type SubscriberTaskType = { "taskType": "sync_one_subscription_feeds_incremental" } & SyncOneSubscriptionFeedsIncrementalTask | { "taskType": "sync_one_subscription_feeds_full" } & SyncOneSubscriptionFeedsFullTask | { "taskType": "sync_one_subscription_sources" } & SyncOneSubscriptionSourcesTask; */ /** type SubscriberTaskType = { "taskType": "sync_one_subscription_feeds_incremental" } & SyncOneSubscriptionFeedsIncrementalTask | { "taskType": "sync_one_subscription_feeds_full" } & SyncOneSubscriptionFeedsFullTask | { "taskType": "sync_one_subscription_sources" } & SyncOneSubscriptionSourcesTask; */
SubscriberTaskType: { input: SubscriberTaskInput; output: SubscriberTaskType; } SubscriberTaskType: { input: SubscriberTaskInput; output: SubscriberTaskType; }
/** type SystemTaskType = { "taskType": "optimize_image" } & OptimizeImageTask; */
SystemTaskType: { input: any; output: any; }
}; };
export type Bangumi = { export type Bangumi = {
@ -354,13 +356,30 @@ export type Cron = {
status: CronStatusEnum; status: CronStatusEnum;
subscriber?: Maybe<Subscribers>; subscriber?: Maybe<Subscribers>;
subscriberId?: Maybe<Scalars['Int']['output']>; subscriberId?: Maybe<Scalars['Int']['output']>;
subscriberTask?: Maybe<Scalars['SubscriberTaskType']['output']>; subscriberTask: SubscriberTasksConnection;
subscriberTaskCron?: Maybe<Scalars['SubscriberTaskType']['output']>;
subscription?: Maybe<Subscriptions>; subscription?: Maybe<Subscriptions>;
subscriptionId?: Maybe<Scalars['Int']['output']>; subscriptionId?: Maybe<Scalars['Int']['output']>;
systemTask: SystemTasksConnection;
systemTaskCron?: Maybe<Scalars['SystemTaskType']['output']>;
timeoutMs: Scalars['Int']['output']; timeoutMs: Scalars['Int']['output'];
updatedAt: Scalars['String']['output']; updatedAt: Scalars['String']['output'];
}; };
export type CronSubscriberTaskArgs = {
filter?: InputMaybe<SubscriberTasksFilterInput>;
orderBy?: InputMaybe<SubscriberTasksOrderInput>;
pagination?: InputMaybe<PaginationInput>;
};
export type CronSystemTaskArgs = {
filter?: InputMaybe<SystemTasksFilterInput>;
orderBy?: InputMaybe<SystemTasksOrderInput>;
pagination?: InputMaybe<PaginationInput>;
};
export type CronBasic = { export type CronBasic = {
__typename?: 'CronBasic'; __typename?: 'CronBasic';
attempts: Scalars['Int']['output']; attempts: Scalars['Int']['output'];
@ -377,8 +396,9 @@ export type CronBasic = {
priority: Scalars['Int']['output']; priority: Scalars['Int']['output'];
status: CronStatusEnum; status: CronStatusEnum;
subscriberId?: Maybe<Scalars['Int']['output']>; subscriberId?: Maybe<Scalars['Int']['output']>;
subscriberTask?: Maybe<Scalars['SubscriberTaskType']['output']>; subscriberTaskCron?: Maybe<Scalars['SubscriberTaskType']['output']>;
subscriptionId?: Maybe<Scalars['Int']['output']>; subscriptionId?: Maybe<Scalars['Int']['output']>;
systemTaskCron?: Maybe<Scalars['SystemTaskType']['output']>;
timeoutMs: Scalars['Int']['output']; timeoutMs: Scalars['Int']['output'];
updatedAt: Scalars['String']['output']; updatedAt: Scalars['String']['output'];
}; };
@ -414,8 +434,9 @@ export type CronFilterInput = {
priority?: InputMaybe<IntegerFilterInput>; priority?: InputMaybe<IntegerFilterInput>;
status?: InputMaybe<CronStatusEnumFilterInput>; status?: InputMaybe<CronStatusEnumFilterInput>;
subscriberId?: InputMaybe<SubscriberIdFilterInput>; subscriberId?: InputMaybe<SubscriberIdFilterInput>;
subscriberTask?: InputMaybe<Scalars['JsonbFilterInput']['input']>; subscriberTaskCron?: InputMaybe<Scalars['JsonbFilterInput']['input']>;
subscriptionId?: InputMaybe<IntegerFilterInput>; subscriptionId?: InputMaybe<IntegerFilterInput>;
systemTaskCron?: InputMaybe<Scalars['JsonbFilterInput']['input']>;
timeoutMs?: InputMaybe<IntegerFilterInput>; timeoutMs?: InputMaybe<IntegerFilterInput>;
updatedAt?: InputMaybe<TextFilterInput>; updatedAt?: InputMaybe<TextFilterInput>;
}; };
@ -424,7 +445,8 @@ export type CronInsertInput = {
cronExpr: Scalars['String']['input']; cronExpr: Scalars['String']['input'];
enabled?: InputMaybe<Scalars['Boolean']['input']>; enabled?: InputMaybe<Scalars['Boolean']['input']>;
maxAttempts?: InputMaybe<Scalars['Int']['input']>; maxAttempts?: InputMaybe<Scalars['Int']['input']>;
subscriberTask?: InputMaybe<Scalars['SubscriberTaskType']['input']>; subscriberTaskCron?: InputMaybe<Scalars['SubscriberTaskType']['input']>;
systemTaskCron?: InputMaybe<Scalars['SystemTaskType']['input']>;
timeoutMs?: InputMaybe<Scalars['Int']['input']>; timeoutMs?: InputMaybe<Scalars['Int']['input']>;
}; };
@ -443,8 +465,9 @@ export type CronOrderInput = {
priority?: InputMaybe<OrderByEnum>; priority?: InputMaybe<OrderByEnum>;
status?: InputMaybe<OrderByEnum>; status?: InputMaybe<OrderByEnum>;
subscriberId?: InputMaybe<OrderByEnum>; subscriberId?: InputMaybe<OrderByEnum>;
subscriberTask?: InputMaybe<OrderByEnum>; subscriberTaskCron?: InputMaybe<OrderByEnum>;
subscriptionId?: InputMaybe<OrderByEnum>; subscriptionId?: InputMaybe<OrderByEnum>;
systemTaskCron?: InputMaybe<OrderByEnum>;
timeoutMs?: InputMaybe<OrderByEnum>; timeoutMs?: InputMaybe<OrderByEnum>;
updatedAt?: InputMaybe<OrderByEnum>; updatedAt?: InputMaybe<OrderByEnum>;
}; };
@ -1170,6 +1193,9 @@ export type Mutation = {
subscriptionsCreateOne: SubscriptionsBasic; subscriptionsCreateOne: SubscriptionsBasic;
subscriptionsDelete: Scalars['Int']['output']; subscriptionsDelete: Scalars['Int']['output'];
subscriptionsUpdate: Array<SubscriptionsBasic>; subscriptionsUpdate: Array<SubscriptionsBasic>;
systemTasksCreateOne: SystemTasksBasic;
systemTasksDelete: Scalars['Int']['output'];
systemTasksRetryOne: SystemTasksBasic;
}; };
@ -1402,6 +1428,21 @@ export type MutationSubscriptionsUpdateArgs = {
filter?: InputMaybe<SubscriptionsFilterInput>; filter?: InputMaybe<SubscriptionsFilterInput>;
}; };
export type MutationSystemTasksCreateOneArgs = {
data: SystemTasksInsertInput;
};
export type MutationSystemTasksDeleteArgs = {
filter?: InputMaybe<SystemTasksFilterInput>;
};
export type MutationSystemTasksRetryOneArgs = {
filter?: InputMaybe<SystemTasksFilterInput>;
};
export type OffsetInput = { export type OffsetInput = {
limit: Scalars['Int']['input']; limit: Scalars['Int']['input'];
offset: Scalars['Int']['input']; offset: Scalars['Int']['input'];
@ -1455,6 +1496,7 @@ export type Query = {
subscriptionBangumi: SubscriptionBangumiConnection; subscriptionBangumi: SubscriptionBangumiConnection;
subscriptionEpisode: SubscriptionEpisodeConnection; subscriptionEpisode: SubscriptionEpisodeConnection;
subscriptions: SubscriptionsConnection; subscriptions: SubscriptionsConnection;
systemTasks: SystemTasksConnection;
}; };
@ -1546,6 +1588,13 @@ export type QuerySubscriptionsArgs = {
pagination?: InputMaybe<PaginationInput>; pagination?: InputMaybe<PaginationInput>;
}; };
export type QuerySystemTasksArgs = {
filter?: InputMaybe<SystemTasksFilterInput>;
orderBy?: InputMaybe<SystemTasksOrderInput>;
pagination?: InputMaybe<PaginationInput>;
};
export type StringFilterInput = { export type StringFilterInput = {
between?: InputMaybe<Array<Scalars['String']['input']>>; between?: InputMaybe<Array<Scalars['String']['input']>>;
contains?: InputMaybe<Scalars['String']['input']>; contains?: InputMaybe<Scalars['String']['input']>;
@ -1590,6 +1639,8 @@ export type SubscriberTaskTypeEnum = typeof SubscriberTaskTypeEnum[keyof typeof
export type SubscriberTasks = { export type SubscriberTasks = {
__typename?: 'SubscriberTasks'; __typename?: 'SubscriberTasks';
attempts: Scalars['Int']['output']; attempts: Scalars['Int']['output'];
cron?: Maybe<Cron>;
cronId?: Maybe<Scalars['Int']['output']>;
doneAt?: Maybe<Scalars['String']['output']>; doneAt?: Maybe<Scalars['String']['output']>;
id: Scalars['String']['output']; id: Scalars['String']['output'];
job: Scalars['SubscriberTaskType']['output']; job: Scalars['SubscriberTaskType']['output'];
@ -1610,6 +1661,7 @@ export type SubscriberTasks = {
export type SubscriberTasksBasic = { export type SubscriberTasksBasic = {
__typename?: 'SubscriberTasksBasic'; __typename?: 'SubscriberTasksBasic';
attempts: Scalars['Int']['output']; attempts: Scalars['Int']['output'];
cronId?: Maybe<Scalars['Int']['output']>;
doneAt?: Maybe<Scalars['String']['output']>; doneAt?: Maybe<Scalars['String']['output']>;
id: Scalars['String']['output']; id: Scalars['String']['output'];
job: Scalars['SubscriberTaskType']['output']; job: Scalars['SubscriberTaskType']['output'];
@ -1642,6 +1694,7 @@ export type SubscriberTasksEdge = {
export type SubscriberTasksFilterInput = { export type SubscriberTasksFilterInput = {
and?: InputMaybe<Array<SubscriberTasksFilterInput>>; and?: InputMaybe<Array<SubscriberTasksFilterInput>>;
attempts?: InputMaybe<IntegerFilterInput>; attempts?: InputMaybe<IntegerFilterInput>;
cronId?: InputMaybe<IntegerFilterInput>;
doneAt?: InputMaybe<TextFilterInput>; doneAt?: InputMaybe<TextFilterInput>;
id?: InputMaybe<StringFilterInput>; id?: InputMaybe<StringFilterInput>;
job?: InputMaybe<Scalars['JsonbFilterInput']['input']>; job?: InputMaybe<Scalars['JsonbFilterInput']['input']>;
@ -1665,6 +1718,7 @@ export type SubscriberTasksInsertInput = {
export type SubscriberTasksOrderInput = { export type SubscriberTasksOrderInput = {
attempts?: InputMaybe<OrderByEnum>; attempts?: InputMaybe<OrderByEnum>;
cronId?: InputMaybe<OrderByEnum>;
doneAt?: InputMaybe<OrderByEnum>; doneAt?: InputMaybe<OrderByEnum>;
id?: InputMaybe<OrderByEnum>; id?: InputMaybe<OrderByEnum>;
job?: InputMaybe<OrderByEnum>; job?: InputMaybe<OrderByEnum>;
@ -1693,6 +1747,7 @@ export type Subscribers = {
id: Scalars['Int']['output']; id: Scalars['Int']['output'];
subscriberTask: SubscriberTasksConnection; subscriberTask: SubscriberTasksConnection;
subscription: SubscriptionsConnection; subscription: SubscriptionsConnection;
systemTask: SystemTasksConnection;
updatedAt: Scalars['String']['output']; updatedAt: Scalars['String']['output'];
}; };
@ -1745,6 +1800,13 @@ export type SubscribersSubscriptionArgs = {
pagination?: InputMaybe<PaginationInput>; pagination?: InputMaybe<PaginationInput>;
}; };
export type SubscribersSystemTaskArgs = {
filter?: InputMaybe<SystemTasksFilterInput>;
orderBy?: InputMaybe<SystemTasksOrderInput>;
pagination?: InputMaybe<PaginationInput>;
};
export type SubscribersConnection = { export type SubscribersConnection = {
__typename?: 'SubscribersConnection'; __typename?: 'SubscribersConnection';
edges: Array<SubscribersEdge>; edges: Array<SubscribersEdge>;
@ -2056,6 +2118,114 @@ export type SubscriptionsUpdateInput = {
updatedAt?: InputMaybe<Scalars['String']['input']>; updatedAt?: InputMaybe<Scalars['String']['input']>;
}; };
export const SystemTaskStatusEnum = {
Done: 'Done',
Failed: 'Failed',
Killed: 'Killed',
Pending: 'Pending',
Running: 'Running',
Scheduled: 'Scheduled'
} as const;
export type SystemTaskStatusEnum = typeof SystemTaskStatusEnum[keyof typeof SystemTaskStatusEnum];
export const SystemTaskTypeEnum = {
OptimizeImage: 'optimize_image'
} as const;
export type SystemTaskTypeEnum = typeof SystemTaskTypeEnum[keyof typeof SystemTaskTypeEnum];
export type SystemTasks = {
__typename?: 'SystemTasks';
attempts: Scalars['Int']['output'];
cron?: Maybe<Cron>;
cronId?: Maybe<Scalars['Int']['output']>;
doneAt?: Maybe<Scalars['String']['output']>;
id: Scalars['String']['output'];
job: Scalars['SystemTaskType']['output'];
lastError?: Maybe<Scalars['String']['output']>;
lockAt?: Maybe<Scalars['String']['output']>;
lockBy?: Maybe<Scalars['String']['output']>;
maxAttempts: Scalars['Int']['output'];
priority: Scalars['Int']['output'];
runAt: Scalars['String']['output'];
status: SystemTaskStatusEnum;
subscriber?: Maybe<Subscribers>;
subscriberId?: Maybe<Scalars['Int']['output']>;
taskType: SystemTaskTypeEnum;
};
export type SystemTasksBasic = {
__typename?: 'SystemTasksBasic';
attempts: Scalars['Int']['output'];
cronId?: Maybe<Scalars['Int']['output']>;
doneAt?: Maybe<Scalars['String']['output']>;
id: Scalars['String']['output'];
job: Scalars['SystemTaskType']['output'];
lastError?: Maybe<Scalars['String']['output']>;
lockAt?: Maybe<Scalars['String']['output']>;
lockBy?: Maybe<Scalars['String']['output']>;
maxAttempts: Scalars['Int']['output'];
priority: Scalars['Int']['output'];
runAt: Scalars['String']['output'];
status: SystemTaskStatusEnum;
subscriberId?: Maybe<Scalars['Int']['output']>;
taskType: SystemTaskTypeEnum;
};
export type SystemTasksConnection = {
__typename?: 'SystemTasksConnection';
edges: Array<SystemTasksEdge>;
nodes: Array<SystemTasks>;
pageInfo: PageInfo;
paginationInfo?: Maybe<PaginationInfo>;
};
export type SystemTasksEdge = {
__typename?: 'SystemTasksEdge';
cursor: Scalars['String']['output'];
node: SystemTasks;
};
export type SystemTasksFilterInput = {
and?: InputMaybe<Array<SystemTasksFilterInput>>;
attempts?: InputMaybe<IntegerFilterInput>;
cronId?: InputMaybe<IntegerFilterInput>;
doneAt?: InputMaybe<TextFilterInput>;
id?: InputMaybe<StringFilterInput>;
job?: InputMaybe<Scalars['JsonbFilterInput']['input']>;
lastError?: InputMaybe<StringFilterInput>;
lockAt?: InputMaybe<TextFilterInput>;
lockBy?: InputMaybe<StringFilterInput>;
maxAttempts?: InputMaybe<IntegerFilterInput>;
or?: InputMaybe<Array<SystemTasksFilterInput>>;
priority?: InputMaybe<IntegerFilterInput>;
runAt?: InputMaybe<TextFilterInput>;
status?: InputMaybe<StringFilterInput>;
subscriberId?: InputMaybe<SubscriberIdFilterInput>;
taskType?: InputMaybe<StringFilterInput>;
};
export type SystemTasksInsertInput = {
job: Scalars['SystemTaskType']['input'];
subscriberId?: InputMaybe<Scalars['Int']['input']>;
};
export type SystemTasksOrderInput = {
attempts?: InputMaybe<OrderByEnum>;
cronId?: InputMaybe<OrderByEnum>;
doneAt?: InputMaybe<OrderByEnum>;
id?: InputMaybe<OrderByEnum>;
job?: InputMaybe<OrderByEnum>;
lastError?: InputMaybe<OrderByEnum>;
lockAt?: InputMaybe<OrderByEnum>;
lockBy?: InputMaybe<OrderByEnum>;
maxAttempts?: InputMaybe<OrderByEnum>;
priority?: InputMaybe<OrderByEnum>;
runAt?: InputMaybe<OrderByEnum>;
status?: InputMaybe<OrderByEnum>;
subscriberId?: InputMaybe<OrderByEnum>;
taskType?: InputMaybe<OrderByEnum>;
};
export type TextFilterInput = { export type TextFilterInput = {
between?: InputMaybe<Array<Scalars['String']['input']>>; between?: InputMaybe<Array<Scalars['String']['input']>>;
eq?: InputMaybe<Scalars['String']['input']>; eq?: InputMaybe<Scalars['String']['input']>;

50
pnpm-lock.yaml generated
View File

@ -351,10 +351,10 @@ importers:
devDependencies: devDependencies:
'@vitejs/plugin-react': '@vitejs/plugin-react':
specifier: ^4.5.2 specifier: ^4.5.2
version: 4.5.2(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0)) version: 4.5.2(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))
vitest: vitest:
specifier: ^3.2.3 specifier: ^3.2.3
version: 3.2.3(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) version: 3.2.3(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
packages: packages:
@ -6189,11 +6189,6 @@ packages:
uglify-js: uglify-js:
optional: true optional: true
terser@5.41.0:
resolution: {integrity: sha512-H406eLPXpZbAX14+B8psIuvIr8+3c+2hkuYzpMkoE0ij+NdsVATbA78vb8neA/eqrj7rywa2pIkdmWRsXW6wmw==}
engines: {node: '>=10'}
hasBin: true
terser@5.43.1: terser@5.43.1:
resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -9841,7 +9836,7 @@ snapshots:
dependencies: dependencies:
'@types/node': 24.0.10 '@types/node': 24.0.10
'@vitejs/plugin-react@4.5.2(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0))': '@vitejs/plugin-react@4.5.2(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))':
dependencies: dependencies:
'@babel/core': 7.27.4 '@babel/core': 7.27.4
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4) '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4)
@ -9849,7 +9844,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.11 '@rolldown/pluginutils': 1.0.0-beta.11
'@types/babel__core': 7.20.5 '@types/babel__core': 7.20.5
react-refresh: 0.17.0 react-refresh: 0.17.0
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -9861,13 +9856,13 @@ snapshots:
chai: 5.2.0 chai: 5.2.0
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
'@vitest/mocker@3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0))': '@vitest/mocker@3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))':
dependencies: dependencies:
'@vitest/spy': 3.2.3 '@vitest/spy': 3.2.3
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.17 magic-string: 0.30.17
optionalDependencies: optionalDependencies:
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
'@vitest/pretty-format@3.2.3': '@vitest/pretty-format@3.2.3':
dependencies: dependencies:
@ -13182,14 +13177,6 @@ snapshots:
webpack: 5.97.1 webpack: 5.97.1
optional: true optional: true
terser@5.41.0:
dependencies:
'@jridgewell/source-map': 0.3.10
acorn: 8.15.0
commander: 2.20.3
source-map-support: 0.5.21
optional: true
terser@5.43.1: terser@5.43.1:
dependencies: dependencies:
'@jridgewell/source-map': 0.3.10 '@jridgewell/source-map': 0.3.10
@ -13466,13 +13453,13 @@ snapshots:
d3-time: 3.1.0 d3-time: 3.1.0
d3-timer: 3.0.1 d3-timer: 3.0.1
vite-node@3.2.3(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0): vite-node@3.2.3(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14
debug: 4.4.1 debug: 4.4.1
es-module-lexer: 1.7.0 es-module-lexer: 1.7.0
pathe: 2.0.3 pathe: 2.0.3
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@ -13484,18 +13471,6 @@ snapshots:
- supports-color - supports-color
- terser - terser
vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.5
rollup: 4.29.1
optionalDependencies:
'@types/node': 24.0.10
fsevents: 2.3.3
lightningcss: 1.30.1
sass: 1.77.4
terser: 5.41.0
vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1): vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
dependencies: dependencies:
esbuild: 0.21.5 esbuild: 0.21.5
@ -13507,13 +13482,12 @@ snapshots:
lightningcss: 1.30.1 lightningcss: 1.30.1
sass: 1.77.4 sass: 1.77.4
terser: 5.43.1 terser: 5.43.1
optional: true
vitest@3.2.3(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0): vitest@3.2.3(@types/node@24.0.10)(jsdom@25.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5))(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1):
dependencies: dependencies:
'@types/chai': 5.2.2 '@types/chai': 5.2.2
'@vitest/expect': 3.2.3 '@vitest/expect': 3.2.3
'@vitest/mocker': 3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0)) '@vitest/mocker': 3.2.3(vite@5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1))
'@vitest/pretty-format': 3.2.3 '@vitest/pretty-format': 3.2.3
'@vitest/runner': 3.2.3 '@vitest/runner': 3.2.3
'@vitest/snapshot': 3.2.3 '@vitest/snapshot': 3.2.3
@ -13531,8 +13505,8 @@ snapshots:
tinyglobby: 0.2.14 tinyglobby: 0.2.14
tinypool: 1.1.0 tinypool: 1.1.0
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) vite: 5.4.11(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
vite-node: 3.2.3(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.41.0) vite-node: 3.2.3(@types/node@24.0.10)(lightningcss@1.30.1)(sass@1.77.4)(terser@5.43.1)
why-is-node-running: 2.3.0 why-is-node-running: 2.3.0
optionalDependencies: optionalDependencies:
'@types/node': 24.0.10 '@types/node': 24.0.10