Rayfin

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.

rayfin/data/Todo.ts
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 up

From 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.

src/services/rayfinClient.ts
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 the schema.ts registration 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 / execute chain, filtering, and pagination.
  • Aggregations — sums, averages, and counts computed on the server with groupBy() and aggregate().
  • 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.
PromptModel your first entity
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`.
Something wrong on this page?Report an issueEdit this page

On this page