MantisDocs

Live queries

Subscribe to a select and get its rows again every time they change.

A live query is a select that stays open. It sends the rows once, then sends them again each time a write changes the result, whoever made the write.

In React

app/todos.tsx
"use client";

import { useQuery } from "@shipmantis/sdk/react";
import { mantis } from "@/lib/mantis";

export function Todos() {
  const { rows, error, loading } = useQuery(mantis, "todos", {
    where: { done: false },
    orderBy: [{ column: "createdAt", direction: "desc" }],
  });

  if (loading) return <p>Loading…</p>;
  if (error) return <p>{error.message}</p>;
  return (
    <ul>
      {rows!.map((todo) => (
        <li key={todo.id}>{todo.title}</li>
      ))}
    </ul>
  );
}

useQuery(client, table, options) takes the same options as select and returns:

FieldWhat it holds
rowsThe latest rows, typed from the schema. undefined until the first answer.
errorA MantisError if the query was refused.
loadingtrue until the first rows or the first error.

Change the options and the hook stops the old query and starts the new one. It stops when the component unmounts.

A browser holds the publishable key, not the secret one. Live queries made with it see only what your access rules allow, so set the rules and a userToken first.

Without React

const stop = mantis.from("todos").live(
  { where: { done: false } },
  {
    rows: (rows) => render(rows),
    error: (error) => console.error(error.status, error.reasons),
  },
);

// later
stop();

live(options, handlers) calls rows with the whole result each time, not the change, so you can render it as it is. It returns a function that stops the query. After an error the query is stopped.

How it connects

The client opens one WebSocket to /v1/live on the first live query and shares it between all of them. It closes the socket when the last one stops. With a userToken, a query refused because the user's token expired asks for a new token and joins again.

On this page