# 機能設計書 67-SQLiteストレージ

## 概要

本ドキュメントは、Nushellにおけるインメモリ SQLite データベース機能（stor コマンド群）の設計を記述する。セッション内で永続化されるインメモリデータベースを使用して、構造化データの保存・検索・更新・削除を行う。

### 本機能の処理概要

SQLiteストレージ機能は、Nushell セッション内でインメモリ SQLite データベースを操作するためのコマンド群を提供する。テーブルの作成、データの挿入・更新・削除、外部ファイルへのエクスポート・インポートをサポートする。

**業務上の目的・背景**：シェルスクリプト内で構造化データを一時的に保存し、SQL を使わずに操作したい場面がある。本機能により、パイプラインデータをデータベースに保存し、後で参照・更新することが可能となる。

**機能の利用シーン**：
- セッション内でのデータの一時保存
- 大量のレコードの効率的な保存・検索
- 複数コマンド間でのデータ共有
- データベースファイルへのエクスポート・インポート
- 構造化データの永続化

**主要な処理内容**：
1. `stor create` - テーブルを作成
2. `stor insert` - データを挿入
3. `stor update` - データを更新
4. `stor delete` - データまたはテーブルを削除
5. `stor open` - データベースを開く
6. `stor reset` - 全テーブルを削除
7. `stor export` - ファイルにエクスポート
8. `stor import` - ファイルからインポート

**関連システム・外部連携**：rusqlite クレートによる SQLite 連携。

**権限による制御**：特別な権限制御はなく、すべてのユーザーが実行可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLI専用機能（画面関連なし） |

## 機能種別

データストレージ / データベース操作

## 入力仕様

### 入力パラメータ

#### stor create

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --table-name, -t | String | Yes | テーブル名 | - |
| --columns, -c | Record | Yes | カラム名とデータ型のレコード | int, float, str, bool, datetime, json, jsonb |

#### stor insert

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --table-name, -t | String | Yes | テーブル名 | - |
| --data-record, -d | Record | No | 挿入するデータ | パイプライン入力と排他 |

#### stor update

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --table-name, -t | String | Yes | テーブル名 | - |
| --update-record, -u | Record | No | 更新するデータ | パイプライン入力と排他 |
| --where-clause, -w | String | No | WHERE句（WHEREキーワードなし） | - |

#### stor delete

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --table-name, -t | String | Yes | テーブル名 | - |
| --where-clause, -w | String | No | WHERE句（省略時はテーブル削除） | - |

#### stor export / stor import

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --file-name, -f | String | Yes | ファイル名 | - |

### 入力データソース

- **パイプライン入力**: Record, Table（stor insert, stor update）
- **フラグ**: --data-record, --update-record

## 出力仕様

### 出力データ

| コマンド | 出力型 | 説明 |
|---------|--------|------|
| stor create | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor insert | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor update | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor delete | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor open | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor reset | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor export | Custom(SQLiteDatabase) | データベースオブジェクト |
| stor import | Custom(SQLiteDatabase) | データベースオブジェクト |

### 出力先

パイプラインへの出力（PipelineData）。カスタム値として SQLiteDatabase を返す。

## 処理フロー

### 処理シーケンス

