# 機能設計書 29-nest_join

## 概要

本ドキュメントは、dplyrパッケージにおける`nest_join`関数の機能設計を定義する。`nest_join`は、左側テーブル（x）の各行に対して、右側テーブル（y）からマッチするすべての行をリスト列としてネストする結合関数である。

### 本機能の処理概要

`nest_join`関数は、左側のデータフレーム（x）をほぼ変更せずに保持し、各行に対応するyのマッチング行をネストされたデータフレームとしてリスト列に追加する。これにより、1対多の関係を持つデータを、xの行数を維持したまま保持できる。

**業務上の目的・背景**：階層的なデータ構造を維持しながら結合を行いたい場合に使用する。例えば、「顧客ごとにすべての注文をネストしたリストとして保持する」「部門ごとに所属する従業員をリスト列として追加する」などのケースである。`nest_join`は、`inner_join`後に`nest()`を適用するのと類似の結果を得られるが、より直接的で効率的である。他の結合操作（inner_join、left_join、semi_join、anti_join）の基礎として再構成可能な操作である。

**機能の利用シーン**：
- 1対多の関係を持つデータの階層的な保持
- 関連データをリスト列として保持したい場合
- 後続のpurrrやtidyrでの操作を前提としたデータ準備
- 各行に対するマッチング結果のグループ化

**主要な処理内容**：
1. 結合キーの特定（by引数の解析またはcommon columnsの自動検出）
2. キー列の型の共通化（型が異なる場合のキャスト処理）
3. vctrs::vec_locate_matchesによるマッチング処理
4. vec_splitでマッチ結果をグループ化
5. yのマッチ行をリスト列として追加
6. 結果データフレームの構築

**関連システム・外部連携**：vctrパッケージのvec_locate_matches、vec_split関数を使用。tidyrパッケージのunnestと組み合わせることでinner_joinやleft_joinを再現可能。

**権限による制御**：特になし。Rの通常のオブジェクト操作権限に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはRライブラリであり、UIは存在しない |

## 機能種別

データ変換 / 結合処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| x | data.frame / tibble | Yes | 左側（メイン）テーブル | data.frameまたはその拡張型 |
| y | data.frame / tibble | Yes | 右側（ネスト対象）テーブル | data.frameまたはその拡張型 |
| by | join_by / character / NULL | No | 結合キーの指定 | join_by()、文字ベクトル、またはNULL |
| copy | logical | No | 異なるソース間でのコピー許可 | TRUE/FALSE（デフォルト: FALSE） |
| keep | logical / NULL | No | ネストされたデータにキー列を含めるか | TRUE/FALSE/NULL |
| name | character / NULL | No | リスト列の名前 | NULL（デフォルト）またはyの名前を使用 |
| na_matches | character | No | NAの一致方法 | "na"（デフォルト）または"never" |
| unmatched | character | No | 非マッチ行の処理 | "drop"または"error" |

### 入力データソース

R環境内のdata.frame、tibble、またはdbplyr/dtplyrによるリモートテーブル

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | data.frame / tibble | xと同じ型で、yのマッチ行を含むリスト列が追加されたデータフレーム |
| {name} | list | 各要素がyと同じ型のデータフレームであるリスト列 |

### 出力先

R環境内のオブジェクトとして返却

## 処理フロー

### 処理シーケンス

