Skip to content

Commit

Permalink
Introduce Filter and StringFilter inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
sandreae committed Mar 21, 2023
1 parent 4d6ad2f commit 01244f5
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 7 deletions.
7 changes: 6 additions & 1 deletion aquadoggo/src/graphql/queries/all_documents.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

use async_graphql::dynamic::{Field, FieldFuture, Object, TypeRef};
use async_graphql::dynamic::{Field, FieldFuture, InputValue, Object, TypeRef};
use dynamic_graphql::FieldValue;
use log::debug;
use p2panda_rs::document::traits::AsDocument;
Expand All @@ -10,6 +10,7 @@ use p2panda_rs::storage_provider::traits::DocumentStore;
use crate::db::SqlStore;
use crate::graphql::constants;
use crate::graphql::scalars::{DocumentIdScalar, DocumentViewIdScalar};
use crate::graphql::utils::filter_name;

/// Adds GraphQL query for getting all documents of a certain p2panda schema to the root query
/// object.
Expand Down Expand Up @@ -53,6 +54,10 @@ pub fn build_all_documents_query(query: Object, schema: &Schema) -> Object {
})
},
)
.argument(InputValue::new(
"filter",
TypeRef::named(filter_name(&schema.id())),
).description("Filter the query based on passed arguments"))
.description(format!("Get all {} documents.", schema.name())),
)
}
Expand Down
19 changes: 13 additions & 6 deletions aquadoggo/src/graphql/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ use crate::graphql::scalars::{
DocumentIdScalar, DocumentViewIdScalar, EncodedEntryScalar, EncodedOperationScalar,
EntryHashScalar, LogIdScalar, PublicKeyScalar, SeqNumScalar,
};
use crate::graphql::types::{Document, DocumentFields, DocumentMeta, NextArguments};
use crate::graphql::types::{
Document, DocumentFields, DocumentMeta, FilterInput, NextArguments, StringFilter,
};
use crate::schema::SchemaProvider;

/// Returns GraphQL API schema for p2panda node.
Expand Down Expand Up @@ -48,7 +50,8 @@ pub async fn build_root_schema(
.register::<EntryHashScalar>()
.register::<LogIdScalar>()
.register::<PublicKeyScalar>()
.register::<SeqNumScalar>();
.register::<SeqNumScalar>()
.register::<StringFilter>();

// Construct the schema builder.
let mut schema_builder = Schema::build("Query", Some("MutationRoot"), None);
Expand All @@ -63,16 +66,20 @@ pub async fn build_root_schema(
// Loop through all schema retrieved from the schema store, create types and a root query for the
// documents they describe.
for schema in all_schema {
// Construct the document fields object which will be named `<schema_id>Field`.
// Construct the fields type object which will be named `<schema_id>Field`.
let document_schema_fields = DocumentFields::build(&schema);

// Construct the document schema which has "fields" and "meta" fields.
// Construct the schema type object which contains "fields" and "meta" fields.
let document_schema = Document::build(&schema);

// Register a schema and schema fields type for every schema.
// Construct the filter input type object.
let filter_input = FilterInput::build(&schema);

// Register a schema, schema fields and filter type for every schema.
schema_builder = schema_builder
.register(document_schema_fields)
.register(document_schema);
.register(document_schema)
.register(filter_input);

// Add a query object for each schema. It offers an interface to retrieve a single
// document of this schema by it's document id or view id. Its resolver parses and
Expand Down
71 changes: 71 additions & 0 deletions aquadoggo/src/graphql/types/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: AGPL-3.0-or-later

use async_graphql::dynamic::{InputObject, InputValue, TypeRef};
use dynamic_graphql::InputObject;
use p2panda_rs::schema::Schema;

use crate::graphql::utils::filter_name;

/// A filter input type for string field values.
#[derive(InputObject)]
pub struct StringFilter {
/// Filter by values in set.
#[graphql(name = "in")]
is_in: Option<Vec<String>>,

/// Filter by values not in set.
#[graphql(name = "notIn")]
is_not_in: Option<Vec<String>>,

/// Filter by equal to.
#[graphql(name = "eq")]
eq: Option<String>,

/// Filter by not equal to.
#[graphql(name = "notEq")]
not_eq: Option<String>,

/// Filter by greater than or equal to.
gte: Option<String>,

/// Filter by greater than.
gt: Option<String>,

/// Filter by less than or equal to.
lte: Option<String>,

/// Filter by less than.
lt: Option<String>,

/// Filter for items which contain given string.
contains: Option<String>,

/// Filter for items which don't contain given string.
#[graphql(name = "notContains")]
not_contains: Option<String>,
}

/// GraphQL object which represents a filter input type which contains a filter object for every
/// field on the passed p2panda schema.
///
/// A type is added to the root GraphQL schema for every filter, as these types
/// are not known at compile time we make use of the `async-graphql ` `dynamic` module.
pub struct FilterInput;

impl FilterInput {
/// Build a filter input object for a p2panda schema. It can be used to filter results based
/// on field values when querying for documents of this schema.
pub fn build(schema: &Schema) -> InputObject {
// Construct the document fields object which will be named `<schema_id>Filter`.
let schema_field_name = filter_name(schema.id());
let mut filter_input = InputObject::new(&schema_field_name);

// For every field in the schema we create a type with a resolver.
for (name, _field_type) in schema.fields().iter() {
filter_input =
filter_input.field(InputValue::new(name, TypeRef::named("StringFilter")));
}

filter_input
}
}
2 changes: 2 additions & 0 deletions aquadoggo/src/graphql/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ mod document;
mod document_fields;
mod document_meta;
mod next_arguments;
mod filter;

pub use document::Document;
pub use document_fields::DocumentFields;
pub use document_meta::DocumentMeta;
pub use next_arguments::NextArguments;
pub use filter::{StringFilter, FilterInput};
6 changes: 6 additions & 0 deletions aquadoggo/src/graphql/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ use crate::db::{types::StorageDocument, SqlStore};
use crate::graphql::scalars::{DocumentIdScalar, DocumentViewIdScalar};

const DOCUMENT_FIELDS_SUFFIX: &str = "Fields";
const FILTER_INPUT_SUFFIX: &str = "Filter";

// Correctly formats the name of a document field type.
pub fn fields_name(schema_id: &SchemaId) -> String {
format!("{}{DOCUMENT_FIELDS_SUFFIX}", schema_id)
}

// Correctly formats the name of a document filter type.
pub fn filter_name(schema_id: &SchemaId) -> String {
format!("{}{FILTER_INPUT_SUFFIX}", schema_id)
}

/// Convert non-relation operation values into GraphQL values.
///
/// Panics when given a relation field value.
Expand Down

0 comments on commit 01244f5

Please sign in to comment.