# 通知設計書 8-join_by自動検出

## 概要

本ドキュメントは、dplyrパッケージにおけるjoin関数での`by`引数がNULLの場合に共通変数を自動検出して結合する際の情報通知について、その設計仕様を定義するものである。

### 本通知の処理概要

`left_join()`, `right_join()`, `inner_join()`, `full_join()`などのjoin関数において、`by`引数がNULLの場合、両方のデータフレームに共通する変数を自動的に検出し、その変数を使用して結合を行う。この通知は、どの変数が結合キーとして自動選択されたかをユーザーに知らせる情報メッセージを表示する。

**業務上の目的・背景**：join操作において、結合キーを明示的に指定しないことは、意図しない結果につながる可能性がある。特に本番コードでは推奨されない。この通知は、ユーザーに対してどの変数が結合キーとして使用されたかを明確にし、意図した通りの結合が行われているかを確認する機会を提供する。将来的なコードメンテナンスのために、明示的な`by`指定を促す目的もある。

**通知の送信タイミング**：ユーザーがjoin関数を`by = NULL`（デフォルト）で呼び出した際に、共通変数が検出されると情報メッセージが表示される。共通変数がない場合はエラーとなる。

**通知の受信者**：Rコンソールまたはスクリプトを実行している開発者・データアナリスト。情報メッセージはRの標準出力システムを通じてコンソールに表示される。

**通知内容の概要**：`Joining, by = "変数名"` または `Joining, by = c("変数1", "変数2", ...)` の形式で、使用された結合キーが表示される。

**期待されるアクション**：ユーザーは表示された結合キーが意図したものであることを確認し、可能であれば明示的に`by`引数を指定してコードを修正することが推奨される。

## 通知種別

コンソール情報通知（inform）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期（関数呼び出し時即座に表示） |
| 優先度 | 低（情報レベル） |
| リトライ | 無し |

### 送信先決定ロジック

情報メッセージはRの標準出力（メッセージ出力）に送信される。受信者の決定は不要であり、関数を呼び出したセッションに対して直接表示される。

## 通知テンプレート

### コンソール情報通知の場合

| 項目 | 内容 |
|-----|------|
| 送信元 | rlang パッケージ（inform関数） |
| 形式 | テキスト |

### 本文テンプレート

```
Joining, by = "column_name"
```

または（複数列の場合）

```
Joining, by = c("column1", "column2", "column3")
```

### 添付ファイル

| ファイル名 | 形式 | 条件 | 説明 |
|----------|------|------|------|
| なし | - | - | コンソール通知のため添付ファイルなし |

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| by | 自動検出された共通変数 | intersect(tbl_vars(x), tbl_vars(y)) | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 関数呼び出し | join関数の実行 | `by = NULL`で共通変数が存在する場合 | natural joinとして共通変数を使用 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `by`が明示的に指定されている場合 | ユーザーが結合キーを指定した場合は通知不要 |
| 共通変数がない場合 | エラーとなるため通知は発生しない |
| rlangのmessage抑制設定 | `suppressMessages()`で抑制可能 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[join関数呼び出し] --> B{byがNULL?}
    B -->|No| C[指定されたbyを使用]
    B -->|Yes| D[common_by.NULL実行]
    D --> E[intersect tbl_vars x,y]
    E --> F{共通変数あり?}
    F -->|No| G[エラー発生]
    F -->|Yes| H[auto_by_msg生成]
    H --> I[inform実行]
    I --> J[情報メッセージ表示]
    J --> K[結合処理継続]
    C --> K
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| なし | - | データベースアクセスは発生しない（メモリ内操作） |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | データベース更新は発生しない |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 共通変数なしエラー | xとyに共通する変数がない場合 | `by`引数を明示的に指定するよう促す |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 該当なし |
| リトライ間隔 | 該当なし |
| リトライ対象エラー | 該当なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（ユーザーの関数呼び出しに応じて即座に表示）

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

- 個人情報の取り扱い：なし（変数名のみ表示）
- メッセージには機密情報は含まれない
- 外部通信は発生しない

## 備考

- この動作はSQL標準のnatural joinに相当する
- 本番コードでは明示的な`by`指定が推奨される（not recommended in production code）
- `by`にはcharacter vector、named character vector、list、または`join_by()`の結果を指定可能
- NA値を持つ共通変数は自動検出から除外される
- 変数名はダブルクォートでエンコードされて表示される
- 複数の共通変数がある場合は`c()`で結合されて表示される

---

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

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

### 推奨読解順序

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

`common_by`関数群の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | join-common-by.R | `R/join-common-by.R` | `common_by()`ジェネリック関数（5行目） |

**読解のコツ**: `common_by()`はbyの型に応じてメソッドディスパッチを行う。NULL, character, list, defaultの各ケースを処理する。

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

`common_by.NULL()`メソッドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | join-common-by.R | `R/join-common-by.R` | `common_by.NULL()`メソッド（48-63行目） |

**主要処理フロー**:
1. **49行目**: `intersect(tbl_vars(x), tbl_vars(y))` で共通変数を取得
2. **50行目**: NA値を除外
3. **51-56行目**: 共通変数がない場合のエラー処理
4. **57行目**: `inform(auto_by_msg(by))` で情報メッセージ表示

#### Step 3: メッセージ生成ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | join-common-by.R | `R/join-common-by.R` | `auto_by_msg()`関数（65-73行目） |

**メッセージ構築**:
```r
by_quoted <- encodeString(by, quote = '"')
if (length(by_quoted) == 1L) {
  by_code <- by_quoted
} else {
  by_code <- paste0("c(", paste(by_quoted, collapse = ", "), ")")
}
paste0("Joining, by = ", by_code)
```

#### Step 4: join関数での使用を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | join.R | `R/join.R` | join関数での`common_by()`呼び出し |

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

```
left_join(x, y, by = NULL, ...)
    │
    ├─ common_by(by, x, y)
    │      │
    │      └─ UseMethod("common_by", by)
    │             │
    │             └─ common_by.NULL(by, x, y)
    │                    │
    │                    ├─ intersect(tbl_vars(x), tbl_vars(y))
    │                    │
    │                    ├─ [共通変数がない場合] abort()
    │                    │
    │                    ├─ auto_by_msg(by)
    │                    │      └─ メッセージ文字列生成
    │                    │
    │                    └─ inform(auto_by_msg(by))
    │                           └─ 情報メッセージ表示
    │
    └─ 結合処理継続
```

### データフロー図

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

x, y ───────────▶ join関数(by=NULL) ────────▶ 情報メッセージ（stdout）
                        │                      "Joining, by = ..."
                        ▼
                intersect(vars) ───────────▶ 結合結果（data.frame）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| join-common-by.R | `R/join-common-by.R` | ソース | `common_by()`とメソッド群の定義 |
| join.R | `R/join.R` | ソース | join関数群の定義 |
| join-by.R | `R/join-by.R` | ソース | `join_by()`関数（新しいAPI） |
| tbl-vars.R | `R/tbl-vars.R` | ソース | `tbl_vars()`関数 |
| NAMESPACE | `NAMESPACE` | 設定 | エクスポート定義 |
