Fauna Adventures
<!-- Put the link to this slide here so people can follow -->
slide: https://hackmd.io/@gozala/fauna-adventures/
---
## Supports GraphQL

Just import the schema and db is generate for you
---
Schema In
```graphql
type User {
name: String!
cars: [Car!] @relation
}
type Car {
plate: String!
owner: User!
}
```
---
Schema Out
```graphql
type Mutation {
createCar(data: CarInput!): Car!
deleteCar(id: ID!): Car
updateCar(id: ID! data: CarInput!): Car
# Same for User
}
input CarInput {
plate: String!
owner: CarOwnerRelation
}
input CarOwnerRelation {
create: UserInput
connect: ID
}
```
---
(More) Schema Out
```graphql
type Query {
findUserByID(id: ID!): User
findCarByID(id: ID!): Car
}
```
๐ค What's that `id` you speak of ?
---
(Even more) Schema Out
```graphql
type User {
_id: ID! # <- here's our ID
_ts: Long!
name: String!
cars(_size: Int, _cursor: String): CarPage!
}
type CarPage {
data: [Car]!
after: String
before: String
}
```
---
What I need ๐ฅบ
```graphql
input UserFilter {
name: String
}
type Query {
findCarsByUser(user: UserFilter): [Car!]
}
```
What I get ๐ณ
```graphql
type Query {
findUserByID(id: ID!): User
findCarByID(id: ID!): Car
}
```
---
If you import that schema you'll get ๐ค

---
Why can't I just SQL ๐ญ
```sql
SELECT
*
FORM
cars
INNER JOIN users ON user.id = cars.ownerid
WHERE
users.name = "gozala"
```
---
Enter

Fauna Query Language (FQL)
---
Where our query looks like ๐คฎ
```fql
Reduce(Lambda(["acc", "user"], Let({
owners: Match(Index("car_owner_by_user"), Var("user")),
cars: Map(Paginate(Var("owners")),
Lambda(["ref"], Get(Var("ref"))))
}, Append(Var("cars"), Var("acc")))),
[],
Filter(Documents(Collection("User")),
Lambda(["user"], Equals(
Select(["data", "name"], Get(Var("user"))),
"gozala"))))
```
And don't miss any of the commas or ๐ฃ
---
On the other hand it's uglier lisp ๐ค
```scheme
(reduce
(lambda (acc user)
(let* ([owners (match index("car_owner_by_user") user)]
[cars (map (paginate owners)
(lambda ref (get ref)))])
(append cars acc)))
[]
(filter (documents (collections "User"))
(lambda user (= (select ["data" "name"] user)))))
```
_P.S: Barely resisted writing lisp to FQL compiler_
---
Expose FQL query as User-defined function (UDF) via `@resolver` directive ๐ฅณ
```graphql
type Query {
findCarsByUser(user: UserFilter): [Car!] @resolver
}
```
---
How's GraphQL params looks in UDF ? ๐
```fql
Abort(Format('%@', Var("options")))
```
Welcome to
exception based debugging club!
---
Modeling `N:M` relations are tricky ๐ง
```graphql
type Block {
hash: ID! @unique
tokens: [Token!] @relation # โ ๏ธ Usually >1 token
}
type Token {
id: String! @unique
blocks: [Block!] @relation # โ ๏ธ May appear >1 block
tokenID: String!
tokenAsset: TokenAsset
contract: TokenContract! @relation
owner: Owner! @relation
# ...
}
```
๐จ Arrays of refs aren't going to work ๐จ
---
Fauna generates relation tables

Just Workโข in GraphQL
---
VSCode Plugin ๐

Lets you execute FQL queries
---
## Challenges ๐ฌ
- Derived aggregate state (e.g. doc count)
- Enforce invariants (type unions / state machines)
- [Prevent generating GraphQL CRUD endpoints](https://forums.fauna.com/t/provide-a-mechanism-to-prevent-queries-and-mutations-being-autogenerated-for-a-given-type/35)
- [Migrations]()
---
## Resources
- [FQL Cheat Sheet](https://docs.fauna.com/fauna/current/api/fql/cheat_sheet)
- [FQL for SQL users](https://docs.fauna.com/fauna/current/start/fql_for_sql_users)
- [awesome-faunadb](https://github.com/n400/awesome-faunadb/)
---
{"metaMigratedAt":"2023-06-16T00:54:48.769Z","metaMigratedFrom":"YAML","title":"Fauna Adventures","breaks":true,"description":"View the slide with \"Slide Mode\".","slideOptions":"{\"theme\":\"white\"}","contributors":"[{\"id\":\"fff58d5d-df29-4dd3-93ef-42fd0194a26f\",\"add\":7506,\"del\":3380}]"}