```
1. 引数の検証
   ├─ check_dots_empty0: 不正な追加引数のチェック
   ├─ check_keep: keep引数の検証
   └─ check_na_matches: na_matches引数の検証
2. name引数の処理
   └─ デフォルトはyの名前を使用
3. データソースの同期
   └─ auto_copy: 異なるソースの場合のコピー処理
4. 結合設定
   ├─ join_by_commonまたはas_join_by: by引数の解析
   └─ join_cols: 出力列の決定
5. マッチング処理
   ├─ join_cast_common: キー列の型統一
   └─ join_rows: マッチング（multiple="all"固定）
6. ネスト構造の構築
   ├─ vec_split: マッチ結果をグループ化
   ├─ map(vec_slice, y_out): 各グループのyをスライス
   └─ map(dplyr_reconstruct, y): y型の復元
7. 結果構築とdplyr_reconstruct
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数検証]
    B --> C{name指定?}
    C -->|No| D[yの名前を使用]
    C -->|Yes| E[指定名を使用]
    D --> F[auto_copy]
    E --> F
    F --> G{by指定?}
    G -->|No| H[join_by_common]
    G -->|Yes| I[as_join_by]
    H --> J[join_cols]
    I --> J
    J --> K[join_cast_common]
    K --> L[join_rows multiple=all]
    L --> M[vec_split: マッチをグループ化]
    M --> N[各グループのyをスライス]
    N --> O[リスト列として追加]
    O --> P[dplyr_reconstruct]
    P --> Q[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | 行数保持 | 結果の行数はxと同じ | 常に適用 |
| BR-29-02 | リスト列追加 | yのマッチ行をリスト列として追加 | 常に適用 |
| BR-29-03 | 空データフレーム | マッチがない場合は0行のデータフレームがリストに含まれる | マッチなし時 |
| BR-29-04 | 列名デフォルト | name未指定時はyの名前を使用 | name=NULL時 |
| BR-29-05 | キー列制御 | keep引数でネストデータにキー列を含めるか制御 | keep指定時 |
| BR-29-06 | 全マッチ保持 | multiple="all"固定で全マッチを保持 | 常に適用 |

### 計算ロジック

- **マッチング**: vctrs::vec_locate_matchesを使用（multiple="all"）
- **グループ化**: vec_split(rows$y, rows$x)でxの行ごとにyのインデックスをグループ化
- **スライシング**: 各グループに対してvec_slice(y_out, indices)を実行

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

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

本機能はインメモリ処理のため、データベース操作は発生しない。dbplyrではサポートされない場合がある。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| dplyr_error_join | 結合エラー | キー列の型が互換性なし | 同じ型に変換するか結合キーを見直す |
| dplyr_error_join_matches_remaining | 非マッチエラー | unmatched="error"でyに非マッチ行あり | 非マッチ行を確認するかunmatched="drop"に変更 |

### リトライ仕様

該当なし（同期処理）

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

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

## パフォーマンス要件

- 計算量: O(n + m + matches)（nはxの行数、mはyの行数、matchesはマッチ総数）
- メモリ使用量: xの行数分のリスト + yのマッチ行分のメモリ

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

特になし。入力データの機密性は呼び出し側の責任で管理する。

## 備考

- `nest_join` + `tidyr::unnest()` で `inner_join`を再現可能
- `nest_join` + `tidyr::unnest(keep_empty = TRUE)` で `left_join`を再現可能
- `nest_join` + `filter(lengths(y) > 0)` で `semi_join`を再現可能
- `nest_join` + `filter(lengths(y) == 0)` で `anti_join`を再現可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | join.R | `R/join.R` | nest_joinのドキュメント（530-567行目） |

**読解のコツ**: nest_joinは「leaves x almost unchanged, except that it adds a new list-column」。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | join.R | `R/join.R` | nest_join関数本体（577-683行目） |

**主要処理フロー**:
1. **577-587行目**: nest_joinジェネリック関数定義
2. **591-601行目**: nest_join.data.frameメソッドのパラメータ定義
3. **602行目**: check_dots_empty0
4. **603-610行目**: name引数の処理
5. **615-626行目**: by引数の解析
6. **629行目**: join_cols
7. **638-639行目**: join_cast_common
8. **655-667行目**: join_rows呼び出し
9. **669行目**: vec_split - マッチ結果のグループ化
10. **677行目**: map(vec_slice, y_out) - 各グループのスライス
11. **678行目**: map(dplyr_reconstruct, y) - 型復元
12. **679行目**: リスト列として追加
13. **682行目**: dplyr_reconstruct

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

```
nest_join(x, y, by, copy, keep, name, na_matches, unmatched)
    │
    ├─ check_dots_empty0(...)
    │
    ├─ check_keep(keep)
    │
    ├─ check_na_matches(na_matches)
    │
    ├─ name処理（デフォルト: as_label(enexpr(y))）
    │
    ├─ auto_copy(x, y, copy)
    │
    ├─ as_join_by(by) または join_by_common(x_names, y_names)
    │
    ├─ join_cols(x_names, y_names, by, suffix=c("",""), keep)
    │
    ├─ join_cast_common(x_key, y_key, vars)
    │
    ├─ join_rows(x_key, y_key, type="nest", multiple="all", ...)
    │      └─ dplyr_locate_matches(...)
    │
    ├─ vec_split(rows$y, rows$x)$val  # yインデックスをxでグループ化
    │
    ├─ map(y_loc, vec_slice, x = y_out)  # 各グループをスライス
    │
    ├─ map(y_out, dplyr_reconstruct, template = y)  # 型復元
    │
    ├─ new_cols[[name]] <- y_out  # リスト列として追加
    │
    └─ dplyr_reconstruct(out, x)
```

### データフロー図

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

x (data.frame) ──┐
                 ├─▶ join_rows(type="nest") ─▶ マッチング
y (data.frame) ──┤           │
                 │           └─▶ (x_idx, y_idx) ペア
                 │
                 └─▶ vec_split(y_idx, x_idx)
                           │
                           └─▶ x各行に対応するy_idxのリスト
                                    │
                                    └─▶ map(vec_slice, y)
                                             │
                                             └─▶ リスト列 (各要素がdata.frame)
                                                      │
                                                      └─▶ x + リスト列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| join.R | `R/join.R` | ソース | nest_join関数の定義 |
| join-rows.R | `R/join-rows.R` | ソース | join_rows関数の定義 |
| join-cols.R | `R/join-cols.R` | ソース | join_cols関数の定義 |
| join-by.R | `R/join-by.R` | ソース | join_by関数の定義 |
