# 機能設計書 13-ソート・整列

## 概要

本ドキュメントは、Nushellにおけるソート・整列機能の設計について記述する。sort、sort-by、reverseコマンドを通じて、リストやテーブルの並べ替え機能を提供する。

### 本機能の処理概要

ソート・整列機能は、リスト、テーブル、レコードに対して昇順・降順のソートを行う。単純な値のソートから、複数のカラムや計算値による複雑なソートまで対応し、自然順序（natural sort）や大文字小文字無視のオプションもサポートする。

**業務上の目的・背景**：データ分析やシステム管理において、データを意味のある順序で並べることは基本的かつ重要な操作である。ファイルをサイズ順で表示する、ログを時刻順にソートする、テーブルを複数キーで整列するなど、多様なユースケースに対応する。

**機能の利用シーン**：
- `ls | sort-by size` でファイルをサイズ順にソート
- `[banana apple cherry] | sort` でアルファベット順に並べ替え
- `[[name score]; [Alice 85] [Bob 92]] | sort-by score --reverse` でスコア降順
- `[foo1 foo10 foo2] | sort -n` で自然順序ソート（foo1, foo2, foo10）
- `[1 2 3] | reverse` でリストを逆順に

**主要な処理内容**：
1. 入力データを収集（ストリーミング不可）
2. 比較関数（Comparator）を構築
3. Rustの安定ソートアルゴリズムでソート実行
4. reverseフラグがあれば結果を反転

**関連システム・外部連携**：alphanumeric_sortクレート（自然順序ソート）と連携。

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

## 関連画面

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

## 機能種別

データ操作（ソート処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --reverse, -r | Switch | No | 降順ソート | - |
| --ignore-case, -i | Switch | No | 大文字小文字無視 | - |
| --natural, -n | Switch | No | 自然順序ソート | - |
| --values, -v | Switch | No (sort) | レコードを値でソート | - |
| comparator | CellPath/Closure | Yes (sort-by) | ソートキー | 有効なセルパスまたはクロージャ |
| --custom, -c | Switch | No (sort-by) | カスタム比較クロージャ使用 | - |

### 入力データソース

- パイプライン入力: List、Table、Record
- sortは入力全体をメモリに読み込む必要がある

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| sorted_list | List | ソート済みリスト |
| sorted_table | Table | ソート済みテーブル |
| sorted_record | Record | キーまたは値でソート済みレコード |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. コマンド引数の解析
   └─ ソートオプション（reverse, ignore-case, natural）を取得
   └─ sort-byの場合はcomparatorを取得

2. 入力データの収集
   └─ input.into_value()でメモリに収集

3. 入力型に応じたソート処理
   └─ Record: キーまたは値でソート
   └─ List/Table: 要素比較でソート

4. ソートアルゴリズム実行
   └─ sort_utils::sort() または sort_utils::sort_by()

5. reverseフラグ処理
   └─ 指定時は結果を反転

