-
Notifications
You must be signed in to change notification settings - Fork 7
Detecting Relationships Between Entities
The Problem
Currently, we don't have a mechanism or standardised approach to detect and handle broken relationships between entities.
The outcome of this spike is to outline our existing approach and consider the available strategies we could adopt.
Existing Relationships
Database ERD
GraphQL ERD
Questionnaire Content Tree
We have a simple one-to-many relationships tree for questionnaire content.
Questionnaires
/\
/ \
/ \
Sections Sections
/\ /\
/ \ / \
/ \ / \
Pages Pages Pages Pages
/\ /\ /\ /\
/ \ / \ / \ / \
Answers Answers Answers Answers
/\ /\ /\ /\ /\
Options Options Options Options Options
What happens when you delete an entity from this tree?
- Child nodes are also deleted
Related Questionnaire Content Trees
Some of our content trees become related through piping or routing.
This creates complex scenarios when deleting certain nodes of data.
Questionnaire 1
/\
/ \
/ \
Section 1 Section 2
/ |
... | [Routing Rule]
/ |
Option 1 --------
What happens when...
- You delete "Section 2" -> The routing rule becomes detached and is no longer related to any other nodes
- You delete "Option 1" -> The routing rule becomes detached and is no longer related to any other nodes
- You delete "Routing Rule" -> The relation no longer exists
- You delete "Section 1" -> Child nodes within the tree are deleted alongside routing rules and the relationship no longer exists
How can we detect broken relationships?
The most common approach is to utilise an ORM which would contain a map of relationships between entities.
Examples of ORM's:
How would an ORM help us?
- We can control what to do when deleting a related entity (ignore / cascade / detach / reject)
- We can obtain related entities via a consistent method
- Creates an abstraction layer between the DB and Repositories which has the benefits of:
- a consistent API irrelevant of DB type and schema
- relationship mapping
- performance benefits via cache / query optimisation
An another solution would be to detect relationships between schemas via Postgres' information_schema
table.
This involves complex querying / parsing to obtain the relationships which an ORM would provide for free.
How can GraphQL help us detect relationships?
Our current schema only allows us to explore child relationships. This isn't very useful when trying to explore non-child/parent relationships as all entities are not necessarily connected in our schema.
The Relay Cursor Connections Specification provides a solution to this problem.
This would result in each entity in our schema being structured with the following:
- Node -> represents an entity. In a diagram of circles connected by lines, these would be the circles.
- Edge -> connects two nodes together, may include metadata. In the diagram, these would be the lines.
- Connection -> a page-able list of nodes. In the diagram, this would be a collection of lines.
In our context the schema would look the following:
type Questionnaire {
id: ID!
title: String
description: String
sectionsConnection(
first: Int,
after: String,
last: Int,
before: String
): SectionsConnection
...
}
type SectionsConnection {
edges: SectionsEdge
}
type SectionsEdge {
cursor: String!
node: SectionNode
}
type SectionNode implements Node {
id: ID!
name: String
title: String
answersConnection(
first: Int,
after: String,
last: Int,
before: String
): AnswersConnection
...
}
interface Node {
id: ID!
name: String
}
type AnswersConnection {
edges: AnswersEdge
}
type AnswerEdge {
cursor: String!
node: AnswerNode
}
type AnswerNode implements Node {
id: ID!
name: String
title: String
routingConnection(...): RoutingConnection
pipingConnection(...): PipingConnection
...
}
type RoutingConnection {
edges: RoutingEdge
}
type RoutingEdge {
cursor: String!
node: Routing
}
type RoutingNode implements Node {
id: ID!
answersConnection(...): AnswersConnection
...
}
type PipingConnection {
...
}
type PipingEdge {
...
}
type PipingNode implements Node {
...
}
Pros:
- As all data is connected, relationships can be determined by exploring the connections
- Future proofs for pagination
- Ability to add metadata on each connection and edge
- Common pattern used by Facebook and GitHub
Cons:
Although, Apollo is un-opinionated about this method, it does not provide any tooling to help resolve these types of schemas which:
- Adds complexity to schema and resolvers
- Time intensive to implement edges / connections for each node
More info: https://blog.apollographql.com/explaining-graphql-connections-c48b7c3d6976