Schemas and LDKit
Typed access to the knowledge graph from your app.
The shape of the data in a datastore is described by SHACL shapes: which classes exist, which properties they have and of what type. The SDK turns those shapes into LDKit schemas, so your app reads and writes entities with TypeScript types instead of hand-written queries.
Generate the schemas
@manta-eu/codegen reads the shapes from your datastore and writes the schemas into your project:
-
Sign in once. The login is stored for all Manta CLIs.
pnpm manta-codegen login -
Generate the schemas for your datastore.
pnpm manta-codegen generate --datastore your-datastore --out ./.ldkit
The output has one file per namespace, plus namespaces.ts and an index.ts that re-exports them. Each run replaces
the previous one, so re-run it whenever the shapes change. In CI, set MANTA_CLIENT_SECRET to sign in with a service
account instead of a browser login.
Read entities from React
@manta-eu/react/ldo-ui has hooks that read entities through an LDKit lens. They use the SPARQL connection the Manta
providers set up, so they work anywhere inside EmbeddedChatProviders.
import { useLensFind, useSparqlOptions } from "@manta-eu/react/ldo-ui";
import { YourSchema } from "./.ldkit/your-namespace";
export function YourList() {
const options = useSparqlOptions();
const { data = [] } = useLensFind({ schema: YourSchema, options, queryKey: ["your-entities"] });
return (
<ul>
{data.map((entity) => (
<li key={entity.$id}>{entity.name}</li>
))}
</ul>
);
}
useLensFindByIri reads a single entity and useLensCount counts them. Outside React, createTypedLens from
@manta-eu/react/engine gives you the same lens directly.
Avoid N+1 queries
An N+1 query happens when a list is read with one query and then every row fetches its own details with another, so a list of 50 rows costs 51 round trips. Keep it to one or two:
- Read the list once with the fields you show. Give the schema every property the list renders and read it with a
single
useLensFind, instead of reading ids first and details later. - Bring related entities along in the same read. An LDKit schema can nest another schema under a property
(
"@schema"), so one query returns a campaign together with the fields of its account. - Look up known IRIs in one call. When you already hold a set of IRIs, read them all with
useEntitiesByIris({ schema, iris }). It returns one entry per IRI, in the same order, and the entry isundefinedwhen that IRI is not in the graph, so filter those out before you render. - Prefer
useEntityoruseEntitiesByIrisoveruseLensFindByIriin list rows. Both go through the same batcher, so lookups made in the same render become one query per schema (up to 100 IRIs), while everyuseLensFindByIriis a query of its own. - Let the graph do the counting. Use
useLensCountfor totals, and a rule for derived values, instead of loading every row to compute them in the browser.
import { isPresent } from "@manta-eu/lib/present";
import { useEntitiesByIris } from "@manta-eu/react/ldo-ui";
const { data = [] } = useEntitiesByIris({ schema: AccountSchema, iris: accountIris });
const accounts = data.filter(isPresent);
Keep IRIs opaque
An entity’s $id is its IRI. Pass it to LDKit, but never build URLs from it or parse parts out of it. To show or
link an entity, read the schema:identifier property it carries.