Explore
InstaQL
Instant provides a GraphQL-like interface for querying. We call our query language InstaQL
Why InstaQL
We like the declarative nature of GraphQL queries but are not fans of a) configuration and b) build steps required to get up and running. To get around a) and b) we built InstaQL using only native javascript arrays and objects.
Fetch namespace
These next sections will use the following sample data:
import { id } from '@instantdb/react'
const workoutId = id()
const proteinId = id()
const sleepId = id()
const standupId = id()
const reviewPRsId = id()
const focusId = id()
const healthId = id()
const workId = id()
transact([
tx.todos[workoutId].update({ title: 'Go on a run' }),
tx.todos[proteinId].update({ title: 'Drink protein' }),
tx.todos[sleepId].update({ title: 'Go to bed early' }),
tx.todos[standupId].update({ title: 'Do standup' }),
tx.todos[reviewPRsId].update({ title: 'Review PRs' }),
tx.todos[focusId].update({ title: 'Code a bunch' }),
tx.goals[healthId]
.update({ title: 'Get fit!' })
.link({ todos: workoutId })
.link({ todos: proteinId })
.link({ todos: sleepId }),
tx.goals[workId]
.update({ title: 'Get promoted!' })
.link({ todos: standupId })
.link({ todos: reviewPRsId })
.link({ todos: focusId }),
])
Here we have:
- todos, with unique identifiers
workoutId
,proteinId
,sleepId
,standupId
,reviewPRsId
, andfocusId
- goals, with unique identifiers
healthId
andworkId
- todos
workoutId
,proteinId
, andsleepId
are associated with goalhealth
- todos
standupId
,reviewPRsId
, andfocusId
are associated with goalwork
One of the simpliest queries you can write is to simply get all entities of a namespace.
const query = { goals: {} }
const { isLoading, error, data } = useQuery(query)
Inspecting data
, we'll see:
console.log(data)
{
"goals": [
{
"id": healthId,
"title": "Get fit!"
},
{
"id": workId,
"title": "Get promoted!"
}
]
}
For comparison, the SQL equivalent of this would be something like:
const data = { goals: doSQL('SELECT * FROM goals') }
Fetch multiple namespaces
You can fetch multiple namespaces at once:
const query = { goals: {}, todos: {} }
const { isLoading, error, data } = useQuery(query)
We will now see data for both namespaces.
console.log(data)
{
"goals": [...],
"todos": [
{
"id": focusId,
"title": "Code a bunch"
},
{
"id": proteinId,
"title": "Drink protein"
},
...
]
}
The equivalent of this in SQL would be to write two separate queries.
const data = {
goals: doSQL('SELECT * from goals'),
todos: doSQL('SELECT * from todos'),
}
Fetch a specific entity
If you want to filter entities, you can use the where
keyword. Here we fetch a specific goal
const query = {
goals: {
$: {
where: {
id: 'health',
},
},
},
}
const { isLoading, error, data } = useQuery(query)
console.log(data)
{
"goals": [
{
"id": healthId,
"title": "Get fit!"
}
]
}
The SQL equivalent would be:
const data = { goals: doSQL("SELECT * FROM goals WHERE id = 'health'") }
Fetch associations
We can fetch goals and their related todos.
const query = {
goals: {
todos: {},
},
}
const { isLoading, error, data } = useQuery(query)
goals
would now include nested todos
console.log(data)
{
"goals": [
{
"id": healthId,
"title": "Get fit!",
"todos": [...],
},
{
"id": workId,
"title": "Get promoted!",
"todos": [...],
}
]
}
Comparing InstaQL vs SQL
The SQL equivalent for this would be something along the lines of:
const query = "
SELECT g.*, gt.todos
FROM goals g
JOIN (
SELECT g.id, json_agg(t.*) as todos
FROM goals g
LEFT JOIN todos t on g.id = t.goal_id
GROUP BY 1
) gt on g.id = gt.id
"
const data = {goals: doSQL(query)}
Notice the complexity of this SQL query. Although fetching associations in SQL is straightforward via JOIN
, marshalling the results in a nested structure via SQL is tricky. An alternative approach would be to write two straight-forward queries and then marshall the data on the client.
const _goals = doSQL("SELECT * from goals")
const _todos = doSQL("SELECT * from todos")
const data = {goals: _goals.map(g => (
return {...g, todos: _todos.filter(t => t.goal_id === g.id)}
))
Now compare these two approaches with InstaQL
const query = {
goals: {
todos: {},
},
}
const { isLoading, error, data } = useQuery(query)
Modern applications often need to render nested relations, InstaQL
really starts to shine for these use cases.
Fetch specific associations
A) Fetch associations for filtered namespace
We can fetch a specific entity in a namespace as well as it's related associations.
const query = {
goals: {
$: {
where: {
id: 'health',
},
},
todos: {},
},
}
const { isLoading, error, data } = useQuery(query)
Which returns
console.log(data)
{
"goals": [
{
"id": healthId,
"title": "Get fit!",
"todos": [
{
"id": proteinId,
"title": "Drink protein"
},
{
"id": sleepId,
"title": "Go to bed early"
},
{
"id": workoutId,
"title": "Go on a run"
}
]
}
]
}
B) Filter namespace by associated values
We can filter namespaces by their associations
const query = {
goals: {
$: {
where: {
'todos.title': 'Code a bunch',
},
},
todos: {},
},
}
const { isLoading, error, data } = useQuery(query)
Returns
console.log(data)
{
"goals": [
{
"id": workId,
"title": "Get promoted!",
"todos": [
{
"id": focusId,
"title": "Code a bunch"
},
{
"id": reviewPRsId,
"title": "Review PRs"
},
{
"id": standupId,
"title": "Do standup"
}
]
}
]
}
C) Filter associations
We can also filter associated data.
const query = {
goals: {
$: {
where: {
'todos.title': 'Go on a run',
},
},
},
}
const { isLoading, error, data } = useQuery(query)
This will return goals and filtered todos
console.log(data)
{
"goals": [
{
"id": healthId,
"title": "Get fit!",
"todos": [
{
"id": workoutId,
"title": "Go on a run"
}
]
},
{
"id": workId,
"title": "Get promoted!",
"todos": []
}
]
}
Notice the difference between these three cases.
- A) Fetched all todos for goal with id
health
- B) Filtered goals with a least one todo titled
Code a bunch
- C) Fetched all goals and filtered associated todos by title
Go on a run
Inverse Associations
Associations are also available in the reverse order.
const query = {
todos: {
goals: {},
},
}
const { isLoading, error, data } = useQuery(query)
console.log(data)
{
"todos": [
{
"id": focusId,
"title": "Code a bunch",
"goals": [
{
"id": workId,
"title": "Get promoted!"
}
]
},
...,
]
}
More features to come!
We're actively building more features for InstaQL. Let us know on discord if there's a missing feature you'd love for us to add!