# 機能設計書 17-変形・整形

## 概要

本ドキュメントは、Nushellにおける変形・整形機能の設計について記述する。flatten、transpose、wrapコマンドを通じて、データ構造の形状を変換する機能を提供する。

### 本機能の処理概要

変形・整形機能は、テーブルやレコードの構造を変換する。flattenはネストを展開、transposeは行列を転置、wrapは値をカラムでラップする。

**業務上の目的・背景**：データ処理において、データの形状を目的に合わせて変換することは一般的な要件である。ネストしたデータの平坦化、テーブルの行列入れ替え、値のレコード化など、構造変換の多様なパターンに対応する。

**機能の利用シーン**：
- `[[a b]; [1 [2 3]]] | flatten` でネストしたリストを展開
- `{a: 1, b: 2} | transpose` でレコードをテーブルに変換
- `[1 2 3] | wrap num` でリストをテーブル化
- `ls | transpose key val` でテーブルを転置

**主要な処理内容**：
1. 入力データ構造の解析
2. 構造変換ルールの適用
3. 新しい構造でのデータ再構築
4. 結果を返却

**関連システム・外部連携**：特になし。純粋なインメモリ処理。

**権限による制御**：特になし。純粋なデータ操作機能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | メインREPL | 主画面 | 変形コマンドの入力と結果表示 |

## 機能種別

データ操作（構造変換処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rest | String | No (flatten) | 対象カラム名 | - |
| --all, -a | Switch | No (flatten) | 内部テーブルも展開 | - |
| rest | String | No (transpose) | 出力カラム名 | - |
| --header-row, -r | Switch | No (transpose) | 最初のカラムをヘッダーに | - |
| --ignore-titles, -i | Switch | No (transpose) | タイトル行を無視 | - |
| --as-record, -d | Switch | No (transpose) | 1行の場合レコードで返す | - |
| --keep-last, -l | Switch | No (transpose) | 重複キーで最後の値を保持 | - |
| --keep-all, -a | Switch | No (transpose) | 重複キーで全値をリストに | - |
| name | String | Yes (wrap) | カラム名 | 文字列 |

### 入力データソース

- パイプライン入力: List、Table、Record、Range
- flatten: List/Table/Record
- transpose: Table/Record
- wrap: Any

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| flattened_list | List | (flatten) 展開されたリスト |
| transposed_table | Table | (transpose) 転置されたテーブル |
| transposed_record | Record | (transpose --as-record) 転置されたレコード |
| wrapped_table | Table | (wrap) ラップされたテーブル |
| wrapped_record | Record | (wrap) ラップされたレコード |

### 出力先

- パイプライン出力: `PipelineData`として後続コマンドへ渡す

## 処理フロー

### 処理シーケンス

