# MySqlSchemaInspector Query Builder / Row Mapper 設計

## 1. 文件目的

本文件整理 `MySqlSchemaInspector` 第一版的純程式設計，聚焦在 query builder、row mapper、snapshot assembly、錯誤處理與單元測試。

此設計仍不導入 `MySqlConnector`、不修改 `.csproj`、不建立真實 connection string、不連線 MySQL、不讀取真實 `information_schema`，也不執行任何 DDL。

## 2. 設計結論

第一版建議先把真實 MySQL Inspector 拆成三個可單獨測試的區塊：

| 區塊 | 職責 | 是否需要真實 DB |
|---|---|---|
| Query Builder | 產生 `information_schema` 查詢與參數名稱 | 否 |
| Row Mapper | 將 table / column / index metadata row 轉成中間模型 | 否 |
| Snapshot Assembler | 將中間模型組成 schema snapshot | 否 |

這樣可以先驗證 MySQL 5.6.2 metadata 規則與 mapping 邏輯，等設計穩定後再確認是否導入 `MySqlConnector`。

## 3. 建議元件切分

| 元件 | 建議名稱 | 職責 |
|---|---|---|
| query builder | `MySqlSchemaInspectorQueryBuilder` | 產生 tables / columns / indexes 查詢 |
| metadata row | `MySqlTableMetadataRow` / `MySqlColumnMetadataRow` / `MySqlIndexMetadataRow` | 表示從 `information_schema` 讀出的原始欄位 |
| row mapper | `MySqlSchemaMetadataMapper` | 將 metadata row 轉成 schema model 所需資訊 |
| snapshot assembler | `MySqlSchemaSnapshotAssembler` | 依 table name 合併 table / column / index |
| inspector | `MySqlSchemaInspector` | 後續負責協調連線、查詢、mapping 與 result |

若實作時覺得元件過多，第一版可以先合併 mapper 與 assembler，但 query builder 建議保留獨立，方便測試參數化查詢。

## 4. Query Builder 設計

### 4.1 共通原則

每個 query 都必須符合：

- 使用 `@DatabaseName` 參數，不直接拼接 database name。
- 必須限制 `TABLE_SCHEMA = @DatabaseName`。
- 可接受 table filter，但 table filter 也必須參數化。
- 必須有穩定排序，讓測試與人工驗證輸出一致。
- 不產生任何 DDL。

### 4.2 Table Query

用途：讀取指定 database 內的 table 清單。

建議欄位：

| 欄位 | 對應 |
|---|---|
| `TABLE_NAME` | table name |
| `TABLE_COMMENT` | table description |
| `ENGINE` | table engine |
| `TABLE_COLLATION` | table collation |

建議排序：

```sql
ORDER BY TABLE_NAME
```

### 4.3 Column Query

用途：讀取 table 欄位 metadata。

建議欄位：

| 欄位 | 對應 |
|---|---|
| `TABLE_NAME` | 所屬 table |
| `COLUMN_NAME` | 欄位名稱 |
| `COLUMN_TYPE` | 完整型別，例如 `varchar(64)` |
| `DATA_TYPE` | 基礎型別，例如 `varchar` |
| `CHARACTER_MAXIMUM_LENGTH` | 字串長度 |
| `NUMERIC_PRECISION` | 數值精度 |
| `NUMERIC_SCALE` | 小數位數 |
| `IS_NULLABLE` | nullable |
| `COLUMN_DEFAULT` | default value |
| `COLUMN_COMMENT` | 欄位描述 |
| `ORDINAL_POSITION` | 欄位順序 |

建議排序：

```sql
ORDER BY TABLE_NAME, ORDINAL_POSITION
```

### 4.4 Index Query

用途：讀取 index 與 primary key metadata。

建議欄位：

| 欄位 | 對應 |
|---|---|
| `TABLE_NAME` | 所屬 table |
| `INDEX_NAME` | index name |
| `COLUMN_NAME` | index 欄位 |
| `NON_UNIQUE` | unique 判斷 |
| `SEQ_IN_INDEX` | 複合 index 欄位順序 |

建議排序：

```sql
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX
```

`INDEX_NAME = 'PRIMARY'` 時應轉成 primary key metadata，不應當成一般 index。

## 5. Table Filter 設計

第一版支援兩種模式即可：

| 模式 | 行為 |
|---|---|
| 無指定 table | 讀取 database 內全部 table metadata |
| 指定 table names | 加入 `TABLE_NAME IN (...)` 條件 |

注意事項：

- `IN` 條件需產生 `@TableName0`、`@TableName1` 等參數。
- 空陣列不應產生 `IN ()`，應視為未指定 table filter 或回傳驗證錯誤。
- table name 不能直接串到 SQL 字串。

