mcpField
Z
zenstack-schema-modeling

zenstack-schema-modeling

github.com/zenstackhqデータ・データベース3428 回インストール2 日前に更新
リポジトリ

zenstack-schema-modeling について

zenstack-schema-modelingは、ZenStackのZModelでデータベース構造を定義する開発者向けのスキルです。ZModelはPrisma Schemaを拡張し、ミックスイン、多態モデル、型付きJSON、計算フィールドを扱えます。

主な機能

  1. 01モデル、フィールド、列挙型の定義
  2. 02一対一・多対多リレーションのモデリング
  3. 03カスタム型とフィールドミックスイン
  4. 04多態モデルの継承
  5. 05型付きJSONフィールド
  6. 06計算フィールドとスキーマ検証

活用シーン

  1. 01アプリケーションのデータモデルと関連を定義
  2. 02モデル間で共通フィールドを再利用
  3. 03多態データやJSONデータをモデリング

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zenstackhq/skills --skill zenstack-schema-modeling

インストール後、Claude Code で/zenstack-schema-modelingを入力して読み込まれたか確認します。

詳細

ZenStack — スキーマモデリング(ZModel)

ZModelはZenStackのスキーマ言語で、Prismaのスキーマを拡張したものです。スキーマはデフォルトで zenstack/schema.zmodel にあります。アクセス制御ポリシーやバリデーションには zenstack-access-control、 クエリには zenstack-querying を使用してください。

スキーマを編集した後:

zen check      # only validate the schema for syntax/semantic errors (use --schema <file> for a non-default path)
zen generate   # regenerate the database client — also validates the schema as it compiles

スキーマが有効かどうかだけを確認する場合は zen check を実行します。クライアントを再生成する場合は zen generate を実行します(スキーマ変更後の通常の手順です)。

文字列にはシングルクォートとダブルクォートの両方を使用できます。有効なPrismaスキーマはすべて有効なZModelです。 そのため、既存のPrismaの知識をそのまま活用できます。以下のセクションでは、基本事項とZModel独自の拡張について説明します。

データソース

スキーマごとに datasource ブロックは1つだけ指定できます。ORMのランタイムは url を使用しません(接続は ドライバーが担います)。マイグレーションエンジンでは使用します。

datasource db {
    provider = 'postgresql'        // 'postgresql' | 'mysql' | 'sqlite'
    url      = env('DATABASE_URL') // or 'file:./dev.db' for SQLite
}

ZModelには generator ブロックがありません。コード生成は zen generate によって行われます。オプションの動作は plugin ブロック(例:plugin policy、plugin prisma)で設定します。

モデルとフィールド

model User {
    id        Int      @id @default(autoincrement())
    email     String   @unique
    name      String?              // optional
    role      Role     @default(USER)
    tags      String[]             // list
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}

スカラー型:String、Boolean、Int、BigInt、Float、Decimal、DateTime、Json、 Bytes、Unsupported("...")。

修飾子:? はオプション、[] はリストを表します。フィールドにオプションとリストの両方を指定することはできません。

フィールド属性(@)

@id、@unique、@default(...)、@updatedAt、@map('col')、@relation(...)、@db.*(ネイティブ 型。例:@db.VarChar(64))、@json(型付きJSONフィールド)、@computed(仮想フィールド)。

モデル属性(@@)

@@id([a, b])(複合主キー)、@@unique([a, b])、@@index([a, b])、@@map('table')、 @@delegate(field)(ポリモーフィズム)、および @@allow / @@deny / @@validate(詳細は zenstack-access-control を参照)。

model City {
    country String
    name    String
    @@id([country, name])     // composite primary key
    @@map('cities')
}

モデルには識別子が必要です。@id フィールド、@@id([...])、または、それらがない場合は @unique フィールドか @@unique([...]) を指定してください。

デフォルト値関数

autoincrement()、now()、cuid()、uuid() / uuid(4)、ulid()、nanoid()、 dbgenerated("...") のほか、リテラル値と列挙型の値を使用できます。

v3.1.0以降、文字列ID生成関数では %s を含む format を指定できます。

id String @id @default(uuid(4, "user_%s"))   // -> "user_<uuid>"

列挙型

enum Role {
    USER
    ADMIN
}

列挙型の値の名前はグローバルであり、重複してはなりません。

リレーション

所有側には外部キー(@relation(fields: [...], references: [...]))を指定します。

1対1 — 外部キーは @unique であり、非所有側はオプションです。

model User {
    id      Int      @id
    profile Profile?
}
model Profile {
    id     Int  @id
    user   User @relation(fields: [userId], references: [id])
    userId Int  @unique
}

