🆔 エンティティユーティリティ
Nodeblocks SDK は、自動フィールド生成を伴うデータベースエンティティの作成と管理に不可欠なユーティリティを提供します。これらのユーティリティは、自動タイムスタンプと一意識別子により、アプリケーション全体で一貫したエンティティ構造を確保します。
🎯 概要
エンティティユーティリティは、自動フィールド生成を伴うデータベースエンティティの作成および更新を標準化する関数を提供します。エンティティ構造の一貫性を確保し、定型コードを減らします。
主な機能
- ID の自動生成: エンティティ識別子用の UUID v4 生成(
uuidパッケージ経由) - タイムスタンプ管理:
createdAtおよびupdatedAtフィールドの自動生成 - 一貫した構造: 標準化されたエンティティ作成・更新パターン
- 型安全性: エクスポートされた
BaseEntity型を備えたジェネリック入力Record<string, unknown>
このモジュールは createBaseEntity、updateBaseEntity、BaseEntity の 3 つのシンボルをエクスポートします。
🆔 エンティティの作成
createBaseEntity
自動フィールド生成を伴う新しいエンティティを作成します。
import { utils } from '@nodeblocks/backend-sdk';
const { createBaseEntity } = utils;
const userData = {
email: 'user@example.com',
name: 'John Doe',
role: 'user'
};
const user = createBaseEntity(userData);
生成されるフィールド:
id: UUID v4 文字列createdAt: ISO タイムスタンプ文字列updatedAt: ISO タイムスタンプ文字列
パラメーター:
data: エンティティペイロード(Record<string, unknown>)
動作:
{ ...data, createdAt, id, updatedAt }を返します。- 生成フィールドは、
data内の同名キーを常に上書きします(例: クライアントが指定したidは置き換えられます)。 - ID 生成は
uuidv4 を直接使用します(generateUUIDと同等ですが、同じ関数呼び出しではありません)。
結果:
{
email: 'user@example.com',
name: 'John Doe',
role: 'user',
id: '550e8400-e29b-41d4-a716-446655440000',
createdAt: '2024-01-15T10:30:00.000Z',
updatedAt: '2024-01-15T10:30:00.000Z'
}
ハンドラーでの使用
以下のハンドラー例は説明用です。ok、mergeData、RouteHandlerPayload は別の SDK モジュール(neverthrow、ハンドラーユーティリティ、primitives)から取得します。
import { ok } from 'neverthrow';
import { utils, handlers } from '@nodeblocks/backend-sdk';
import { primitives } from '@nodeblocks/backend-sdk';
const { createBaseEntity } = utils;
const { mergeData } = handlers;
type RouteHandlerPayload = primitives.RouteHandlerPayload;
const createUserHandler = async (payload: RouteHandlerPayload) => {
const { params } = payload;
// 基本フィールドを含むエンティティを作成
const userEntity = createBaseEntity(params.requestBody);
// データベースへ保存
const result = await payload.context.db.users.insertOne(userEntity);
return ok(mergeData(payload, { userId: userEntity.id }));
};
🔄 エンティティの更新
updateBaseEntity
自動タイムスタンプ管理を伴って既存のエンティティを更新します。
import { utils } from '@nodeblocks/backend-sdk';
const { updateBaseEntity } = utils;
const updateData = {
name: 'Jane Doe',
email: 'jane@example.com'
};
const updatedUser = updateBaseEntity(updateData);
生成されるフィールド:
updatedAt: 現在の ISO タイムスタンプ文字列
パラメーター:
data: 更新に含めるフィールド(Record<string, unknown>)
動作:
{ ...data, updatedAt }を返します。既存ドキュメントの取得やマージは行いません。idまたはcreatedAtは追加しません。呼び出し元は MongoDB の$setへ入れるフィールドを渡します。- 空のオブジェクトを渡すと
updatedAtだけを更新できます:updateBaseEntity({})
updatedAt のみを更新:
import { utils } from '@nodeblocks/backend-sdk';
const { updateBaseEntity } = utils;
// 他のフィールドを変更せず updatedAt を更新する(SDK で一般的なパターン)
await collection.updateOne(
{ id: entityId },
{ $set: updateBaseEntity({}) }
);
結果:
{
name: 'Jane Doe',
email: 'jane@example.com',
updatedAt: '2024-01-15T11:45:00.000Z'
}
更新ハンドラーでの使用
import { ok } from 'neverthrow';
import { utils, handlers } from '@nodeblocks/backend-sdk';
import { primitives } from '@nodeblocks/backend-sdk';
const { updateBaseEntity } = utils;
const { mergeData } = handlers;
type RouteHandlerPayload = primitives.RouteHandlerPayload;
const updateUserHandler = async (payload: RouteHandlerPayload) => {
const { params, context } = payload;
const userId = params.requestParams?.userId;
// タイムスタンプを含む更新データを準備
const updateData = updateBaseEntity(params.requestBody);
// データベースを更新
const result = await context.db.users.updateOne(
{ id: userId },
{ $set: updateData }
);
return ok(mergeData(payload, { updated: true }));
};
🔧 高度な使用方法
以下の例は SDK ユーティリティを基にした説明用のパターンであり、追加の SDK エクスポートではありません。
ネストしたサブエンティティ
SDK は、最上位のデータベースドキュメントだけでなく、ネストしたサブドキュメント(添付ファイル、画像、フォロー記録、ワンタイムトークン)にも createBaseEntity を使用します。
import { utils } from '@nodeblocks/backend-sdk';
const { createBaseEntity, updateBaseEntity } = utils;
// 独自の ID とタイムスタンプを持つネストしたエンティティを追加
await productsCollection.updateOne(
{ id: productId },
{
$push: { images: createBaseEntity({ url: imageUrl, alt: 'Product photo' }) },
$set: updateBaseEntity({}),
}
);
カスタムエンティティの作成
import { utils } from '@nodeblocks/backend-sdk';
const { createBaseEntity } = utils;
const createProduct = (productData: ProductData) => {
const baseEntity = createBaseEntity(productData);
// カスタムフィールドを追加
return {
...baseEntity,
status: 'active',
category: productData.category || 'general'
};
};
const product = createProduct({
name: 'Sample Product',
price: 29.99,
description: 'A sample product'
});
バッチエンティティの作成
import { utils } from '@nodeblocks/backend-sdk';
const { createBaseEntity } = utils;
const createMultipleUsers = (usersData: UserData[]) => {
return usersData.map(userData => createBaseEntity(userData));
};
const users = createMultipleUsers([
{ name: 'User 1', email: 'user1@example.com' },
{ name: 'User 2', email: 'user2@example.com' }
]);
条件付き更新
import { utils } from '@nodeblocks/backend-sdk';
const { updateBaseEntity } = utils;
const updateUserConditionally = (userId: string, updateData: Partial<User>) => {
const baseUpdate = updateBaseEntity(updateData);
// 条件付きロジックを追加
if (updateData.status === 'inactive') {
return {
...baseUpdate,
deactivatedAt: new Date().toISOString()
};
}
return baseUpdate;
};
📊 型
BaseEntity
生成される基本フィールドを持つエンティティの標準形です。ブロック(チャットメッセージ、商品など)でジェネリック制約として使用されます。
import { utils } from '@nodeblocks/backend-sdk';
type BaseEntity = utils.BaseEntity;
// 次と同等:
interface BaseEntity {
id: string;
createdAt: string;
updatedAt: string;
}
createBaseEntity(data) は data にこの 3 フィールドをマージして返します。コレクションやブロック関数を型付けする際には BaseEntity を拡張してください。
type Product = BaseEntity & {
name: string;
price: number;
};
📊 フィールド仕様
生成フィールド
| フィールド | 型 | 説明 | 生成元 |
|---|---|---|---|
id | string | UUID v4 識別子 | createBaseEntity |
createdAt | string | 作成時の ISO タイムスタンプ | createBaseEntity |
updatedAt | string | 最終更新時の ISO タイムスタンプ | 両方の関数 |
フィールド形式
- ID: UUID v4 形式(
550e8400-e29b-41d4-a716-446655440000) - タイムスタンプ: ISO 8601 形式(
2024-01-15T10:30:00.000Z)
📐️ ベストプラクティス
1. 一貫して使用する
// ✅ 良い例: 常にエンティティユーティリティを使用
const user = createBaseEntity(userData);
const updatedUser = updateBaseEntity(updateData);
// ❌ 避ける: 手動のフィールド生成 — 代わりに createBaseEntity を使用
const user = {
...userData,
id: generateUUID(), // createBaseEntity が内部で id/タイムスタンプを処理
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
基本エンティティ以外に追加の一意フィールドが必要な場合の UUID 単独生成については、Common ユーティリティを参照してください。
2. 型安全性
// ✅ 良い例: 適切な型付けを使用
interface UserData {
email: string;
name: string;
}
const userData: UserData = { email: 'user@example.com', name: 'John' };
const user = createBaseEntity(userData);
3. データベースとの統合
// ✅ 良い例: データベース操作で使用
const createUser = async (userData: UserData) => {
const entity = createBaseEntity(userData);
return await db.users.insertOne(entity);
};
const updateUser = async (userId: string, updateData: Partial<UserData>) => {
const update = updateBaseEntity(updateData);
return await db.users.updateOne({ id: userId }, { $set: update });
};
🔗 関連項目
- Common ユーティリティ - UUID 生成と型チェック
- ハンドラーコンポーネント - ハンドラーでのエンティティ使用方法