Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022
の9日目。株式会社mofmofに生息しているshwldです。
前日はTaskEither型について書きました。
エンティティの状態遷移関数
モデルのプロジェクト構造は以下のようになっています。
models
┣━ account
┃ ┣━ mutations
┃ ┃ ┣━ build-account.test.ts
┃ ┃ ┣━ build-account.ts ← 状態遷移メソッド「新規作成」
┃ ┃ ┣━ edit-account.test.ts
┃ ┃ ┣━ edit-account.ts ← 状態遷移メソッド「更新」
┃ ┃ ┗━ index.ts
┃ ┣━ account-entity.ts
┃ ┣━ account-interfaces.ts
┃ ┣━ account-policies.ts
┃ ┣━ account-validator.ts
┃ ┗━ index.ts
┣━ story
...
https://github.com/shwld/uzumaki/tree/main/domain/core/src/models
上記のmutationsフォルダ内について解説していきます。
こちらのフォルダには、エンティティの状態を変異させるメソッドが入っています。
一つの状態変更イベントを1ファイルとして格納しています。
ファイルの中身は以下のようになっています
// 入力データの型
export interface Account_BuildInput {
id: ID;
name: string;
createdById: string;
}
// 出力データの型
export interface Account_BuiltAttributes
__state: 'Built';
id: ID;
name: string;
createdById: string;
}
/**
* Validation
*/
export const validationSchema = z // バリデーションはzodを利用
.object({
...AccountValidator.validators,
createdById: genericValidator.id,
})
.strict();
/**
* Mutation
*/
export const build = (
input: Account_BuildInput
): Result<InvalidAttributesError, Account_BuiltAttributes> => {
return pipe(
{
...input,
createdAt: new Date(),
updatedAt: new Date(),
},
validateWith(validationSchema),
map(v => ({
...v,
__state: 'Built',
}))
);
};
GitHubで /models/account/mutations/build-account.tsを みる
TypeScriptによるGraphQLバックエンド開発 ──TypeScriptの型システムとデータフローに着目した宣言的プログラミング
では、バリデーション後なども型を用意していましたが、自分はそれはしませんでした。
理由としては、特にそこの処理を分離して使う利用シーンが思い浮かばなかったというところです。
基本的にはmutationとセットでバリデーションも実行しており、バリデーション結果に応じて状態を遷移させる処理となります。
mutationそれぞれに対応した型を用意することで、イベントからイベントへの遷移をどうやって行うのかを型で説明できるようになるとともに、どの型は永続化できるのかも型で判断できるようになります(リポジトリに永続化処理があるかどうかをみる)
また、mutationsをフォルダ内に一つ一つファイルで作ることによって、コマンドとクエリが分離され、クエリを安心して使えるようになりました。
次回予告
次回はエンティティのバリデーションについて書きます。