メインコンテンツまでスキップ
バージョン: 0.13.0 (Previous)

🆔 エンティティユーティリティ

Nodeblocks SDK は、自動フィールド生成を伴うデータベースエンティティの作成と管理に不可欠なユーティリティを提供します。これらのユーティリティは、自動タイムスタンプと一意識別子により、アプリケーション全体で一貫したエンティティ構造を確保します。


🎯 概要

エンティティユーティリティは、自動フィールド生成を伴うデータベースエンティティの作成および更新を標準化する関数を提供します。エンティティ構造の一貫性を確保し、定型コードを減らします。

主な機能

  • ID の自動生成: エンティティ識別子用の UUID v4 生成(uuid パッケージ経由)
  • タイムスタンプ管理: createdAt および updatedAt フィールドの自動生成
  • 一貫した構造: 標準化されたエンティティ作成・更新パターン
  • 型安全性: エクスポートされた BaseEntity 型を備えたジェネリック入力 Record<string, unknown>

このモジュールは createBaseEntityupdateBaseEntityBaseEntity の 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 生成は uuid v4 を直接使用します(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'
}

ハンドラーでの使用

以下のハンドラー例は説明用です。okmergeDataRouteHandlerPayload は別の 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;
};

📊 フィールド仕様

生成フィールド

フィールド説明生成元
idstringUUID v4 識別子createBaseEntity
createdAtstring作成時の ISO タイムスタンプcreateBaseEntity
updatedAtstring最終更新時の 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 });
};

🔗 関連項目