# 通知設計書 9-join_by自動生成

## 概要

本ドキュメントは、dplyrパッケージにおけるjoin関数で新しい`join_by()`構文の使用を促す情報通知について、その設計仕様を定義するものである。

### 本通知の処理概要

`left_join()`, `right_join()`, `inner_join()`, `full_join()`などのjoin関数において、`by`引数がNULLで共通変数を自動検出した場合、新しい`join_by()`構文での記述方法を情報メッセージとして表示する。これはNo.8の通知と関連するが、より新しいAPIへの移行を促すメッセージである。

**業務上の目的・背景**：dplyr 1.1.0で導入された`join_by()`関数は、結合条件を指定するための新しい、より表現力のあるAPIである。等値結合だけでなく、不等結合（inequality joins）、ローリング結合（rolling joins）、オーバーラップ結合（overlap joins）をサポートする。この通知は、ユーザーに対して新しいAPIの存在を知らせ、より明示的で読みやすいコードへの移行を促すことを目的としている。

**通知の送信タイミング**：join関数で`by`引数がNULLの場合、または古い形式の`by`が使用された場合に、共通変数が検出されると`join_by()`を使用した形式での記述を促す情報メッセージが表示される。

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

**通知内容の概要**：`Joining with `by = join_by(変数名)`` の形式で、`join_by()`を使用した推奨される記述方法が表示される。

**期待されるアクション**：ユーザーは表示された`join_by()`形式を参考に、コードを新しいAPI形式に更新することが推奨される。これにより、コードの可読性と保守性が向上する。

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

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

### 本文テンプレート

```
Joining with `by = join_by(column_name)`
```

または（複数列の場合）

```
Joining with `by = join_by(column1, column2)`
```

### 添付ファイル

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

## テンプレート変数

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

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 関数呼び出し | join関数の実行 | `by`がNULLで共通変数が存在する場合 | join_by()形式での記述を推奨 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| `by`が`join_by()`で指定されている場合 | 既に新しいAPIを使用している |
| 共通変数がない場合 | エラーとなるため通知は発生しない |
| rlangのmessage抑制設定 | `suppressMessages()`で抑制可能 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[join関数呼び出し] --> B{byがNULL?}
    B -->|No| C{byがjoin_by形式?}
    B -->|Yes| D[join_by_common実行]
    C -->|Yes| E[そのまま使用]
    C -->|No| F[古い形式を変換]
    D --> G[intersect x_names,y_names]
    G --> H{共通変数あり?}
    H -->|No| I[エラー発生]
    H -->|Yes| J[メッセージ生成]
    J --> K[inform実行]
    K --> L[情報メッセージ表示]
    L --> M[結合処理継続]
    E --> M
    F --> M
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

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

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 共通変数なしエラー | xとyに共通する変数がない場合 | `cross_join()`の使用を案内 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

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

## 備考

- `join_by()`はdplyr 1.1.0で導入された新しいAPI
- 等値結合（`==`）、不等結合（`>=`, `>`, `<=`, `<`）をサポート
- ローリング結合は`closest()`ヘルパーで実現
- オーバーラップ結合は`between()`, `within()`, `overlaps()`ヘルパーで実現
- 変数名はバッククォートで囲まれて表示される場合がある（特殊文字を含む場合）
- `tick_if_needed()`関数で必要に応じてバッククォートが追加される
- `glue_collapse()`でカンマ区切りに結合される

---

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

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

### 推奨読解順序

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

`dplyr_join_by`クラスの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | join-by.R | `R/join-by.R` | `join_by()`関数と戻り値の構造（224-269行目） |
| 1-2 | join-by.R | `R/join-by.R` | `new_join_by()`関数（282-297行目） |

**読解のコツ**: `dplyr_join_by`クラスは`exprs`（式）、`condition`（条件）、`filter`（フィルタ）、`x`（左テーブル列）、`y`（右テーブル列）を持つ。

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

`join_by_common()`関数を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | join-by.R | `R/join-by.R` | `join_by_common()`関数（376-394行目） |

**主要処理フロー**:
1. **379行目**: `intersect(x_names, y_names)` で共通変数を取得
2. **381-387行目**: 共通変数がない場合のエラー処理（cross_join推奨）
3. **389-391行目**: メッセージ生成と`inform()`呼び出し
4. **393行目**: `finalise_equi_join_by()`で結合仕様を生成

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | join-by.R | `R/join-by.R` | メッセージ生成部分（389-391行目） |

**メッセージ構築**:
```r
by_names <- tick_if_needed(by)
by_names <- glue_collapse(by_names, sep = ", ")
inform(glue("Joining with `by = join_by({by_names})`"))
```

#### Step 4: join_by()の機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | join-by.R | `R/join-by.R` | 等値結合パース（591-627行目） |
| 4-2 | join-by.R | `R/join-by.R` | closest()ヘルパー（668-708行目） |
| 4-3 | join-by.R | `R/join-by.R` | between()ヘルパー（748-803行目） |

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

```
left_join(x, y, by = NULL, ...)
    │
    ├─ [byがNULLの場合]
    │      │
    │      └─ join_by_common(x_names, y_names)
    │             │
    │             ├─ intersect(x_names, y_names)
    │             │
    │             ├─ [共通変数がない場合] abort()
    │             │      └─ "Use `cross_join()` to perform a cross-join"
    │             │
    │             ├─ tick_if_needed(by)
    │             │      └─ 必要に応じてバッククォート追加
    │             │
    │             ├─ glue_collapse(by_names, sep = ", ")
    │             │
    │             ├─ inform(glue("Joining with `by = join_by({by_names})`"))
    │             │      └─ 情報メッセージ表示
    │             │
    │             └─ finalise_equi_join_by(by, by)
    │                    └─ dplyr_join_by オブジェクト生成
    │
    └─ 結合処理継続
```

### データフロー図

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

x, y ───────────▶ join関数(by=NULL) ────────▶ 情報メッセージ（stdout）
                        │                      "Joining with `by = join_by(...)`"
                        ▼
               join_by_common() ───────────▶ dplyr_join_by オブジェクト
                        │
                        ▼
               結合処理 ───────────────────▶ 結合結果（data.frame）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| join-by.R | `R/join-by.R` | ソース | `join_by()`と`join_by_common()`の定義 |
| join-common-by.R | `R/join-common-by.R` | ソース | 古い`common_by()`関数（互換性） |
| join.R | `R/join.R` | ソース | join関数群の定義 |
| utils.R | `R/utils.R` | ソース | `tick_if_needed()`関数 |
| NAMESPACE | `NAMESPACE` | 設定 | エクスポート定義 |
