编程模型概述

Rayfin SDK 使用修饰器驱动的编程模型,可在 TypeScript 中定义一次数据架构,并自动接收生产就绪的 API、类型安全的客户端和基础结构。

重要概念

Rayfin SDK 结合了三个核心元素:

  • 修饰器驱动的架构:使用 TypeScript 修饰器定义数据模型、权限和关系。
  • 自动生成 API:带有装饰器的类会自动变成 GraphQL 端点,无需编写控制器代码。
  • 类型安全客户端:生成的 TypeScript 客户端为查询和突变提供编译时验证。

工作原理

创建Fabric应用时,代码将流经以下阶段:

# 阶段 发生的情况
1 开发人员 在所选编辑器中创作应用。
2 TypeScript 在 TypeScript 中编写实体类。
3 Decorators 你可以使用 @entity、@uuid、@text、@role 和其他装饰器为类和字段添加注解。
4 Schema CLI 将修饰的类编译为数据库架构、权限策略和 API 配置。
5 应用程序接口 该模式以 GraphQL 端点的形式发布。
6 Client 生成的 RayfinClient 通过这些端点提供一个类型安全的数据和身份验证客户端。
7 应用程序 前端应用程序使用客户端来读取和写入数据。

1. 使用修饰器定义数据模型

你可以使用来自 @microsoft/rayfin-core 的 TypeScript 类和修饰器来定义数据结构:

import { entity, uuid, text, int } from '@microsoft/rayfin-core';

@entity()
export class Product {
  @uuid() id!: string;
  @text() name!: string;
  @text({ optional: true }) description?: string;
  @int() price!: number;
}

2. 架构生成

Rayfin CLI(npx rayfin)分析带有装饰器的类,并生成:

  • 数据库架构 - 表、列、约束和索引
  • API 配置 - GraphQL 终结点定义
  • 权限策略 - 行级安全性和字段级访问控制

4. 类型安全的客户端用法

GraphQL API 可用于对数据库执行 CRUD 操作。 Rayfin SDK 提供现装的数据客户端操作,用于读取或删除数据。

import { RayfinClient } from '@microsoft/rayfin-client';

const client = new RayfinClient();

// TypeScript knows about Product fields
const products = await client.data.products.query()
  .select(['id', 'name', 'price'])
  .execute();

// Compile-time error if field doesn't exist
const invalid = await client.data.products.query()
  .select(['nonexistentField'])  // ❌ TypeScript error
  .execute();

装饰器参考

Rayfin SDK 为常见数据建模模式提供修饰器:

实体修饰器

装饰者 Purpose 例子
@entity() 将类标记为数据库实体 @entity() class Product

属性修饰器

装饰者 数据库类型 TypeScript 类型
@uuid() UNIQUEIDENTIFIER string
@text() NVARCHAR string
@int() INT number
@decimal() DECIMAL number
@bool() 位 boolean
@date() DATETIME2 Date

权限修饰器

装饰者 Purpose
@role() 定义基于角色的权限

有关授权详细信息,请参阅 “定义数据权限 ”。

Functions

创建一个 UserDataFunctions 实例,并通过调用 udf.func(name, handler, connections?)来注册每个函数。

定义函数时请遵循以下规则:

  • 将参数放置在 RayfinContext 处理器签名的任意位置。 运行时通过类型识别它,注入它,并将其排除在生成的函数输入中。
  • 为函数所需的每个委托令牌声明一个连接。 对于只访问应用数据或不需要委托令牌的函数,省略连接数组。

以下示例注册了一个普通函数和一个使用调用上下文的函数:

import {
  UserDataFunctions,
  type RayfinContext,
} from '@microsoft/fabric-user-data-functions';

// Match rayfin/data/schema.ts so getDataClient() is fully typed.
import type { TripPlan } from '../../data/TripPlan.js';

type AppSchema = { TripPlan: TripPlan };

const udf = new UserDataFunctions();

udf.func('greet', async (name: string): Promise<string> => {
  return `Hello, ${name}!`;
});

udf.func(
  'whoAmI',
  async (ctx: RayfinContext<AppSchema>): Promise<string> => {
    return ctx.accessToken ? 'authenticated' : 'anonymous';
  },
);

RayfinContext 为该函数提供运行时服务:

成员 Purpose
ctx.accessToken 为登录用户提供 Rayfin JSON Web 令牌(JWT)。 解码声明 sub 以获得稳定的用户ID。
ctx.Tokens.<Audience> 获得一个平台提供的资源令牌,用于注释中 RayfinContext 声明的受众。 部署功能使用应用身份及其权限。 详情请参见 “连接功能与外部资源”。
ctx.getSecret('NAME') 获取当前调用的机密。 当未设置密钥时,返回 undefined。
ctx.getDataClient() 它获取你实体的类型数据 API。 客户端支持创建、 findMany更新、删除和上传文本操作。
ctx.baseUrl 提供当前项的 Rayfin 端点。
ctx.publishableKey 提供当前项目的可发布密钥。

关于设置、本地调试和部署说明,请参见“在 Fabric 应用中使用函数”。

开发工作流

典型的开发周期遵循以下模式:

  1. 定义或修改数据模型 - 使用修饰器添加或更新 TypeScript 类
  2. 使用远程后端进行本地测试 - 运行 npm run dev,在 Fabric 中针对应用后端测试前端代码更改。
  3. 部署到 Fabric - 运行 npx rayfin up 以部署到托管的 Fabric 服务并应用架构更改。

对 TypeScript 模型的更改会自动传播到整个堆栈, 从数据库架构到 API 终结点到客户端类型。

Authorization

权限与数据模型一起使用 @role 修饰器进行定义:

@entity()
@role('authenticated', ['create', 'read', 'update', 'delete'], {
  policy: (claims, item) => claims.sub.eq(item.userId)
})
export class UserDocument {
  @uuid() id!: string;
  @text() userId!: string;
  @text() content!: string;
}

此方法可确保:

  • 安全规则位于他们保护的数据旁边
  • 类型安全的策略表达式可在编译时发现错误
  • 重构实体字段时会自动更新权限检查