feat: add custom types for subscriber id input filter

This commit is contained in:
master 2025-02-23 00:02:03 +08:00
parent c2f74dc369
commit 4f9e74ceb4
5 changed files with 81 additions and 49 deletions

View File

@ -91,7 +91,7 @@ bollard = { version = "0.18", optional = true }
async-graphql = { version = "7.0.15", features = [] } async-graphql = { version = "7.0.15", features = [] }
async-graphql-axum = "7.0.15" async-graphql-axum = "7.0.15"
fastrand = "2.3.0" fastrand = "2.3.0"
seaography = "1.1" seaography = { version = "1.1" }
quirks_path = "0.1.1" quirks_path = "0.1.1"
base64 = "0.22.1" base64 = "0.22.1"
tower = "0.5.2" tower = "0.5.2"

View File

@ -1,27 +0,0 @@
use std::sync::Arc;
use async_graphql::{
ServerResult, Value,
extensions::{Extension, ExtensionContext, ExtensionFactory, NextResolve, ResolveInfo},
};
pub struct GraphqlAuthExtension;
#[async_trait::async_trait]
impl Extension for GraphqlAuthExtension {
async fn resolve(
&self,
ctx: &ExtensionContext<'_>,
info: ResolveInfo<'_>,
next: NextResolve<'_>,
) -> ServerResult<Option<Value>> {
dbg!(info.field);
next.run(ctx, info).await
}
}
impl ExtensionFactory for GraphqlAuthExtension {
fn create(&self) -> Arc<dyn Extension> {
Arc::new(GraphqlAuthExtension)
}
}

View File

@ -0,0 +1,46 @@
use async_graphql::dynamic::{ObjectAccessor, TypeRef};
use maplit::btreeset;
use once_cell::sync::OnceCell;
use sea_orm::{ColumnTrait, Condition, EntityTrait, Value};
use seaography::{BuilderContext, FilterInfo, FilterOperation, SeaResult};
pub static SUBSCRIBER_ID_FILTER_INFO: OnceCell<FilterInfo> = OnceCell::new();
pub fn init_custom_filter_info() {
SUBSCRIBER_ID_FILTER_INFO.get_or_init(|| FilterInfo {
type_name: String::from("SubscriberIdFilterInput"),
base_type: TypeRef::INT.into(),
supported_operations: btreeset! { FilterOperation::Equals },
});
}
pub type FnFilterCondition =
Box<dyn Fn(Condition, &ObjectAccessor) -> SeaResult<Condition> + Send + Sync>;
pub fn subscriber_id_condition_function<T>(
_context: &BuilderContext,
column: &T::Column,
) -> FnFilterCondition
where
T: EntityTrait,
<T as EntityTrait>::Model: Sync,
{
let column = *column;
Box::new(move |mut condition, filter| {
let subscriber_id_filter_info = SUBSCRIBER_ID_FILTER_INFO.get().unwrap();
let operations = &subscriber_id_filter_info.supported_operations;
for operation in operations {
match operation {
FilterOperation::Equals => {
if let Some(value) = filter.get("eq") {
let value: i32 = value.i64()?.try_into()?;
let value = Value::Int(Some(value));
condition = condition.add(column.eq(value));
}
}
_ => unreachable!("unreachable filter operation for subscriber_id"),
}
}
Ok(condition)
})
}

View File

@ -1,8 +1,8 @@
pub mod config; pub mod config;
pub mod extention;
pub mod guard; pub mod guard;
pub mod schema_root; pub mod schema_root;
pub mod service; pub mod service;
pub mod util; pub mod util;
pub mod filter;
pub use schema_root::schema; pub use schema_root::schema;

View File