```
1. コマンド引数の解析
   └─ flatten: 対象カラムと--allフラグを取得
   └─ transpose: カラム名とフラグを取得
   └─ wrap: カラム名を取得

2. flatten処理
   └─ 各レコードの指定カラムを展開
   └─ 内部リスト/テーブルを外側に展開

3. transpose処理
   └─ 入力のカラム名を抽出
   └─ 各カラムを新しい行として出力
   └─ --header-rowで最初のカラムをキーに

4. wrap処理
   └─ 各要素を指定名のカラムでラップ

5. 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{コマンド種別}
    B -->|flatten| C[対象カラム解析]
    B -->|transpose| D[フラグ解析]
    B -->|wrap| E[カラム名取得]

    C --> F{カラム指定?}
    F -->|Yes| G[指定カラムのみ展開]
    F -->|No| H[全カラムを展開]
    G --> I{--all?}
    H --> I
    I -->|Yes| J[内部テーブルも展開]
    I -->|No| K[リストのみ展開]
    J --> L[flat_value実行]
    K --> L

    D --> M{--header-row?}
    M -->|Yes| N[最初のカラムをキーに]
    M -->|No| O[column0, column1...命名]
    N --> P[各カラムを行に変換]
    O --> P
    P --> Q{--as-record?}
    Q -->|Yes| R[1行ならRecordで返す]
    Q -->|No| S[Tableで返す]

    E --> T{入力型}
    T -->|List/Range| U[各要素をRecord化]
    T -->|Value| V[単一Record化]
    T -->|ByteStream| W[into_value後Record化]

    L --> X[終了]
    R --> X
    S --> X
    U --> X
    V --> X
    W --> X
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 単一リスト展開 | flattenは同時に1つのリストカラムのみ展開可能 | flatten使用時 |
| BR-02 | カラム名衝突回避 | flattenでカラム名衝突時はprefix追加 | カラム名重複時 |
| BR-03 | 転置カラム命名 | transposeでカラム名未指定時はcolumn0, column1... | 名前未指定時 |
| BR-04 | 単一レコード変換 | wrap入力が単一値の場合Record、リストの場合Table | 入力型による |

### 計算ロジック

flatten処理:
- TableInside::Entries: リストを各要素ごとに行に展開
- TableInside::FlattenedRows: 内部テーブルの各レコードを親レコードにマージ

transpose処理:
- 入力のカラム名を収集
- 各カラムを新しい行として出力
- --header-rowで最初のカラム値をキーとして使用

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

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UnsupportedInput | 入力エラー | flattenで複数リストカラム同時展開 | 1つずつ展開 |
| GenericError | パラメータエラー | transposeで--header-rowと名前指定を併用 | どちらか一方を使用 |
| OnlySupportsThisInputType | 型エラー | transposeで非record入力 | テーブルまたはレコードを入力 |
| IncompatibleParameters | パラメータエラー | --keep-allと--keep-lastを同時指定 | どちらか一方を使用 |

### リトライ仕様

該当なし（同期処理のため）

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

該当なし（状態変更を伴わない）

## パフォーマンス要件

- flatten: flat_mapでストリーミング処理
- transpose: 入力を収集してから処理（全カラム名取得が必要）
- wrap: ストリーミング処理可能

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

- 特になし。読み取り専用操作のみ。

## 備考

- flattenの--allフラグは内部テーブル（レコードのリスト）の展開に必要
- transposeの--keep-allは同一キーの値をリストに集約
- wrapはmergeと組み合わせてカラム追加に便利

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | flatten.rs | `crates/nu-command/src/filters/flatten.rs` | TableInside列挙型(134-148行目)で展開種別を理解 |
| 1-2 | transpose.rs | `crates/nu-command/src/filters/transpose.rs` | TransposeArgs構造体(6-13行目)でオプションを理解 |

**読解のコツ**: `TableInside::Entries`は単純なリスト展開、`TableInside::FlattenedRows`は内部テーブルの展開を表す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | flatten.rs | `crates/nu-command/src/filters/flatten.rs` | flatten関数(116-132行目)でflat_map使用を理解 |
| 2-2 | transpose.rs | `crates/nu-command/src/filters/transpose.rs` | transpose関数(132-309行目)で転置処理を理解 |
| 2-3 | wrap.rs | `crates/nu-command/src/filters/wrap.rs` | run関数(27-53行目)でラップ処理を理解 |

**主要処理フロー (flatten)**:
1. **122行目**: 対象カラムを取得
2. **124行目**: --allフラグを取得
3. **126-131行目**: `flat_map()`で各要素をflat_value処理

**主要処理フロー (transpose)**:
1. **139-146行目**: フラグを取得
2. **196行目**: `get_columns()`でカラム名収集
3. **251-294行目**: 各カラムを新しい行に変換

**主要処理フロー (wrap)**:
1. **35行目**: カラム名を取得
2. **42-45行目**: List/Range入力はmap処理
3. **51行目**: 単一値はRecord化

#### Step 3: 展開ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | flatten.rs | `crates/nu-command/src/filters/flatten.rs` | flat_value関数(150-308行目)で展開処理を理解 |

**主要処理フロー**:
- **158-159行目**: 展開対象カラムを判定
- **179-226行目**: リストの処理（--allで内部テーブル展開）
- **235-254行目**: Entries展開（リストを行に分割）
- **256-298行目**: FlattenedRows展開（内部レコードをマージ）

#### Step 4: 転置ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | transpose.rs | `crates/nu-command/src/filters/transpose.rs` | カラム処理(251-294行目) |

**主要処理フロー**:
- **256-262行目**: --ignore-titlesでタイトル行スキップ
- **264-267行目**: 各入力行から値を取得
- **268-286行目**: --keep-all/--keep-lastで重複キー処理
- **295-308行目**: --as-recordで1行ならRecord返却

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

```
Flatten::run() / Transpose::run() / Wrap::run()
    │
    ├─ Flatten:
    │      ├─ columns, flatten_all 取得
    │      │
    │      └─ input.flat_map(flat_value)
    │             │
    │             ├─ Record処理:
    │             │      ├─ 各カラムを走査
    │             │      ├─ TableInside判定
    │             │      │      ├─ Entries: リスト展開
    │             │      │      └─ FlattenedRows: テーブル展開
    │             │      │
    │             │      └─ expanded行を生成
    │             │
    │             └─ List処理: valsを返す
    │
    ├─ Transpose:
    │      ├─ TransposeArgs解析
    │      │
    │      ├─ get_columns(input)
    │      │
    │      └─ 各カラムを行に変換
    │             ├─ --header-row: 最初のカラム値をキーに
    │             ├─ --keep-all: 値をリストに集約
    │             └─ --as-record: 1行ならRecord
    │
    └─ Wrap:
           ├─ name取得
           │
           └─ match input:
                  ├─ List/Range: map(record!{name => x})
                  ├─ ByteStream: into_value後Record化
                  └─ Value: record!{name => input}
```

### データフロー図

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

                       ┌─────────────────────────────────┐
PipelineData ─────────▶│        flatten処理               │
     │                 │  flat_map(flat_value)           │
     │                 │    └─ 内部リスト/テーブル展開   │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                          List (flattened)
     │
     │                 ┌─────────────────────────────────┐
     ├────────────────▶│       transpose処理              │
     │                 │  columns = get_columns(input)   │
     │                 │  for desc in columns:           │
     │                 │    row = {col0: desc, ...}      │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                          Table / Record
     │
     │                 ┌─────────────────────────────────┐
     └────────────────▶│          wrap処理                │
                       │  input.map(|x| {name: x})       │
                       └─────────────────────────────────┘
                                        │
                                        ▼
                                 Table / Record
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| flatten.rs | `crates/nu-command/src/filters/flatten.rs` | ソース | flattenコマンド実装 |
| transpose.rs | `crates/nu-command/src/filters/transpose.rs` | ソース | transposeコマンド実装 |
| wrap.rs | `crates/nu-command/src/filters/wrap.rs` | ソース | wrapコマンド実装 |
| mod.rs | `crates/nu-command/src/filters/mod.rs` | ソース | フィルターモジュールエクスポート |
