From 5b001f95841999f7b633296cab2c824ef9d39b75 Mon Sep 17 00:00:00 2001 From: lonelyhentxi Date: Wed, 2 Jul 2025 01:25:44 +0800 Subject: [PATCH] refactor: refactor graphql --- Cargo.lock | 185 +----------- Cargo.toml | 4 +- apps/recorder/Cargo.toml | 4 +- apps/recorder/bindings/SubscriberTaskInput.ts | 6 + ...ubscriberTask.ts => SubscriberTaskType.ts} | 2 +- .../SyncOneSubscriptionFeedsFullTask.ts | 2 +- .../SyncOneSubscriptionFeedsFullTaskInput.ts | 3 + ...SyncOneSubscriptionFeedsIncrementalTask.ts | 2 +- ...neSubscriptionFeedsIncrementalTaskInput.ts | 3 + .../SyncOneSubscriptionSourcesTask.ts | 2 +- .../SyncOneSubscriptionSourcesTaskInput.ts | 3 + .../src/graphql/domains/credential_3rd.rs | 4 +- apps/recorder/src/graphql/domains/cron.rs | 7 +- apps/recorder/src/graphql/domains/feeds.rs | 2 +- .../src/graphql/domains/subscriber_tasks.rs | 84 +++--- .../src/graphql/domains/subscribers.rs | 6 +- .../src/graphql/domains/subscriptions.rs | 2 +- apps/recorder/src/graphql/infra/crypto.rs | 4 +- apps/recorder/src/graphql/infra/custom.rs | 267 ++++++++++-------- apps/recorder/src/graphql/infra/json.rs | 30 +- apps/recorder/src/graphql/schema.rs | 33 ++- .../src/models/subscriber_tasks/mod.rs | 4 +- apps/recorder/src/task/core.rs | 4 + apps/recorder/src/task/mod.rs | 10 +- apps/recorder/src/task/registry/mod.rs | 5 +- .../src/task/registry/subscriber/base.rs | 30 +- .../src/task/registry/subscriber/mod.rs | 59 ++-- .../task/registry/subscriber/subscription.rs | 7 +- apps/webui/graphql-codegen.ts | 6 + .../src/domains/recorder/schema/tasks.ts | 16 +- apps/webui/src/infra/graphql/gql/gql.ts | 6 +- apps/webui/src/infra/graphql/gql/graphql.ts | 40 +-- .../routes/_app/tasks/detail.$id.tsx | 15 +- packages/util-derive/src/lib.rs | 142 +--------- 34 files changed, 376 insertions(+), 623 deletions(-) create mode 100644 apps/recorder/bindings/SubscriberTaskInput.ts rename apps/recorder/bindings/{SubscriberTask.ts => SubscriberTaskType.ts} (56%) create mode 100644 apps/recorder/bindings/SyncOneSubscriptionFeedsFullTaskInput.ts create mode 100644 apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTaskInput.ts create mode 100644 apps/recorder/bindings/SyncOneSubscriptionSourcesTaskInput.ts diff --git a/Cargo.lock b/Cargo.lock index 29aa39b..f460588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,7 +82,6 @@ dependencies = [ "cfg-if", "getrandom 0.3.3", "once_cell", - "serde", "version_check", "zerocopy", ] @@ -920,12 +919,6 @@ dependencies = [ "serde_with", ] -[[package]] -name = "borrow-or-share" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" - [[package]] name = "borsh" version = "1.5.7" @@ -1042,12 +1035,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bytecount" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" - [[package]] name = "bytemuck" version = "1.23.1" @@ -2212,15 +2199,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "email_address" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" -dependencies = [ - "serde", -] - [[package]] name = "encode_unicode" version = "1.0.0" @@ -2489,17 +2467,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "fluent-uri" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" -dependencies = [ - "borrow-or-share", - "ref-cast", - "serde", -] - [[package]] name = "flume" version = "0.11.1" @@ -2547,16 +2514,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fraction" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" -dependencies = [ - "lazy_static", - "num 0.4.3", -] - [[package]] name = "fs4" version = "0.13.1" @@ -4129,33 +4086,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonschema" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b46a0365a611fbf1d2143104dcf910aada96fafd295bab16c60b802bf6fa1d" -dependencies = [ - "ahash 0.8.12", - "base64 0.22.1", - "bytecount", - "email_address", - "fancy-regex", - "fraction", - "idna", - "itoa", - "num-cmp", - "num-traits", - "once_cell", - "percent-encoding", - "referencing", - "regex", - "regex-syntax 0.8.5", - "reqwest", - "serde", - "serde_json", - "uuid-simd", -] - [[package]] name = "jwtk" version = "0.4.0" @@ -5063,27 +4993,13 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ - "num-complex 0.2.4", + "num-complex", "num-integer", "num-iter", "num-rational 0.2.4", "num-traits", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex 0.4.6", - "num-integer", - "num-iter", - "num-rational 0.4.2", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -5111,12 +5027,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-cmp" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" - [[package]] name = "num-complex" version = "0.2.4" @@ -5127,15 +5037,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -5453,12 +5354,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" -[[package]] -name = "outref" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" - [[package]] name = "overload" version = "0.1.1" @@ -6884,7 +6779,6 @@ dependencies = [ "itertools 0.14.0", "jpegxl-rs", "jpegxl-sys", - "jsonschema", "jwtk", "lazy_static", "lightningcss", @@ -6899,6 +6793,7 @@ dependencies = [ "once_cell", "opendal", "openidconnect", + "paste", "percent-encoding", "polars", "quick-xml", @@ -6909,7 +6804,6 @@ dependencies = [ "rss", "rstest", "rust_decimal", - "schemars 1.0.3", "scraper", "sea-orm", "sea-orm-migration", @@ -7019,20 +6913,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "referencing" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8eff4fa778b5c2a57e85c5f2fe3a709c52f0e60d23146e2151cbef5893f420e" -dependencies = [ - "ahash 0.8.12", - "fluent-uri", - "once_cell", - "parking_lot 0.12.4", - "percent-encoding", - "serde_json", -] - [[package]] name = "reflink-copy" version = "0.1.26" @@ -7115,7 +6995,6 @@ dependencies = [ "cookie", "cookie_store", "encoding_rs", - "futures-channel", "futures-core", "futures-util", "h2", @@ -7561,31 +7440,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "schemars" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d" -dependencies = [ - "dyn-clone", - "ref-cast", - "schemars_derive", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b13ed22d6d49fe23712e068770b5c4df4a693a2b02eeff8e7ca3135627a24f6" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.104", -] - [[package]] name = "scoped-tls" version = "1.0.1" @@ -7791,6 +7645,7 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "seaography" version = "1.1.4" +source = "git+https://github.com/dumtruck/seaography.git?rev=9f7fc7c#9f7fc7cf05234abe35fd9144c895321dd2b5db62" dependencies = [ "async-graphql", "fnv", @@ -7917,17 +7772,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "serde_json" version = "1.0.140" @@ -8011,7 +7855,7 @@ dependencies = [ "hex 0.4.3", "indexmap 1.9.3", "indexmap 2.9.0", - "schemars 0.9.0", + "schemars", "serde", "serde_derive", "serde_json", @@ -8185,7 +8029,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" dependencies = [ - "outref 0.1.0", + "outref", ] [[package]] @@ -8228,7 +8072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed5f6ab2122c6dec69dca18c72fa4590a27e581ad20d44960fe74c032a0b23b" dependencies = [ "generic-array 0.12.4", - "num 0.2.1", + "num", ] [[package]] @@ -9719,17 +9563,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "uuid-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" -dependencies = [ - "outref 0.5.2", - "uuid", - "vsimd", -] - [[package]] name = "v_frame" version = "0.3.9" @@ -9771,12 +9604,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index bb74589..89cb03a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,6 +87,4 @@ nanoid = "0.4.0" webp = "0.3.0" [patch.crates-io] -# seaography = { git = "https://github.com/dumtruck/seaography.git", rev = "395d50f" } - -seaography = { path = "../seaography" } +seaography = { git = "https://github.com/dumtruck/seaography.git", rev = "9f7fc7c" } diff --git a/apps/recorder/Cargo.toml b/apps/recorder/Cargo.toml index b0ac53a..802a930 100644 --- a/apps/recorder/Cargo.toml +++ b/apps/recorder/Cargo.toml @@ -125,6 +125,7 @@ seaography = { version = "1.1", features = [ "with-bigdecimal", "with-postgres-array", "with-json-as-scalar", + "with-custom-as-json", ] } tower = { version = "0.5.2", features = ["util"] } tower-http = { version = "0.6", features = [ @@ -167,8 +168,7 @@ quick-xml = { version = "0.37.5", features = [ croner = "2.2.0" ts-rs = "11.0.1" secrecy = { version = "0.10.3", features = ["serde"] } -schemars = "1.0.3" -jsonschema = "0.30.0" +paste = "1.0.15" [dev-dependencies] inquire = { workspace = true } diff --git a/apps/recorder/bindings/SubscriberTaskInput.ts b/apps/recorder/bindings/SubscriberTaskInput.ts new file mode 100644 index 0000000..8eae570 --- /dev/null +++ b/apps/recorder/bindings/SubscriberTaskInput.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SyncOneSubscriptionFeedsFullTaskInput } from "./SyncOneSubscriptionFeedsFullTaskInput"; +import type { SyncOneSubscriptionFeedsIncrementalTaskInput } from "./SyncOneSubscriptionFeedsIncrementalTaskInput"; +import type { SyncOneSubscriptionSourcesTaskInput } from "./SyncOneSubscriptionSourcesTaskInput"; + +export type SubscriberTaskInput = { "taskType": "sync_one_subscription_feeds_incremental" } & SyncOneSubscriptionFeedsIncrementalTaskInput | { "taskType": "sync_one_subscription_feeds_full" } & SyncOneSubscriptionFeedsFullTaskInput | { "taskType": "sync_one_subscription_sources" } & SyncOneSubscriptionSourcesTaskInput; diff --git a/apps/recorder/bindings/SubscriberTask.ts b/apps/recorder/bindings/SubscriberTaskType.ts similarity index 56% rename from apps/recorder/bindings/SubscriberTask.ts rename to apps/recorder/bindings/SubscriberTaskType.ts index d12ac40..c9d44b2 100644 --- a/apps/recorder/bindings/SubscriberTask.ts +++ b/apps/recorder/bindings/SubscriberTaskType.ts @@ -3,4 +3,4 @@ import type { SyncOneSubscriptionFeedsFullTask } from "./SyncOneSubscriptionFeed import type { SyncOneSubscriptionFeedsIncrementalTask } from "./SyncOneSubscriptionFeedsIncrementalTask"; import type { SyncOneSubscriptionSourcesTask } from "./SyncOneSubscriptionSourcesTask"; -export type SubscriberTask = { "taskType": "sync_one_subscription_feeds_incremental" } & SyncOneSubscriptionFeedsIncrementalTask | { "taskType": "sync_one_subscription_feeds_full" } & SyncOneSubscriptionFeedsFullTask | { "taskType": "sync_one_subscription_sources" } & SyncOneSubscriptionSourcesTask; +export type SubscriberTaskType = { "taskType": "sync_one_subscription_feeds_incremental" } & SyncOneSubscriptionFeedsIncrementalTask | { "taskType": "sync_one_subscription_feeds_full" } & SyncOneSubscriptionFeedsFullTask | { "taskType": "sync_one_subscription_sources" } & SyncOneSubscriptionSourcesTask; diff --git a/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTask.ts b/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTask.ts index 644ca01..5d97653 100644 --- a/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTask.ts +++ b/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTask.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type SyncOneSubscriptionFeedsFullTask = { subscriptionId: number, subscriberId: number, cronId: number | null, }; +export type SyncOneSubscriptionFeedsFullTask = { subscriptionId: number, subscriberId: number, cronId?: number | null, }; diff --git a/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTaskInput.ts b/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTaskInput.ts new file mode 100644 index 0000000..f47cfc0 --- /dev/null +++ b/apps/recorder/bindings/SyncOneSubscriptionFeedsFullTaskInput.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SyncOneSubscriptionFeedsFullTaskInput = { subscriptionId: number, subscriberId?: number | null, cronId?: number | null, }; diff --git a/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTask.ts b/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTask.ts index 1f3e9a4..f58fe59 100644 --- a/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTask.ts +++ b/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTask.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type SyncOneSubscriptionFeedsIncrementalTask = { subscriptionId: number, subscriberId: number, cronId: number | null, }; +export type SyncOneSubscriptionFeedsIncrementalTask = { subscriptionId: number, subscriberId: number, cronId?: number | null, }; diff --git a/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTaskInput.ts b/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTaskInput.ts new file mode 100644 index 0000000..65ab5a3 --- /dev/null +++ b/apps/recorder/bindings/SyncOneSubscriptionFeedsIncrementalTaskInput.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SyncOneSubscriptionFeedsIncrementalTaskInput = { subscriptionId: number, subscriberId?: number | null, cronId?: number | null, }; diff --git a/apps/recorder/bindings/SyncOneSubscriptionSourcesTask.ts b/apps/recorder/bindings/SyncOneSubscriptionSourcesTask.ts index 01a5d5e..6e5517b 100644 --- a/apps/recorder/bindings/SyncOneSubscriptionSourcesTask.ts +++ b/apps/recorder/bindings/SyncOneSubscriptionSourcesTask.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type SyncOneSubscriptionSourcesTask = { subscriptionId: number, subscriberId: number, cronId: number | null, }; +export type SyncOneSubscriptionSourcesTask = { subscriptionId: number, subscriberId: number, cronId?: number | null, }; diff --git a/apps/recorder/bindings/SyncOneSubscriptionSourcesTaskInput.ts b/apps/recorder/bindings/SyncOneSubscriptionSourcesTaskInput.ts new file mode 100644 index 0000000..e730ead --- /dev/null +++ b/apps/recorder/bindings/SyncOneSubscriptionSourcesTaskInput.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type SyncOneSubscriptionSourcesTaskInput = { subscriptionId: number, subscriberId?: number | null, cronId?: number | null, }; diff --git a/apps/recorder/src/graphql/domains/credential_3rd.rs b/apps/recorder/src/graphql/domains/credential_3rd.rs index 5844252..c14f54d 100644 --- a/apps/recorder/src/graphql/domains/credential_3rd.rs +++ b/apps/recorder/src/graphql/domains/credential_3rd.rs @@ -105,10 +105,10 @@ pub fn register_credential3rd_to_schema_builder( { let check_available_mutation_name = get_entity_custom_mutation_field_name::< credential_3rd::Entity, - >(&builder_context, "CheckAvailable"); + >(builder_context, "CheckAvailable"); let check_available_mutation = generate_entity_filtered_mutation_field::( - builder_context.clone(), + builder_context, check_available_mutation_name, TypeRef::named_nn(Credential3rdCheckAvailableInfo::object_type_name()), Arc::new(|_resolver_ctx, app_ctx, filters| { diff --git a/apps/recorder/src/graphql/domains/cron.rs b/apps/recorder/src/graphql/domains/cron.rs index 5de6e63..722fa10 100644 --- a/apps/recorder/src/graphql/domains/cron.rs +++ b/apps/recorder/src/graphql/domains/cron.rs @@ -1,4 +1,3 @@ -use convert_case::Case; use sea_orm::Iterable; use seaography::{Builder as SeaographyBuilder, BuilderContext}; @@ -44,11 +43,7 @@ fn skip_columns_for_entity_input(context: &mut BuilderContext) { pub fn register_cron_to_schema_context(context: &mut BuilderContext) { restrict_subscriber_for_entity::(context, &cron::Column::SubscriberId); - restrict_subscriber_tasks_for_entity::( - context, - &cron::Column::SubscriberTask, - Some(Case::Snake), - ); + restrict_subscriber_tasks_for_entity::(context, &cron::Column::SubscriberTask); skip_columns_for_entity_input(context); } diff --git a/apps/recorder/src/graphql/domains/feeds.rs b/apps/recorder/src/graphql/domains/feeds.rs index a106a36..c044c6a 100644 --- a/apps/recorder/src/graphql/domains/feeds.rs +++ b/apps/recorder/src/graphql/domains/feeds.rs @@ -29,7 +29,7 @@ pub fn register_feeds_to_schema_context(context: &mut BuilderContext) { context.types.input_none_conversions.insert( get_entity_and_column_name::(context, &feeds::Column::Token), - Arc::new( + Box::new( move |context: &ResolverContext| -> SeaResult> { let field_name = context.field().name(); if field_name == entity_create_one_mutation_field_name.as_str() diff --git a/apps/recorder/src/graphql/domains/subscriber_tasks.rs b/apps/recorder/src/graphql/domains/subscriber_tasks.rs index d11d3ca..230d7e2 100644 --- a/apps/recorder/src/graphql/domains/subscriber_tasks.rs +++ b/apps/recorder/src/graphql/domains/subscriber_tasks.rs @@ -1,6 +1,6 @@ use std::{ops::Deref, sync::Arc}; -use async_graphql::dynamic::{FieldValue, TypeRef}; +use async_graphql::dynamic::{FieldValue, Scalar, TypeRef}; use convert_case::Case; use sea_orm::{ ActiveModelBehavior, ColumnTrait, ConnectionTrait, EntityTrait, Iterable, QueryFilter, @@ -9,9 +9,9 @@ use sea_orm::{ use seaography::{ Builder as SeaographyBuilder, BuilderContext, SeaographyError, prepare_active_model, }; +use ts_rs::TS; use crate::{ - app::AppContextTrait, auth::AuthUserInfo, errors::RecorderError, graphql::{ @@ -32,7 +32,6 @@ use crate::{ }, models::subscriber_tasks, task::{ApalisJobs, ApalisSchema, SubscriberTaskTrait}, - utils::json::convert_json_keys, }; fn skip_columns_for_entity_input(context: &mut BuilderContext) { @@ -49,11 +48,8 @@ fn skip_columns_for_entity_input(context: &mut BuilderContext) { } } -pub fn restrict_subscriber_tasks_for_entity( - context: &mut BuilderContext, - column: &T::Column, - case: Option>, -) where +pub fn restrict_subscriber_tasks_for_entity(context: &mut BuilderContext, column: &T::Column) +where T: EntityTrait, ::Model: Sync, { @@ -62,42 +58,33 @@ pub fn restrict_subscriber_tasks_for_entity( restrict_jsonb_filter_input_for_entity::(context, column); convert_jsonb_output_for_entity::(context, column, Some(Case::Camel)); let entity_column_name = get_entity_and_column_name::(context, column); + + context.types.input_type_overwrites.insert( + entity_column_name.clone(), + TypeRef::Named(subscriber_tasks::SubscriberTask::ident().into()), + ); + context.types.output_type_overwrites.insert( + entity_column_name.clone(), + TypeRef::Named(subscriber_tasks::SubscriberTask::ident().into()), + ); context.types.input_conversions.insert( entity_column_name.clone(), - Arc::new(move |resolve_context, value_accessor| { - let mut json_value = value_accessor - .as_value() - .clone() - .into_json() - .map_err(|err| { - SeaographyError::TypeConversionError( - err.to_string(), - format!("Json - {entity_column_name}"), - ) - })?; - - if let Some(case) = case { - json_value = convert_json_keys(json_value, case); - } + Box::new(move |resolve_context, value_accessor| { + let task: subscriber_tasks::SubscriberTaskInput = value_accessor.deserialize()?; let subscriber_id = resolve_context .data::()? .subscriber_auth .subscriber_id; - if let Some(obj) = json_value.as_object_mut() { - obj.entry("subscriber_id") - .or_insert_with(|| serde_json::Value::from(subscriber_id)); - } + let task = subscriber_tasks::SubscriberTask::from_input(task, subscriber_id); - subscriber_tasks::subscriber_task_schema() - .validate(&json_value) - .map_err(|err| { - SeaographyError::TypeConversionError( - err.to_string(), - format!("Json - {entity_column_name}"), - ) - })?; + let json_value = serde_json::to_value(task).map_err(|err| { + SeaographyError::TypeConversionError( + err.to_string(), + format!("Json - {entity_column_name}"), + ) + })?; Ok(sea_orm::Value::Json(Some(Box::new(json_value)))) }), @@ -114,7 +101,6 @@ pub fn register_subscriber_tasks_to_schema_context(context: &mut BuilderContext) restrict_subscriber_tasks_for_entity::( context, &subscriber_tasks::Column::Job, - Some(Case::Snake), ); skip_columns_for_entity_input(context); @@ -123,22 +109,26 @@ pub fn register_subscriber_tasks_to_schema_context(context: &mut BuilderContext) pub fn register_subscriber_tasks_to_schema_builder( mut builder: SeaographyBuilder, ) -> SeaographyBuilder { + builder.schema = builder.schema.register( + Scalar::new(subscriber_tasks::SubscriberTask::ident()) + .description(subscriber_tasks::SubscriberTask::decl()), + ); builder.register_enumeration::(); builder.register_enumeration::(); builder = register_entity_default_readonly!(builder, subscriber_tasks); - let builder_context = builder.context.clone(); + let builder_context = builder.context; { builder .outputs .push(generate_entity_default_basic_entity_object::< subscriber_tasks::Entity, - >(builder_context.clone())); + >(builder_context)); } { let delete_mutation = generate_entity_delete_mutation_field::( - builder_context.clone(), + builder_context, Arc::new(|_resolver_ctx, app_ctx, filters| { Box::pin(async move { let db = app_ctx.db(); @@ -169,13 +159,13 @@ pub fn register_subscriber_tasks_to_schema_builder( { let entity_retry_one_mutation_name = get_entity_custom_mutation_field_name::< subscriber_tasks::Entity, - >(&builder_context, "RetryOne"); + >(builder_context, "RetryOne"); let retry_one_mutation = generate_entity_filtered_mutation_field::( - builder_context.clone(), + builder_context, entity_retry_one_mutation_name, TypeRef::named_nn(get_entity_basic_type_name::( - &builder_context, + builder_context, )), Arc::new(|_resolver_ctx, app_ctx, filters| { Box::pin(async move { @@ -214,15 +204,15 @@ pub fn register_subscriber_tasks_to_schema_builder( .inputs .push(generate_entity_default_insert_input_object::< subscriber_tasks::Entity, - >(&builder.context)); + >(builder_context)); let create_one_mutation = generate_entity_create_one_mutation_field::( - builder.context.clone(), + builder_context, Arc::new(move |resolver_ctx, app_ctx, input_object| { - let active_model: Result = - prepare_active_model(&builder_context.clone(), &input_object, resolver_ctx); - Box::pin(async move { + let active_model: Result = + prepare_active_model(builder_context, &input_object, resolver_ctx); + let task_service = app_ctx.task(); let active_model = active_model?; diff --git a/apps/recorder/src/graphql/domains/subscribers.rs b/apps/recorder/src/graphql/domains/subscribers.rs index ce99711..13bd7e8 100644 --- a/apps/recorder/src/graphql/domains/subscribers.rs +++ b/apps/recorder/src/graphql/domains/subscribers.rs @@ -79,7 +79,7 @@ where T: EntityTrait, ::Model: Sync, { - Arc::new(move |context: &ResolverContext| -> GuardAction { + Box::new(move |context: &ResolverContext| -> GuardAction { match context.ctx.data::() { Ok(_) => GuardAction::Allow, Err(err) => GuardAction::Block(Some(err.message)), @@ -106,7 +106,7 @@ where let entity_update_mutation_data_field_name = Arc::new(get_entity_update_mutation_data_field_name(context).to_string()); - Arc::new(move |context: &ResolverContext| -> GuardAction { + Box::new(move |context: &ResolverContext| -> GuardAction { match context.ctx.data::() { Ok(user_info) => { let subscriber_id = user_info.subscriber_auth.subscriber_id; @@ -253,7 +253,7 @@ where Arc::new(get_entity_create_one_mutation_field_name::(context)); let entity_create_batch_mutation_field_name = Arc::new(get_entity_create_batch_mutation_field_name::(context)); - Arc::new( + Box::new( move |context: &ResolverContext| -> SeaResult> { let field_name = context.field().name(); if field_name == entity_create_one_mutation_field_name.as_str() diff --git a/apps/recorder/src/graphql/domains/subscriptions.rs b/apps/recorder/src/graphql/domains/subscriptions.rs index bdb8955..f25f107 100644 --- a/apps/recorder/src/graphql/domains/subscriptions.rs +++ b/apps/recorder/src/graphql/domains/subscriptions.rs @@ -2,7 +2,7 @@ use seaography::{Builder as SeaographyBuilder, BuilderContext}; use crate::{ graphql::{ - domains::subscribers::restrict_subscriber_for_entity, infra, + domains::subscribers::restrict_subscriber_for_entity, infra::custom::register_entity_default_writable, }, models::subscriptions, diff --git a/apps/recorder/src/graphql/infra/crypto.rs b/apps/recorder/src/graphql/infra/crypto.rs index 6c8d624..f17cb9c 100644 --- a/apps/recorder/src/graphql/infra/crypto.rs +++ b/apps/recorder/src/graphql/infra/crypto.rs @@ -16,7 +16,7 @@ pub fn register_crypto_column_input_conversion_to_schema_context( { context.types.input_conversions.insert( get_entity_and_column_name::(context, column), - Arc::new( + Box::new( move |_resolve_context: &ResolverContext<'_>, value: &ValueAccessor| -> SeaResult { @@ -38,7 +38,7 @@ pub fn register_crypto_column_output_conversion_to_schema_context( { context.types.output_conversions.insert( get_entity_and_column_name::(context, column), - Arc::new( + Box::new( move |value: &sea_orm::Value| -> SeaResult { if let SeaValue::String(s) = value { if let Some(s) = s { diff --git a/apps/recorder/src/graphql/infra/custom.rs b/apps/recorder/src/graphql/infra/custom.rs index 30d21b9..9cf0b69 100644 --- a/apps/recorder/src/graphql/infra/custom.rs +++ b/apps/recorder/src/graphql/infra/custom.rs @@ -34,9 +34,9 @@ pub type FilterMutationFn = Arc< pub type CreateOneMutationFn = Arc< dyn for<'a> Fn( - &ResolverContext<'a>, + &'a ResolverContext<'a>, Arc, - ObjectAccessor<'_>, + ObjectAccessor<'a>, ) -> Pin> + Send + 'a>> + Send + Sync, @@ -44,9 +44,9 @@ pub type CreateOneMutationFn = Arc< pub type CreateBatchMutationFn = Arc< dyn for<'a> Fn( - &ResolverContext<'a>, + &'a ResolverContext<'a>, Arc, - Vec>, + Vec>, ) -> Pin>> + Send + 'a>> + Send + Sync, @@ -54,10 +54,10 @@ pub type CreateBatchMutationFn = Arc< pub type UpdateMutationFn = Arc< dyn for<'a> Fn( - &ResolverContext<'a>, + &'a ResolverContext<'a>, Arc, Condition, - ObjectAccessor<'_>, + ObjectAccessor<'a>, ) -> Pin>> + Send + 'a>> + Send + Sync, @@ -89,12 +89,13 @@ where EntityInputBuilder::update_input_object::(context) } -pub fn generate_entity_default_basic_entity_object(context: Arc) -> Object +pub fn generate_entity_default_basic_entity_object(context: &'static BuilderContext) -> Object where T: EntityTrait, ::Model: Sync, { - EntityObjectBuilder::basic_to_object::(context) + let entity_object_builder = EntityObjectBuilder { context }; + entity_object_builder.basic_to_object::() } pub fn generate_entity_input_object( @@ -113,7 +114,7 @@ where } pub fn generate_entity_filtered_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, field_name: N, type_ref: R, mutation_fn: FilterMutationFn, @@ -124,189 +125,221 @@ where N: Into, R: Into, { - let object_name: String = get_entity_name::(&builder_context); + let object_name: String = get_entity_name::(builder_context); - let guard = builder_context - .guards - .entity_guards - .get(&object_name) - .cloned(); + let guard = builder_context.guards.entity_guards.get(&object_name); - let filter_input_value = InputValue::new( - get_entity_renormalized_filter_field_name(), - TypeRef::named(get_entity_filter_input_type_name::(&builder_context)), - ); - - Field::new(field_name, type_ref, move |ctx| { + Field::new(field_name, type_ref, move |resolve_context| { let mutation_fn = mutation_fn.clone(); - let builder_context = builder_context.clone(); - let guard_flag = if let Some(guard) = guard.as_ref() { - (*guard)(&ctx) - } else { - GuardAction::Allow - }; + FieldFuture::new(async move { + let guard_flag = if let Some(guard) = guard { + (*guard)(&resolve_context) + } else { + GuardAction::Allow + }; + if let GuardAction::Block(reason) = guard_flag { return Err::, async_graphql::Error>(async_graphql::Error::new( reason.unwrap_or("Entity guard triggered.".into()), )); } - let app_ctx = ctx.data::>()?; + let filters = resolve_context + .args + .get(get_entity_renormalized_filter_field_name()); - let filters = ctx.args.get(get_entity_renormalized_filter_field_name()); + let filters = get_filter_conditions::(&resolve_context, builder_context, filters); - let filters = get_filter_conditions::(&ctx, &builder_context, filters); + let app_ctx = resolve_context.data::>()?; - let result = mutation_fn(&ctx, app_ctx.clone(), filters) - .await - .map_err(async_graphql::Error::new_with_source)?; + let result = mutation_fn(&resolve_context, app_ctx.clone(), filters).await?; Ok(result) }) }) - .argument(filter_input_value) + .argument(InputValue::new( + get_entity_renormalized_filter_field_name(), + TypeRef::named(get_entity_filter_input_type_name::(builder_context)), + )) } pub fn generate_entity_create_one_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, mutation_fn: CreateOneMutationFn, ) -> Field where E: EntityTrait, ::Model: Sync, { - EntityCreateOneMutationBuilder::to_field_with_mutation_fn::( - builder_context.clone(), - Arc::new(move |resolver_ctx, input_object| { - let result = resolver_ctx - .data::>() - .map(|app_ctx| mutation_fn(&resolver_ctx, app_ctx.clone(), input_object)); - Box::pin(async move { result?.await.map_err(async_graphql::Error::new_with_source) }) - }), - ) + let entity_create_one_mutation_builder = EntityCreateOneMutationBuilder { + context: builder_context, + }; + entity_create_one_mutation_builder.to_field_with_mutation_fn::(Arc::new( + move |resolver_ctx, input_object| { + let mutation_fn = mutation_fn.clone(); + + Box::pin(async move { + let app_ctx = resolver_ctx.data::>()?; + + let result = mutation_fn(resolver_ctx, app_ctx.clone(), input_object).await?; + + Ok(result) + }) + }, + )) } pub fn generate_entity_default_create_one_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, active_model_hooks: bool, ) -> Field where E: EntityTrait, - ::Model: Sync, - ::Model: IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + ::Model: Sync + IntoActiveModel, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, { - EntityCreateOneMutationBuilder::to_field::(builder_context, active_model_hooks) + let entity_create_one_mutation_builder = EntityCreateOneMutationBuilder { + context: builder_context, + }; + entity_create_one_mutation_builder.to_field::(active_model_hooks) } pub fn generate_entity_create_batch_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, mutation_fn: CreateBatchMutationFn, ) -> Field where E: EntityTrait, ::Model: Sync, { - EntityCreateBatchMutationBuilder::to_field_with_mutation_fn::( - builder_context, - Arc::new(move |resolver_ctx, input_objects| { - let result = resolver_ctx - .data::>() - .map(|app_ctx| mutation_fn(&resolver_ctx, app_ctx.clone(), input_objects)); - Box::pin(async move { result?.await.map_err(async_graphql::Error::new_with_source) }) - }), - ) + let entity_create_batch_mutation_builder = EntityCreateBatchMutationBuilder { + context: builder_context, + }; + entity_create_batch_mutation_builder.to_field_with_mutation_fn::(Arc::new( + move |resolver_ctx, input_objects| { + let mutation_fn = mutation_fn.clone(); + + Box::pin(async move { + let app_ctx = resolver_ctx.data::>()?; + + let result = mutation_fn(resolver_ctx, app_ctx.clone(), input_objects).await?; + + Ok(result) + }) + }, + )) } pub fn generate_entity_default_create_batch_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, active_model_hooks: bool, ) -> Field where E: EntityTrait, ::Model: Sync, ::Model: IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, { - EntityCreateBatchMutationBuilder::to_field::(builder_context, active_model_hooks) + let entity_create_batch_mutation_builder = EntityCreateBatchMutationBuilder { + context: builder_context, + }; + entity_create_batch_mutation_builder.to_field::(active_model_hooks) } pub fn generate_entity_update_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, mutation_fn: UpdateMutationFn, ) -> Field where E: EntityTrait, ::Model: Sync, { - EntityUpdateMutationBuilder::to_field_with_mutation_fn::( - builder_context.clone(), - Arc::new(move |resolver_ctx, filters, input_object| { - let result = resolver_ctx - .data::>() - .map(|app_ctx| { - mutation_fn( - &resolver_ctx, - app_ctx.clone(), - get_filter_conditions::(&resolver_ctx, &builder_context, filters), - input_object, - ) - }); - Box::pin(async move { result?.await.map_err(async_graphql::Error::new_with_source) }) - }), - ) + let entity_update_mutation_builder = EntityUpdateMutationBuilder { + context: builder_context, + }; + entity_update_mutation_builder.to_field_with_mutation_fn::(Arc::new( + move |resolver_ctx, filters, input_object| { + let mutation_fn = mutation_fn.clone(); + + Box::pin(async move { + let app_ctx = resolver_ctx.data::>()?; + + let result = mutation_fn( + resolver_ctx, + app_ctx.clone(), + get_filter_conditions::(resolver_ctx, builder_context, filters), + input_object, + ) + .await + .map_err(async_graphql::Error::new_with_source)?; + + Ok(result) + }) + }, + )) } pub fn generate_entity_default_update_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, active_model_hooks: bool, ) -> Field where E: EntityTrait, ::Model: Sync, ::Model: IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, { - EntityUpdateMutationBuilder::to_field::(builder_context, active_model_hooks) + let entity_update_mutation_builder = EntityUpdateMutationBuilder { + context: builder_context, + }; + entity_update_mutation_builder.to_field::(active_model_hooks) } pub fn generate_entity_delete_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, mutation_fn: DeleteMutationFn, ) -> Field where E: EntityTrait, ::Model: Sync, { - EntityDeleteMutationBuilder::to_field_with_mutation_fn::( - builder_context.clone(), - Arc::new(move |resolver_ctx, filters| { - let result = resolver_ctx - .data::>() - .map(|app_ctx| { - mutation_fn( - &resolver_ctx, - app_ctx.clone(), - get_filter_conditions::(&resolver_ctx, &builder_context, filters), - ) - }); - Box::pin(async move { result?.await.map_err(async_graphql::Error::new_with_source) }) - }), - ) + let entity_delete_mutation_builder = EntityDeleteMutationBuilder { + context: builder_context, + }; + entity_delete_mutation_builder.to_field_with_mutation_fn::(Arc::new( + move |resolver_ctx, filters| { + let mutation_fn = mutation_fn.clone(); + + Box::pin(async move { + let app_ctx = resolver_ctx.data::>()?; + let result = mutation_fn( + resolver_ctx, + app_ctx.clone(), + get_filter_conditions::(resolver_ctx, builder_context, filters), + ) + .await + .map_err(async_graphql::Error::new_with_source)?; + + Ok(result) + }) + }, + )) } pub fn generate_entity_default_delete_mutation_field( - builder_context: Arc, + builder_context: &'static BuilderContext, active_model_hooks: bool, ) -> Field where E: EntityTrait, - ::Model: Sync, - ::Model: IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + ::Model: Sync + IntoActiveModel, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, { - EntityDeleteMutationBuilder::to_field::(builder_context, active_model_hooks) + let entity_delete_mutation_builder = EntityDeleteMutationBuilder { + context: builder_context, + }; + entity_delete_mutation_builder.to_field::(active_model_hooks) } pub fn register_entity_default_mutations( @@ -316,37 +349,31 @@ pub fn register_entity_default_mutations( where E: EntityTrait, ::Model: Sync + IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, { - let builder_context = &builder.context; + let builder_context = builder.context; builder .outputs .push(generate_entity_default_basic_entity_object::( - builder_context.clone(), + builder_context, )); builder.inputs.extend([ - generate_entity_default_insert_input_object::(&builder.context), - generate_entity_default_update_input_object::(&builder.context), + generate_entity_default_insert_input_object::(builder_context), + generate_entity_default_update_input_object::(builder_context), ]); builder.mutations.extend([ generate_entity_default_create_one_mutation_field::( - builder_context.clone(), + builder_context, active_model_hooks, ), generate_entity_default_create_batch_mutation_field::( - builder_context.clone(), - active_model_hooks, - ), - generate_entity_default_update_mutation_field::( - builder_context.clone(), - active_model_hooks, - ), - generate_entity_default_delete_mutation_field::( - builder_context.clone(), + builder_context, active_model_hooks, ), + generate_entity_default_update_mutation_field::(builder_context, active_model_hooks), + generate_entity_default_delete_mutation_field::(builder_context, active_model_hooks), ]); builder @@ -364,7 +391,7 @@ where { builder.register_entity::( ::iter() - .map(|rel| RelationBuilder::get_relation(&rel, builder.context.clone())) + .map(|rel| RelationBuilder::get_relation(&rel, builder.context)) .collect(), ); builder = builder.register_entity_dataloader_one_to_one(entity, tokio::spawn); @@ -380,7 +407,7 @@ pub(crate) fn register_entity_default_writable_impl( where T: EntityTrait, ::Model: Sync + IntoActiveModel, - A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send + 'static, + A: ActiveModelTrait + sea_orm::ActiveModelBehavior + std::marker::Send, RE: sea_orm::Iterable + RelationBuilder, I: Iterator + Clone + DoubleEndedIterator + ExactSizeIterator + FusedIterator, { diff --git a/apps/recorder/src/graphql/infra/json.rs b/apps/recorder/src/graphql/infra/json.rs index c306446..7dc5b90 100644 --- a/apps/recorder/src/graphql/infra/json.rs +++ b/apps/recorder/src/graphql/infra/json.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use async_graphql::{ Error as GraphqlError, dynamic::{ResolverContext, Scalar, SchemaError}, @@ -7,7 +5,6 @@ use async_graphql::{ }; use convert_case::Case; use itertools::Itertools; -use jsonschema::Validator; use rust_decimal::{Decimal, prelude::FromPrimitive}; use sea_orm::{ Condition, EntityTrait, @@ -946,16 +943,20 @@ where T: EntityTrait, ::Model: Sync, { + let entity_column_name = get_entity_and_column_name::(context, column); context.filter_types.overwrites.insert( get_entity_and_column_name::(context, column), Some(FilterType::Custom(JSONB_FILTER_NAME.to_string())), ); + context.filter_types.condition_functions.insert( + entity_column_name.clone(), + generate_jsonb_filter_condition_function::(context, column), + ); } pub fn try_convert_jsonb_input_for_entity( context: &mut BuilderContext, column: &T::Column, - validator: &'static Validator, case: Option>, ) where T: EntityTrait, @@ -965,19 +966,14 @@ pub fn try_convert_jsonb_input_for_entity( let entity_column_name = get_entity_and_column_name::(context, column); context.types.input_conversions.insert( entity_column_name.clone(), - Arc::new(move |_resolve_context, accessor| { - let mut json_value = accessor.as_value().clone().into_json().map_err(|err| { - SeaographyError::TypeConversionError( - err.to_string(), - format!("Json - {entity_column_name}"), - ) - })?; + Box::new(move |_resolve_context, accessor| { + let mut json_value: serde_json::Value = accessor.deserialize()?; if let Some(case) = case { json_value = convert_json_keys(json_value, case); } - validator.validate(&json_value).map_err(|err| { + serde_json::from_value::(json_value.clone()).map_err(|err| { SeaographyError::TypeConversionError( err.to_string(), format!("Json - {entity_column_name}"), @@ -997,10 +993,10 @@ pub fn convert_jsonb_output_for_entity( T: EntityTrait, ::Model: Sync, { - let entity_column_key = get_entity_and_column_name::(context, column); + let entity_column_name = get_entity_and_column_name::(context, column); context.types.output_conversions.insert( - entity_column_key.clone(), - Arc::new(move |value| { + entity_column_name.clone(), + Box::new(move |value| { if let sea_orm::Value::Json(Some(json)) = value { let mut json_value = json.as_ref().clone(); if let Some(case) = case { @@ -1009,14 +1005,14 @@ pub fn convert_jsonb_output_for_entity( let result = async_graphql::Value::from_json(json_value).map_err(|err| { SeaographyError::TypeConversionError( err.to_string(), - format!("Json - {entity_column_key}"), + format!("Json - {entity_column_name}"), ) })?; Ok(result) } else { Err(SeaographyError::TypeConversionError( "value should be json".to_string(), - format!("Json - {entity_column_key}"), + format!("Json - {entity_column_name}"), )) } }), diff --git a/apps/recorder/src/graphql/schema.rs b/apps/recorder/src/graphql/schema.rs index 45ba480..c4e18cf 100644 --- a/apps/recorder/src/graphql/schema.rs +++ b/apps/recorder/src/graphql/schema.rs @@ -59,24 +59,27 @@ pub fn build_schema( ) -> Result { let database = app_ctx.db().as_ref().clone(); - let context = Arc::new({ + let context = CONTEXT.get_or_init(|| { let mut context = BuilderContext::default(); - // basic + renormalize_filter_field_names_to_schema_context(&mut context); renormalize_data_field_names_to_schema_context(&mut context); - // domains - register_feeds_to_schema_context(&mut context); - register_subscribers_to_schema_context(&mut context); - register_subscriptions_to_schema_context(&mut context); - register_subscriber_tasks_to_schema_context(&mut context); - register_credential3rd_to_schema_context(&mut context, app_ctx.clone()); - register_downloaders_to_schema_context(&mut context); - register_downloads_to_schema_context(&mut context); - register_episodes_to_schema_context(&mut context); - register_subscription_bangumi_to_schema_context(&mut context); - register_subscription_episode_to_schema_context(&mut context); - register_bangumi_to_schema_context(&mut context); - register_cron_to_schema_context(&mut context); + + { + // domains + register_feeds_to_schema_context(&mut context); + register_subscribers_to_schema_context(&mut context); + register_subscriptions_to_schema_context(&mut context); + register_subscriber_tasks_to_schema_context(&mut context); + register_credential3rd_to_schema_context(&mut context, app_ctx.clone()); + register_downloaders_to_schema_context(&mut context); + register_downloads_to_schema_context(&mut context); + register_episodes_to_schema_context(&mut context); + register_subscription_bangumi_to_schema_context(&mut context); + register_subscription_episode_to_schema_context(&mut context); + register_bangumi_to_schema_context(&mut context); + register_cron_to_schema_context(&mut context); + } context }); diff --git a/apps/recorder/src/models/subscriber_tasks/mod.rs b/apps/recorder/src/models/subscriber_tasks/mod.rs index fdc9e35..b2d53dc 100644 --- a/apps/recorder/src/models/subscriber_tasks/mod.rs +++ b/apps/recorder/src/models/subscriber_tasks/mod.rs @@ -3,8 +3,8 @@ use sea_orm::{ActiveValue, entity::prelude::*}; use crate::task::SubscriberTaskTrait; pub use crate::task::{ - SubscriberTask, SubscriberTaskType, SubscriberTaskTypeEnum, SubscriberTaskTypeVariant, - SubscriberTaskTypeVariantIter, subscriber_task_schema, + SubscriberTask, SubscriberTaskInput, SubscriberTaskType, SubscriberTaskTypeEnum, + SubscriberTaskTypeVariant, SubscriberTaskTypeVariantIter, }; #[derive(Clone, Debug, PartialEq, Eq, DeriveActiveEnum, EnumIter, DeriveDisplay)] diff --git a/apps/recorder/src/task/core.rs b/apps/recorder/src/task/core.rs index 4da9e44..ffd9fb6 100644 --- a/apps/recorder/src/task/core.rs +++ b/apps/recorder/src/task/core.rs @@ -42,9 +42,13 @@ where } pub trait SubscriberTaskTrait: AsyncTaskTrait { + type InputType: Serialize + DeserializeOwned + Sized + Send; + fn get_subscriber_id(&self) -> i32; fn get_cron_id(&self) -> Option; + + fn from_input(input: Self::InputType, subscriber_id: i32) -> Self; } pub trait SystemTaskTrait: AsyncTaskTrait {} diff --git a/apps/recorder/src/task/mod.rs b/apps/recorder/src/task/mod.rs index 9d327c1..e45a4a2 100644 --- a/apps/recorder/src/task/mod.rs +++ b/apps/recorder/src/task/mod.rs @@ -12,10 +12,10 @@ pub use core::{ pub use config::TaskConfig; pub use r#extern::{ApalisJobs, ApalisSchema}; pub use registry::{ - OptimizeImageTask, SubscriberTask, SubscriberTaskType, SubscriberTaskTypeEnum, - SubscriberTaskTypeVariant, SubscriberTaskTypeVariantIter, SyncOneSubscriptionFeedsFullTask, - SyncOneSubscriptionFeedsIncrementalTask, SyncOneSubscriptionSourcesTask, SystemTask, - SystemTaskType, SystemTaskTypeEnum, SystemTaskTypeVariant, SystemTaskTypeVariantIter, - subscriber_task_schema, + OptimizeImageTask, SubscriberTask, SubscriberTaskInput, SubscriberTaskType, + SubscriberTaskTypeEnum, SubscriberTaskTypeVariant, SubscriberTaskTypeVariantIter, + SyncOneSubscriptionFeedsFullTask, SyncOneSubscriptionFeedsIncrementalTask, + SyncOneSubscriptionSourcesTask, SystemTask, SystemTaskType, SystemTaskTypeEnum, + SystemTaskTypeVariant, SystemTaskTypeVariantIter, }; pub use service::TaskService; diff --git a/apps/recorder/src/task/registry/mod.rs b/apps/recorder/src/task/registry/mod.rs index 2ac9e39..e740667 100644 --- a/apps/recorder/src/task/registry/mod.rs +++ b/apps/recorder/src/task/registry/mod.rs @@ -2,10 +2,9 @@ mod subscriber; mod system; pub use subscriber::{ - SubscriberTask, SubscriberTaskType, SubscriberTaskTypeEnum, SubscriberTaskTypeVariant, - SubscriberTaskTypeVariantIter, SyncOneSubscriptionFeedsFullTask, + SubscriberTask, SubscriberTaskInput, SubscriberTaskType, SubscriberTaskTypeEnum, + SubscriberTaskTypeVariant, SubscriberTaskTypeVariantIter, SyncOneSubscriptionFeedsFullTask, SyncOneSubscriptionFeedsIncrementalTask, SyncOneSubscriptionSourcesTask, - subscriber_task_schema, }; pub use system::{ OptimizeImageTask, SystemTask, SystemTaskType, SystemTaskTypeEnum, SystemTaskTypeVariant, diff --git a/apps/recorder/src/task/registry/subscriber/base.rs b/apps/recorder/src/task/registry/subscriber/base.rs index 04ec593..7af076b 100644 --- a/apps/recorder/src/task/registry/subscriber/base.rs +++ b/apps/recorder/src/task/registry/subscriber/base.rs @@ -6,16 +6,36 @@ macro_rules! register_subscriber_task_type { } ) => { $(#[$type_meta])* - #[derive(typed_builder::TypedBuilder, schemars::JsonSchema, ts_rs::TS)] + #[derive(typed_builder::TypedBuilder, ts_rs::TS, serde::Serialize, serde::Deserialize)] #[ts(export, rename_all = "camelCase")] $task_vis struct $task_name { $($(#[$field_meta])* pub $field_name: $field_type,)* pub subscriber_id: i32, #[builder(default = None)] + #[serde(default, skip_serializing_if = "Option::is_none")] pub cron_id: Option, } + paste::paste! { + $(#[$type_meta])* + #[derive(ts_rs::TS, serde::Serialize, serde::Deserialize)] + #[serde(rename_all = "camelCase")] + #[ts(export, rename_all = "camelCase")] + $task_vis struct [<$task_name Input>] { + $($(#[$field_meta])* pub $field_name: $field_type,)* + #[serde(default, skip_serializing_if = "Option::is_none")] + pub subscriber_id: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cron_id: Option, + } + } + + impl $crate::task::SubscriberTaskTrait for $task_name { + paste::paste! { + type InputType = [<$task_name Input>]; + } + fn get_subscriber_id(&self) -> i32 { self.subscriber_id } @@ -23,6 +43,14 @@ macro_rules! register_subscriber_task_type { fn get_cron_id(&self) -> Option { self.cron_id } + + fn from_input(input: Self::InputType, subscriber_id: i32) -> Self { + Self { + $($field_name: input.$field_name,)* + cron_id: input.cron_id, + subscriber_id: input.subscriber_id.unwrap_or(subscriber_id), + } + } } } } diff --git a/apps/recorder/src/task/registry/subscriber/mod.rs b/apps/recorder/src/task/registry/subscriber/mod.rs index 8aaf108..a4373c0 100644 --- a/apps/recorder/src/task/registry/subscriber/mod.rs +++ b/apps/recorder/src/task/registry/subscriber/mod.rs @@ -1,22 +1,17 @@ mod base; mod subscription; -use jsonschema::Validator; -use once_cell::sync::OnceCell; -use schemars::JsonSchema; use sea_orm::{DeriveActiveEnum, DeriveDisplay, EnumIter, FromJsonQueryResult}; -use serde::{Deserialize, Serialize}; pub use subscription::{ SyncOneSubscriptionFeedsFullTask, SyncOneSubscriptionFeedsIncrementalTask, SyncOneSubscriptionSourcesTask, }; -use ts_rs::TS; macro_rules! register_subscriber_task_types { ( task_type_enum: { $(#[$type_enum_meta:meta])* - pub enum $type_enum_name:ident { + $type_vis:vis enum $type_enum_name:ident { $( $(#[$variant_meta:meta])* $variant:ident => $string_value:literal @@ -25,7 +20,7 @@ macro_rules! register_subscriber_task_types { }, task_enum: { $(#[$task_enum_meta:meta])* - pub enum $task_enum_name:ident { + $task_vis:vis enum $task_enum_name:ident { $( $(#[$task_variant_meta:meta])* $task_variant:ident($task_type:ty) @@ -34,8 +29,9 @@ macro_rules! register_subscriber_task_types { } ) => { $(#[$type_enum_meta])* + #[derive(serde::Serialize, serde::Deserialize)] #[sea_orm(rs_type = "String", db_type = "Text")] - pub enum $type_enum_name { + $type_vis enum $type_enum_name { $( $(#[$variant_meta])* #[serde(rename = $string_value)] @@ -46,9 +42,10 @@ macro_rules! register_subscriber_task_types { $(#[$task_enum_meta])* + #[derive(ts_rs::TS, serde::Serialize, serde::Deserialize)] #[serde(tag = "task_type")] - #[ts(export, rename_all = "camelCase", tag = "taskType")] - pub enum $task_enum_name { + #[ts(export,rename = "SubscriberTaskType", rename_all = "camelCase", tag = "taskType")] + $task_vis enum $task_enum_name { $( $(#[$task_variant_meta])* #[serde(rename = $string_value)] @@ -56,6 +53,20 @@ macro_rules! register_subscriber_task_types { )* } + paste::paste! { + $(#[$task_enum_meta])* + #[derive(ts_rs::TS, serde::Serialize, serde::Deserialize)] + #[serde(tag = "taskType", rename_all = "camelCase")] + #[ts(export,rename_all = "camelCase", tag = "taskType")] + $task_vis enum [<$task_enum_name Input>] { + $( + $(#[$task_variant_meta])* + #[serde(rename = $string_value)] + $task_variant(<$task_type as $crate::task::SubscriberTaskTrait>::InputType), + )* + } + } + impl TryFrom<$task_enum_name> for serde_json::Value { type Error = $crate::errors::RecorderError; @@ -92,6 +103,10 @@ macro_rules! register_subscriber_task_types { } impl $crate::task::SubscriberTaskTrait for $task_enum_name { + paste::paste! { + type InputType = [<$task_enum_name Input>]; + } + fn get_subscriber_id(&self) -> i32 { match self { $(Self::$task_variant(t) => @@ -105,6 +120,14 @@ macro_rules! register_subscriber_task_types { <$task_type as $crate::task::SubscriberTaskTrait>::get_cron_id(t),)* } } + + fn from_input(input: Self::InputType, subscriber_id: i32) -> Self { + match input { + $(Self::InputType::$task_variant(t) => + Self::$task_variant(<$task_type as $crate::task::SubscriberTaskTrait>::from_input(t, subscriber_id)),)* + } + + } } $( @@ -122,8 +145,6 @@ register_subscriber_task_types!( #[derive( Clone, Debug, - Serialize, - Deserialize, PartialEq, Eq, Copy, @@ -138,7 +159,7 @@ register_subscriber_task_types!( } }, task_enum: { - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, FromJsonQueryResult, JsonSchema, TS)] + #[derive(Clone, Debug, PartialEq, Eq, FromJsonQueryResult)] pub enum SubscriberTask { SyncOneSubscriptionFeedsIncremental(SyncOneSubscriptionFeedsIncrementalTask), SyncOneSubscriptionFeedsFull(SyncOneSubscriptionFeedsFullTask), @@ -146,15 +167,3 @@ register_subscriber_task_types!( } } ); - -static SUBSCRIBER_TASK_SCHEMA: OnceCell = OnceCell::new(); - -pub fn subscriber_task_schema() -> &'static Validator { - SUBSCRIBER_TASK_SCHEMA.get_or_init(|| { - let schema = schemars::schema_for!(SubscriberTask); - jsonschema::options() - .with_draft(jsonschema::Draft::Draft7) - .build(&serde_json::to_value(&schema).unwrap()) - .unwrap() - }) -} diff --git a/apps/recorder/src/task/registry/subscriber/subscription.rs b/apps/recorder/src/task/registry/subscriber/subscription.rs index 8f9ef44..678b636 100644 --- a/apps/recorder/src/task/registry/subscriber/subscription.rs +++ b/apps/recorder/src/task/registry/subscriber/subscription.rs @@ -1,5 +1,4 @@ use sea_orm::prelude::*; -use serde::{Deserialize, Serialize}; use super::base::register_subscriber_task_type; use crate::{errors::RecorderResult, models::subscriptions::SubscriptionTrait}; @@ -40,7 +39,7 @@ macro_rules! register_subscription_task_type { } register_subscription_task_type! { - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] pub struct SyncOneSubscriptionFeedsIncrementalTask { } => async |subscription, ctx| -> RecorderResult<()> { subscription.sync_feeds_incremental(ctx).await?; @@ -49,7 +48,7 @@ register_subscription_task_type! { } register_subscription_task_type! { - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] pub struct SyncOneSubscriptionFeedsFullTask { } => async |subscription, ctx| -> RecorderResult<()> { subscription.sync_feeds_full(ctx).await?; @@ -58,7 +57,7 @@ register_subscription_task_type! { } register_subscription_task_type! { - #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] + #[derive(Clone, Debug, PartialEq, Eq)] pub struct SyncOneSubscriptionSourcesTask { } => async |subscription, ctx| -> RecorderResult<()> { subscription.sync_sources(ctx).await?; diff --git a/apps/webui/graphql-codegen.ts b/apps/webui/graphql-codegen.ts index 4c60969..018646b 100644 --- a/apps/webui/graphql-codegen.ts +++ b/apps/webui/graphql-codegen.ts @@ -12,6 +12,12 @@ const config: CodegenConfig = { }, config: { enumsAsConst: true, + scalars: { + SubscriberTaskType: { + input: 'recorder/bindings/SubscriberTaskInput#SubscriberTaskInput', + output: 'recorder/bindings/SubscriberTaskType#SubscriberTaskType', + }, + }, }, }, }, diff --git a/apps/webui/src/domains/recorder/schema/tasks.ts b/apps/webui/src/domains/recorder/schema/tasks.ts index 84fd0a2..ab5ddbb 100644 --- a/apps/webui/src/domains/recorder/schema/tasks.ts +++ b/apps/webui/src/domains/recorder/schema/tasks.ts @@ -1,6 +1,5 @@ import type { GetTasksQuery } from '@/infra/graphql/gql/graphql'; import { gql } from '@apollo/client'; -import type { SubscriberTask } from 'recorder/bindings/SubscriberTask'; export const GET_TASKS = gql` query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) { @@ -21,7 +20,11 @@ export const GET_TASKS = gql` lockAt, lockBy, doneAt, - priority + priority, + subscription { + displayName + sourceUrl + } } paginationInfo { total @@ -64,11 +67,4 @@ export const RETRY_TASKS = gql` } `; -export type SubscriberTaskInsertDto = Omit; - -export type TaskDto = Omit< - GetTasksQuery['subscriberTasks']['nodes'][number], - 'job' -> & { - job: SubscriberTask; -}; +export type TaskDto = GetTasksQuery['subscriberTasks']['nodes'][number]; diff --git a/apps/webui/src/infra/graphql/gql/gql.ts b/apps/webui/src/infra/graphql/gql/gql.ts index f4b3c67..dd50b60 100644 --- a/apps/webui/src/infra/graphql/gql/gql.ts +++ b/apps/webui/src/infra/graphql/gql/gql.ts @@ -27,7 +27,7 @@ type Documents = { "\n mutation UpdateSubscriptions(\n $data: SubscriptionsUpdateInput!,\n $filter: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filter\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": typeof types.UpdateSubscriptionsDocument, "\n mutation DeleteSubscriptions($filter: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filter)\n }\n": typeof types.DeleteSubscriptionsDocument, "\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": typeof types.GetSubscriptionDetailDocument, - "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": typeof types.GetTasksDocument, + "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": typeof types.GetTasksDocument, "\n mutation InsertSubscriberTask($data: SubscriberTasksInsertInput!) {\n subscriberTasksCreateOne(data: $data) {\n id\n }\n }\n": typeof types.InsertSubscriberTaskDocument, "\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": typeof types.DeleteTasksDocument, "\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n }\n": typeof types.RetryTasksDocument, @@ -46,7 +46,7 @@ const documents: Documents = { "\n mutation UpdateSubscriptions(\n $data: SubscriptionsUpdateInput!,\n $filter: SubscriptionsFilterInput!,\n ) {\n subscriptionsUpdate (\n data: $data\n filter: $filter\n ) {\n id\n createdAt\n updatedAt\n displayName\n category\n sourceUrl\n enabled\n }\n}\n": types.UpdateSubscriptionsDocument, "\n mutation DeleteSubscriptions($filter: SubscriptionsFilterInput) {\n subscriptionsDelete(filter: $filter)\n }\n": types.DeleteSubscriptionsDocument, "\nquery GetSubscriptionDetail ($id: Int!) {\n subscriptions(filter: { id: {\n eq: $id\n } }) {\n nodes {\n id\n subscriberId\n displayName\n createdAt\n updatedAt\n category\n sourceUrl\n enabled\n feed {\n nodes {\n id\n createdAt\n updatedAt\n token\n feedType\n feedSource\n }\n }\n subscriberTask {\n nodes {\n id\n taskType\n status\n }\n }\n credential3rd {\n id\n username\n }\n bangumi {\n nodes {\n createdAt\n updatedAt\n id\n mikanBangumiId\n displayName\n season\n seasonRaw\n fansub\n mikanFansubId\n rssLink\n posterLink\n homepage\n }\n }\n }\n }\n}\n": types.GetSubscriptionDetailDocument, - "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": types.GetTasksDocument, + "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n": types.GetTasksDocument, "\n mutation InsertSubscriberTask($data: SubscriberTasksInsertInput!) {\n subscriberTasksCreateOne(data: $data) {\n id\n }\n }\n": types.InsertSubscriberTaskDocument, "\n mutation DeleteTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksDelete(filter: $filter)\n }\n": types.DeleteTasksDocument, "\n mutation RetryTasks($filter: SubscriberTasksFilterInput!) {\n subscriberTasksRetryOne(filter: $filter) {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n }\n": types.RetryTasksDocument, @@ -121,7 +121,7 @@ export function gql(source: "\nquery GetSubscriptionDetail ($id: Int!) {\n subs /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function gql(source: "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"): (typeof documents)["\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"]; +export function gql(source: "\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"): (typeof documents)["\n query GetTasks($filter: SubscriberTasksFilterInput!, $orderBy: SubscriberTasksOrderInput!, $pagination: PaginationInput!) {\n subscriberTasks(\n pagination: $pagination\n filter: $filter\n orderBy: $orderBy\n ) {\n nodes {\n id,\n job,\n taskType,\n status,\n attempts,\n maxAttempts,\n runAt,\n lastError,\n lockAt,\n lockBy,\n doneAt,\n priority,\n subscription {\n displayName\n sourceUrl\n }\n }\n paginationInfo {\n total\n pages\n }\n }\n }\n"]; /** * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/apps/webui/src/infra/graphql/gql/graphql.ts b/apps/webui/src/infra/graphql/gql/graphql.ts index 25054a8..050c1d8 100644 --- a/apps/webui/src/infra/graphql/gql/graphql.ts +++ b/apps/webui/src/infra/graphql/gql/graphql.ts @@ -1,4 +1,6 @@ /* eslint-disable */ +import { SubscriberTaskInput } from 'recorder/bindings/SubscriberTaskInput'; +import { SubscriberTaskType } from 'recorder/bindings/SubscriberTaskType'; import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core'; export type Maybe = T | null; export type InputMaybe = Maybe; @@ -17,6 +19,8 @@ export type Scalars = { /** The `JSON` scalar type represents raw JSON values */ Json: { 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; */ + SubscriberTaskType: { input: SubscriberTaskInput; output: SubscriberTaskType; } }; export type Bangumi = { @@ -350,7 +354,7 @@ export type Cron = { status: CronStatusEnum; subscriber?: Maybe; subscriberId?: Maybe; - subscriberTask?: Maybe; + subscriberTask?: Maybe; subscription?: Maybe; subscriptionId?: Maybe; timeoutMs: Scalars['Int']['output']; @@ -373,7 +377,7 @@ export type CronBasic = { priority: Scalars['Int']['output']; status: CronStatusEnum; subscriberId?: Maybe; - subscriberTask?: Maybe; + subscriberTask?: Maybe; subscriptionId?: Maybe; timeoutMs: Scalars['Int']['output']; updatedAt: Scalars['String']['output']; @@ -420,7 +424,7 @@ export type CronInsertInput = { cronExpr: Scalars['String']['input']; enabled?: InputMaybe; maxAttempts?: InputMaybe; - subscriberTask?: InputMaybe; + subscriberTask?: InputMaybe; timeoutMs?: InputMaybe; }; @@ -1165,9 +1169,6 @@ export type Mutation = { subscriptionsCreateBatch: Array; subscriptionsCreateOne: SubscriptionsBasic; subscriptionsDelete: Scalars['Int']['output']; - subscriptionsSyncOneFeedsFull: SubscriberTasksBasic; - subscriptionsSyncOneFeedsIncremental: SubscriberTasksBasic; - subscriptionsSyncOneSources: SubscriberTasksBasic; subscriptionsUpdate: Array; }; @@ -1396,21 +1397,6 @@ export type MutationSubscriptionsDeleteArgs = { }; -export type MutationSubscriptionsSyncOneFeedsFullArgs = { - filter?: InputMaybe; -}; - - -export type MutationSubscriptionsSyncOneFeedsIncrementalArgs = { - filter?: InputMaybe; -}; - - -export type MutationSubscriptionsSyncOneSourcesArgs = { - filter?: InputMaybe; -}; - - export type MutationSubscriptionsUpdateArgs = { data: SubscriptionsUpdateInput; filter?: InputMaybe; @@ -1606,7 +1592,7 @@ export type SubscriberTasks = { attempts: Scalars['Int']['output']; doneAt?: Maybe; id: Scalars['String']['output']; - job: Scalars['Json']['output']; + job: Scalars['SubscriberTaskType']['output']; lastError?: Maybe; lockAt?: Maybe; lockBy?: Maybe; @@ -1626,7 +1612,7 @@ export type SubscriberTasksBasic = { attempts: Scalars['Int']['output']; doneAt?: Maybe; id: Scalars['String']['output']; - job: Scalars['Json']['output']; + job: Scalars['SubscriberTaskType']['output']; lastError?: Maybe; lockAt?: Maybe; lockBy?: Maybe; @@ -1673,7 +1659,7 @@ export type SubscriberTasksFilterInput = { }; export type SubscriberTasksInsertInput = { - job: Scalars['Json']['input']; + job: Scalars['SubscriberTaskType']['input']; subscriberId?: InputMaybe; }; @@ -2189,7 +2175,7 @@ export type GetTasksQueryVariables = Exact<{ }>; -export type GetTasksQuery = { __typename?: 'Query', subscriberTasks: { __typename?: 'SubscriberTasksConnection', nodes: Array<{ __typename?: 'SubscriberTasks', id: string, job: any, taskType: SubscriberTaskTypeEnum, status: SubscriberTaskStatusEnum, attempts: number, maxAttempts: number, runAt: string, lastError?: string | null, lockAt?: string | null, lockBy?: string | null, doneAt?: string | null, priority: number }>, paginationInfo?: { __typename?: 'PaginationInfo', total: number, pages: number } | null } }; +export type GetTasksQuery = { __typename?: 'Query', subscriberTasks: { __typename?: 'SubscriberTasksConnection', nodes: Array<{ __typename?: 'SubscriberTasks', id: string, job: SubscriberTaskType, taskType: SubscriberTaskTypeEnum, status: SubscriberTaskStatusEnum, attempts: number, maxAttempts: number, runAt: string, lastError?: string | null, lockAt?: string | null, lockBy?: string | null, doneAt?: string | null, priority: number, subscription?: { __typename?: 'Subscriptions', displayName: string, sourceUrl: string } | null }>, paginationInfo?: { __typename?: 'PaginationInfo', total: number, pages: number } | null } }; export type InsertSubscriberTaskMutationVariables = Exact<{ data: SubscriberTasksInsertInput; @@ -2210,7 +2196,7 @@ export type RetryTasksMutationVariables = Exact<{ }>; -export type RetryTasksMutation = { __typename?: 'Mutation', subscriberTasksRetryOne: { __typename?: 'SubscriberTasksBasic', id: string, job: any, taskType: SubscriberTaskTypeEnum, status: SubscriberTaskStatusEnum, attempts: number, maxAttempts: number, runAt: string, lastError?: string | null, lockAt?: string | null, lockBy?: string | null, doneAt?: string | null, priority: number } }; +export type RetryTasksMutation = { __typename?: 'Mutation', subscriberTasksRetryOne: { __typename?: 'SubscriberTasksBasic', id: string, job: SubscriberTaskType, taskType: SubscriberTaskTypeEnum, status: SubscriberTaskStatusEnum, attempts: number, maxAttempts: number, runAt: string, lastError?: string | null, lockAt?: string | null, lockBy?: string | null, doneAt?: string | null, priority: number } }; export const GetCredential3rdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetCredential3rd"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Credential3rdFilterInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Credential3rdOrderInput"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PaginationInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"credential3rd"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"cookies"}},{"kind":"Field","name":{"kind":"Name","value":"username"}},{"kind":"Field","name":{"kind":"Name","value":"password"}},{"kind":"Field","name":{"kind":"Name","value":"userAgent"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"credentialType"}}]}},{"kind":"Field","name":{"kind":"Name","value":"paginationInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -2226,7 +2212,7 @@ export const InsertSubscriptionDocument = {"kind":"Document","definitions":[{"ki export const UpdateSubscriptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateSubscriptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsUpdateInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsUpdate"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}}]}}]}}]} as unknown as DocumentNode; export const DeleteSubscriptionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteSubscriptions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionsFilterInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptionsDelete"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}]}]}}]} as unknown as DocumentNode; export const GetSubscriptionDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetSubscriptionDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriptions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"subscriberId"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"enabled"}},{"kind":"Field","name":{"kind":"Name","value":"feed"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"token"}},{"kind":"Field","name":{"kind":"Name","value":"feedType"}},{"kind":"Field","name":{"kind":"Name","value":"feedSource"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"subscriberTask"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"taskType"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"credential3rd"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"bangumi"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"mikanBangumiId"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"season"}},{"kind":"Field","name":{"kind":"Name","value":"seasonRaw"}},{"kind":"Field","name":{"kind":"Name","value":"fansub"}},{"kind":"Field","name":{"kind":"Name","value":"mikanFansubId"}},{"kind":"Field","name":{"kind":"Name","value":"rssLink"}},{"kind":"Field","name":{"kind":"Name","value":"posterLink"}},{"kind":"Field","name":{"kind":"Name","value":"homepage"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetTasksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTasks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksFilterInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksOrderInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PaginationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriberTasks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"job"}},{"kind":"Field","name":{"kind":"Name","value":"taskType"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"attempts"}},{"kind":"Field","name":{"kind":"Name","value":"maxAttempts"}},{"kind":"Field","name":{"kind":"Name","value":"runAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastError"}},{"kind":"Field","name":{"kind":"Name","value":"lockAt"}},{"kind":"Field","name":{"kind":"Name","value":"lockBy"}},{"kind":"Field","name":{"kind":"Name","value":"doneAt"}},{"kind":"Field","name":{"kind":"Name","value":"priority"}}]}},{"kind":"Field","name":{"kind":"Name","value":"paginationInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetTasksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetTasks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksFilterInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksOrderInput"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"PaginationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriberTasks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"Variable","name":{"kind":"Name","value":"pagination"}}},{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"nodes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"job"}},{"kind":"Field","name":{"kind":"Name","value":"taskType"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"attempts"}},{"kind":"Field","name":{"kind":"Name","value":"maxAttempts"}},{"kind":"Field","name":{"kind":"Name","value":"runAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastError"}},{"kind":"Field","name":{"kind":"Name","value":"lockAt"}},{"kind":"Field","name":{"kind":"Name","value":"lockBy"}},{"kind":"Field","name":{"kind":"Name","value":"doneAt"}},{"kind":"Field","name":{"kind":"Name","value":"priority"}},{"kind":"Field","name":{"kind":"Name","value":"subscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"paginationInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"total"}},{"kind":"Field","name":{"kind":"Name","value":"pages"}}]}}]}}]}}]} as unknown as DocumentNode; export const InsertSubscriberTaskDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"InsertSubscriberTask"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"data"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksInsertInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriberTasksCreateOne"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"data"},"value":{"kind":"Variable","name":{"kind":"Name","value":"data"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const DeleteTasksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteTasks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriberTasksDelete"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}]}]}}]} as unknown as DocumentNode; export const RetryTasksDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RetryTasks"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filter"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriberTasksFilterInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscriberTasksRetryOne"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filter"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filter"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"job"}},{"kind":"Field","name":{"kind":"Name","value":"taskType"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"attempts"}},{"kind":"Field","name":{"kind":"Name","value":"maxAttempts"}},{"kind":"Field","name":{"kind":"Name","value":"runAt"}},{"kind":"Field","name":{"kind":"Name","value":"lastError"}},{"kind":"Field","name":{"kind":"Name","value":"lockAt"}},{"kind":"Field","name":{"kind":"Name","value":"lockBy"}},{"kind":"Field","name":{"kind":"Name","value":"doneAt"}},{"kind":"Field","name":{"kind":"Name","value":"priority"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/apps/webui/src/presentation/routes/_app/tasks/detail.$id.tsx b/apps/webui/src/presentation/routes/_app/tasks/detail.$id.tsx index 070c5c5..067e328 100644 --- a/apps/webui/src/presentation/routes/_app/tasks/detail.$id.tsx +++ b/apps/webui/src/presentation/routes/_app/tasks/detail.$id.tsx @@ -32,6 +32,7 @@ import { } from '@tanstack/react-router'; import { format } from 'date-fns'; import { ArrowLeft, RefreshCw } from 'lucide-react'; +import { useMemo } from 'react'; import { toast } from 'sonner'; import { prettyTaskType } from './-pretty-task-type'; import { getStatusBadge } from './-status-badge'; @@ -104,6 +105,16 @@ function TaskDetailRouteComponent() { }, }); + const job = useMemo(() => { + if (!task) { + return null; + } + return { + ...task.job, + subscription: task.subscription, + }; + }, [task]); + if (loading) { return ; } @@ -247,14 +258,14 @@ function TaskDetailRouteComponent() { {/* Job Details */} - {task.job && ( + {job && ( <>
-                      {JSON.stringify(task.job, null, 2)}
+                      {JSON.stringify(job, null, 2)}
                     
diff --git a/packages/util-derive/src/lib.rs b/packages/util-derive/src/lib.rs index e7020e2..eddbe0e 100644 --- a/packages/util-derive/src/lib.rs +++ b/packages/util-derive/src/lib.rs @@ -2,14 +2,10 @@ extern crate proc_macro; use convert_case::{Case, Casing}; use darling::{FromDeriveInput, FromField, ast::Data, util::Ignored}; -use heck::ToLowerCamelCase; use proc_macro::TokenStream; -use proc_macro_crate::{FoundCrate, crate_name}; -use proc_macro2::{Ident, Span, TokenStream}; -use quote::{format_ident, quote, quote_spanned}; -use syn::{Attribute, DeriveInput, Generics, Ident, parse_macro_input}; - -use crate::derives::attributes::related_attr; +use proc_macro2::Ident; +use quote::{format_ident, quote}; +use syn::{Attribute, DeriveInput, Generics, parse_macro_input}; #[derive(snafu::Snafu, Debug)] enum GeneratorError { @@ -165,135 +161,3 @@ pub fn derive_dynamic_graphql(input: TokenStream) -> TokenStream { Err(err) => err.write_errors().into(), } } - -enum Error { - InputNotEnum, - InvalidEntityPath, - Syn(syn::Error), -} - -struct DeriveRelatedEntity { - entity_ident: TokenStream, - ident: syn::Ident, - variants: syn::punctuated::Punctuated, -} - -impl DeriveRelatedEntity { - fn new(input: syn::DeriveInput) -> Result { - let sea_attr = related_attr::SeaOrm::try_from_attributes(&input.attrs) - .map_err(Error::Syn)? - .unwrap_or_default(); - - let ident = input.ident; - let entity_ident = match sea_attr.entity.as_ref().map(Self::parse_lit_string) { - Some(entity_ident) => entity_ident.map_err(|_| Error::InvalidEntityPath)?, - None => quote! { Entity }, - }; - - let variants = match input.data { - syn::Data::Enum(syn::DataEnum { variants, .. }) => variants, - _ => return Err(Error::InputNotEnum), - }; - - Ok(DeriveRelatedEntity { - entity_ident, - ident, - variants, - }) - } - - fn expand(&self) -> syn::Result { - let ident = &self.ident; - let entity_ident = &self.entity_ident; - - let variant_implementations: Vec = self - .variants - .iter() - .map(|variant| { - let attr = related_attr::SeaOrm::from_attributes(&variant.attrs)?; - - let enum_name = &variant.ident; - - let target_entity = attr - .entity - .as_ref() - .map(Self::parse_lit_string) - .ok_or_else(|| { - syn::Error::new_spanned(variant, "Missing value for 'entity'") - })??; - - let def = match attr.def { - Some(def) => Some(Self::parse_lit_string(&def).map_err(|_| { - syn::Error::new_spanned(variant, "Missing value for 'def'") - })?), - None => None, - }; - - let name = enum_name.to_string().to_lower_camel_case(); - - if let Some(def) = def { - Result::<_, syn::Error>::Ok(quote! { - Self::#enum_name => builder.get_relation::<#entity_ident, #target_entity>(#name, #def) - }) - } else { - Result::<_, syn::Error>::Ok(quote! { - Self::#enum_name => via_builder.get_relation::<#entity_ident, #target_entity>(#name) - }) - } - - }) - .collect::, _>>()?; - - // Get the path of the `async-graphql` on the application's Cargo.toml - let async_graphql_crate = match crate_name("async-graphql") { - // if found, use application's `async-graphql` - Ok(FoundCrate::Name(name)) => { - let ident = Ident::new(&name, Span::call_site()); - quote! { #ident } - } - Ok(FoundCrate::Itself) => quote! { async_graphql }, - // if not, then use the `async-graphql` re-exported by `seaography` - Err(_) => quote! { seaography::async_graphql }, - }; - - Ok(quote! { - impl seaography::RelationBuilder for #ident { - fn get_relation(&self, context: & 'static seaography::BuilderContext) -> #async_graphql_crate::dynamic::Field { - let builder = seaography::EntityObjectRelationBuilder { context }; - let via_builder = seaography::EntityObjectViaRelationBuilder { context }; - match self { - #(#variant_implementations,)* - _ => panic!("No relations for this entity"), - } - } - - } - }) - } - - fn parse_lit_string(lit: &syn::Lit) -> syn::Result { - match lit { - syn::Lit::Str(lit_str) => lit_str - .value() - .parse() - .map_err(|_| syn::Error::new_spanned(lit, "attribute not valid")), - _ => Err(syn::Error::new_spanned(lit, "attribute must be a string")), - } - } -} - -/// Method to derive a Related enumeration -fn expand_derive_related_entity(input: syn::DeriveInput) -> syn::Result { - let ident_span = input.ident.span(); - - match DeriveRelatedEntity::new(input) { - Ok(model) => model.expand(), - Err(Error::InputNotEnum) => Ok(quote_spanned! { - ident_span => compile_error!("you can only derive DeriveRelation on enums"); - }), - Err(Error::InvalidEntityPath) => Ok(quote_spanned! { - ident_span => compile_error!("invalid attribute value for 'entity'"); - }), - Err(Error::Syn(err)) => Err(err), - } -}