# 機能設計書 117-onlyx

## 概要

本ドキュメントは、Hack Standard Library (HSL) の `C\onlyx` 関数の機能設計について記述する。この関数は、Traversable（走査可能コレクション）が正確に1つの要素を持つことを検証し、その要素を取得する。複数またはゼロの要素がある場合は例外をスローする。

### 本機能の処理概要

`C\onlyx` 関数は、Traversable が正確に1つの要素のみを含むことを検証し、その要素を取得する関数である。要素が0個または2個以上の場合は `InvariantException` をスローする。オプションでカスタムエラーメッセージを指定できる。

**業務上の目的・背景**：データの整合性を検証する場面で使用される。外部キー参照の結果が必ず1件であることを保証したい場合や、ユニークな検索結果の取得など、「正確に1つ」であることがビジネスルールである場合に有用である。

**機能の利用シーン**：
- データベースクエリ結果が正確に1件であることの検証
- ユニーク制約を持つデータの取得
- 設定ファイルから単一の設定値を取得
- 検証後の安全な単一要素アクセス

**主要な処理内容**：
1. foreach でコレクションをイテレーション
2. 最初の要素を取得し、2回目のイテレーションを検出
3. 2回目のイテレーションがあれば例外をスロー（複数要素）
4. イテレーションが0回の場合も例外をスロー（空）
5. 正確に1回のイテレーションの場合のみ要素を返却

**関連システム・外部連携**：本機能は外部システムとの連携はなく、純粋な検証・取得ロジックを提供する。

**権限による制御**：特になし。純粋な関数であり、権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 画面なし | - | 本機能はUIを持たないライブラリ関数 |

## 機能種別

データアクセス / バリデーション / 要素選択

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $traversable | Traversable<T> | Yes | 走査可能コレクション | 正確に1要素であること |
| $format_string | ?Str\SprintfFormatString | No | カスタムエラーメッセージのフォーマット文字列 | - |
| ...$format_args | mixed | No | フォーマット文字列の引数（可変長） | - |

### 入力データソース

関数呼び出し時の引数として直接渡される。vec、dict、keyset、Vector、Map、Set、Generator等のTraversableを実装する任意の型を受け付ける。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | T | コレクションの唯一の要素 |

### 出力先

関数の戻り値として呼び出し元に返却される。

## 処理フロー

### 処理シーケンス

```
1. 初期化
   └─ $first = true, $result = null
2. イテレーション開始
   └─ foreach ($traversable as $value)
3. 2回目以降のイテレーション検出
   └─ $first が false の場合、invariant で例外をスロー
   └─ エラーメッセージ: カスタムまたはデフォルト
4. 最初のイテレーション
   └─ $result = $value
   └─ $first = false
5. イテレーション終了後
   └─ $first が true（0回イテレーション）の場合、invariant で例外をスロー
6. 結果返却
   └─ $result を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[foreach開始]
    B --> C{要素あり?}
    C -->|No| D{$first == true?}
    D -->|Yes| E[InvariantException: 空]
    D -->|No| F[結果を返却]
    C -->|Yes| G{$first == true?}
    G -->|Yes| H[結果を保持, $first=false]
    H --> B
    G -->|No| I[InvariantException: 複数要素]
    F --> J[終了]
    E --> J
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-117-01 | 単一要素必須 | 正確に1つの要素のみを許容 | 常に適用 |
| BR-117-02 | 空コレクション禁止 | 空のコレクションが渡された場合は例外をスロー | 常に適用 |
| BR-117-03 | 複数要素禁止 | 2つ以上の要素がある場合は例外をスロー | 常に適用 |
| BR-117-04 | カスタムエラー | フォーマット文字列指定時はカスタムメッセージを使用 | $format_string が指定された場合 |

### 計算ロジック

特に計算ロジックは存在しない。要素数の検証後、唯一の要素をそのまま返却する。

## データベース操作仕様

### 操作別データベース影響一覧

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | InvariantException | コレクションが空の場合 | データの存在を確認、または `first` を使用 |
| - | InvariantException | コレクションが2要素以上の場合 | データのフィルタリングを確認、または `first` を使用 |

### リトライ仕様

リトライは不要。例外発生時は呼び出し元で適切にハンドリングする。

## トランザクション仕様

本機能はトランザクション管理を行わない純粋関数である。

## パフォーマンス要件

- 時間計算量: O(1) - 最大2回のイテレーションで判定
- 空間計算量: O(1)

## セキュリティ考慮事項

本機能は純粋関数であり、特別なセキュリティ考慮事項はない。入力データの検証は型システムにより保証される。

## 備考

- `first` 関数との違い: `first` は複数要素があっても最初の1つを返す
- `firstx` 関数との違い: `firstx` は空の場合のみ例外をスロー
- カスタムエラーメッセージにより、より詳細なデバッグ情報を提供可能
- Container の場合はエラーメッセージに要素数が含まれる

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Hack言語のTraversable型と可変長引数について理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/c/select.php` | 関数シグネチャと型パラメータ T、可変長引数の理解 |

