Skip to content

Commit

Permalink
feat(api): more filters and basic ordering (#18)
Browse files Browse the repository at this point in the history
* misc: Cleanup

* feat(sdk): Refactor query building and add more filters + sorting

* feat(api): Add more filters and ordering to API

* style: fmt

* misc: Rename `Attribute` to `Property` across the board

* Revert "misc: Rename `Attribute` to `Property` across the board"

This reverts commit 00dc6a0.

* fix(api): Entity types

* misc: "Fix" codegen

* test(sdk): Fix tests

* docs: Update GraphQL schema

* style(sdk): clippy + fmt

* test: Remove unused tests

* test(sdk): Fix tests (again)
  • Loading branch information
cvauclair authored Jan 21, 2025
1 parent 631c30b commit 77cf985
Show file tree
Hide file tree
Showing 33 changed files with 2,246 additions and 635 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ serde = "1.0.216"
serde_json = "1.0.133"
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }

sdk = { version = "0.1.0", path = "../sdk" }
chrono = "0.4.39"
Expand Down
99 changes: 87 additions & 12 deletions api/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
directive @specifiedBy(url: String!) on SCALAR

input AttributeFilter {
valueType: ValueType
}
Expand Down Expand Up @@ -26,19 +28,69 @@ type Entity {
attributes(filter: AttributeFilter): [Triple!]!

"""Relations outgoing from the entity"""
relations: [Relation!]!
relations(where: EntityRelationFilter): [Relation!]!
}

"""Filter the entities by attributes and their values and value types"""
input EntityAttributeFilter {
attribute: String!
value: String
valueNot: String
valueIn: [String!]
valueNotIn: [String!]
valueType: ValueType
valueTypeNot: ValueType
valueTypeIn: [ValueType!]
valueTypeNotIn: [ValueType!]
}

"""
Entity filter input object
```graphql
query {
entities(where: {
space_id: "BJqiLPcSgfF8FRxkFr76Uy",
types_contain: ["XG26vy98XAA6cR6DosTALk", "XG26vy98XAA6cR6DosTALk"],
attributes_contain: [
{id: "XG26vy98XAA6cR6DosTALk", value: "value", value_type: TEXT},
]
})
}
```
"""
input EntityFilter {
id: String
idNot: String
idIn: [String!]
idNotIn: [String!]

"""Exact match for the entity types"""
types: [String!]
typesNot: [String!]
typesContains: [String!]
typesNotContains: [String!]
attributes: [EntityAttributeFilter!]
}