1対多 — 非所有側にリストを指定します。

model User {
    id    Int    @id
    posts Post[]
}
model Post {
    id       Int  @id
    author   User @relation(fields: [authorId], references: [id])
    authorId Int
}

多対多(暗黙) — 両側にリストを指定すると、マイグレーションエンジンが結合テーブルを作成します。

model User { id Int @id  posts Post[] }
model Post { id Int @id  editors User[] }

多対多(明示) — 追加フィールドが必要な場合は、結合テーブルを独自にモデル化します。

model UserPost {
    user   User @relation(fields: [userId], references: [id])
    userId Int
    post   Post @relation(fields: [postId], references: [id])
    postId Int
    @@id([userId, postId])
}

名前付きリレーションは、同じ2つのモデル間に複数のリレーションがある場合に区別するためのものです(両端に 同じ名前を付けます):@relation('UserPosts', ...)。

自己リレーションでは名前付きリレーションを使用します。たとえば、1対多のマネージャー/部下のツリーです。

model Employee {
    id           Int        @id
    managerId    Int?
    manager      Employee?  @relation('Mgmt', fields: [managerId], references: [id])
    subordinates Employee[] @relation('Mgmt')
}

参照アクションは所有側で指定します:onDelete / onUpdate に Cascade、Restrict、 NoAction、SetNull、SetDefault を指定します。

author User @relation(fields: [authorId], references: [id], onDelete: Cascade)

カスタム型とミックスイン

type 宣言はテーブルを作成しません。型付きJSON(以下を参照)または再利用可能なフィールドのミックスインとして 使用し、with で適用します。

type BaseFields {
    id        String   @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}

model User with BaseFields {
    email String @unique
}
model Post with BaseFields {
    title String
}

ミックスインのフィールドはモデルにインライン展開されます。名前が重複しなければ、複数のミックスインを使用できます。 これは、モデル間でフィールドを共有するZModelの仕組みです(抽象基底モデルの代わりに使用してください)。

型にリレーションフィールドを含めることもできます(v3.6.0以降)。ただし、その場合はミックスインとしてのみ使用でき、 JSONフィールドとしては使用できません。

type AuditMixin {
    createdBy   User   @relation('CreatedBy', fields: [createdById], references: [id])
    createdById String
}
model Post with AuditMixin { title String }

ポリモーフィズム — @@delegate

複数テーブル継承では、判別フィールドと @@delegate を持つ基底モデル、および extends を使用する具象モデルを 定義します。具象モデルと基底モデルの行は同じIDを共有します。作成するのは具象モデルであり、基底モデルを直接作成することはありません。

model Content {
    id        Int      @id @default(autoincrement())
    createdAt DateTime @default(now())
    owner     User     @relation(fields: [ownerId], references: [id])
    ownerId   Int
    type      String   // discriminator
    @@delegate(type)
}

model Post extends Content {
    content String
}
model Image extends Content {
    data Bytes
}

保存される判別値は @@delegateMap でカスタマイズできます(v3.7.1以降)。列挙型の判別子にも使用できます。

model Video extends Content {
    url String
    @@delegateMap("video")
}

強い型付けの JSON

type を定義してフィールドの型として使用し、そのフィールドに @json を付けます。データベース上の列は通常の JSON ですが、ZenStack は書き込みを検証し、型付けされた値を返します。

type Address {
    street  String
    city    String
    zip     Int
}
model User {
    id      Int     @id
    address Address @json
}

計算フィールド

@computed を使って仮想フィールドを宣言し、クライアント設定で Kysely 式を使って実装します。選択、フィルタリング、並べ替えができ、ポリシーから参照することもできます。

model User {
    id        Int @id
    postCount Int @computed
}
const db = new ZenStackClient(schema, {
    dialect,
    computedFields: {
        User: {
            postCount: (eb) =>
                eb.selectFrom('Post')
                    .whereRef('Post.authorId', '=', 'id')
                    .select(({ fn }) => fn.countAll<number>().as('count')),
        },
    },
});

Prisma にはない ZModel の追加機能

  • generator ブロックはありません(zen generate と plugin を使用します)。
  • type 宣言と with ミックスイン、@@delegate によるポリモーフィズム、@json による型付き JSON、@computed フィールドは、Prisma にはない ZenStack の追加機能です。
  • シングルクォートとダブルクォートのどちらも使用できます。

リファレンスドキュメント

このトピックに関する ZenStack のドキュメント全文は、references/ に同梱されています。

コメント