# 通知設計書 10-rows操作のby自動検出

## 概要

本ドキュメントは、dplyrパッケージにおける`rows_*`関数群（`rows_insert`, `rows_update`, `rows_patch`, `rows_upsert`, `rows_delete`）で`by`引数がNULLの場合に最初の列を自動的にキーとして使用する際の情報通知について、その設計仕様を定義するものである。

### 本通知の処理概要

`rows_insert()`, `rows_update()`, `rows_patch()`, `rows_upsert()`, `rows_delete()`などの行操作関数において、`by`引数がNULLの場合、yデータフレームの最初の列を自動的にキー列として使用する。この通知は、どの列がキーとして自動選択されたかをユーザーに知らせる情報メッセージを表示する。

**業務上の目的・背景**：`rows_*`関数群はSQL的なINSERT、UPDATE、DELETE操作をデータフレームに対して行うための関数である。これらの操作ではキー列の指定が重要であり、意図しないキーでの操作はデータの不整合を引き起こす可能性がある。デフォルトでは最初の列をキーとして使用するが、これはIDや主キーが最初の列に配置されることが多いという慣習に基づいている。この通知により、ユーザーは自動選択されたキーを確認し、意図通りの操作が行われることを確認できる。

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

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

**通知内容の概要**：`Matching, by = "列名"` の形式で、使用されたキー列が表示される。

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

## 通知種別

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

## 送信仕様

### 基本情報

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

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

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

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| 送信元 | rlang パッケージ（inform関数） |
| 形式 | テキスト |
| メッセージクラス | `dplyr_message_matching_by`, `dplyr_message` |

### 本文テンプレート

```
Matching, by = "column_name"
```

### 添付ファイル

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

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| by | 自動選択されたキー列名 | names(y)[[1]] | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 関数呼び出し | `rows_*`関数の実行 | `by = NULL`でyに列が存在する場合 | yの最初の列をキーとして使用 |

### 送信抑止条件

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

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[rows_*関数呼び出し] --> B[rows_check_by実行]
    B --> C{byがNULL?}
    C -->|No| D[指定されたbyを検証]
    C -->|Yes| E{yに列があり?}
    E -->|No| F[エラー発生]
    E -->|Yes| G[names y 1 をbyに設定]
    G --> H[メッセージ生成]
    H --> I[inform実行]
    I --> J[情報メッセージ表示]
    J --> K[by検証継続]
    D --> K
    K --> L[行操作実行]
```

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

### 参照テーブル一覧

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

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | データフレームの更新はメモリ内で行われる |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| 列なしエラー | yに列が存在しない場合 | yに最低1つの列が必要 |
| by不正エラー | byがcharacter vectorでない場合 | 適切な形式でbyを指定 |
| by空エラー | byが空のcharacter vectorの場合 | 最低1列のキーを指定 |
| 名前付きエラー | byに名前がついている場合 | 名前なしのcharacter vectorを使用 |

### リトライ仕様

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

## 配信設定

### レート制限

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

### 配信時間帯

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

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

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

## 備考

- `rows_*`関数群はSQLのINSERT、UPDATE、DELETE操作に対応
- `rows_insert()`: 新しい行を追加（キーの重複はエラーまたは無視）
- `rows_append()`: キーを無視して行を追加
- `rows_update()`: 既存の行を更新（キーの一意性が必要）
- `rows_patch()`: NA値のみを上書きする部分更新
- `rows_upsert()`: 存在すれば更新、なければ挿入
- `rows_delete()`: 一致する行を削除
- メッセージには`dplyr_message_matching_by`と`dplyr_message`のクラスが付与される
- デフォルトでは最初の列をキーとして使用（IDが最初の列にあることが多いため）
- `by`は名前なしのcharacter vectorである必要がある

---

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

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

### 推奨読解順序

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

`rows_*`関数群の引数構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | rows.R | `R/rows.R` | 関数群の共通引数（37-47行目） |

**読解のコツ**: `x`がターゲットデータフレーム、`y`が変更を適用するデータフレーム、`by`がキー列の指定である。

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | rows.R | `R/rows.R` | `rows_check_by()`関数（476-503行目） |

**主要処理フロー**:
1. **479-481行目**: yが空の場合のエラーチェック
2. **483-484行目**: `by = NULL`の場合、yの最初の列名を取得
3. **486-489行目**: `inform()`による情報メッセージ表示
4. **492-500行目**: byの形式バリデーション

#### Step 3: 情報通知の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | rows.R | `R/rows.R` | メッセージ生成と`inform()`（486-489行目） |

**メッセージ構築**:
```r
inform(
  message = glue("Matching, by = \"{by}\""),
  class = c("dplyr_message_matching_by", "dplyr_message")
)
```

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | rows.R | `R/rows.R` | `rows_insert.data.frame()`での使用（149行目） |
| 4-2 | rows.R | `R/rows.R` | `rows_update.data.frame()`での使用（217行目） |
| 4-3 | rows.R | `R/rows.R` | `rows_delete.data.frame()`での使用（436行目） |

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

```
rows_insert(x, y, by = NULL, ...)
    │
    ├─ rows_check_by(by, y)
    │      │
    │      ├─ [yが空の場合] abort()
    │      │
    │      ├─ [byがNULLの場合]
    │      │      ├─ by <- names(y)[[1]]
    │      │      │
    │      │      └─ inform(glue("Matching, by = \"{by}\""), class = ...)
    │      │             └─ 情報メッセージ表示
    │      │
    │      ├─ [byがcharacterでない場合] abort()
    │      │
    │      ├─ [byが空の場合] abort()
    │      │
    │      └─ [byに名前がある場合] abort()
    │
    ├─ rows_check_x_contains_y(x, y)
    │
    ├─ rows_check_contains_by(x, by, "x")
    │
    ├─ rows_check_contains_by(y, by, "y")
    │
    └─ 行操作実行
```

### データフロー図

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

x, y ───────────▶ rows_*関数(by=NULL) ──────▶ 情報メッセージ（stdout）
                        │                      "Matching, by = ..."
                        ▼
               rows_check_by() ────────────▶ バリデーション済みby
                        │
                        ▼
               行操作実行 ─────────────────▶ 更新済みデータフレーム
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| rows.R | `R/rows.R` | ソース | `rows_*`関数群と`rows_check_by()`の定義 |
| utils.R | `R/utils.R` | ソース | ユーティリティ関数 |
| NAMESPACE | `NAMESPACE` | 設定 | エクスポート定義 |
