# 機能設計書 16-選択・抽出

## 概要

本ドキュメントは、Nushellにおける選択・抽出機能の設計について記述する。select、get、first、lastコマンドを通じて、データ構造から特定の要素やカラムを抽出する機能を提供する。

### 本機能の処理概要

選択・抽出機能は、テーブルやリストから必要なデータのみを取り出す。selectはカラムを選択、getは値を抽出、first/lastは先頭/末尾の要素を取得する。

**業務上の目的・背景**：データ処理において、必要な部分だけを取り出すことは最も基本的な操作である。巨大なデータセットから必要なカラムのみを抽出、リストの先頭/末尾を取得、ネストした構造から値を取り出すなど、データアクセスの多様なパターンに対応する。

**機能の利用シーン**：
- `ls | select name size` で必要なカラムのみ表示
- `$record | get name` でレコードから値を取得
- `[1 2 3] | first` でリストの先頭要素を取得
- `open log.txt | lines | last 10` で最後の10行を取得

**主要な処理内容**：
1. セルパスまたはインデックスの解析
2. 入力データから該当要素を抽出
3. 結果を適切な形式で返却

**関連システム・外部連携**：SQLite機能（select/first/lastはSQLiteQueryBuilderの最適化に対応）。

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

## 関連画面

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

## 機能種別

データ操作（選択・抽出処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| rest | CellPath | No (select) | 選択するカラム/行 | 有効なセルパス |
| --optional, -o | Switch | No (select/get) | 欠損値をnullで返す | - |
| --ignore-case | Switch | No (select/get) | 大文字小文字無視 | - |
| cell_path | CellPath | Yes (get) | 抽出するパス | 有効なセルパス |
| rows | Int | No (first/last) | 取得する行数 | 正の整数 |
| --strict, -s | Switch | No (first/last) | 空入力でエラー | - |

### 入力データソース

- パイプライン入力: Record、Table、List、Range、Binary
- select: テーブルまたはレコード
- get: 任意の構造化データ
- first/last: List、Range、Binary、ByteStream

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| selected_table | Table | (select) 選択されたカラムのテーブル |
| selected_record | Record | (select) 選択されたフィールドのレコード |
| extracted_value | Any | (get) 抽出された値 |
| first_element | Any | (first) 先頭の要素 |
| last_element | Any | (last) 末尾の要素 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. コマンド引数の解析
   └─ select: カラム/行パスを取得
   └─ get: セルパスを取得
   └─ first/last: 行数を取得

2. オプション処理
   └─ --optional: セルパスをoptionalに変更
   └─ --ignore-case: セルパスをinsensitiveに変更

3. 入力処理
   └─ select: 各行からパスに従って値を抽出
   └─ get: follow_cell_pathで値取得
   └─ first: イテレータからtake
   └─ last: VecDequeで末尾をバッファリング