input EntityWhereFilter {
spaceId: String
typesContain: [String!]
attributesContain: [EntityAttributeFilter!]
"""Filters the outgoing relations of the entity"""
input EntityRelationFilter {
id: String
idNot: String
idIn: [String!]
idNotIn: [String!]
toId: String
toIdNot: String
toIdIn: [String!]
toIdNotIn: [String!]
relationType: String
relationTypeNot: String
relationTypeIn: [String!]
relationTypeNotIn: [String!]

"""Filter the relations by the entity they point to"""
to: EntityFilter
attributes: [EntityAttributeFilter!]
}

type Options {
Expand All @@ -47,22 +99,27 @@ type Options {
language: String
}

enum OrderDirection {
ASC
DESC
}

type Query {
"""Returns a single entity identified by its ID and space ID"""
entity(id: String!, spaceId: String!): Entity

"""
Returns multiple entities according to the provided space ID and filter
"""
entities(where: EntityWhereFilter): [Entity!]!
entities(spaceId: String!, orderBy: String, orderDirection: OrderDirection, where: EntityFilter): [Entity!]!

"""Returns a single relation identified by its ID and space ID"""
relation(id: String!, spaceId: String!): Relation

"""
Returns multiple relations according to the provided space ID and filter
"""
relations(spaceId: String!, filter: RelationFilter): [Relation!]!
relations(spaceId: String!, orderBy: String, orderDirection: OrderDirection, filter: RelationFilter): [Relation!]!
}

"""
Expand All @@ -86,8 +143,8 @@ type Relation {
"""Attributes of the relation"""
attributes: [Triple!]!

"""Relation types of the relation"""
relationTypes: [Entity!]!
"""Relation type of the relation"""
relationType: [Entity!]!

"""Entity from which the relation originates"""
from: Entity!
Expand All @@ -96,13 +153,31 @@ type Relation {
to: Entity!

"""Relations outgoing from the relation"""
relations: [Relation!]!
relations(spaceId: String!, where: EntityRelationFilter): [Relation!]!
}

"""Relation filter input object"""
input RelationFilter {
"""Filter by relation types"""
relationTypes: [String!]
"""Filter the relations by their id"""
id: String
idNot: String
idIn: [String!]
idNotIn: [String!]

"""Filter the relations by their relation type"""
relationType: String
relationTypeNot: String
relationTypeIn: [String!]
relationTypeNotIn: [String!]

"""Filter the relations by the entity they point to"""
to: EntityFilter

"""Filter the relations by the entity they point from"""
from: EntityFilter

"""Filter the relations by their attributes"""
attributes: [EntityAttributeFilter!]
}

type Triple {
Expand Down
119 changes: 119 additions & 0 deletions api/src/schema/attribute_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use juniper::GraphQLInputObject;

use sdk::mapping;

use crate::schema::ValueType;

/// Filter the entities by attributes and their values and value types
#[derive(Debug, GraphQLInputObject)]
pub struct EntityAttributeFilter {
pub attribute: String,

pub value: Option<String>,
pub value_not: Option<String>,
pub value_in: Option<Vec<String>>,
pub value_not_in: Option<Vec<String>>,

pub value_type: Option<ValueType>,
pub value_type_not: Option<ValueType>,
pub value_type_in: Option<Vec<ValueType>>,
pub value_type_not_in: Option<Vec<ValueType>>,
}

impl EntityAttributeFilter {
pub fn add_to_entity_query(
self,
mut query: mapping::entity_queries::FindMany,
) -> mapping::entity_queries::FindMany {
if let Some(value) = self.value {
query = query.attribute(&self.attribute, &value);
}

if let Some(value_not) = self.value_not {
query = query.attribute_not(&self.attribute, &value_not);
}

if let Some(value_in) = self.value_in {
query = query.attribute_in(&self.attribute, value_in.clone());
}

if let Some(value_not_in) = self.value_not_in {
query = query.attribute_not_in(&self.attribute, value_not_in.clone());
}

if let Some(value_type) = self.value_type {
query = query.attribute_value_type(&self.attribute, &value_type.to_string());
}

if let Some(value_type_not) = self.value_type_not {
query = query.attribute_value_type_not(&self.attribute, &value_type_not.to_string());
}

if let Some(value_type_in) = self.value_type_in {
query = query.attribute_value_type_in(
&self.attribute,
value_type_in.into_iter().map(|vt| vt.to_string()).collect(),
);
}

if let Some(value_type_not_in) = self.value_type_not_in {
query = query.attribute_value_type_not_in(
&self.attribute,
value_type_not_in
.into_iter()
.map(|vt| vt.to_string())
.collect(),
);
}

query
}

pub fn add_to_relation_query(
self,
mut query: mapping::relation_queries::FindMany,
) -> mapping::relation_queries::FindMany {
if let Some(value) = self.value {
query = query.attribute(&self.attribute, &value);
}

if let Some(value_not) = self.value_not {
query = query.attribute_not(&self.attribute, &value_not);
}

if let Some(value_in) = self.value_in {
query = query.attribute_in(&self.attribute, value_in.clone());
}

if let Some(value_not_in) = self.value_not_in {
query = query.attribute_not_in(&self.attribute, value_not_in.clone());
}

if let Some(value_type) = self.value_type {
query = query.attribute_value_type(&self.attribute, &value_type.to_string());
}

if let Some(value_type_not) = self.value_type_not {
query = query.attribute_value_type_not(&self.attribute, &value_type_not.to_string());
}

if let Some(value_type_in) = self.value_type_in {
query = query.attribute_value_type_in(
&self.attribute,
value_type_in.into_iter().map(|vt| vt.to_string()).collect(),
);
}

if let Some(value_type_not_in) = self.value_type_not_in {
query = query.attribute_value_type_not_in(
&self.attribute,
value_type_not_in
.into_iter()
.map(|vt| vt.to_string())
.collect(),
);
}

query
}
}
Loading

0 comments on commit 77cf985

Please sign in to comment.