Skip to content

Commit

Permalink
doc: Add docs to graphql schema
Browse files Browse the repository at this point in the history
  • Loading branch information
cvauclair committed Dec 20, 2024
1 parent 3ae7ecf commit e6b50a3
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 45 deletions.
123 changes: 123 additions & 0 deletions api/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
"""Entity object"""
type Entity {
"""Entity ID"""
id: String!

"""Entity name (if available)"""
name: String

"""
The space ID of the entity (note: the same entity can exist in multiple spaces)
"""
spaceId: String!
createdAt: String!
createdAtBlock: String!
updatedAt: String!
updatedAtBlock: String!

"""Types of the entity (which are entities themselves)"""
types: [Entity!]!

"""Attributes of the entity"""
attributes: [Triple!]!

"""Relations outgoing from the entity"""
relations: [Relation!]!
}

"""Entity filter input object"""
input EntityFilter {
"""Filter by entity types"""
types: [String!]
}

type Options {
format: String
unit: String
language: String
}

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(spaceId: String!, filter: 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!]!
}

"""
Relation object
Note: Relations are also entities, but they have a different structure in the database.
In other words, the Relation object is a "view" on a relation entity. All relations
can also be queried as entities.
"""
type Relation {
"""Relation ID"""
id: String!

"""Relation name (if available)"""
name: String
createdAt: String!
createdAtBlock: String!
updatedAt: String!
updatedAtBlock: String!

"""Attributes of the relation"""
attributes: [Triple!]!

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

"""Entity from which the relation originates"""
from: Entity!

"""Entity to which the relation points"""
to: Entity!

"""Relations outgoing from the relation"""
relations: [Relation!]!
}

"""Relation filter input object"""
input RelationFilter {
"""Filter by relation types"""
relationTypes: [String!]
}

type Triple {
"""Attribute ID of the triple"""
attribute: String!

"""Value of the triple"""
value: String!

"""Value type of the triple"""
valueType: ValueType!

"""Options of the triple (if any)"""
options: Options!

"""Name of the attribute (if available)"""
name: String
}

enum ValueType {
TEXT
NUMBER
CHECKBOX
URL
TIME
POINT
}

78 changes: 33 additions & 45 deletions api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub struct Query;
#[graphql_object]
#[graphql(context = KnowledgeGraph, scalar = S: ScalarValue)]
impl Query {
/// Returns a single entity identified by its ID and space ID
async fn entity<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand All @@ -45,6 +46,7 @@ impl Query {
.map(Entity::from)
}

/// Returns multiple entities according to the provided space ID and filter
async fn entities<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand Down Expand Up @@ -79,6 +81,7 @@ impl Query {
}
}

/// Returns a single relation identified by its ID and space ID
async fn relation<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand All @@ -92,6 +95,7 @@ impl Query {
.map(|rel| rel.into())
}