6. 結果をPipelineDataとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{コマンド種別}
    B -->|sort| C[オプション解析]
    B -->|sort-by| D[comparator解析]
    B -->|reverse| E[入力収集]

    C --> F[入力収集]
    D --> F

    F --> G{入力型}
    G -->|Record| H[キー/値ソート]
    G -->|List/Table| I[要素比較ソート]

    H --> J{--values?}
    J -->|Yes| K[値でソート]
    J -->|No| L[キーでソート]
    K --> M[reverse処理]
    L --> M

    I --> N{Table?}
    N -->|Yes| O[カラム順比較]
    N -->|No| P[要素直接比較]
    O --> M
    P --> M

    E --> Q[reverse配列]
    Q --> R[結果返却]
    M --> R
    R --> S[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | Null末尾配置 | Nothing値は常にソート結果の末尾に配置 | 常に適用 |
| BR-02 | 数値グループ化 | int/floatは同一グループとして数値比較 | 通常ソート時 |
| BR-03 | 自然順序優先 | --naturalで数値文字列は数値として比較 | -nフラグ指定時 |
| BR-04 | 安定ソート | 同一キーの要素は入力順序を維持 | 常に適用 |

### 計算ロジック

比較関数の優先順位:
1. カスタムクロージャ（--custom）: ユーザー定義の比較ロジック
2. キークロージャ: クロージャ結果を比較キーとして使用
3. セルパス: 指定パスの値を比較キーとして使用
4. 直接比較: Value::partial_cmp()による比較

自然順序ソート:
- alphanumeric_sort::compare_str()を使用
- 文字列中の数字部分を数値として比較

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| PipelineEmpty | 入力エラー | 空の入力 | 有効なデータを入力 |
| OnlySupportsThisInputType | 型エラー | record/list以外の入力 | サポート型を入力 |
| MissingParameter | パラメータエラー | sort-byでcomparator未指定 | ソートキーを指定 |
| TypeMismatch | 型エラー | 無効なcomparator指定 | セルパスまたはクロージャを指定 |

### リトライ仕様

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

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

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

## パフォーマンス要件

- 安定ソート: Rustのslice::sort_by()を使用（O(n log n)）
- メモリ使用: 入力全体をメモリに収集する必要あり
- 大規模データ: 数百万行規模では注意が必要

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

- クロージャ実行: sort-byのクロージャはエンジンのサンドボックス内で実行

## 備考

- テーブルのソートではカラムの辞書順で比較キーが決定される
- レコードのキーソートは大文字小文字を区別しない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | Comparator列挙型(6-14行目)でソート基準の種類を理解 |

**読解のコツ**: `Comparator`には3種類（CellPath, KeyClosure, CustomClosure）がある。KeyClosureは比較キーを返し、CustomClosureは比較結果を返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sort.rs | `crates/nu-command/src/filters/sort.rs` | run関数(131-204行目)で入力型ごとの処理を理解 |
| 2-2 | sort_by.rs | `crates/nu-command/src/filters/sort_by.rs` | run関数(124-175行目)でcomparator処理を理解 |
| 2-3 | reverse.rs | `crates/nu-command/src/filters/reverse.rs` | run関数(55-67行目)で単純な反転処理を理解 |

**主要処理フロー (sort)**:
1. **138-141行目**: フラグ（reverse, insensitive, natural, sort_by_value）を取得
2. **145行目**: `input.into_value()`で入力を収集
3. **147-157行目**: Recordの場合は`sort_record()`呼び出し
4. **158-188行目**: Listの場合はTable型かどうかで分岐

**主要処理フロー (sort-by)**:
1. **132行目**: comparator値を取得
2. **147-165行目**: comparatorをCellPath/Closureに変換
3. **167行目**: `sort_by()`関数でソート実行

#### Step 3: ソートアルゴリズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | sort関数(27-50行目)で基本ソートロジックを理解 |
| 3-2 | sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | sort_by関数(53-92行目)でcomparator使用ソートを理解 |
| 3-3 | sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | compare_values関数(197-213行目)で値比較ロジックを理解 |

**主要処理フロー**:
- **33-43行目**: `vec.sort_by()`でRustの安定ソートを使用
- **39-42行目**: エラー発生時はcompare_errに格納し、Ordering::Equalを返す
- **203-212行目**: 文字列比較の判定と実行

#### Step 4: 文字列比較オプションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | compare_strings関数(215-233行目) |

**主要処理フロー**:
- **220-225行目**: naturalフラグでalphanumeric_sort使用
- **228-229行目**: insensitiveフラグでto_folded_case()使用

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

```
Sort::run() / SortBy::run() / Reverse::run()
    │
    ├─ Sort:
    │      ├─ input.into_value()
    │      │
    │      └─ match value:
    │             ├─ Record: sort_record()
    │             │
    │             └─ List:
    │                    ├─ Table: sort_by(columns)
    │                    │         └─ compare_by()
    │                    │                └─ compare_cell_path()
    │                    │
    │                    └─ List: sort()
    │                           └─ compare_values()
    │                                  └─ compare_strings()
    │
    ├─ SortBy:
    │      ├─ comparators構築
    │      │      └─ CellPath / KeyClosure / CustomClosure
    │      │
    │      └─ sort_by(comparators)
    │             └─ compare_by()
    │                    ├─ compare_cell_path()
    │                    ├─ compare_key_closure()
    │                    └─ compare_custom_closure()
    │
    └─ Reverse:
           └─ input.into_iter().rev()
```

### データフロー図

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

PipelineData ───────▶ into_value() ───────▶ Value (collected)
     │                                            │
     │                                            ▼
     │                                   ┌─────────────────┐
     │                                   │ 型判定          │
     │                                   │ Record/List/    │
     │                                   │ Table           │
     │                                   └─────────────────┘
     │                                            │
     │              ┌─────────────────────────────┼─────────────────────────────┐
     │              │                             │                             │
     │              ▼                             ▼                             ▼
     │      ┌───────────────┐            ┌───────────────┐            ┌───────────────┐
     │      │ sort_record   │            │ sort (List)   │            │ sort_by       │
     │      │ key/value     │            │ compare_      │            │ (Table)       │
     │      │ compare       │            │ values()      │            │ compare_by()  │
     │      └───────────────┘            └───────────────┘            └───────────────┘
     │              │                             │                             │
     │              └─────────────────────────────┼─────────────────────────────┘
     │                                            │
     │                                            ▼
     │                                   ┌─────────────────┐
     │                                   │ reverse?       │
     │                                   │ vec.reverse()  │
     │                                   └─────────────────┘
     │                                            │
     └────────────────────────────────────────────▶ PipelineData (sorted)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| sort.rs | `crates/nu-command/src/filters/sort.rs` | ソース | sortコマンド実装 |
| sort_by.rs | `crates/nu-command/src/filters/sort_by.rs` | ソース | sort-byコマンド実装 |
| reverse.rs | `crates/nu-command/src/filters/reverse.rs` | ソース | reverseコマンド実装 |
| sort_utils.rs | `crates/nu-command/src/sort_utils.rs` | ソース | ソートユーティリティ関数 |
| mod.rs | `crates/nu-command/src/filters/mod.rs` | ソース | フィルターモジュールエクスポート |