@ -1,10 +1,13 @@
use async_graphql::dynamic::*; use async_graphql::dynamic::*;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use sea_orm::{DatabaseConnection, EntityTrait, Iterable}; use sea_orm::{DatabaseConnection, EntityTrait, Iterable};
use seaography::{Builder, BuilderContext, FilterType, FnGuard}; use seaography::{Builder, BuilderContext, FilterType, FilterTypesMapHelper};
use super::util::{get_entity_column_key, get_entity_key}; use super::{
use crate::graphql::guard::guard_entity_with_subscriber_id; filter::{SUBSCRIBER_ID_FILTER_INFO, subscriber_id_condition_function},
util::{get_entity_column_key, get_entity_key},
};
use crate::graphql::{filter::init_custom_filter_info, guard::guard_entity_with_subscriber_id};
static CONTEXT: OnceCell<BuilderContext> = OnceCell::new(); static CONTEXT: OnceCell<BuilderContext> = OnceCell::new();
@ -20,19 +23,27 @@ fn restrict_filter_input_for_entity<T>(
context.filter_types.overwrites.insert(key, filter_type); context.filter_types.overwrites.insert(key, filter_type);
} }
fn restrict_subscriber_for_entity<T>( fn restrict_subscriber_for_entity<T>(context: &mut BuilderContext, column: &T::Column)
context: &mut BuilderContext, where
column: &T::Column,
entity_guard: impl FnOnce(&BuilderContext, &T::Column) -> FnGuard,
) where
T: EntityTrait, T: EntityTrait,
<T as EntityTrait>::Model: Sync, <T as EntityTrait>::Model: Sync,
{ {
let entity_key = get_entity_key::<T>(context); let entity_key = get_entity_key::<T>(context);
context let entity_column_key = get_entity_column_key::<T>(context, column);
.guards context.guards.entity_guards.insert(
.entity_guards entity_key,
.insert(entity_key, entity_guard(context, column)); guard_entity_with_subscriber_id::<T>(context, column),
);
context.filter_types.overwrites.insert(
entity_column_key.clone(),
Some(FilterType::Custom(
SUBSCRIBER_ID_FILTER_INFO.get().unwrap().type_name.clone(),
)),
);
context.filter_types.condition_functions.insert(
entity_column_key,
subscriber_id_condition_function::<T>(context, column),
);
} }
pub fn schema( pub fn schema(
@ -41,47 +52,41 @@ pub fn schema(
complexity: Option<usize>, complexity: Option<usize>,
) -> Result<Schema, SchemaError> { ) -> Result<Schema, SchemaError> {
use crate::models::*; use crate::models::*;
init_custom_filter_info();
let context = CONTEXT.get_or_init(|| { let context = CONTEXT.get_or_init(|| {
let mut context = BuilderContext::default(); let mut context = BuilderContext::default();
restrict_subscriber_for_entity::<bangumi::Entity>( restrict_subscriber_for_entity::<bangumi::Entity>(
&mut context, &mut context,
&bangumi::Column::SubscriberId, &bangumi::Column::SubscriberId,
guard_entity_with_subscriber_id::<bangumi::Entity>,
); );
restrict_subscriber_for_entity::<downloaders::Entity>( restrict_subscriber_for_entity::<downloaders::Entity>(
&mut context, &mut context,
&downloaders::Column::SubscriberId, &downloaders::Column::SubscriberId,
guard_entity_with_subscriber_id::<downloaders::Entity>,
); );
restrict_subscriber_for_entity::<downloads::Entity>( restrict_subscriber_for_entity::<downloads::Entity>(
&mut context, &mut context,
&downloads::Column::SubscriberId, &downloads::Column::SubscriberId,
guard_entity_with_subscriber_id::<downloads::Entity>,
); );
restrict_subscriber_for_entity::<episodes::Entity>( restrict_subscriber_for_entity::<episodes::Entity>(
&mut context, &mut context,
&episodes::Column::SubscriberId, &episodes::Column::SubscriberId,
guard_entity_with_subscriber_id::<episodes::Entity>,
); );
restrict_subscriber_for_entity::<subscriptions::Entity>( restrict_subscriber_for_entity::<subscriptions::Entity>(
&mut context, &mut context,
&subscriptions::Column::SubscriberId, &subscriptions::Column::SubscriberId,
guard_entity_with_subscriber_id::<subscriptions::Entity>,
); );
restrict_subscriber_for_entity::<subscribers::Entity>( restrict_subscriber_for_entity::<subscribers::Entity>(
&mut context, &mut context,
&subscribers::Column::Id, &subscribers::Column::Id,
guard_entity_with_subscriber_id::<subscribers::Entity>,
); );
restrict_subscriber_for_entity::<subscription_bangumi::Entity>( restrict_subscriber_for_entity::<subscription_bangumi::Entity>(
&mut context, &mut context,
&subscription_bangumi::Column::SubscriberId, &subscription_bangumi::Column::SubscriberId,
guard_entity_with_subscriber_id::<subscription_bangumi::Entity>,
); );
restrict_subscriber_for_entity::<subscription_episode::Entity>( restrict_subscriber_for_entity::<subscription_episode::Entity>(
&mut context, &mut context,
&subscription_episode::Column::SubscriberId, &subscription_episode::Column::SubscriberId,
guard_entity_with_subscriber_id::<subscription_episode::Entity>,
); );
for column in subscribers::Column::iter() { for column in subscribers::Column::iter() {
if !matches!(column, subscribers::Column::Id) { if !matches!(column, subscribers::Column::Id) {
@ -96,6 +101,14 @@ pub fn schema(
}); });
let mut builder = Builder::new(context, database.clone()); let mut builder = Builder::new(context, database.clone());
{
let filter_types_map_helper = FilterTypesMapHelper { context };
builder.schema = builder.schema.register(
filter_types_map_helper.generate_filter_input(SUBSCRIBER_ID_FILTER_INFO.get().unwrap()),
);
}
{ {
builder.register_entity::<subscribers::Entity>( builder.register_entity::<subscribers::Entity>(
<subscribers::RelatedEntity as sea_orm::Iterable>::iter() <subscribers::RelatedEntity as sea_orm::Iterable>::iter()