/// Returns multiple relations according to the provided space ID and filter
async fn relations<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand All @@ -100,7 +104,7 @@ impl Query {
filter: Option<RelationFilter>,

Check warning on line 104 in api/src/main.rs

View workflow job for this annotation

GitHub Actions / stable / fmt

Diff in /home/runner/work/kg-node/kg-node/api/src/main.rs
) -> Vec<Relation> {
match filter {
(Some(RelationFilter { relation_types: Some(types) })) if !types.is_empty() => {
Some(RelationFilter { relation_types: Some(types) }) if !types.is_empty() => {
mapping::Relation::<mapping::Triples>::find_by_types(
&executor.context().0.neo4j,
&types,
Expand All @@ -124,59 +128,20 @@ impl Query {
}
}

/// Entity filter input object
#[derive(Debug, GraphQLInputObject)]
struct EntityFilter {
/// Filter by entity types
types: Option<Vec<String>>,
}

/// Relation filter input object
#[derive(Debug, GraphQLInputObject)]
struct RelationFilter {
/// Filter by relation types
relation_types: Option<Vec<String>>,
}

// Attributes GraphQL scalar
#[derive(Clone, Debug, GraphQLScalar)]
#[graphql(with = attributes)]
pub struct Attributes(HashMap<String, serde_json::Value>);

mod attributes {
use juniper::{InputValue, ParseScalarResult, ScalarToken, ScalarValue, Value};

use super::*;

fn serde_to_graphql<S: ScalarValue>(v: &serde_json::Value) -> Value<S> {
match v {
serde_json::Value::String(s) => Value::scalar(s.clone()),
serde_json::Value::Number(n) => Value::scalar(n.as_i64().unwrap() as i32),
serde_json::Value::Bool(b) => Value::scalar(*b),
serde_json::Value::Array(a) => Value::List(a.iter().map(serde_to_graphql).collect()),
_ => Value::null(),
}
}

pub(super) fn to_output<S: ScalarValue>(v: &Attributes) -> Value<S> {
Value::Object(v.0.iter().fold(
juniper::Object::with_capacity(v.0.len()),
|mut obj, (k, v)| {
obj.add_field(k, serde_to_graphql(v));
obj
},
))
}

pub(super) fn from_input<S: ScalarValue>(_v: &InputValue<S>) -> Result<Attributes, String> {
// v.as_string_value()
// .map(|s| StringOrInt::String(s.into()))
// .or_else(|| v.as_int_value().map(StringOrInt::Int))
// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
unimplemented!()
}

pub(super) fn parse_token<S: ScalarValue>(_t: ScalarToken<'_>) -> ParseScalarResult<S> {
unimplemented!()
}
}

#[derive(Debug)]
pub struct Entity {
id: String,
Expand Down Expand Up @@ -221,18 +186,22 @@ impl From<mapping::Entity<mapping::Triples>> for Entity {

#[graphql_object]
#[graphql(context = KnowledgeGraph, scalar = S: ScalarValue)]
/// Entity object
impl Entity {
/// Entity ID
fn id(&self) -> &str {
&self.id
}

/// Entity name (if available)
fn name(&self) -> Option<&str> {
self.attributes
.iter()
.find(|triple| triple.attribute == system_ids::NAME)
.map(|triple| triple.value.as_str())
}

/// The space ID of the entity (note: the same entity can exist in multiple spaces)
fn space_id(&self) -> &str {
&self.space_id
}
Expand All @@ -253,6 +222,7 @@ impl Entity {
&self.updated_at_block
}

/// Types of the entity (which are entities themselves)
async fn types<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand Down Expand Up @@ -295,10 +265,12 @@ impl Entity {
}
}

/// Attributes of the entity
fn attributes(&self) -> &[Triple] {
&self.attributes
}

/// Relations outgoing from the entity
async fn relations<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand Down Expand Up @@ -382,11 +354,18 @@ impl From<mapping::Relation<mapping::Triples>> for Relation {

#[graphql_object]

Check warning on line 355 in api/src/main.rs

View workflow job for this annotation

GitHub Actions / stable / fmt

Diff in /home/runner/work/kg-node/kg-node/api/src/main.rs
#[graphql(context = KnowledgeGraph, scalar = S: ScalarValue)]
/// Relation object
///
/// Note: Relations are also entities, but they have a different structure in the database.
/// In other words, the Relation object is a "view" on a relation entity. All relations
/// can also be queried as entities.
impl Relation {
/// Relation ID
fn id(&self) -> &str {
&self.id
}

/// Relation name (if available)
fn name(&self) -> Option<&str> {
self.attributes
.iter()
Expand All @@ -410,15 +389,16 @@ impl Relation {
&self.updated_at_block
}

/// Attributes of the relation
fn attributes(&self) -> &[Triple] {
&self.attributes
}

/// Relation types of the relation
async fn relation_types<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
) -> Vec<Entity> {
println!("Relation types: {:?}", self.relation_types);
mapping::Entity::<mapping::Triples>::find_by_ids(
&executor.context().0.neo4j,
&self.relation_types,
Expand All @@ -432,6 +412,7 @@ impl Relation {
.collect::<Vec<_>>()
}

/// Entity from which the relation originates
async fn from<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand All @@ -447,6 +428,7 @@ impl Relation {
.unwrap()
}

/// Entity to which the relation points
async fn to<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand All @@ -462,6 +444,7 @@ impl Relation {
.unwrap()
}

/// Relations outgoing from the relation
async fn relations<'a, S: ScalarValue>(
&'a self,
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand Down Expand Up @@ -491,22 +474,27 @@ struct Triple {
#[graphql_object]
#[graphql(context = KnowledgeGraph, scalar = S: ScalarValue)]
impl Triple {
/// Attribute ID of the triple
fn attribute(&self) -> &str {
&self.attribute
}

/// Value of the triple
fn value(&self) -> &str {
&self.value
}

/// Value type of the triple
fn value_type(&self) -> &ValueType {
&self.value_type
}

/// Options of the triple (if any)
fn options(&self) -> &Options {
&self.options
}

/// Name of the attribute (if available)
async fn name<'a, S: ScalarValue>(
&'a self,

Check warning on line 499 in api/src/main.rs

View workflow job for this annotation

GitHub Actions / stable / fmt

Diff in /home/runner/work/kg-node/kg-node/api/src/main.rs
executor: &'a Executor<'_, '_, KnowledgeGraph, S>,
Expand Down

0 comments on commit e6b50a3

Please sign in to comment.