```
1. コマンドの引数解析
   └─ テーブル名、データ、フラグを取得

2. インメモリデータベース接続
   └─ MEMORY_DB (file:memdb1?mode=memory&cache=shared) に接続

3. SQL文の構築と実行
   └─ CREATE TABLE / INSERT / UPDATE / DELETE / DROP TABLE

4. 結果の返却
   └─ SQLiteDatabase を Value::custom として返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{コマンド種別}
    B -->|create| C[CREATE TABLE SQL生成]
    B -->|insert| D[INSERT SQL生成]
    B -->|update| E[UPDATE SQL生成]
    B -->|delete| F[DELETE/DROP SQL生成]
    B -->|open| G[空データベース返却]
    B -->|reset| H[全テーブル削除]
    B -->|export| I[VACUUM INTO実行]
    B -->|import| J[restore実行]
    C --> K[conn.execute]
    D --> K
    E --> K
    F --> K
    G --> L[Value::custom]
    H --> K
    I --> K
    J --> K
    K --> L
    L --> M[PipelineData返却]
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 型マッピング | int->INTEGER, float->REAL, str->VARCHAR(255), bool->BOOLEAN, datetime->DATETIME | stor create |
| BR-002 | JSON型 | json, jsonb 型をサポート | stor create |
| BR-003 | 入力排他 | パイプライン入力とフラグは排他的 | stor insert/update |
| BR-004 | テーブル削除 | where-clause 省略時はテーブル全体を削除 | stor delete |
| BR-005 | リセット | foreign_keys を一時的にOFFにして全テーブル削除 | stor reset |

### 計算ロジック

- **stor create**: `CREATE TABLE {name} ({col1} {type1}, ...)` を構築
- **stor insert**: `INSERT INTO {name} ({cols}) VALUES (?1, ?2, ...)` を構築、params_from_iter でバインド
- **stor update**: `UPDATE {name} SET {col}=?1, ... WHERE {where}` を構築
- **stor delete**: `DELETE FROM {name} WHERE {where}` または `DROP TABLE {name}` を構築
- **stor export**: `VACUUM main INTO '{filename}'` で外部ファイルにエクスポート
- **stor import**: `conn.restore()` でファイルからインポート

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

### インメモリデータベース

- **接続URI**: `file:memdb1?mode=memory&cache=shared`
- **永続性**: セッション内で共有、セッション終了時に消失
- **同時接続**: cache=shared により複数接続で共有可能

### サポートするデータ型

| Nushell型 | SQLite型 | 説明 |
|----------|---------|------|
| int | INTEGER | 整数 |
| float | REAL | 浮動小数点 |
| str | VARCHAR(255) | 文字列 |
| bool | BOOLEAN | 真偽値 |
| datetime | DATETIME | 日時（デフォルト値付き） |
| json | JSON | JSON文字列 |
| jsonb | JSONB | JSONバイナリ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MissingParameter | パラメータエラー | 必須パラメータ不足 | 必須パラメータを指定 |
| UnsupportedInput | 型エラー | 未サポートのカラム型 | サポートする型を使用 |
| GenericError | SQLエラー | SQL実行エラー | SQL構文・テーブル名を確認 |
| OnlySupportsThisInputType | 型エラー | Record以外の入力 | Recordを入力 |

### リトライ仕様

- busy_handler により SQLITE_BUSY 時に 250ms 待機してリトライ

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

本機能は自動コミットモードで動作する。明示的なトランザクション管理は行わない。

## パフォーマンス要件

- インメモリデータベースにより高速なアクセス
- 大量データの挿入は複数レコードを一度に処理可能
- busy_handler によるロック競合時のリトライ

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

- WHERE句は文字列として直接SQLに埋め込まれるため、信頼できない入力の使用に注意
- エクスポートファイルのパーミッションに注意

## 備考

- SQLiteDatabase は CustomValue として実装
- to_base_value() でテーブル内容をRecord形式に変換可能
- SQLiteQueryBuilder による遅延評価クエリをサポート

---

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

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

### 推奨読解順序

#### Step 1: モジュール構成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mod.rs | `crates/nu-command/src/stor/mod.rs` | 公開コマンド一覧 |
| 1-2 | stor_.rs | `crates/nu-command/src/stor/stor_.rs` | 親コマンド（ヘルプ表示） |

**主要処理フロー**:
- **11-19行目（mod.rs）**: 8つのサブコマンドをエクスポート
- **18行目（stor_.rs）**: "in-memory sqlite database" の説明

#### Step 2: データベースコアを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | sqlite.rs | `crates/nu-command/src/database/values/sqlite.rs` | SQLiteDatabase 実装 |

**主要処理フロー**:
- **20行目**: MEMORY_DB 定数定義
- **23-33行目**: SQLiteDatabase 構造体
- **35-41行目**: new() コンストラクタ
- **111-132行目**: open_connection() でインメモリDB接続
- **134-138行目**: sleeper() busy_handler
- **140-158行目**: get_tables() でテーブル一覧取得
- **160-168行目**: drop_all_tables() で全テーブル削除
- **170-179行目**: export_in_memory_database_to_file() でエクスポート
- **190-210行目**: restore_database_from_file() でインポート
- **355-409行目**: CustomValue 実装

#### Step 3: テーブル作成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | create.rs | `crates/nu-command/src/stor/create.rs` | stor create 実装 |

**主要処理フロー**:
- **15-29行目**: シグネチャ定義（--table-name, --columns）
- **64-67行目**: SQLiteDatabase インスタンス作成
- **75-155行目**: process() 関数
- **91-128行目**: カラム型のマッピング（int->INTEGER など）
- **137-144行目**: conn.execute() でCREATE TABLE実行

#### Step 4: データ挿入を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | insert.rs | `crates/nu-command/src/stor/insert.rs` | stor insert 実装 |

**主要処理フロー**:
- **94行目**: handle() でパイプラインまたはフラグからレコード取得
- **158-210行目**: process() 関数
- **173-190行目**: INSERT SQL 構築
- **195行目**: values_to_sql() でパラメータ変換
- **198行目**: params_from_iter() でバインド実行

#### Step 5: データ更新・削除を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | update.rs | `crates/nu-command/src/stor/update.rs` | stor update 実装 |
| 5-2 | delete.rs | `crates/nu-command/src/stor/delete.rs` | stor delete 実装 |

**主要処理フロー（delete.rs）**:
- **93-108行目**: where_clause の有無でDELETE FROM/DROP TABLEを切り替え

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

```
stor (stor_.rs)
    │
    ├─ stor create (create.rs)
    │      └─ run() → process()
    │             └─ conn.execute("CREATE TABLE ...")
    │
    ├─ stor insert (insert.rs)
    │      └─ run() → handle() → process()
    │             └─ values_to_sql()
    │             └─ conn.execute("INSERT INTO ...")
    │
    ├─ stor update (update.rs)
    │      └─ run() → handle() → process()
    │             └─ conn.execute("UPDATE ...")
    │
    ├─ stor delete (delete.rs)
    │      └─ run()
    │             └─ conn.execute("DROP TABLE" / "DELETE FROM")
    │
    ├─ stor open (open.rs)
    │      └─ run() → SQLiteDatabase::new()
    │
    ├─ stor reset (reset.rs)
    │      └─ run() → db.drop_all_tables()
    │
    ├─ stor export (export.rs)
    │      └─ run() → db.export_in_memory_database_to_file()
    │
    └─ stor import (import.rs)
           └─ run() → db.restore_database_from_file()
