Fabric Apps のデータ モデルを定義する

Fabric Apps では、TypeScript デコレーターを使用して、データベース テーブルと API を生成するデータ モデルを定義します。 各エンティティは、 @entity()で修飾されたクラスとして定義し、データ型のフィールド デコレーターを追加し、エンティティ間のリレーションシップをマップします。

承認とアクセス制御のガイダンスについては、「 データのアクセス許可の定義」を参照してください。

前提条件

  • npm create @microsoft/rayfin@latest で作成されるか、npx rayfin init で初期化されたFabric Apps プロジェクト。
  • TypeScript クラスとデコレーターの基本的な理解。

エンティティを定義する

データ モデルを作成するには、typeScript クラスに @entity() デコレーターを追加します。 次に、必要なデコレーターを @microsoft/rayfin-coreからインポートします。

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

@entity()
export class Todo {
  @uuid() id!: string;
  @text() title!: string;
  @text({ optional: true }) description?: string;
  @date() createdAt!: Date;
  @date() updatedAt!: Date;
}

このエンティティは、Todoidtitledescription、およびcreatedAtの列を含むupdatedAt テーブルを生成します。

主キー

すべてのエンティティは、主キーとして string という UUID id フィールドを使用します。 id を明示的に宣言しない場合は、Fabric Apps によってスキーマに自動的に追加されます。

  • id フィールドは、作成操作中は省略可能です。このフィールドを省略すると、サーバーによって UUID が生成されます。
  • クライアントによって生成される識別子を使用する場合は、作成時に独自の UUID を指定できます。
  • 複合主キーとカスタム キー名はサポートされていません。
@entity()
export class Note {
  @uuid() id!: string;  // UUID primary key, auto-generated when omitted
  @text() title!: string;
  @text() content!: string;
}

サポートされているデータの種類

フィールド型を定義するには、次のデコレーターを使用します。

デコレーター タイプ 説明
@uuid() 文字列 一意の識別子フィールド
@text() 文字列 省略可能な長さの制約を持つテキスト フィールド。
@int() 数値 整数フィールド。
@decimal() 数値 10進数フィールドまたは数値フィールド。
@boolean() boolean True または false フィールド。
@date() Date 日付と時刻フィールド。ISO 文字列または Date オブジェクトからシリアル化されます。
@email() 文字列 電子メールの検証を含むテキスト フィールド。
@set() 文字列 文字列リテラルの列挙されたセット。

複数の型を含む例

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

@entity()
export class Product {
  @uuid() id!: string;
  @text() name!: string;
  @decimal() price!: number;
  @int() stockQuantity!: number;
  @boolean() isAvailable!: boolean;
  @date() createdAt!: Date;
  @set('draft', 'published', 'archived') status!: 'draft' | 'published' | 'archived';
}

型修飾子

フィールド デコレーターに修飾子を追加して、検証と制約を構成します。

修飾子 説明
{ optional: true } NULL 値を許可します。 フィールドは既定で必須です。
{ unique: true } 一意制約を追加します。
{ default: value } 既定値の式を設定します。
{ max: n }{ min: n } 文字列の長さの制約 (最大文字数と最小文字数)。
{ min: n }{ max: n } 数値制約。

Note

TypeScript の省略可能なマーカー (プロパティ名の後に? ) は、静的な TypeScript 型にのみ影響します。 データベース列を null 値にすることはできません。 フィールドを null 許容にするには、デコレーターに { optional: true } を追加します。 !を使用して、必要なフィールドがフレームワークによって初期化されていることをアサートします。

修飾子を使用した例

@entity()
export class User {
  @uuid() id!: string;
  @email({ unique: true }) email!: string;
  @text({ min: 3, max: 50 }) username!: string;
  @text({ optional: true, max: 500 }) bio?: string;
  @int({ min: 0, max: 150 }) age!: number;
  @boolean({ default: false }) isVerified!: boolean;
}

リレーションシップを定義する

@one()および@many()デコレーターを使用して、エンティティ間のナビゲーション プロパティを定義します。 Fabric Apps では、リレーションシップを定義すると外部キー列が自動生成されます。

  • 一対多 – 親に @many() を使用し、子に @one() します。
  • 多対一 – 子側で @one() を使用して親を参照します。
  • 多対多リレーションシップはサポートされていません。代わりに明示的な結合エンティティを使用してください。

一対多リレーションシップの例

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

@entity()
export class Notebook {
  @uuid() id!: string;
  @text() name!: string;
  @date() createdAt!: Date;
  @many(() => Note) notes?: Note[];
}

@entity()
export class Note {
  @uuid() id!: string;
  @text() title!: string;
  @text() content!: string;
  @date() createdAt!: Date;
  @text() notebook_id!: string;
  @one(() => Notebook) notebook?: Notebook;
}

@one(() => Notebook) エンティティで Note を定義すると、Fabric Apps によって外部キー列notebook_id が自動的に作成されます。 外部キー フィールドは、アプリケーション コードで読み取りまたは設定する場合にのみ明示的に宣言します。

外部キーの名前付け規則

外部キー フィールドを定義する場合は、 {property}_id 名前付け規則を使用します。

@entity()
export class Note {
  @uuid() id!: string;
  @text() notebook_id!: string;      // Foreign key field
  @one(() => Notebook) notebook?: Notebook;  // Navigation property
}

カスタム外部キー名 (foreignKeytargetKey オプション) はサポートされていません。

参照システム エンティティ

Fabric Apps では、組み込みの @one() エンティティなどのシステム エンティティを指す USER リレーションシップはサポートされていません。 サインインしているユーザーに行を関連付けるには、user_id型のプレーンな@text() フィールドを追加し、認証要求 (通常はclaims.sub) から設定します。

@entity()
export class Task {
  @uuid() id!: string;
  @text() title!: string;
  @text() user_id!: string;  // System user ID from claims.sub
}

ロール ポリシーの user_id で行をフィルター処理して、ユーザーごとのアクセスを強制します。

スキーマにエンティティを登録する

クライアントが GraphQL プロキシを生成できるように、すべてのエンティティ クラスを rayfin/data/schema.ts に追加します。

import type { Note } from './Note.js';
import type { Notebook } from './Notebook.js';

export type NotesAppSchema = {
  Note: Note;
  Notebook: Notebook;
};

新しいエンティティを作成するたびに、この型を更新します。

スキーマの変更を適用する

エンティティを定義または変更した後、データベースに変更を適用します。

  1. 更新されたスキーマをFabricにデプロイします。

    npx rayfin up db apply
    
  2. スキーマの変更に破壊的操作 (列の削除、テーブルの名前変更) が含まれている場合、CLI によって警告が表示され、続行は拒否されます。 --forceを使用して、安全性チェックをオーバーライドします。

    npx rayfin up db apply --force
    

Note

--forceを使用すると、データが失われる可能性があります。 続行する前に、一覧表示されている操作を注意深く確認してください。

ベスト プラクティス

  • 外部キー フィールドは、コードで読み取りまたは設定する必要がある場合にのみ定義します。Fabric Apps では、ナビゲーション デコレーターから自動的に生成されます。
  • 生成された ESM JavaScript が正しく解決されるように、エンティティ ファイル内の .js 拡張機能で相対インポートを使用します。
  • 承認パターンとロールベースのアクセスについては、「データアクセス 許可の定義」を参照してください。

Troubleshooting

リレーションシップが見つからない

API にリレーションシップが表示されない場合は、次のことを確認します。

  • ナビゲーション デコレーター (@one() または @many()) が存在します。
  • エンティティは rayfin/data/schema.tsに登録されます。