Skip to content

Querying content

Everything below assumes you ran GemSync and have a gemRouter.ts in your repo. The client is a plain tRPC client, so each collection under gem.tables exposes typed procedures: find, all and where for reads, create, update and destroy for writes.

import { createGemClient } from "@gemzero0/sdk-core";
import type { GemRouter } from "./gemRouter";
const gem = createGemClient<GemRouter>({
url: process.env.GEM_URL!,
key: process.env.GEM_KEY!,
});
// One document by id (null when it doesn't exist)
const post = await gem.tables.posts.find.query({
id: "20240119104533_1705657533",
});
// A page of documents
const { results } = await gem.tables.posts.all.query({ limit: 10 });
// Filtered
const { results: published } = await gem.tables.posts.where.query({
query: { published: { $eq: true } },
limit: 20,
});

all and where accept limit, cursor and sort (an array of { field: "asc" | "desc" } entries). where takes a query built from these operators:

OperatorsMeaning
$eq, $neEquals / not equals
$lt, $lte, $gt, $gteComparisons
$in, $ninValue in / not in a list
$existsField present or absent
$regexMatch a regular expression
$sizeArray length
$and, $orGroup conditions

Documents carry two meta fields: _uid (the id) and _ver (the version). Updates and deletes require both. A stale _ver is rejected, so a concurrent edit fails loudly instead of silently overwriting; fetch before you write.

// Create
const { data: created } = await gem.tables.posts.create.mutate({
title: "Hello",
published: false,
});
// Update: fetch, change, send back with _uid and _ver
const post = await gem.tables.posts.find.query({ id });
if (post) {
await gem.tables.posts.update.mutate({ ...post, title: "New title" });
}
// Delete
await gem.tables.posts.destroy.mutate({
_uid: post._uid,
_ver: post._ver,
});

Writes run the same validations as the dashboard. Collections can be read-only; write procedures are only generated where the schema allows writing.

Reads accept two options alongside their parameters:

  • without_links: true skips expanding link fields into full documents (pair it with gemsync --without-links so the types match).
  • with_base64: true includes file contents inline for file fields instead of metadata only.

@gemzero0/sdk-react wraps the same router in React Query hooks:

import { createGemProvider } from "@gemzero0/sdk-react";
import type { GemRouter } from "./gemRouter";
const { GemProvider, Gem } = createGemProvider<GemRouter>();
// In your root:
// <GemProvider gemUrl={GEM_URL} gemKey={GEM_KEY}>...</GemProvider>
// In a component:
const { data } = Gem.tables.posts.all.useQuery({ limit: 10 });

@gemzero0/sdk-next provides the same for Next.js apps.