```

### データフロー図

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

Record ───────────────▶ INSERT SQL生成 ─────────────────▶ SQLiteDatabase
                              │
Table ────────────────▶ 各行をINSERT ───────────────────▶ SQLiteDatabase
                              │
フラグ ───────────────▶ SQL生成・実行 ──────────────────▶ SQLiteDatabase
                              │
                              ▼
                       Value::custom(db)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mod.rs | `crates/nu-command/src/stor/mod.rs` | ソース | モジュール定義 |
| stor_.rs | `crates/nu-command/src/stor/stor_.rs` | ソース | 親コマンド |
| create.rs | `crates/nu-command/src/stor/create.rs` | ソース | stor create 実装 |
| insert.rs | `crates/nu-command/src/stor/insert.rs` | ソース | stor insert 実装 |
| update.rs | `crates/nu-command/src/stor/update.rs` | ソース | stor update 実装 |
| delete.rs | `crates/nu-command/src/stor/delete.rs` | ソース | stor delete 実装 |
| open.rs | `crates/nu-command/src/stor/open.rs` | ソース | stor open 実装 |
| reset.rs | `crates/nu-command/src/stor/reset.rs` | ソース | stor reset 実装 |
| export.rs | `crates/nu-command/src/stor/export.rs` | ソース | stor export 実装 |
| import.rs | `crates/nu-command/src/stor/import.rs` | ソース | stor import 実装 |
| sqlite.rs | `crates/nu-command/src/database/values/sqlite.rs` | ソース | SQLiteDatabase実装 |