4. 結果を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{コマンド種別}
    B -->|select| C[カラムパス解析]
    B -->|get| D[セルパス解析]
    B -->|first| E[行数取得]
    B -->|last| F[行数取得]

    C --> G{行番号指定?}
    G -->|Yes| H[NthIteratorで行選択]
    G -->|No| I[カラム選択]
    H --> J[結果返却]
    I --> J

    D --> K{複数パス?}
    K -->|Yes| L[各パスの値をリストに]
    K -->|No| M[単一値を抽出]
    L --> J
    M --> J

    E --> N{rows指定?}
    N -->|Yes| O[take(rows)]
    N -->|No| P[単一要素]
    O --> J
    P --> J

    F --> Q{rows指定?}
    Q -->|Yes| R[VecDequeでバッファ]
    Q -->|No| S[最後の要素]
    R --> J
    S --> J

    J --> T[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 単一要素返却 | first/lastで行数未指定時は単一値を返す | rows未指定時 |
| BR-02 | リスト返却 | first/lastで行数指定時はリストを返す | rows指定時 |
| BR-03 | Optional処理 | --optionalで欠損時はnullを返す | フラグ指定時 |
| BR-04 | 空入力処理 | first/lastで空入力時はnothingを返す | --strictなしの場合 |

### 計算ロジック

select処理:
- 行番号指定: NthIteratorで指定行のみ抽出
- カラム指定: `follow_cell_path()`で各行から値を抽出

last処理:
- VecDequeをバッファとして使用
- バッファサイズがrows以上になったらpop_front

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

SQLite最適化:
- select: SQLiteQueryBuilder.with_select()でSELECT句を生成
- first: SQLiteQueryBuilder.with_limit()でLIMIT句を生成
- last: SQLiteQueryBuilder.with_order_by("rowid DESC").with_limit()

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| AccessEmptyContent | 入力エラー | --strictで空入力 | 入力データを確認 |
| NeedsPositiveValue | パラメータエラー | 負のrows指定 | 正の整数を指定 |
| PipelineEmpty | 入力エラー | getで空パイプライン | 有効なデータを入力 |
| OnlySupportsThisInputType | 型エラー | 非対応の入力型 | サポート型を入力 |

### リトライ仕様

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

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

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

## パフォーマンス要件

- select: ストリーミング処理可能（ListStream対応）
- get: ストリーミング処理可能（int以外のパス）
- first: take()で効率的に先頭取得
- last: VecDequeで固定メモリ使用（O(rows)）

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

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

## 備考

- selectの--ignore-errors（0.106.0で非推奨）は--optionalに置き換え
- getの--sensitive（0.105.0で非推奨）は不要（デフォルトで大文字小文字区別）
- firstの行数未指定と`first 1`は異なる（前者は単一値、後者はリスト）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.rs | `crates/nu-command/src/filters/select.rs` | NthIterator構造体(379-405行目)で行選択を理解 |

**読解のコツ**: `NthIterator`は指定行のみを返すイテレータ。BTreeSetで行番号を管理し、順序を保持。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.rs | `crates/nu-command/src/filters/select.rs` | run関数(69-141行目)でパス処理を理解 |
| 2-2 | get.rs | `crates/nu-command/src/filters/get.rs` | action関数(212-254行目)で値取得を理解 |
| 2-3 | first.rs | `crates/nu-command/src/filters/first.rs` | first_helper関数(81-289行目)で先頭取得を理解 |
| 2-4 | last.rs | `crates/nu-command/src/filters/last.rs` | run関数(70-291行目)で末尾取得を理解 |

**主要処理フロー (select)**:
1. **76-122行目**: カラムパスを解析
2. **123-138行目**: --optional/--ignore-caseでパス修正
3. **140行目**: `select()`関数でカラム選択実行

**主要処理フロー (get)**:
1. **174-178行目**: セルパスとフラグを取得
2. **221-226行目**: --optional/--ignore-caseでパス修正
3. **239-240行目**: `follow_cell_path()`で値取得

**主要処理フロー (first)**:
1. **88-104行目**: rows引数とフラグを解析
2. **118-131行目**: Listの場合truncateまたはfirst_mut
3. **223-238行目**: ListStreamの場合take

#### Step 3: 選択ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.rs | `crates/nu-command/src/filters/select.rs` | select関数(226-377行目)で選択処理を理解 |
| 3-2 | get.rs | `crates/nu-command/src/filters/get.rs` | follow_cell_path_into_stream関数(263-295行目)でストリーミング取得を理解 |

**主要処理フロー**:
- **260-276行目**: 行番号指定時はNthIteratorで行選択
- **310-339行目**: List入力時は各行からfollow_cell_path
- **275-288行目**: ListStream入力時はストリーミングでfollow_cell_path

#### Step 4: 末尾取得ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | last.rs | `crates/nu-command/src/filters/last.rs` | ListStream処理(102-129行目)でバッファリングを理解 |

**主要処理フロー**:
- **106行目**: VecDequeをバッファとして初期化
- **108-114行目**: 各要素をバッファに追加、rowsを超えたらpop_front
- **116-128行目**: 結果を返却

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

```
Select::run() / Get::run() / First::run() / Last::run()
    │
    ├─ Select:
    │      ├─ CellPath解析
    │      │      └─ make_optional() / make_insensitive()
    │      │
    │      └─ select()
    │             ├─ NthIterator (行番号指定時)
    │             │
    │             └─ input.map(follow_cell_path)
    │
    ├─ Get:
    │      ├─ CellPath解析
    │      │
    │      └─ action()
    │             ├─ follow_cell_path_into_stream() [単一パス]
    │             │      └─ stream.map(follow_cell_path)
    │             │
    │             └─ input.follow_cell_path() [複数パス]
    │
    ├─ First:
    │      └─ first_helper()
    │             ├─ Value::List → vals.first_mut() / truncate()
    │             ├─ Value::Range → iter.take(rows)
    │             ├─ ListStream → stream.modify(take)
    │             └─ ByteStream → reader.take(rows)
    │
    └─ Last:
           ├─ ListStream/Range → VecDeque バッファリング
           │
           └─ Value::List → vals.drain(..i)
```

### データフロー図

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

                       ┌─────────────────────────────────┐
PipelineData ─────────▶│         select処理               │
     │                 │  columns = CellPath解析         │
     │                 │  for row in input:              │
     │                 │    record = {}                  │
     │                 │    for path in columns:         │
     │                 │      record[path] = follow()    │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                          Table (selected columns)
     │
     │                 ┌─────────────────────────────────┐
     ├────────────────▶│           get処理                │
     │                 │  path = CellPath解析            │
     │                 │  value = follow_cell_path(path) │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                              Value
     │
     │                 ┌─────────────────────────────────┐
     ├────────────────▶│         first処理                │
     │                 │  iter.take(rows)                │
     │                 └─────────────────────────────────┘
     │                                  │
     │                                  ▼
     │                          Value / List
     │
     │                 ┌─────────────────────────────────┐
     └────────────────▶│          last処理                │
                       │  buf = VecDeque::new()          │
                       │  for v in input:                │
                       │    if buf.len() == rows:        │
                       │      buf.pop_front()            │
                       │    buf.push_back(v)             │
                       └─────────────────────────────────┘
                                        │
                                        ▼
                                 Value / List
```

### 関連ファイル一覧

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