A realtime GraphQL backend as a compiler in Haskell
http://bit.ly/graphql-haskell
A realtime GraphQL backend as a compiler in Haskell - - PowerPoint PPT Presentation
A realtime GraphQL backend as a compiler in Haskell http://bit.ly/graphql-haskell Heippa! Tanmai Gopal @tanmaigo http://bit.ly/graphql-haskell Contents 1. The compiler approach 2. Compiler pipeline a. Parse b. GraphQL AST c.
http://bit.ly/graphql-haskell
Tanmai Gopal @tanmaigo Heippa!
http://bit.ly/graphql-haskell
1. The compiler approach 2. Compiler pipeline
a. Parse b. GraphQL AST c. Transform to SQL AST <> inject auth d. Optimise SQL AST
3. Realtime (concurrent programming)
http://bit.ly/graphql-haskell
GraphQL queries come from app and need to be translated to data calls (with access control) to the database. Goal:
Hasura
App
Database
Resolver based approach:
Resolver can:
nodes
If there are N authors with N articles each, you’re making 1 + n + n + n2 queries!
query { author { name address { city } articles { title tags { name } } } } SELECT author.name, address.city, articles.title, tag.name FROM author, address, articles, tags WHERE author.id = address.author_id, author.id = articles.author_id, articles.id = tag.article_id
joining tables containing 100M rows each
query { author { id name } }
ExecutableDefinition (OperationDefinition) OperationType: query SelectionSet: ... SelectionSet: [Selection] Selection: Field: Name: author SelectionSet: [Selection] Selection: Field: Name: id SelectionSet: [] Selection: Field: Name: name SelectionSet: []
SELECT id, name FROM author WHERE id = <session.user-id>
parse AST SQL
Algebraic Data Types
query { author { id name } }
1. Lex into “tokens” (words and braces) 2. Read the first word 3. This should be an ExecutableDefinition. 4. Check if this is one of the operation types 5. If yes, the rest of the document is a SelectionSet 6. In a SelectionSet, we need to assemble an array of fields 7. ...
query { author { id name } }
ExecutableDefinition (OperationDefinition)
The Magic Try to parse an operationDefinition or parse a fragmentDefinition.
Try to parse an operationDefinition by 1. Parsing an operationType 2. Optionally parsing a Name 3. Optionally parsing variables 4. Optionally parsing directives 5. Parsing a selectionSet
Try to parse an operationType by: 1. Parsing a “query” token OR 2. Parsing a “mutation” token OR 3. Parsing a “subscription” token
ExecutableDefinition (OperationDefinition) OperationType: query SelectionSet: ...
SELECT id, name FROM author WHERE id = <session.user-id>
SelectionSet: [Selection] Selection: Field: Name: author SelectionSet: [Selection] Selection: Field: Name: id SelectionSet: [] Selection: Field: Name: name SelectionSet: []
Create a connection object + thread for every new connection
Conn1
(+Delivery thread)
Conn2
(+Delivery thread)
Conn3
(+Delivery thread)
...
Event sourcing threads
Thread1 Thread2 Thread3 ...
Database
App App App App App App App App
1. Create a new connection object and attach to the right event-source thread or create a new thread 2. In every thread, take an event and deliver to all relevant connection
3. In case GraphQL schema or auth config changes, close/refresh all connections
Define a thread-safe operation:
Define a thread-safe operation:
Compose:
The composition is not safe! Option 1: Lock1 && Lock2
Release Option 2: Acquire in sequence: Lock1 then Lock2
Release Thread1 Conn1
(+Delivery thread)
Conn2
(+Delivery thread)
If pop and push are safe actions, then compose them safely atomically $ do pop push Software transactional memory is the idea
Writing compilers is easy:
https://github.com/Gabriel439/post-rfc/blob/master/sotu.md#compilers Doing concurrent programming is easy:
https://github.com/Gabriel439/post-rfc/blob/master/sotu.md#single-machine-concurrency
hasura.io github.com/hasura/graphql-engine @HasuraHQ Talk to me about: Haskell Postgres GraphQL Subscriptions Serverless https://3factor.app