-
I've seen a few people get and/or/not filters working in graphql. This appears to be a weird use case so it's fair that graphql doesn't support it. I would like to build an "adavanced search" where the user can do stuff like "Show me all users who are active AND who's name starts with "wil" OR "bob". I'd like some input from the developers on what would be the best approach for tackling this. I believe an input type would make every provided field an "AND" so right now I'm thinking the front end will just have to make multiple calls and combine the "AND" queries as best it can then do the actual filtering on the browser side |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
@twiclo GraphQL doesn't have native support for the operations, so your options are:
{
products(first: 5, query: "(title:Caramel Apple) OR (inventory_total:>500 inventory_total:<=1000)" ) {
edges {
node {
id
title
createdAt
totalInventory
}
}
}
}
#[derive(GraphQLInputObject)]
struct UserFilter {
and: Option<Vec<Box<UserFilter>>>,
or: Option<Vec<Box<UserFilter>>>,
id: Option<i32>,
name: Option<String>,
} Full exampleuse std::env;
use actix_cors::Cors;
use actix_web::{
http::header,
middleware,
web::{self, Data},
App, Error, HttpResponse, HttpServer,
};
use juniper::{
graphql_object, EmptyMutation, EmptySubscription, GraphQLInputObject, GraphQLObject, RootNode,
};
use juniper_actix::{graphiql_handler, graphql_handler, playground_handler};
#[derive(Clone, GraphQLObject)]
pub struct User {
id: i32,
name: String,
}
#[derive(GraphQLInputObject)]
struct UserFilter {
and: Option<Vec<Box<UserFilter>>>,
or: Option<Vec<Box<UserFilter>>>,
id: Option<i32>,
name: Option<String>,
}
struct Query;
#[graphql_object]
impl Query {
fn users(filter: UserFilter) -> Vec<User> {
// TODO: actual query
filter
.and
.into_iter()
.chain(filter.or)
.flatten()
.filter_map(|u| {
(u.id.is_some() || u.name.is_some()).then(|| User {
id: u.id.unwrap_or(1),
name: u.name.unwrap_or_else(|| "unknown".to_owned()),
})
})
.collect()
}
}
type Schema = RootNode<'static, Query, EmptyMutation, EmptySubscription>;
fn schema() -> Schema {
Schema::new(Query, EmptyMutation::new(), EmptySubscription::new())
}
async fn graphiql_route() -> Result<HttpResponse, Error> {
graphiql_handler("/graphql", None).await
}
async fn playground_route() -> Result<HttpResponse, Error> {
playground_handler("/graphql", None).await
}
async fn graphql_route(
req: actix_web::HttpRequest,
payload: web::Payload,
schema: Data<Schema>,
) -> Result<HttpResponse, Error> {
graphql_handler(&schema, &(), req, payload).await
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env::set_var("RUST_LOG", "info");
env_logger::init();
let server = HttpServer::new(move || {
App::new()
.app_data(Data::new(schema()))
.wrap(
Cors::default()
.allow_any_origin()
.allowed_methods(vec!["POST", "GET"])
.allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT])
.allowed_header(header::CONTENT_TYPE)
.supports_credentials()
.max_age(3600),
)
.wrap(middleware::Compress::default())
.wrap(middleware::Logger::default())
.service(
web::resource("/graphql")
.route(web::post().to(graphql_route))
.route(web::get().to(graphql_route)),
)
.service(web::resource("/playground").route(web::get().to(playground_route)))
.service(web::resource("/graphiql").route(web::get().to(graphiql_route)))
});
server.bind("127.0.0.1:8080").unwrap().run().await
} Querying at query {
users(filter: { or: [{ id: 10, name: "ten" }, { id: 12 }, { name: "Ben" }] }) {
id
name
}
} Response: {
"data": {
"users": [
{
"id": 10,
"name": "ten"
},
{
"id": 12,
"name": "unknown"
},
{
"id": 1,
"name": "Ben"
}
]
}
} |
Beta Was this translation helpful? Give feedback.
@twiclo GraphQL doesn't have native support for the operations, so your options are:
String!
query and parse it on the backend. Shopify does thisFull example