## 6. Row Mapper 設計

### 6.1 Table Row

| 輸入 | Mapping |
|---|---|
| `TABLE_NAME` | required |
| `TABLE_COMMENT` | null 時轉空字串 |
| `ENGINE` | 保留 metadata，可作 warning 判斷 |
| `TABLE_COLLATION` | 保留 metadata，可作 warning 判斷 |

若缺少 `TABLE_NAME`，應回傳標準錯誤。

### 6.2 Column Row

| 輸入 | Mapping |
|---|---|
| `COLUMN_NAME` | required |
| `COLUMN_TYPE` | 作為第一版型別比對主要來源 |
| `DATA_TYPE` | 作為基礎型別與 warning 判斷 |
| `IS_NULLABLE` | `YES` 轉 true，`NO` 轉 false |
| `COLUMN_DEFAULT` | 保留原始值 |
| `COLUMN_COMMENT` | null 時轉空字串 |
| `ORDINAL_POSITION` | 用於排序 |

型別比對第一版建議保留完整 `COLUMN_TYPE`，不要過度正規化，避免 MySQL 5.6.2 的細節被吃掉。

### 6.3 Index Row

| 輸入 | Mapping |
|---|---|
| `INDEX_NAME` | required |
| `COLUMN_NAME` | required |
| `NON_UNIQUE` | `0` 轉 unique，`1` 轉 non-unique |
| `SEQ_IN_INDEX` | 欄位順序 |

同一個 `TABLE_NAME + INDEX_NAME` 的多筆 row 應合併成同一個 index，欄位依 `SEQ_IN_INDEX` 排序。

## 7. Snapshot Assembly 設計

組裝順序建議：

1. 先以 table rows 建立 table dictionary。
2. 將 column rows 依 `TABLE_NAME` 加入對應 table。
3. 將 index rows 依 `TABLE_NAME + INDEX_NAME` 分組。
4. `PRIMARY` index 轉成 primary key metadata。
5. 一般 index 加入 table indexes。
6. 若 column / index 指到不存在的 table，產生 warning 或 error。

第一版建議：

- table row 缺失但 column row 存在：回傳 warning，並建立 minimal table snapshot。
- index 指到不存在欄位：回傳 warning，不直接失敗。
- 欄位型別未知：回傳 manual review warning，不直接套用。

## 8. Result 與錯誤格式

建議 query builder / mapper / assembler 各自保留可測試的結果：

| 元件 | 成功輸出 | 失敗輸出 |
|---|---|---|
| Query Builder | SQL + parameter names | validation error |
| Row Mapper | metadata row model | missing required field error |
| Snapshot Assembler | schema snapshot + warnings | assembly error |

錯誤資訊至少包含：

- `ErrorCode`
- `Message`
- `Source`
- `TableName`
- `ColumnName`
- `IndexName`
- `CorrelationId`

## 9. 單元測試設計

第一批測試不依賴真實 DB，建議包含：

| 測試 | 預期 |
|---|---|
| Table query 必含 `TABLE_SCHEMA = @DatabaseName` | 避免讀到其他 database |
| Column query 依 `TABLE_NAME, ORDINAL_POSITION` 排序 | 輸出穩定 |
| Index query 依 `TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX` 排序 | 複合 index 順序穩定 |
| table filter 產生參數化 `IN` 條件 | 不直接拼接 table name |
| 空 table filter 不產生 `IN ()` | 避免 SQL 錯誤 |
| nullable mapping | `YES` / `NO` 正確轉換 |
| unique mapping | `NON_UNIQUE` 正確轉換 |
| primary key mapping | `PRIMARY` 不當成一般 index |
| 複合 index assembly | 欄位順序正確 |
| 缺少 required metadata | 回傳標準錯誤 |
| 不存在 table 的 column / index | 回傳 warning |

## 10. 實作前停止線

以下仍需先確認，不得在本設計自動執行：

| 事項 | 原因 |
|---|---|
| 導入 `MySqlConnector` | 新增套件 |
| 修改 `.csproj` | 影響 restore / build |
| 實作真實 DB connection | 外部服務與密碼管理 |
| 讀取真實 `information_schema` | 真實 DB metadata 存取 |
| 修改 public method 簽章 | 可能破壞既有契約 |
| 改 ConsoleHost 啟動參數 | 影響使用流程 |
| 執行任何 DDL | 會修改資料庫 |

## 11. 建議下一步

若使用者尚未確認導入 `MySqlConnector`，下一步建議先做「Query Builder / Row Mapper 實作前確認」，把要新增的 class、method、測試檔與不改 public contract 的方式列清楚。

若使用者確認可導入 `MySqlConnector`，再進入 `MySqlConnector` 套件導入與真實 Inspector 第一版實作。