**読解のコツ**: `Str\SprintfFormatString` は型安全な sprintf フォーマット文字列を表す。`...$format_args` は可変長引数。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.php | `src/c/select.php` | onlyx 関数の実装（329-361行目） |

**主要処理フロー**:
1. **329-333行目**: 関数シグネチャ - Traversable<T>、オプションのフォーマット文字列、可変長引数
2. **334-335行目**: 初期化 - $first = true, $result = null
3. **336-350行目**: foreach でイテレーション、2回目以降で例外
4. **337-348行目**: invariant で複数要素チェック
5. **340-346行目**: エラーメッセージ生成（カスタムまたはデフォルト）
6. **349-350行目**: 最初の要素を保持
7. **352-358行目**: イテレーション0回の場合の例外
8. **360行目**: 結果を返却

#### Step 3: 関連関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.php | `src/c/select.php` | first 関数（88-98行目）- 単に最初の要素を返す |
| 3-2 | select.php | `src/c/select.php` | firstx 関数（112-132行目）- 空の場合のみ例外 |
| 3-3 | introspect.php | `src/c/introspect.php` | count 関数（89-93行目）- エラーメッセージ用 |

**主要処理フロー**:
- **329-361行目**: onlyx は正確に1要素を要求
- **88-98行目**: first は複数でも最初の1つを返す
- **112-132行目**: firstx は空のみ例外、複数はOK

### プログラム呼び出し階層図

```
C\onlyx($traversable, $format_string?, ...$format_args)
    │
    ├─ foreach ($traversable as $value) [イテレーション]
    │      │
    │      ├─ 2回目以降 → invariant(...) [例外]
    │      │                  │
    │      │                  ├─ カスタムメッセージ → vsprintf()
    │      │                  │
    │      │                  └─ デフォルト → Str\format()
    │      │                         │
    │      │                         └─ $traversable is Container
    │      │                               → count() で要素数表示
    │      │
    │      └─ 1回目 → 結果を保持
    │
    ├─ 0回イテレーション → invariant(...) [例外]
    │
    └─ 結果を返却
```

### データフロー図

```
[入力]                    [処理]                         [出力]

Traversable<T> ───▶ 要素数検証 ───▶ 正確に1つ ───▶ T（唯一の要素）
                         │
                         ├─────▶ 0個 ───▶ InvariantException
                         │
                         └─────▶ 2個以上 ───▶ InvariantException
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/c/select.php` | ソース | onlyx 関数の実装 |
| introspect.php | `src/c/introspect.php` | ソース | count 関数（エラーメッセージ用） |
| CSelectTest.php | `tests/c/CSelectTest.php` | テスト | onlyx のユニットテスト（715-790行目） |
