Prisma スキーマを利用したローカル開発
GASsma は clasp+esbuild 等を利用し TypeScript を使ってローカルで GAS を開発する際に、Prisma 形式のスキーマファイルから型安全なクライアントコードを自動生成する機能を提供しています。
この機能を利用すると、リレーション定義や defaults・map 等の設定がスキーマから自動生成されるため、GASsma 独自のコンストラクタオプション(relations、defaults、updatedAt、ignore、map など)を手動で記述する必要がなくなります。Prisma のスキーマ構文さえ知っていれば、Prisma と同じ感覚で開発を始められます。
CLI なし(手動設定):
import { Gassma } from "gassma";
const gassma = new Gassma.GassmaClient({
id: "SPREAD_SHEET_ID",
relations: {
User: {
posts: { type: "oneToMany", to: "Post", field: "id", reference: "authorId", onDelete: "Cascade" },
},
Post: {
author: { type: "manyToOne", to: "User", field: "authorId", reference: "id" },
},
},
defaults: { User: { role: "USER" } },
updatedAt: { Post: "updatedAt" },
map: { User: { firstName: "名前" } },
});
CLI あり(スキーマから自動生成):
import { GassmaClient } from "./generated/gassma/schemaClient";
// リレーション・defaults・updatedAt・map 等すべて自動注入済み
const gassma = new GassmaClient();
前提
以下のコマンドで GASsma の CLI ツールをインストールしてください。
$ npm i gassma
スキーマファイルの作成
プロジェクト内に .prisma ファイルを作成します。デフォルトでは ./gassma ディレクトリ配下が探索されます。
my-project/
├── gassma/
│ └── schema.prisma ← ここにスキーマを記述
├── package.json
└── ...
基本的な書き方
Prisma の文法でモデルを定義します。generator ブロックの output で出力先を指定してください。
generator client {
provider = "prisma-client-js"
output = "./generated/gassma"
}
model User {
id Int @id
name String
email String?
age Int
}
previewFeatures
generator ブロックに previewFeatures を指定すると、オプトインの機能を有効化できます(Prisma の previewFeatures と同じ書き方です)。
generator client {
provider = "prisma-client-js"
output = "./generated/gassma"
previewFeatures = ["strictUndefinedChecks"]
}
現在サポートされている機能:
| 機能 | 説明 | 参照 |
|---|---|---|
strictUndefinedChecks | クエリ入力の明示的な undefined を実行時エラーにする | strictUndefinedChecks / Gassma.skip |
有効化すると、生成されるクライアント JS に strictUndefinedChecks: true が埋め込まれ、生成される型定義にも Gassma.skip を受け付ける型が反映されます。
型マッピング
Prisma の型は以下の TypeScript 型に変換されます。
| Prisma 型 | TypeScript 型 |
|---|---|
Int | number |
Float | number |
Decimal | number |
BigInt | number |
String | string |
Boolean | boolean |
DateTime | Date |
Json | string |
Bytes | string |
? を付けるとオプショナルフィールドになります(null が許容されます)。
リレーション定義
Prisma の @relation 属性を使うと、リレーション情報が自動的に抽出され、生成されたクライアントに注入されます。
generator client {
provider = "prisma-client-js"
output = "./generated/gassma"
}
model User {
id Int @id
name String
posts Post[]
}
model Post {
id Int @id
title String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId Int
}
上記の定義から以下のリレーション設定が自動生成されます。
User.posts: oneToMany(User → Post)Post.author: manyToOne(Post → User、onDelete: Cascade)
暗黙的 Many-to-Many
双方向の配列参照がある場合、暗黙的な Many-to-Many リレーションが自動検出されます。
model Post {
id Int @id
tags Tag[]
}
model Tag {
id Int @id
name String
posts Post[]
}
生成されるクライアントでは、中間テーブル名が _PostToTag(モデル名のアルファベット順)として自動的に解決されます。@relation("PostTags") のようにリレーションに名前を付けた場合は、リレーション名がそのまま中間テーブル名(_PostTags)になります(Prisma と同じ規則です)。
中間テーブル(シート)自体は migrate / db push で自動作成できます(スプレッドシート側に同名のシートを手動で用意しても構いません)。
中間テーブル名を変更したい場合は、@relation でリレーションに名前を付けてください。
enum
Prisma の enum 定義からリテラルユニオン型が自動生成されます。
enum Role {
ADMIN
USER
MODERATOR
}
model User {
id Int @id
role Role
}
生成される型:
"role": "ADMIN" | "USER" | "MODERATOR"
enum の @map
enum メンバーに @map を付けると、コード上の名前とスプレッドシート上の値をマッピングできます。
enum Role {
admin @map("ADMIN")
user @map("USER")
moderator @map("MODERATOR")
}
生成される定数:
const Role = {
admin: "ADMIN",
user: "USER",
moderator: "MODERATOR",
} as const;
型定義には @map の値が使用されます:
"role": "ADMIN" | "USER" | "MODERATOR"
@gassma.addType
Prisma のフィールドコメント(///)に @gassma.addType を記述すると、フィールドの型にユニオン型を追加できます。
model User {
/// @gassma.addType string
id Int @id // 生成型: number | string
/// @gassma.addType string, boolean
score Int // 生成型: number | string | boolean
name String // 生成型: string(コメントなしなら通常通り)
}
@gassma.replaceType
@gassma.addType は基底型とのユニオンですが、@gassma.replaceType は基底型を置換して指定した型のみ生成します。
model User {
/// @gassma.replaceType "admin", "user", "moderator"
role String
}
生成される型:
"role": "admin" | "user" | "moderator" // string を含まない
優先順位: enum > replaceType > addType。enum がある場合は replaceType / addType は無視されます。
@default
@default() が付いたフィールドは、生成される Create 入力型でオプショナル(?)になります。
model User {
id Int @id @default(autoincrement())
name String
isActive Boolean @default(true)
createdAt DateTime @default(now())
}
生成される型:
"isActive"?: boolean // @default(true) → オプショナル
"createdAt"?: Date // @default(now()) → オプショナル
生成されるクライアント JS には defaults 設定が自動的に埋め込まれます。
@default() | 生成される JS |
|---|---|
@default(true) / @default(false) | true / false |
@default(0) (数値) | 0 |
@default("USER") (文字列) | "USER" |
@default(ADMIN) (enum 値) | "ADMIN" |
@default(active) (enum 値・active @map("ACTIVE")) | "ACTIVE"(@map 後の値) |
@default(now()) | () => new Date() |
@default(uuid()) | () => Utilities.getUuid() |
@default(autoincrement()) | autoincrement 設定として別途生成 |
@updatedAt
@updatedAt が付いたフィールドは Create 入力型でオプショナルになり、生成されるクライアント JS に updatedAt 設定が埋め込まれます。
model Post {
id Int @id
title String
updatedAt DateTime @updatedAt
}
@ignore
@ignore が付いたフィールドは型定義から完全に除外され、生成されるクライアント JS に ignore 設定が埋め込まれます。
model User {
id Int @id
name String
secret String @ignore // 型定義に含まれない
}
@map
@map("name") でフィールド名のマッピングを定義できます。生成されるクライアント JS に map 設定が埋め込まれます。
model User {
id Int @id
firstName String @map("名前")
lastName String @map("名字")
}
コード上は firstName / lastName で操作し、スプレッドシート上は「名前」「名字」カラムに対応します。
@@ignore
モデルレベルの @@ignore でシート全体を除外できます。生成されるクライアント JS に ignoreSheets 設定が埋め込まれます。
model Logs {
id Int @id
message String
@@ignore
}
@@map
モデルレベルの @@map("name") でシート名をマッピングできます。
model Users {
id Int @id
name String
@@map("ユーザー一覧")
}
コード上は Users でアクセスし、スプレッドシート上は「ユーザー一覧」シートに対応します。
CLI コマンド
gassma generate
型ファイルとクライアントコードを生成します。
$ npx gassma generate
デフォルトでは ./gassma ディレクトリ内の .prisma ファイルが探索されます。--schema オプションで特定のスキーマファイルまたはディレクトリを指定できます(Prisma の prisma generate --schema に相当)。
$ npx gassma generate --schema gassma/user.prisma
$ npx gassma generate --schema ./schemas
--watch オプションでスキーマファイルの変更を監視し、自動で再生成できます。
$ npx gassma generate --watch
--schema との併用も可能です。
--config オプションで設定ファイルのパスを明示的に指定できます(Prisma の --config に相当)。
$ npx gassma generate --config configs/gassma.config.ts
指定したファイルが存在しない場合は ConfigFileNotFoundError になります。未指定時は従来どおりデフォルトの場所が探索されます(後述の「設定ファイルの探索規則」を参照)。
gassma init
プロジェクトを初期化し、スキーマファイルと設定ファイルを自動生成します。
$ npx gassma init
以下のファイルが生成されます:
gassma/schema.prisma— 初期スキーマgassma.config.ts— 設定ファイル
| オプション | 説明 |
|---|---|
--output <path> | 生成先パスをカスタマイズ |
--with-model | サンプル User モデルを含むスキーマを生成 |
既に schema.prisma が存在する場合はエラーで安全に停止します。
gassma validate
スキーマファイルの構文チェック・整合性チェックを行います(Prisma の prisma validate に相当)。
$ npx gassma validate
$ npx gassma validate --schema gassma/test.prisma
--config オプションで設定ファイルのパスを指定することもできます。
チェック項目:
- 構文エラー(パーサーエラー検出)
generatorブロックの存在チェックoutputフィールドの必須チェック- モデルが 1 つ以上定義されていること
成功時は以下のように出力されます:
The schema at /path/to/gassma/test.prisma is valid 🚀
gassma format
.prisma ファイルを Prisma 公式と同じフォーマットで整形します(@prisma/internals の formatSchema を使用)。
$ npx gassma format
| オプション | 説明 |
|---|---|
--schema <path> | 特定ファイルのみ整形 |
--config <path> | 設定ファイルのパスを指定 |
--check | フォーマット済みかチェック(CI 用、未整形時は exit 1) |
gassma studio
datasource に設定したスプレッドシートを、OS のデフォルトブラウザで開きます。
$ npx gassma studio
| オプション | 説明 |
|---|---|
--config <path> | 設定ファイルのパスを指定 |
URL は以下の順で解決されます。
- スキーマ内の
datasourceブロックのurl gassma.config.tsのdatasource.url
url にフル URL(https://...)を指定している場合はそのまま開き、スプレッドシート ID を指定している場合は https://docs.google.com/spreadsheets/d/<id>/edit を組み立てて開きます。どちらにも URL が設定されていない場合は NoDatasourceUrlError になります。
gassma version
GASsma CLI のバージョンを表示します。
$ npx gassma version
--version / -V フラグでも確認できます。
| オプション | 説明 |
|---|---|
--json | バージョン情報を JSON で出力 |
--json を付けると、バージョン情報を JSON 形式({"gassma":"<version>"})で出力します。
$ npx gassma version --json
{"gassma":"1.2.3"}
生成されるファイル
スキーマファイル名をもとに以下のファイルが生成されます。例えば schema.prisma の場合:
| ファイル | 内容 |
|---|---|
schema.d.ts | 型定義(モデル型、クエリ型、共通型) |
schemaClient.js | クライアント実装(リレーション定義の自動注入込み) |
schemaClient.d.ts | クライアントの型定義 |
出力先は generator ブロックの output で指定したディレクトリです。
生成されたクライアントの使い方
生成されたクライアントファイルから GassmaClient をインポートしてそのまま使えます。リレーション定義は自動注入済みです。
import { GassmaClient } from "./generated/gassma/schemaClient";
const gassma = new GassmaClient();
// 型安全にシートへアクセス
const users = gassma.User.findMany({
where: { age: { gte: 20 } },
select: { name: true, email: true },
});
Prisma と同じパターンでインスタンス化できます。
// Prisma
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// GASsma(同じパターン)
import { GassmaClient } from "./generated/gassma/schemaClient";
const gassma = new GassmaClient();
オプション付きの初期化
// スプレッドシートID指定
const gassma = new GassmaClient("SPREAD_SHEET_ID");
// オプションオブジェクト
const gassma = new GassmaClient({
id: "SPREAD_SHEET_ID",
omit: {
User: { password: true },
},
});
設定ファイル(gassma.config.ts)
プロジェクトルートに gassma.config.ts を配置することで、CLI の設定を一元管理できます(Prisma の prisma.config.ts に相当)。TypeScript 以外の拡張子(.js / .mjs / .cjs / .mts / .cts)や .config/ ディレクトリへの配置にも対応しています(後述の「設定ファイルの探索規則」を参照)。
設定インターフェース
設定ファイルの記述方法は 2 つあります。
1. defineConfig ヘルパーを使用(推奨):
import { defineConfig } from "gassma/config";
export default defineConfig({
schema: "gassma/schema.prisma",
datasource: {
url: "https://docs.google.com/spreadsheets/d/XXXXX/edit",
},
});
2. satisfies 演算子を使用:
import type { GassmaConfig } from "gassma";
export default {
schema: "gassma/schema.prisma",
datasource: {
url: "https://docs.google.com/spreadsheets/d/XXXXX/edit",
},
} satisfies GassmaConfig;
GassmaConfig 型は gassma パッケージのルートから import できます。
設定オプション
| オプション | 型 | 必須 | 説明 |
|---|---|---|---|
schema | string | いいえ | スキーマファイルまたはディレクトリのパス(デフォルト: ./gassma) |
datasource.url | string | いいえ | スプレッドシートの URL または ID |
設定ファイルの探索規則
設定ファイルは以下の順序で探索され、最初に見つかったファイル が採用されます。
gassma.config.jsgassma.config.tsgassma.config.mjsgassma.config.cjsgassma.config.mtsgassma.config.cts.config/gassma.js.config/gassma.ts.config/gassma.mjs.config/gassma.cjs.config/gassma.mts.config/gassma.cts
プロジェクトルート直下の gassma.config.* が全拡張子ぶん先に探索され、その後 .config/ ディレクトリ内の gassma.* が探索されます。.js が .ts より先に採用される点も含め、Prisma の設定ファイル探索と同じ順序です。
--config オプション
generate(--watch 含む)/ validate / format / studio の各コマンドでは、--config オプションで設定ファイルのパスを明示的に指定できます(Prisma の --config に相当)。
$ npx gassma generate --config configs/gassma.config.ts
- 相対パスは実行時のカレントディレクトリ基準で解決されます。
- 指定したファイルが存在しない場合は
ConfigFileNotFoundErrorになります。 - 未指定時は上記の探索規則に従ってデフォルトの場所が探索されます。
ロード時の挙動
gassma generate 実行時、設定ファイルのロードに成功すると以下のように表示されます。
⚙️ Loaded config from gassma.config.ts
- 設定ファイルに構文エラー・実行時エラーがある場合や、既知のキー(
schema/datasource.url)の型が不正な場合はGassmaConfigLoadErrorになります。 - 未知のキーが含まれている場合は警告が表示され、そのキーは無視されます(エラーにはなりません)。
Warning: Unknown property `outut` in /path/to/gassma.config.ts. Known properties are: schema, datasource. It will be ignored.
env() ヘルパー
env() 関数を使うと、環境変数からスプレッドシート URL を取得できます(Prisma の env() に相当)。
import "dotenv/config";
import { defineConfig, env } from "gassma/config";
export default defineConfig({
schema: "gassma",
datasource: {
url: env("SPREADSHEET_URL"),
},
});
satisfies パターンでも使用できます。
import "dotenv/config";
import type { GassmaConfig } from "gassma";
import { env } from "gassma/config";
export default {
schema: "gassma",
datasource: {
url: env("SPREADSHEET_URL"),
},
} satisfies GassmaConfig;
型付きの env()
型引数に環境変数のインターフェースを渡すと、env() に指定できる名前がそのキーに限定され、補完も効くようになります。
import "dotenv/config";
import { defineConfig, env } from "gassma/config";
interface Env {
SPREADSHEET_URL: string;
}
export default defineConfig({
schema: "gassma",
datasource: {
url: env<Env>("SPREADSHEET_URL"),
},
});
指定できるのは値が string(または string | undefined)型のキーのみです。存在しないキーを指定するとコンパイルエラーになります。
env() は環境変数が未設定または空文字の場合に GassmaConfigEnvError をスローします。オプショナルな環境変数には process.env を直接使用してください。
datasource.url
datasource.url にスプレッドシートの URL または ID を指定すると、生成されるクライアント JS に id が自動埋め込みされます。これにより new GassmaClient() だけで対象スプレッドシートに接続できます。
フル URL とスプレッドシート ID の両方に対応しています。
// フル URL
datasource: {
url: "https://docs.google.com/spreadsheets/d/XXXXX/edit",
}
// ID 直接指定
datasource: {
url: "XXXXX",
}
スキーマ内の datasource ブロック
スキーマファイル内に datasource ブロックを記述することでも URL を指定できます。
datasource db {
provider = "google-spreadsheet"
url = "https://docs.google.com/spreadsheets/d/XXXXX/edit"
}
URL 解決の優先順位
- スキーマ内の
datasourceブロック(最優先) gassma.config.tsのdatasource.url
スキーマ解決の優先順位
--schemaオプション(最優先)gassma.config.tsのschema設定- デフォルト
./gassmaディレクトリ
相対パスの解決基準はそれぞれ異なります。--schema オプションは実行時のカレントディレクトリ基準、設定ファイルの schema は 設定ファイルのある場所基準 で解決されます(Prisma と同じ)。
gassma init を実行すると gassma.config.ts も自動生成されます。
マルチファイルスキーマ
同じディレクトリ(およびサブディレクトリ)内に複数の .prisma ファイルを配置すると、自動的に 1 つのスキーマとして統合 されます。Prisma の Multi-file schema と同等の機能です。
gassma/
├── schema.prisma ← generator ブロックをここに記述
├── models/
│ ├── user.prisma ← User, Profile モデル
│ └── post.prisma ← Post, Comment モデル
generator ブロックはいずれか 1 ファイルに記述すれば、全ファイルで共有されます。すべてのモデルが 1 つのクライアント出力にまとめられます。
複数スキーマ(複数スプレッドシート)
異なるスプレッドシートを扱う場合は、スキーマを別々のディレクトリに分けて個別に生成します。型名にはスキーマ名のプレフィックスが付与されるため、同名モデルがあっても衝突しません。
schemas/
├── user/
│ └── schema.prisma → userClient.js, user.d.ts
└── order/
└── schema.prisma → orderClient.js, order.d.ts
import { GassmaClient as UserClient } from "./generated/user/schemaClient";
import { GassmaClient as OrderClient } from "./generated/order/schemaClient";
const userGassma = new UserClient();
const orderGassma = new OrderClient();
生成される型の概要
生成される .d.ts には以下の型が含まれます。
- モデル型: 各フィールドの型定義(
GassmaUserUse等) - クエリ型:
FindData、CreateData、UpdateData、DeleteData、UpsertData等 - Select / Omit 型: フィールド選択・除外の型
- フィルタ型:
WhereUse、FilterConditions(FieldRef対応含む) - OrderBy 型: ソート条件(リレーションソート、
_countソート、nulls 制御含む) - Include 型: リレーション取得の型(
_count含む) - Nested Write 型: リレーション先の作成・接続・更新・削除操作
- 数値操作型:
NumberOperation(increment / decrement / multiply / divide) - 共通型:
FieldRef、GassmaClientOptions、エラークラス群 - 設定型:
DefaultsConfig、UpdatedAtConfig、IgnoreConfig、AutoincrementConfig、MapConfig等 - コントローラー型: 全メソッドの引数・戻り値型