UNPKG

@gftdcojp/ksqldb-orm

Version:

ksqldb-orm - Server-Side TypeScript ORM for ksqlDB with enterprise security extensions

377 lines (296 loc) 10.8 kB
# 列名変換機能 (Column Name Transform) KsqlDBの列名が強制的に大文字になる仕様に対応するため、TypeScriptのキャメルケースやスネークケースの列名を自動的にKsqlDB用の大文字に変換する機能です。 ## 問題の背景 ### KsqlDBの仕様 - 引用符なしの識別子(列名)は自動的に大文字に変換される - `userId` → `USERID`、`email` → `EMAIL` - これによりTypeScriptコードで小文字の列名を使用するとエラーが発生 ### 発生していた問題 ```typescript // ❌ エラーが発生 const { data: userDataFromDb, error: userFetchError } = await ksqldbClient .from("users") .eq("email", auth0User.email) // "email" がKsqlDBで認識されない .single(); // Result: Error - User fetch error in withAuth: null ``` ## 解決策 ### 自動列名変換機能 この機能により、TypeScriptコードでは小文字の列名を使用し、内部的にKsqlDB用の大文字に自動変換されます。 ```typescript // ✅ 自動変換により正常に動作 const { data: userDataFromDb, error: userFetchError } = await ksqldbClient .from("users") .eq("email", auth0User.email) // 内部で "EMAIL" に自動変換 .single(); ``` ## 基本的な使用方法 ### 1. 設定の追加 ```typescript import { createKsqlDbClient, PRESET_COLUMN_TRANSFORM_CONFIGS } from '@gftdcojp/ksqldb-orm'; const ksqldbClient = createKsqlDbClient({ url: 'https://your-ksqldb-server.com:8088', apiKey: 'your-api-key', apiSecret: 'your-api-secret', // 列名変換設定を追加 columnNameTransform: PRESET_COLUMN_TRANSFORM_CONFIGS.CAMEL_CASE }); ``` ### 2. クエリでの使用 ```typescript // TypeScriptコードでは小文字の列名を使用 const users = await ksqldbClient .from('users') .select('userId, email, firstName, lastName') // 内部で大文字に変換 .eq('email', 'test@example.com') // 内部で "EMAIL" に変換 .order('createdAt', false) // 内部で "CREATEDAT" に変換 .execute(); // レスポンスは自動的にcamelCaseに変換される console.log(users.data); // [{ userId: "123", email: "test@example.com", firstName: "John", lastName: "Doe" }] ``` ## 設定オプション ### 1. 事前定義された設定パターン ```typescript import { PRESET_COLUMN_TRANSFORM_CONFIGS } from '@gftdcojp/ksqldb-orm'; // camelCase → UPPERCASE const camelCaseConfig = PRESET_COLUMN_TRANSFORM_CONFIGS.CAMEL_CASE; // snake_case → UPPERCASE const snakeCaseConfig = PRESET_COLUMN_TRANSFORM_CONFIGS.SNAKE_CASE; // 変換なし const noneConfig = PRESET_COLUMN_TRANSFORM_CONFIGS.NONE; ``` ### 2. カスタム戦略設定 ```typescript import { ColumnNameTransformConfig } from '@gftdcojp/ksqldb-orm'; const customConfig: ColumnNameTransformConfig = { strategy: 'uppercase', // 'uppercase' | 'lowercase' | 'camelCase' | 'snake_case' | 'none' preserveExistingUppercase: true }; ``` ### 3. 明示的マッピング設定 ```typescript const mappingConfig: ColumnNameTransformConfig = { strategy: 'uppercase', columnMappings: { 'userId': 'USER_IDENTIFIER', 'email': 'EMAIL_ADDRESS', 'createdAt': 'CREATION_TIMESTAMP' } }; ``` ### 4. カスタム変換関数 ```typescript const customTransformConfig: ColumnNameTransformConfig = { customTransform: (columnName: string) => { // カスタムロジック if (columnName === 'id') return 'UNIQUE_ID'; return columnName.toUpperCase(); } }; ``` ## TypeScript型定義との統合 ### 1. インターフェース定義 ```typescript interface User { userId: string; // TypeScript: camelCase email: string; // TypeScript: camelCase accountId: string; // TypeScript: camelCase firstName: string; lastName: string; createdAt: string; isActive: boolean; } // ORMが内部で以下に変換 // KsqlDB: USERID, EMAIL, ACCOUNTID, FIRSTNAME, LASTNAME, CREATEDAT, ISACTIVE ``` ### 2. 完全な使用例 ```typescript import { createKsqlDbClient, PRESET_COLUMN_TRANSFORM_CONFIGS } from '@gftdcojp/ksqldb-orm'; // 設定 const ksqldbClient = createKsqlDbClient({ url: process.env.KSQLDB_URL!, apiKey: process.env.KSQLDB_API_KEY!, apiSecret: process.env.KSQLDB_API_SECRET!, columnNameTransform: PRESET_COLUMN_TRANSFORM_CONFIGS.CAMEL_CASE }); // 認証機能での使用例 async function authenticateUser(email: string): Promise<User | null> { const { data: userData, error } = await ksqldbClient .from('users') .select('userId, email, accountId, firstName, lastName, isActive') .eq('email', email) // 自動的に "EMAIL" に変換 .eq('isActive', true) // 自動的に "ISACTIVE" に変換 .single(); if (error) { console.error('Authentication error:', error); return null; } return userData; // { userId: "123", email: "test@example.com", ... } } // データ挿入での使用例 async function createUser(userData: Partial<User>): Promise<User | null> { const { data, error } = await ksqldbClient .from('users') .insert({ userId: generateId(), email: userData.email, // 内部で "EMAIL" に変換 firstName: userData.firstName,// 内部で "FIRSTNAME" に変換 lastName: userData.lastName, // 内部で "LASTNAME" に変換 isActive: true // 内部で "ISACTIVE" に変換 }); return error ? null : data; } ``` ## 高度な使用例 ### 1. 複数の変換戦略 ```typescript // 開発環境:変換なし const devConfig: ColumnNameTransformConfig = { strategy: 'none' }; // 本番環境:自動変換 const prodConfig: ColumnNameTransformConfig = { strategy: 'uppercase', columnMappings: { 'id': 'UNIQUE_IDENTIFIER', 'timestamp': 'EVENT_TIMESTAMP' } }; const config = process.env.NODE_ENV === 'production' ? prodConfig : devConfig; ``` ### 2. 動的マッピング ```typescript const dynamicConfig: ColumnNameTransformConfig = { customTransform: (columnName: string) => { // 特別な命名規則 if (columnName.endsWith('Id')) { return columnName.replace('Id', '_IDENTIFIER').toUpperCase(); } if (columnName.startsWith('is')) { return `${columnName.substring(2).toUpperCase()}_FLAG`; } return columnName.toUpperCase(); } }; // userId → USER_IDENTIFIER // isActive → ACTIVE_FLAG // email → EMAIL ``` ### 3. 条件付き変換 ```typescript const conditionalConfig: ColumnNameTransformConfig = { strategy: 'uppercase', customTransform: (columnName: string) => { // 既に大文字の場合はそのまま if (columnName === columnName.toUpperCase()) { return columnName; } // 特定のパターンの場合は特別な処理 const specialMappings: Record<string, string> = { 'createdAt': 'CREATION_TIMESTAMP', 'updatedAt': 'MODIFICATION_TIMESTAMP', 'deletedAt': 'DELETION_TIMESTAMP' }; return specialMappings[columnName] || columnName.toUpperCase(); } }; ``` ## バックワード互換性 ### 既存コードとの互換性 ```typescript // 既存の大文字指定も引き続きサポート const legacyQuery = await ksqldbClient .from('users') .eq('EMAIL', 'test@example.com') // 既存の大文字指定 .eq('email', 'test@example.com') // 新しい小文字指定(自動変換) .execute(); ``` ### 段階的移行 ```typescript // 設定で移行をコントロール const migrationConfig: ColumnNameTransformConfig = { strategy: 'uppercase', preserveExistingUppercase: true, // 既存の大文字を保持 columnMappings: { // 新しい列名のマッピングのみ追加 'newField': 'NEW_FIELD_NAME' } }; ``` ## トラブルシューティング ### 1. 変換が効かない場合 ```typescript // デバッグ用に変換結果を確認 import { transformColumnNameForKsqlDb } from '@gftdcojp/ksqldb-orm'; const config = { strategy: 'uppercase' as const }; console.log(transformColumnNameForKsqlDb('email', config)); // "EMAIL" ``` ### 2. 予期しない変換結果 ```typescript // カスタム変換でデバッグ const debugConfig: ColumnNameTransformConfig = { customTransform: (columnName: string) => { const result = columnName.toUpperCase(); console.log(`Column transform: ${columnName} → ${result}`); return result; } }; ``` ### 3. パフォーマンス最適化 ```typescript // マッピング辞書を使って高速化 import { COMMON_COLUMN_MAPPINGS } from '@gftdcojp/ksqldb-orm'; const optimizedConfig: ColumnNameTransformConfig = { strategy: 'uppercase', columnMappings: { ...COMMON_COLUMN_MAPPINGS.CAMEL_TO_UPPER, // プロジェクト固有のマッピングを追加 'customField': 'CUSTOM_FIELD_NAME' } }; ``` ## 実装の詳細 ### 変換タイミング 1. **クエリ送信時**: `eq()`, `select()`, `order()`などのメソッドで列名を大文字に変換 2. **レスポンス受信時**: KsqlDBからのレスポンスでキーをcamelCaseに変換 ### 変換ロジック 1. 明示的マッピング辞書をチェック 2. カスタム変換関数をチェック 3. 既存の大文字列名の保持設定をチェック 4. 設定された戦略に基づいて変換 ### パフォーマンス - 列名変換はメモ化されており、同じ列名の変換は高速 - マッピング辞書による変換は O(1) の時間計算量 - 文字列変換操作は軽量で、パフォーマンスへの影響は最小 ## 制限事項 ### 1. 複雑な列名 特殊文字や数字を含む列名では、期待と異なる変換結果になる場合があります。この場合は明示的マッピングを使用してください。 ### 2. 動的列名 動的に生成される列名(例:`SELECT ${field} FROM table`)は、実行時まで変換できません。 ### 3. エイリアス SQLのエイリアス(AS句)は現在サポートされていません。 ## ベストプラクティス ### 1. 事前定義設定の使用 ```typescript // 推奨:事前定義された設定を使用 columnNameTransform: PRESET_COLUMN_TRANSFORM_CONFIGS.CAMEL_CASE ``` ### 2. 明示的マッピング ```typescript // 重要な列名は明示的にマッピング columnMappings: { 'userId': 'USER_IDENTIFIER', 'email': 'EMAIL_ADDRESS' } ``` ### 3. テスト ```typescript // 変換結果をテストで検証 describe('Column name transformation', () => { it('should transform email to EMAIL', () => { expect(transformColumnNameForKsqlDb('email', config)).toBe('EMAIL'); }); }); ``` この機能により、KsqlDBの列名の大文字強制仕様による認証エラーやその他の問題が解決され、TypeScriptコードでより自然な列名を使用できるようになります。