Data
Model entities once as decorated TypeScript classes and get a database schema, GraphQL API, type-safe client, permissions, and validation from the same source.
A Rayfin entity is a TypeScript class. Decorate it once and Rayfin generates the database table, a GraphQL API, a type-safe client, row-level security, and form validation from that single definition — there is no separate schema file, migration file, or API contract to keep in sync by hand.
import { entity, authenticated, uuid, text, boolean, date } from '@microsoft/rayfin-core';
@entity()
@authenticated('*', {
policy: (claims, item) => claims.sub.eq(item.user_id),
})
export class Todo {
@uuid() id!: string;
@text({ max: 200 }) title!: string;
@boolean({ default: false }) isCompleted!: boolean;
@date() createdAt!: Date;
@text({ max: 128 }) user_id!: string;
}Register it in schema.ts, then apply it:
npx rayfin upFrom there, client.data.Todo is a fully typed read/write API, scoped by the row-level
policy declared above.
Set up the client
Construct one RayfinClient and reuse it across your app. Type it with your AppSchema so
every entity access is fully typed.
import { RayfinClient } from '@microsoft/rayfin-client';
import type { AppSchema } from '../../rayfin/data/schema';
export const rayfinClient = new RayfinClient<AppSchema>({
baseUrl: import.meta.env.VITE_RAYFIN_API_URL,
publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY ?? '',
});VITE_RAYFIN_API_URL and VITE_RAYFIN_PUBLISHABLE_KEY are generated into .env.local by
rayfin up — see Schema changes for the apply workflow that
produces them.
That one client also carries client.auth and, when enabled,
client.functions. To additionally reach existing
Fabric data sources, swap it for ConnectorsRayfinClient — see
Wiring connectors into your app.
Model your schema
- Modeling entities —
@entity(), file layout, primary keys, and theschema.tsregistration step. - Field types — every field decorator and its options, including the MSSQL text-length rule.
- Relationships —
@one()/@many(), foreign key columns, and the many-to-many workaround. - Permissions —
@role(),@anonymous(),@authenticated(), and the row-level policy DSL.
Read and write
- Querying — the
select/where/orderBy/executechain, filtering, and pagination. - Aggregations — sums, averages, and counts computed on the
server with
groupBy()andaggregate(). - Creating, updating, deleting — writes, and setting relationships correctly.
- Form validation — generate form validation from the same entity, with no separate schema library.
Operate
- Schema changes — how edits to
rayfin/data/reach the database, and how to verify they actually did. - Seeding data — populate a database from a Node.js script.
In my Rayfin project, create a new entity in rayfin/data/ that models [describe your
data]. Give it a uuid id, appropriate field decorators from @microsoft/rayfin-core with
explicit max lengths on every text field, and an @authenticated('*') permission decorator
with a policy scoping rows to the signed-in user via claims.sub. Register it in
rayfin/data/schema.ts, then apply the schema with `rayfin up`.