# 列名変換機能 (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コードでより自然な列名を使用できるようになります。 