docs: restore docs/private/roadmap from 7b4908f9 (Phase 20.31)
This commit is contained in:
500
docs/private/roadmap/phases/phase-21/README.md
Normal file
500
docs/private/roadmap/phases/phase-21/README.md
Normal file
@ -0,0 +1,500 @@
|
||||
# Phase 21: データベース駆動開発(DDD: Database-Driven Development)
|
||||
|
||||
## 📋 概要
|
||||
|
||||
ソースコードをファイルではなくデータベースで管理する革命的開発パラダイム。
|
||||
Box、メソッド、名前空間を構造化データとして扱い、リファクタリングを瞬時に完了させる。
|
||||
**「ファイルは1970年代の遺物。21世紀のコードは構造化データベースに住む」**
|
||||
|
||||
## 🎯 背景と動機
|
||||
|
||||
### 現状の問題
|
||||
- **ファイルベース**:物理的な区切り(人間の都合)
|
||||
- **Box/メソッド**:論理的な単位(プログラムの本質)
|
||||
- **不一致の結果**:リファクタリングが遅い、検索が非効率、依存関係が不透明
|
||||
|
||||
### 解決策
|
||||
- コードをSQLiteデータベースで管理
|
||||
- Box、メソッド、依存関係を正規化されたテーブルで表現
|
||||
- SQLクエリでリファクタリング・検索・分析を高速化
|
||||
|
||||
### Nyashの決定的優位性(2025-09-30追加)
|
||||
- **グローバル変数なし** → 状態が完全に追跡可能、並列リファクタリング安全
|
||||
- **Everything is Box** → 統一的なテーブル設計、1対1マッピング
|
||||
- **Static box** → グローバル状態も管理可能、副作用が局所的
|
||||
- **スコープ明確** → 依存関係が単純、循環参照の検出容易
|
||||
|
||||
## 🏗️ データベーススキーマ
|
||||
|
||||
### 基本テーブル構造
|
||||
|
||||
```sql
|
||||
-- Boxの定義
|
||||
CREATE TABLE boxes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
namespace TEXT,
|
||||
parent_box_id INTEGER,
|
||||
box_type TEXT CHECK(box_type IN ('normal', 'static', 'abstract')),
|
||||
source_code TEXT,
|
||||
metadata JSON, -- 型情報、アノテーション、ドキュメント
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (parent_box_id) REFERENCES boxes(id)
|
||||
);
|
||||
|
||||
-- メソッド定義
|
||||
CREATE TABLE methods (
|
||||
id INTEGER PRIMARY KEY,
|
||||
box_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
visibility TEXT CHECK(visibility IN ('public', 'private', 'protected')),
|
||||
params JSON, -- パラメータ情報
|
||||
return_type JSON,
|
||||
body TEXT,
|
||||
mir_cache BLOB, -- コンパイル済みMIRをキャッシュ
|
||||
optimization_hints JSON,
|
||||
FOREIGN KEY (box_id) REFERENCES boxes(id),
|
||||
UNIQUE(box_id, name) -- 同一Box内でメソッド名は一意
|
||||
);
|
||||
|
||||
-- フィールド定義
|
||||
CREATE TABLE fields (
|
||||
id INTEGER PRIMARY KEY,
|
||||
box_id INTEGER NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
field_type JSON,
|
||||
default_value TEXT,
|
||||
metadata JSON,
|
||||
FOREIGN KEY (box_id) REFERENCES boxes(id)
|
||||
);
|
||||
|
||||
-- 依存関係
|
||||
CREATE TABLE dependencies (
|
||||
from_type TEXT CHECK(from_type IN ('box', 'method')),
|
||||
from_id INTEGER,
|
||||
to_type TEXT CHECK(to_type IN ('box', 'method')),
|
||||
to_id INTEGER,
|
||||
dep_type TEXT CHECK(dep_type IN ('uses', 'extends', 'calls', 'implements')),
|
||||
metadata JSON, -- 呼び出し位置、使用頻度など
|
||||
PRIMARY KEY (from_type, from_id, to_type, to_id, dep_type)
|
||||
);
|
||||
|
||||
-- 名前空間
|
||||
CREATE TABLE namespaces (
|
||||
id INTEGER PRIMARY KEY,
|
||||
path TEXT UNIQUE NOT NULL,
|
||||
parent_id INTEGER,
|
||||
metadata JSON,
|
||||
FOREIGN KEY (parent_id) REFERENCES namespaces(id)
|
||||
);
|
||||
|
||||
-- ファイルマッピング(2025-09-30追加)
|
||||
CREATE TABLE files (
|
||||
id INTEGER PRIMARY KEY,
|
||||
path TEXT UNIQUE NOT NULL, -- 'src/user/auth.nyash'
|
||||
last_modified TIMESTAMP,
|
||||
is_generated BOOLEAN DEFAULT FALSE -- DBから生成されたファイルか
|
||||
);
|
||||
|
||||
CREATE TABLE file_boxes (
|
||||
file_id INTEGER NOT NULL,
|
||||
box_id INTEGER NOT NULL,
|
||||
line_start INTEGER, -- 何行目から
|
||||
line_end INTEGER, -- 何行目まで
|
||||
PRIMARY KEY (file_id, box_id),
|
||||
FOREIGN KEY (file_id) REFERENCES files(id),
|
||||
FOREIGN KEY (box_id) REFERENCES boxes(id)
|
||||
);
|
||||
|
||||
-- コンパイルキャッシュ
|
||||
CREATE TABLE compile_cache (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_type TEXT,
|
||||
entity_id INTEGER,
|
||||
mir_version INTEGER,
|
||||
mir_data BLOB,
|
||||
metadata JSON, -- 最適化レベル、ターゲットなど
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 全文検索用インデックス
|
||||
CREATE VIRTUAL TABLE code_search USING fts5(
|
||||
entity_type,
|
||||
entity_id,
|
||||
name,
|
||||
content,
|
||||
tokenize = 'porter'
|
||||
);
|
||||
```
|
||||
|
||||
## 🚀 革命的な機能
|
||||
|
||||
### 1. 瞬間リファクタリング
|
||||
|
||||
```sql
|
||||
-- 名前変更:トランザクション一発
|
||||
BEGIN TRANSACTION;
|
||||
UPDATE boxes SET name = 'NewBoxName' WHERE name = 'OldBoxName';
|
||||
UPDATE code_search SET name = 'NewBoxName'
|
||||
WHERE entity_type = 'box' AND name = 'OldBoxName';
|
||||
-- 依存コードも自動更新(トリガーで実装)
|
||||
COMMIT;
|
||||
|
||||
-- メソッド移動:Box間でメソッドを移動
|
||||
UPDATE methods SET box_id = (SELECT id FROM boxes WHERE name = 'TargetBox')
|
||||
WHERE id = ? AND box_id = ?;
|
||||
```
|
||||
|
||||
### 2. 高度な検索・分析
|
||||
|
||||
```sql
|
||||
-- 未使用コード検出
|
||||
SELECT b.namespace || '.' || b.name AS unused_box
|
||||
FROM boxes b
|
||||
LEFT JOIN dependencies d ON
|
||||
(d.to_type = 'box' AND d.to_id = b.id)
|
||||
WHERE d.from_id IS NULL;
|
||||
|
||||
-- 循環依存検出(再帰CTE)
|
||||
WITH RECURSIVE dep_path AS (
|
||||
SELECT from_id, to_id,
|
||||
from_id || '->' || to_id as path
|
||||
FROM dependencies
|
||||
WHERE from_type = 'box' AND to_type = 'box'
|
||||
UNION ALL
|
||||
SELECT d.from_id, dp.to_id,
|
||||
dp.path || '->' || d.to_id
|
||||
FROM dependencies d
|
||||
JOIN dep_path dp ON d.to_id = dp.from_id
|
||||
WHERE d.from_type = 'box' AND d.to_type = 'box'
|
||||
AND dp.path NOT LIKE '%' || d.to_id || '%'
|
||||
)
|
||||
SELECT path FROM dep_path WHERE from_id = to_id;
|
||||
|
||||
-- 類似コード検出(全文検索)
|
||||
SELECT b1.name AS box1, m1.name AS method1,
|
||||
b2.name AS box2, m2.name AS method2,
|
||||
similarity_score(m1.body, m2.body) AS similarity
|
||||
FROM methods m1
|
||||
JOIN methods m2 ON m1.id < m2.id
|
||||
JOIN boxes b1 ON m1.box_id = b1.id
|
||||
JOIN boxes b2 ON m2.box_id = b2.id
|
||||
WHERE similarity_score(m1.body, m2.body) > 0.8;
|
||||
```
|
||||
|
||||
### 3. ファイル操作とリファクタリング(2025-09-30追加)
|
||||
|
||||
```sql
|
||||
-- Box抽出して新ファイルへ移動
|
||||
UPDATE file_boxes
|
||||
SET file_id = (SELECT id FROM files WHERE path = 'auth/user.nyash')
|
||||
WHERE box_id = (SELECT id FROM boxes WHERE name = 'UserBox');
|
||||
|
||||
-- 関連Boxをまとめて移動(依存関係ベース)
|
||||
WITH related_boxes AS (
|
||||
SELECT DISTINCT to_id as box_id
|
||||
FROM dependencies
|
||||
WHERE from_id = ? AND dep_type IN ('uses', 'extends')
|
||||
)
|
||||
UPDATE file_boxes
|
||||
SET file_id = (SELECT id FROM files WHERE path = 'auth/related.nyash')
|
||||
WHERE box_id IN (SELECT box_id FROM related_boxes);
|
||||
|
||||
-- 肥大化ファイルの自動分割提案
|
||||
SELECT f.path, COUNT(*) as box_count,
|
||||
GROUP_CONCAT(b.name) as boxes_to_extract
|
||||
FROM files f
|
||||
JOIN file_boxes fb ON f.id = fb.file_id
|
||||
JOIN boxes b ON fb.box_id = b.id
|
||||
GROUP BY f.path
|
||||
HAVING COUNT(*) > 10;
|
||||
```
|
||||
|
||||
### 4. インテリジェントなキャッシング
|
||||
|
||||
```sql
|
||||
-- 変更影響分析
|
||||
CREATE TRIGGER invalidate_cache_on_method_update
|
||||
AFTER UPDATE ON methods
|
||||
BEGIN
|
||||
-- 直接依存するエンティティのキャッシュを無効化
|
||||
DELETE FROM compile_cache
|
||||
WHERE entity_id IN (
|
||||
SELECT from_id FROM dependencies
|
||||
WHERE to_type = 'method' AND to_id = NEW.id
|
||||
);
|
||||
END;
|
||||
```
|
||||
|
||||
### 4. バージョン管理の統合
|
||||
|
||||
```sql
|
||||
-- 変更履歴
|
||||
CREATE TABLE history (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_type TEXT,
|
||||
entity_id INTEGER,
|
||||
version INTEGER,
|
||||
change_type TEXT,
|
||||
old_value TEXT,
|
||||
new_value TEXT,
|
||||
changed_by TEXT,
|
||||
changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
commit_message TEXT
|
||||
);
|
||||
|
||||
-- Git風のブランチ管理
|
||||
CREATE TABLE branches (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
base_version INTEGER,
|
||||
is_active BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
```
|
||||
|
||||
## 🎨 実装例
|
||||
|
||||
```nyash
|
||||
box CodeDB {
|
||||
db: SQLiteBox
|
||||
cache: MapBox
|
||||
|
||||
birth(dbPath) {
|
||||
me.db = new SQLiteBox(dbPath)
|
||||
me.cache = new MapBox()
|
||||
me.initSchema()
|
||||
}
|
||||
|
||||
// Boxを保存
|
||||
saveBox(box) {
|
||||
local tx = me.db.beginTransaction()
|
||||
try {
|
||||
local boxId = me.db.insert("boxes", {
|
||||
name: box.name,
|
||||
namespace: box.namespace,
|
||||
source_code: box.toString(),
|
||||
metadata: box.getMetadata()
|
||||
})
|
||||
|
||||
// メソッドも保存
|
||||
for method in box.methods {
|
||||
me.saveMethod(boxId, method)
|
||||
}
|
||||
|
||||
tx.commit()
|
||||
} catch (e) {
|
||||
tx.rollback()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
// リファクタリング:名前変更
|
||||
renameBox(oldName, newName) {
|
||||
me.db.execute(
|
||||
"UPDATE boxes SET name = ? WHERE name = ?",
|
||||
[newName, oldName]
|
||||
)
|
||||
|
||||
// 全文検索インデックスも更新
|
||||
me.updateSearchIndex()
|
||||
|
||||
// キャッシュ無効化
|
||||
me.invalidateCache(oldName)
|
||||
}
|
||||
|
||||
// 未使用コード検出
|
||||
findUnusedCode() {
|
||||
return me.db.query("
|
||||
SELECT b.namespace || '.' || b.name AS unused
|
||||
FROM boxes b
|
||||
LEFT JOIN dependencies d ON d.to_id = b.id
|
||||
WHERE d.from_id IS NULL
|
||||
")
|
||||
}
|
||||
|
||||
// AI連携:類似コード提案
|
||||
suggestRefactoring(methodId) {
|
||||
local similar = me.findSimilarMethods(methodId)
|
||||
if similar.length() > 3 {
|
||||
return {
|
||||
suggestion: "共通Boxに抽出",
|
||||
methods: similar
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔧 開発ツール
|
||||
|
||||
### 1. CLI拡張
|
||||
|
||||
```bash
|
||||
# DBクエリ実行
|
||||
nyash db query "SELECT * FROM boxes WHERE name LIKE '%Handler'"
|
||||
|
||||
# リファクタリング
|
||||
nyash db refactor rename-box OldName NewName
|
||||
|
||||
# 依存関係グラフ生成
|
||||
nyash db deps --format=dot | dot -Tpng -o deps.png
|
||||
|
||||
# 未使用コード削除
|
||||
nyash db clean --remove-unused --dry-run
|
||||
```
|
||||
|
||||
### 2. VSCode拡張
|
||||
|
||||
- **DBエクスプローラー**:Box/メソッドをツリー表示
|
||||
- **リアルタイム検索**:SQLクエリで即座に検索
|
||||
- **依存関係ビュー**:グラフィカルに表示
|
||||
|
||||
### 3. Box単位インクリメンタルチェック(2025-09-30追加)
|
||||
|
||||
```bash
|
||||
# Box単位でのチェック(Rust cargo checkに相当)
|
||||
nyash check --box UserBox # 特定Boxのみ
|
||||
nyash check --changed # 変更されたBoxのみ
|
||||
nyash check --affected # 影響を受けるBoxも含む
|
||||
|
||||
# DB内でのMIRキャッシュ活用
|
||||
SELECT b.name, cc.mir_version, cc.created_at
|
||||
FROM boxes b
|
||||
LEFT JOIN compile_cache cc ON b.id = cc.entity_id
|
||||
WHERE cc.mir_version < (SELECT MAX(mir_version) FROM compile_cache);
|
||||
```
|
||||
|
||||
### 4. Web UI
|
||||
|
||||
```nyash
|
||||
box CodeDBWebUI {
|
||||
server: WebServerBox
|
||||
db: CodeDB
|
||||
|
||||
birth(dbPath, port) {
|
||||
me.db = new CodeDB(dbPath)
|
||||
me.server = new WebServerBox(port)
|
||||
me.setupRoutes()
|
||||
}
|
||||
|
||||
setupRoutes() {
|
||||
// コードグラフ表示
|
||||
me.server.get("/graph") { req, res ->
|
||||
local deps = me.db.getAllDependencies()
|
||||
res.json(me.buildD3Graph(deps))
|
||||
}
|
||||
|
||||
// リアルタイムSQL実行
|
||||
me.server.post("/query") { req, res ->
|
||||
local result = me.db.query(req.body.sql)
|
||||
res.json(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 実装の容易性(2025-09-30追加)
|
||||
|
||||
### なぜNyashでは簡単なのか
|
||||
|
||||
```nyash
|
||||
# すべてが箱 → テーブル設計が自然
|
||||
box UserBox { ... } → INSERT INTO boxes VALUES (...)
|
||||
|
||||
# グローバル変数なし → 依存関係が明確
|
||||
static box Config { } → 完全に追跡可能
|
||||
|
||||
# local変数もBoxスコープ内 → 状態管理がシンプル
|
||||
local temp = new Box() → scope_id で管理
|
||||
```
|
||||
|
||||
### 実装見積もり
|
||||
- **基本DB化**: 1-2週間(スキーマ作成とインポート/エクスポート)
|
||||
- **リファクタリング機能**: 1-2週間(SQL操作のラッパー)
|
||||
- **IDE統合**: 2-3週間(VSCode拡張)
|
||||
- **合計**: 1-2ヶ月で実用レベル(当初予想の9ヶ月より大幅短縮!)
|
||||
|
||||
### 他言語では困難な理由
|
||||
- **JavaScript**: グローバル汚染、prototype chain、動的すぎる
|
||||
- **Python**: `__builtins__`、モジュールの副作用、メタクラス
|
||||
- **Java**: 静的フィールド、クラスローダー、リフレクション
|
||||
- **Nyash**: **これらの問題がすべて存在しない!**
|
||||
|
||||
## 📊 移行戦略
|
||||
|
||||
### Phase 1: ハイブリッドモード(3ヶ月)
|
||||
- 既存ファイル→DB同期ツール開発
|
||||
- DB→ファイルエクスポート(Git互換性維持)
|
||||
- 開発者が徐々に慣れる期間
|
||||
|
||||
### Phase 2: DB優先モード(3ヶ月)
|
||||
- 新規開発はDB直接
|
||||
- ファイルは自動生成
|
||||
- リファクタリング効率を体感
|
||||
|
||||
### Phase 3: 完全DB化(3ヶ月)
|
||||
- ファイルシステムは配布用のみ
|
||||
- 開発は100% DB駆動
|
||||
- 新しい開発パラダイムの確立
|
||||
|
||||
## 🌟 期待される効果
|
||||
|
||||
### 開発効率
|
||||
- **リファクタリング**: 100倍高速化(秒単位→ミリ秒単位)
|
||||
- **検索**: SQLによる高度な検索(正規表現、構造検索)
|
||||
- **分析**: 依存関係、複雑度、類似性を瞬時に把握
|
||||
|
||||
### コード品質
|
||||
- **重複排除**: 類似コードを自動検出
|
||||
- **整合性**: DB制約で不整合を防止
|
||||
- **追跡可能性**: すべての変更を記録
|
||||
|
||||
### AI連携
|
||||
- **構造化データ**: AIが理解しやすい
|
||||
- **メタデータ**: 型情報、使用頻度など豊富
|
||||
- **学習効率**: コードパターンを効率的に学習
|
||||
|
||||
## 🚀 革新性
|
||||
|
||||
### 世界初の要素
|
||||
1. **完全DB駆動言語**: ファイルシステムからの解放
|
||||
2. **構造認識エディタ**: Box/メソッド単位の編集
|
||||
3. **瞬間リファクタリング**: SQLトランザクションで完結
|
||||
4. **依存関係DB**: コンパイル時情報も含む
|
||||
|
||||
### 技術的優位性
|
||||
- **SQLite**: 軽量、高速、信頼性
|
||||
- **Everything is Box**: DB表現と相性抜群
|
||||
- **MIRキャッシュ**: コンパイル高速化
|
||||
|
||||
## 📅 実施時期
|
||||
|
||||
- **開始条件**: Phase 15(セルフホスティング)完了後
|
||||
- **推定期間**: 9ヶ月
|
||||
- **優先度**: 高(開発効率の革命的向上)
|
||||
|
||||
## 🔗 関連フェーズ
|
||||
|
||||
- [Phase 15: セルフホスティング](../phase-15/) - 基盤技術
|
||||
- [Phase 12: 統一実行パス](../phase-12/) - MIRキャッシュ活用
|
||||
- [Phase 16: プラグインエコシステム](../phase-16/) - DB APIの公開
|
||||
|
||||
---
|
||||
|
||||
> 「コードはファイルに書くもの」という固定観念を打ち破る。
|
||||
> 21世紀の開発は、構造化データベースで行うべきだにゃ!
|
||||
|
||||
## 📚 関連ドキュメント
|
||||
|
||||
### Phase 21の進化過程
|
||||
- [技術的考慮事項](technical-considerations.md) - 詳細な技術検討
|
||||
- [可逆変換アプローチ](reversible-conversion.md) - Git互換性を保つ方法
|
||||
- [箱データベース構想v2](README_v2.md) - シンプル化された実装
|
||||
- [自己解析アプローチ](self-parsing-approach.md) - Nyashの自己パース能力活用
|
||||
|
||||
### 学術的評価
|
||||
- **[AI評価フォルダ](ai-evaluation/)** - Gemini/Codexによる詳細な評価
|
||||
- [Gemini評価](ai-evaluation/gemini-evaluation.md) - 完全な学術的分析
|
||||
- [Codex評価(部分)](ai-evaluation/codex-evaluation-partial.md) - 深い思考過程
|
||||
- [評価サマリー](ai-evaluation/evaluation-summary.md) - 統合的な分析
|
||||
313
docs/private/roadmap/phases/phase-21/reversible-conversion.md
Normal file
313
docs/private/roadmap/phases/phase-21/reversible-conversion.md
Normal file
@ -0,0 +1,313 @@
|
||||
# Phase 21: ソースコード⇔データベース完全可逆変換システム
|
||||
|
||||
## 📋 概要
|
||||
|
||||
データベース駆動開発の最大の課題であるGit互換性を、**完全可逆変換**によって根本的に解決する革新的アプローチ。
|
||||
ソースコードとデータベースを自在に行き来できることで、両方の利点を最大限に活用する。
|
||||
|
||||
## 🎯 核心的なアイデア
|
||||
|
||||
```
|
||||
ソースコード(.nyash) ⇔ データベース(SQLite)
|
||||
↓ ↓
|
||||
Git管理 高速リファクタリング
|
||||
エディタ編集 構造化分析
|
||||
既存ツール互換 AI最適化
|
||||
```
|
||||
|
||||
**重要な原則:**
|
||||
- ソースコード → DB → ソースコードで100%元に戻る(情報の欠落なし)
|
||||
- 開発者は好きな方式(ファイルまたはDB)を自由に選択可能
|
||||
- Git運用は完全に従来通り(テキストファイルとしてコミット)
|
||||
|
||||
## 🏗️ 技術設計
|
||||
|
||||
### 1. 完全可逆変換の要件
|
||||
|
||||
```nyash
|
||||
box ReversibleConverter {
|
||||
// 変換の基本原則
|
||||
verify(sourceCode) {
|
||||
local db = me.sourceToDb(sourceCode)
|
||||
local restored = me.dbToSource(db)
|
||||
return sourceCode == restored // 必ずtrue
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. メタデータの完全保存
|
||||
|
||||
```sql
|
||||
-- コード構造
|
||||
CREATE TABLE code_structure (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_type TEXT, -- 'box', 'method', 'field'
|
||||
entity_id INTEGER,
|
||||
source_order INTEGER,
|
||||
indentation_level INTEGER,
|
||||
line_start INTEGER,
|
||||
line_end INTEGER,
|
||||
column_start INTEGER,
|
||||
column_end INTEGER
|
||||
);
|
||||
|
||||
-- スタイル情報
|
||||
CREATE TABLE style_metadata (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_id INTEGER,
|
||||
whitespace_before TEXT,
|
||||
whitespace_after TEXT,
|
||||
line_endings TEXT, -- '\n' or '\r\n'
|
||||
indentation_style TEXT, -- 'space' or 'tab'
|
||||
indentation_width INTEGER
|
||||
);
|
||||
|
||||
-- コメント保存
|
||||
CREATE TABLE comments (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_id INTEGER,
|
||||
comment_type TEXT, -- 'line', 'block', 'doc'
|
||||
content TEXT,
|
||||
position TEXT, -- 'before', 'after', 'inline'
|
||||
line_number INTEGER,
|
||||
column_number INTEGER
|
||||
);
|
||||
|
||||
-- 元のソース(差分検証用)
|
||||
CREATE TABLE original_sources (
|
||||
file_path TEXT PRIMARY KEY,
|
||||
content_hash TEXT,
|
||||
full_content TEXT,
|
||||
last_synced TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 変換アルゴリズム
|
||||
|
||||
#### ソース → DB
|
||||
|
||||
```nyash
|
||||
box SourceToDbConverter {
|
||||
convert(filePath, sourceCode) {
|
||||
// 1. AST解析
|
||||
local ast = Parser.parseWithFullInfo(sourceCode)
|
||||
|
||||
// 2. 構造抽出
|
||||
local boxes = me.extractBoxes(ast)
|
||||
local methods = me.extractMethods(ast)
|
||||
local dependencies = me.analyzeDependencies(ast)
|
||||
|
||||
// 3. メタデータ抽出
|
||||
local metadata = {
|
||||
comments: me.extractComments(sourceCode),
|
||||
whitespace: me.extractWhitespace(sourceCode),
|
||||
style: me.detectCodingStyle(sourceCode),
|
||||
positions: me.mapSourcePositions(ast)
|
||||
}
|
||||
|
||||
// 4. DB保存(トランザクション)
|
||||
me.db.transaction {
|
||||
me.saveStructure(boxes, methods)
|
||||
me.saveMetadata(metadata)
|
||||
me.saveDependencies(dependencies)
|
||||
me.saveOriginal(filePath, sourceCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### DB → ソース
|
||||
|
||||
```nyash
|
||||
box DbToSourceConverter {
|
||||
convert(filePath) {
|
||||
// 1. 構造読み込み
|
||||
local structure = me.db.loadStructure(filePath)
|
||||
local metadata = me.db.loadMetadata(filePath)
|
||||
|
||||
// 2. ソース再構築
|
||||
local builder = new SourceBuilder(metadata.style)
|
||||
|
||||
for entity in structure.entities {
|
||||
// 元の位置情報を使って再配置
|
||||
builder.addEntity(entity, metadata.positions[entity.id])
|
||||
|
||||
// コメントの復元
|
||||
for comment in metadata.comments[entity.id] {
|
||||
builder.addComment(comment)
|
||||
}
|
||||
|
||||
// 空白の復元
|
||||
builder.applyWhitespace(metadata.whitespace[entity.id])
|
||||
}
|
||||
|
||||
return builder.toString()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. スタイルの扱い
|
||||
|
||||
```nyash
|
||||
box StylePreserver {
|
||||
modes: {
|
||||
EXACT: "完全保持", // 空白・改行すべて元通り
|
||||
NORMALIZE: "正規化", // フォーマッタ適用
|
||||
HYBRID: "ハイブリッド" // コメント保持+コード正規化
|
||||
}
|
||||
|
||||
preserveStyle(source, mode) {
|
||||
switch mode {
|
||||
case EXACT:
|
||||
return me.captureEverything(source)
|
||||
case NORMALIZE:
|
||||
return me.formatCode(source)
|
||||
case HYBRID:
|
||||
return me.preserveComments(me.formatCode(source))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 同期メカニズム
|
||||
|
||||
### 1. リアルタイム同期
|
||||
|
||||
```nyash
|
||||
box FileSyncDaemon {
|
||||
watchers: MapBox
|
||||
|
||||
birth() {
|
||||
me.watchers = new MapBox()
|
||||
}
|
||||
|
||||
watch(directory) {
|
||||
local watcher = new FileWatcher(directory)
|
||||
|
||||
watcher.on("change") { event ->
|
||||
if event.file.endsWith(".nyash") {
|
||||
me.syncFileToDb(event.file)
|
||||
}
|
||||
}
|
||||
|
||||
watcher.on("db_change") { event ->
|
||||
if not event.fromFile {
|
||||
me.syncDbToFile(event.entity)
|
||||
}
|
||||
}
|
||||
|
||||
me.watchers.set(directory, watcher)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Git統合
|
||||
|
||||
```bash
|
||||
# .git/hooks/pre-commit
|
||||
#!/bin/bash
|
||||
nyash sync --db-to-files --verify
|
||||
|
||||
# .git/hooks/post-checkout
|
||||
#!/bin/bash
|
||||
nyash sync --files-to-db --incremental
|
||||
|
||||
# .git/hooks/post-merge
|
||||
#!/bin/bash
|
||||
nyash sync --files-to-db --full
|
||||
```
|
||||
|
||||
### 3. 差分最適化
|
||||
|
||||
```sql
|
||||
-- 変更追跡
|
||||
CREATE TABLE sync_status (
|
||||
entity_id INTEGER PRIMARY KEY,
|
||||
file_modified TIMESTAMP,
|
||||
db_modified TIMESTAMP,
|
||||
sync_status TEXT, -- 'synced', 'file_newer', 'db_newer', 'conflict'
|
||||
last_sync_hash TEXT
|
||||
);
|
||||
|
||||
-- 差分計算の高速化
|
||||
CREATE INDEX idx_sync_status ON sync_status(sync_status, file_modified);
|
||||
```
|
||||
|
||||
## 🚀 実装段階
|
||||
|
||||
### Phase 1: 基本的な可逆変換(1ヶ月)
|
||||
- Box/メソッドレベルの変換
|
||||
- コメントなし、インデント固定
|
||||
- 単体テストで100%可逆性検証
|
||||
|
||||
### Phase 2: メタデータ保持(1ヶ月)
|
||||
- コメントの位置と内容を保存
|
||||
- インデントスタイルの保持
|
||||
- 改行コードの維持
|
||||
|
||||
### Phase 3: 完全なスタイル保存(1ヶ月)
|
||||
- 任意の空白パターン対応
|
||||
- コーディングスタイルの自動検出
|
||||
- チーム規約との調整機能
|
||||
|
||||
### Phase 4: 高度な同期(2ヶ月)
|
||||
- 増分同期アルゴリズム
|
||||
- コンフリクト解決UI
|
||||
- パフォーマンス最適化
|
||||
|
||||
## 📊 利点の整理
|
||||
|
||||
### 開発者にとって
|
||||
- **選択の自由**: ファイル編集もDB操作も可能
|
||||
- **既存ツール互換**: VSCode、Vim、Git等すべて使える
|
||||
- **高速リファクタリング**: 必要な時だけDB機能を活用
|
||||
|
||||
### システムにとって
|
||||
- **Git完全互換**: 通常のテキストファイルとして管理
|
||||
- **増分コンパイル**: DB側で依存関係を高速解析
|
||||
- **AI連携強化**: 構造化データで学習効率UP
|
||||
|
||||
### チームにとって
|
||||
- **移行リスクなし**: 段階的導入が可能
|
||||
- **レビュー互換**: PRは従来通りのテキスト差分
|
||||
- **柔軟な運用**: プロジェクト毎に最適な方式を選択
|
||||
|
||||
## 🎯 成功の指標
|
||||
|
||||
1. **完全可逆性**: 1000ファイルで往復変換してもバイト単位で一致
|
||||
2. **パフォーマンス**: 1000行のファイルを100ms以内で変換
|
||||
3. **互換性**: 既存のNyashプロジェクトがそのまま動作
|
||||
4. **開発者満足度**: 90%以上が「便利」と評価
|
||||
|
||||
## 🔮 将来の拡張
|
||||
|
||||
### 意味的な可逆変換
|
||||
- コードの意味を保ちながらスタイルを自動最適化
|
||||
- チーム規約への自動適応
|
||||
- リファクタリング履歴の保存
|
||||
|
||||
### マルチビュー編集
|
||||
```nyash
|
||||
// 同じコードを異なる視点で編集
|
||||
- ファイルビュー: 従来のテキストエディタ
|
||||
- 構造ビュー: Box/メソッドのツリー表示
|
||||
- 依存ビュー: グラフィカルな関係表示
|
||||
- クエリビュー: SQLで直接操作
|
||||
```
|
||||
|
||||
### バージョン管理の革新
|
||||
- 意味的な差分表示(「名前を変更」vs「全行変更」)
|
||||
- 構造認識マージ(メソッド単位での自動解決)
|
||||
- リファクタリング履歴の永続化
|
||||
|
||||
## 📝 実装優先順位
|
||||
|
||||
1. **コア変換エンジン**: 可逆性の証明
|
||||
2. **メタデータ設計**: 完全な情報保存
|
||||
3. **同期デーモン**: リアルタイム連携
|
||||
4. **開発ツール**: CLI/IDE統合
|
||||
5. **最適化**: パフォーマンスチューニング
|
||||
|
||||
---
|
||||
|
||||
この可逆変換システムにより、データベース駆動開発の利点を最大化しながら、既存の開発フローとの完全な互換性を実現できるにゃ!
|
||||
266
docs/private/roadmap/phases/phase-21/self-parsing-approach.md
Normal file
266
docs/private/roadmap/phases/phase-21/self-parsing-approach.md
Normal file
@ -0,0 +1,266 @@
|
||||
# Phase 21: Nyash自己解析アプローチ - AST直接保存
|
||||
|
||||
## 📋 概要
|
||||
|
||||
Nyashの最大の強み「自分自身をパースできる」を活かした究極にシンプルなアプローチ。
|
||||
外部パーサー不要、複雑な変換層不要。NyashのASTをそのままデータベースに保存する。
|
||||
|
||||
## 🎯 核心的なアイデア
|
||||
|
||||
```nyash
|
||||
// Nyashは自分自身を解析できる!
|
||||
NyashParser.parse(sourceCode) → AST → Database → NyashPrinter.print(AST) → sourceCode
|
||||
```
|
||||
|
||||
**重要な気づき:**
|
||||
- Nyashにはすでにパーサーがある
|
||||
- ASTから元のソースを生成する機能もある
|
||||
- だから、ASTをDBに保存すれば完全可逆!
|
||||
|
||||
## 🏗️ シンプルな実装
|
||||
|
||||
### データベース構造
|
||||
```sql
|
||||
-- ASTノードをそのまま保存
|
||||
CREATE TABLE ast_nodes (
|
||||
id INTEGER PRIMARY KEY,
|
||||
node_type TEXT, -- "Box", "Method", "Field", "Statement"等
|
||||
node_data JSON, -- ASTノードの完全な情報
|
||||
parent_id INTEGER,
|
||||
position INTEGER, -- 親ノード内での位置
|
||||
source_file TEXT, -- 元のファイルパス
|
||||
metadata JSON, -- 後から追加する解析情報
|
||||
FOREIGN KEY (parent_id) REFERENCES ast_nodes(id)
|
||||
);
|
||||
|
||||
-- インデックス
|
||||
CREATE INDEX idx_node_type ON ast_nodes(node_type);
|
||||
CREATE INDEX idx_parent ON ast_nodes(parent_id);
|
||||
CREATE INDEX idx_source ON ast_nodes(source_file);
|
||||
```
|
||||
|
||||
### 基本実装
|
||||
```nyash
|
||||
box NyashCodeDB {
|
||||
parser: NyashParser
|
||||
printer: NyashPrinter
|
||||
db: SQLiteBox
|
||||
|
||||
birth() {
|
||||
me.parser = new NyashParser()
|
||||
me.printer = new NyashPrinter()
|
||||
me.db = new SQLiteBox("code.db")
|
||||
}
|
||||
|
||||
// ファイルをDBに保存
|
||||
importFile(filePath) {
|
||||
local source = FileBox.read(filePath)
|
||||
local ast = me.parser.parse(source)
|
||||
|
||||
// ASTを再帰的にDBに保存
|
||||
me.saveAST(ast, null, filePath)
|
||||
}
|
||||
|
||||
// ASTノードを保存
|
||||
saveAST(node, parentId, sourceFile) {
|
||||
local nodeId = me.db.insert("ast_nodes", {
|
||||
node_type: node.type,
|
||||
node_data: node.toJSON(),
|
||||
parent_id: parentId,
|
||||
position: node.position,
|
||||
source_file: sourceFile
|
||||
})
|
||||
|
||||
// 子ノードも保存
|
||||
for (i, child) in node.children.enumerate() {
|
||||
child.position = i
|
||||
me.saveAST(child, nodeId, sourceFile)
|
||||
}
|
||||
|
||||
return nodeId
|
||||
}
|
||||
|
||||
// DBからソースコードを復元
|
||||
exportFile(filePath) {
|
||||
local rootNodes = me.db.query(
|
||||
"SELECT * FROM ast_nodes
|
||||
WHERE source_file = ? AND parent_id IS NULL
|
||||
ORDER BY position",
|
||||
filePath
|
||||
)
|
||||
|
||||
local source = ""
|
||||
for node in rootNodes {
|
||||
local ast = me.loadAST(node.id)
|
||||
source += me.printer.print(ast) + "\n"
|
||||
}
|
||||
|
||||
FileBox.write(filePath, source)
|
||||
}
|
||||
|
||||
// ASTを再構築
|
||||
loadAST(nodeId) {
|
||||
local node = me.db.get("ast_nodes", nodeId)
|
||||
local astNode = ASTNode.fromJSON(node.node_data)
|
||||
|
||||
// 子ノードも読み込む
|
||||
local children = me.db.query(
|
||||
"SELECT * FROM ast_nodes
|
||||
WHERE parent_id = ?
|
||||
ORDER BY position",
|
||||
nodeId
|
||||
)
|
||||
|
||||
for child in children {
|
||||
astNode.addChild(me.loadAST(child.id))
|
||||
}
|
||||
|
||||
return astNode
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 高度な機能
|
||||
|
||||
### リファクタリング
|
||||
```nyash
|
||||
box ASTRefactorer {
|
||||
db: SQLiteBox
|
||||
|
||||
// 名前変更
|
||||
renameBox(oldName, newName) {
|
||||
// Box定義を見つける
|
||||
local boxNodes = me.db.query(
|
||||
"SELECT * FROM ast_nodes
|
||||
WHERE node_type = 'Box'
|
||||
AND json_extract(node_data, '$.name') = ?",
|
||||
oldName
|
||||
)
|
||||
|
||||
for node in boxNodes {
|
||||
// AST上で名前を変更
|
||||
local data = JSON.parse(node.node_data)
|
||||
data.name = newName
|
||||
me.db.update("ast_nodes", node.id, {
|
||||
node_data: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
// 使用箇所も更新
|
||||
me.updateReferences(oldName, newName)
|
||||
}
|
||||
|
||||
// メソッド移動
|
||||
moveMethod(methodName, fromBox, toBox) {
|
||||
// SQLで親ノードを変更するだけ!
|
||||
local fromBoxId = me.findBoxNode(fromBox)
|
||||
local toBoxId = me.findBoxNode(toBox)
|
||||
|
||||
me.db.execute(
|
||||
"UPDATE ast_nodes
|
||||
SET parent_id = ?
|
||||
WHERE parent_id = ?
|
||||
AND node_type = 'Method'
|
||||
AND json_extract(node_data, '$.name') = ?",
|
||||
[toBoxId, fromBoxId, methodName]
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### メタデータ解析(オンデマンド)
|
||||
```nyash
|
||||
box MetadataEngine {
|
||||
// 必要な時だけ解析
|
||||
analyzeOnDemand(nodeId) {
|
||||
local node = db.get("ast_nodes", nodeId)
|
||||
|
||||
if not node.metadata or me.isOutdated(node.metadata) {
|
||||
local metadata = {
|
||||
dependencies: me.findDependencies(node),
|
||||
complexity: me.calculateComplexity(node),
|
||||
lastAnalyzed: now()
|
||||
}
|
||||
|
||||
db.update("ast_nodes", nodeId, {
|
||||
metadata: JSON.stringify(metadata)
|
||||
})
|
||||
}
|
||||
|
||||
return JSON.parse(node.metadata)
|
||||
}
|
||||
|
||||
// 依存関係を動的に検出
|
||||
findDependencies(node) {
|
||||
local deps = []
|
||||
|
||||
// "new XXXBox" パターンを検索
|
||||
local matches = me.searchPattern(node, "NewBox")
|
||||
for match in matches {
|
||||
deps.push(match.boxType)
|
||||
}
|
||||
|
||||
// "from XXX" パターンを検索
|
||||
local inherits = me.searchPattern(node, "From")
|
||||
for inherit in inherits {
|
||||
deps.push(inherit.parentBox)
|
||||
}
|
||||
|
||||
return deps
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 利点
|
||||
|
||||
### 1. 実装の簡単さ
|
||||
- パーサーはすでにある(Nyash自身)
|
||||
- プリンターもすでにある
|
||||
- 複雑な変換層不要
|
||||
|
||||
### 2. 100%の正確性
|
||||
- Nyash公式パーサーを使うから完璧
|
||||
- ASTは言語の完全な表現
|
||||
- 情報の欠落なし
|
||||
|
||||
### 3. 柔軟性
|
||||
- メタデータは後から追加
|
||||
- 部分的な解析が可能
|
||||
- 増分更新が簡単
|
||||
|
||||
### 4. 高速性
|
||||
- ASTの一部だけ読み込み可能
|
||||
- SQLの力でクエリが高速
|
||||
- キャッシュも自然に実装
|
||||
|
||||
## 🎯 実装ステップ
|
||||
|
||||
### Phase 1: 基本機能(1週間)
|
||||
- AST保存・読み込み
|
||||
- ファイル単位のインポート・エクスポート
|
||||
- 基本的なクエリ
|
||||
|
||||
### Phase 2: リファクタリング(1週間)
|
||||
- 名前変更
|
||||
- メソッド移動
|
||||
- 依存関係追跡
|
||||
|
||||
### Phase 3: 高度な機能(2週間)
|
||||
- メタデータ解析
|
||||
- インクリメンタル更新
|
||||
- VSCode統合
|
||||
|
||||
## 🌟 まとめ
|
||||
|
||||
**「Nyashの能力をフル活用する」**
|
||||
|
||||
- 外部ツール不要
|
||||
- 複雑な実装不要
|
||||
- Nyashらしいシンプルさ
|
||||
|
||||
このアプローチなら、Phase 21は「NyashのASTをDBに入れるだけ」という
|
||||
極めてシンプルな実装で、強力な機能を実現できる!
|
||||
|
||||
---
|
||||
|
||||
> 「なぜ複雑にする?Nyashにはすでに必要なものが全部ある」 - にゃ
|
||||
409
docs/private/roadmap/phases/phase-21/technical-considerations.md
Normal file
409
docs/private/roadmap/phases/phase-21/technical-considerations.md
Normal file
@ -0,0 +1,409 @@
|
||||
# Phase 21: 技術的考慮事項
|
||||
|
||||
## 🏗️ アーキテクチャ設計
|
||||
|
||||
### レイヤー構造
|
||||
|
||||
```
|
||||
┌─────────────────────────────┐
|
||||
│ 開発ツール層 │ (VSCode, CLI, Web UI)
|
||||
├─────────────────────────────┤
|
||||
│ API層 │ (GraphQL/REST)
|
||||
├─────────────────────────────┤
|
||||
│ CodeDB抽象層 │ (統一インターフェース)
|
||||
├─────────────────────────────┤
|
||||
│ SQLite実装層 │ (具体的なDB操作)
|
||||
├─────────────────────────────┤
|
||||
│ ストレージ層 │ (ローカル/リモート)
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
## 🔐 セキュリティ考慮事項
|
||||
|
||||
### アクセス制御
|
||||
```sql
|
||||
-- ユーザー権限管理
|
||||
CREATE TABLE permissions (
|
||||
user_id INTEGER,
|
||||
resource_type TEXT,
|
||||
resource_id INTEGER,
|
||||
permission TEXT CHECK(permission IN ('read', 'write', 'admin')),
|
||||
granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
granted_by INTEGER,
|
||||
PRIMARY KEY (user_id, resource_type, resource_id, permission)
|
||||
);
|
||||
|
||||
-- 監査ログ
|
||||
CREATE TABLE audit_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
action TEXT,
|
||||
resource_type TEXT,
|
||||
resource_id INTEGER,
|
||||
old_value TEXT,
|
||||
new_value TEXT,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
ip_address TEXT,
|
||||
session_id TEXT
|
||||
);
|
||||
```
|
||||
|
||||
### SQLインジェクション対策
|
||||
```nyash
|
||||
box SecureCodeDB from CodeDB {
|
||||
// パラメータ化クエリを強制
|
||||
query(sql, params) {
|
||||
// SQLをパースして危険な構文をチェック
|
||||
local ast = me.parseSql(sql)
|
||||
if me.hasDangerousPattern(ast) {
|
||||
throw new SecurityError("Dangerous SQL pattern detected")
|
||||
}
|
||||
|
||||
return from CodeDB.query(sql, params)
|
||||
}
|
||||
|
||||
// ホワイトリスト方式のテーブル名検証
|
||||
validateTableName(name) {
|
||||
if not name.matches("^[a-z_]+$") {
|
||||
throw new SecurityError("Invalid table name")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 パフォーマンス最適化
|
||||
|
||||
### インデックス戦略
|
||||
```sql
|
||||
-- 頻繁なクエリ用インデックス
|
||||
CREATE INDEX idx_boxes_namespace ON boxes(namespace);
|
||||
CREATE INDEX idx_methods_box_id ON methods(box_id);
|
||||
CREATE INDEX idx_deps_from ON dependencies(from_type, from_id);
|
||||
CREATE INDEX idx_deps_to ON dependencies(to_type, to_id);
|
||||
|
||||
-- 複合インデックス
|
||||
CREATE INDEX idx_box_namespace_name ON boxes(namespace, name);
|
||||
CREATE INDEX idx_method_box_name ON methods(box_id, name);
|
||||
|
||||
-- 部分インデックス(アクティブなものだけ)
|
||||
CREATE INDEX idx_active_boxes ON boxes(name)
|
||||
WHERE deleted_at IS NULL;
|
||||
```
|
||||
|
||||
### クエリ最適化
|
||||
```nyash
|
||||
box QueryOptimizer {
|
||||
cache: MapBox
|
||||
|
||||
// クエリ結果のキャッシング
|
||||
cachedQuery(sql, params, ttl) {
|
||||
local key = me.hash(sql + params.toString())
|
||||
|
||||
if me.cache.has(key) {
|
||||
local cached = me.cache.get(key)
|
||||
if cached.timestamp + ttl > now() {
|
||||
return cached.result
|
||||
}
|
||||
}
|
||||
|
||||
local result = me.db.query(sql, params)
|
||||
me.cache.set(key, {
|
||||
result: result,
|
||||
timestamp: now()
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔄 同期・レプリケーション
|
||||
|
||||
### マルチデバイス同期
|
||||
```nyash
|
||||
box CodeDBSync {
|
||||
local: CodeDB
|
||||
remote: RemoteCodeDB
|
||||
|
||||
// 変更を追跡
|
||||
trackChanges() {
|
||||
CREATE TRIGGER track_box_changes
|
||||
AFTER INSERT OR UPDATE OR DELETE ON boxes
|
||||
BEGIN
|
||||
INSERT INTO sync_queue (
|
||||
table_name, operation, entity_id, data
|
||||
) VALUES (
|
||||
'boxes',
|
||||
CASE
|
||||
WHEN OLD.id IS NULL THEN 'INSERT'
|
||||
WHEN NEW.id IS NULL THEN 'DELETE'
|
||||
ELSE 'UPDATE'
|
||||
END,
|
||||
COALESCE(NEW.id, OLD.id),
|
||||
json_object('old', OLD, 'new', NEW)
|
||||
);
|
||||
END;
|
||||
}
|
||||
|
||||
// 差分同期
|
||||
sync() {
|
||||
local changes = me.local.query("
|
||||
SELECT * FROM sync_queue
|
||||
WHERE synced_at IS NULL
|
||||
ORDER BY created_at
|
||||
")
|
||||
|
||||
for change in changes {
|
||||
me.remote.applyChange(change)
|
||||
me.local.markSynced(change.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🎯 互換性戦略
|
||||
|
||||
### ファイルシステムとの相互変換
|
||||
```nyash
|
||||
box FileDBBridge {
|
||||
// DB→ファイル エクスポート
|
||||
exportToFiles(outputDir) {
|
||||
local boxes = me.db.query("SELECT * FROM boxes")
|
||||
|
||||
for box in boxes {
|
||||
local path = outputDir + "/" +
|
||||
box.namespace.replace(".", "/") + "/" +
|
||||
box.name + ".nyash"
|
||||
|
||||
local file = new FileBox(path)
|
||||
file.write(me.generateFileContent(box))
|
||||
}
|
||||
}
|
||||
|
||||
// ファイル→DB インポート
|
||||
importFromFiles(sourceDir) {
|
||||
local files = FileBox.glob(sourceDir + "/**/*.nyash")
|
||||
|
||||
me.db.beginTransaction()
|
||||
try {
|
||||
for file in files {
|
||||
local ast = Parser.parse(file.read())
|
||||
me.importAST(ast, file.path)
|
||||
}
|
||||
me.db.commit()
|
||||
} catch (e) {
|
||||
me.db.rollback()
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 高度な分析機能
|
||||
|
||||
### コードメトリクス
|
||||
```sql
|
||||
-- 循環的複雑度の計算
|
||||
CREATE VIEW method_complexity AS
|
||||
SELECT
|
||||
m.id,
|
||||
b.name || '.' || m.name as full_name,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM json_each(m.body)
|
||||
WHERE value LIKE '%if%'
|
||||
OR value LIKE '%loop%'
|
||||
OR value LIKE '%catch%'
|
||||
) + 1 as cyclomatic_complexity
|
||||
FROM methods m
|
||||
JOIN boxes b ON m.box_id = b.id;
|
||||
|
||||
-- コード行数統計
|
||||
CREATE VIEW code_stats AS
|
||||
SELECT
|
||||
COUNT(DISTINCT b.id) as total_boxes,
|
||||
COUNT(DISTINCT m.id) as total_methods,
|
||||
SUM(LENGTH(m.body) - LENGTH(REPLACE(m.body, char(10), ''))) as total_lines,
|
||||
AVG(LENGTH(m.body) - LENGTH(REPLACE(m.body, char(10), ''))) as avg_method_lines
|
||||
FROM boxes b
|
||||
LEFT JOIN methods m ON b.id = m.box_id;
|
||||
```
|
||||
|
||||
### 依存関係の可視化
|
||||
```nyash
|
||||
box DependencyAnalyzer {
|
||||
// 影響範囲分析
|
||||
getImpactedEntities(changedEntity) {
|
||||
return me.db.query("
|
||||
WITH RECURSIVE impacted AS (
|
||||
-- 直接依存
|
||||
SELECT to_type, to_id, 1 as level
|
||||
FROM dependencies
|
||||
WHERE from_type = ? AND from_id = ?
|
||||
|
||||
UNION
|
||||
|
||||
-- 推移的依存
|
||||
SELECT d.to_type, d.to_id, i.level + 1
|
||||
FROM dependencies d
|
||||
JOIN impacted i ON
|
||||
d.from_type = i.to_type AND
|
||||
d.from_id = i.to_id
|
||||
WHERE i.level < 5 -- 最大5階層まで
|
||||
)
|
||||
SELECT DISTINCT * FROM impacted
|
||||
ORDER BY level
|
||||
", [changedEntity.type, changedEntity.id])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🌐 分散開発対応
|
||||
|
||||
### ブランチ・マージ戦略
|
||||
```sql
|
||||
-- ブランチ管理
|
||||
CREATE TABLE branches (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
base_commit_id INTEGER,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by INTEGER,
|
||||
is_active BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
|
||||
-- コミット(変更セット)
|
||||
CREATE TABLE commits (
|
||||
id INTEGER PRIMARY KEY,
|
||||
branch_id INTEGER,
|
||||
parent_commit_id INTEGER,
|
||||
message TEXT,
|
||||
author INTEGER,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
changes JSON, -- 変更の詳細
|
||||
FOREIGN KEY (branch_id) REFERENCES branches(id)
|
||||
);
|
||||
```
|
||||
|
||||
### コンフリクト解決
|
||||
```nyash
|
||||
box ConflictResolver {
|
||||
// 3-way マージ
|
||||
merge(base, mine, theirs) {
|
||||
if mine == theirs {
|
||||
return mine // 変更なし or 同じ変更
|
||||
}
|
||||
|
||||
if base == mine {
|
||||
return theirs // 相手のみ変更
|
||||
}
|
||||
|
||||
if base == theirs {
|
||||
return mine // 自分のみ変更
|
||||
}
|
||||
|
||||
// 両方変更 - コンフリクト
|
||||
return me.resolveConflict(base, mine, theirs)
|
||||
}
|
||||
|
||||
resolveConflict(base, mine, theirs) {
|
||||
// AST レベルでのマージを試みる
|
||||
local baseAST = Parser.parse(base)
|
||||
local mineAST = Parser.parse(mine)
|
||||
local theirsAST = Parser.parse(theirs)
|
||||
|
||||
// メソッド単位でマージ可能か確認
|
||||
if me.canMergeAtMethodLevel(baseAST, mineAST, theirsAST) {
|
||||
return me.mergeASTs(baseAST, mineAST, theirsAST)
|
||||
}
|
||||
|
||||
// マージ不可 - ユーザーに選択させる
|
||||
throw new MergeConflict(base, mine, theirs)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📊 メトリクス・モニタリング
|
||||
|
||||
### パフォーマンス追跡
|
||||
```sql
|
||||
-- クエリパフォーマンスログ
|
||||
CREATE TABLE query_performance (
|
||||
id INTEGER PRIMARY KEY,
|
||||
query_hash TEXT,
|
||||
query_text TEXT,
|
||||
execution_time_ms INTEGER,
|
||||
rows_affected INTEGER,
|
||||
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- DB統計情報
|
||||
CREATE VIEW db_stats AS
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM boxes) as total_boxes,
|
||||
(SELECT COUNT(*) FROM methods) as total_methods,
|
||||
(SELECT COUNT(*) FROM dependencies) as total_dependencies,
|
||||
(SELECT page_count * page_size FROM pragma_page_count(), pragma_page_size()) as db_size_bytes,
|
||||
(SELECT COUNT(*) FROM compile_cache) as cached_compilations;
|
||||
```
|
||||
|
||||
## 🔮 将来の拡張性
|
||||
|
||||
### プラグインアーキテクチャ
|
||||
```nyash
|
||||
box CodeDBPlugin {
|
||||
// フック機能
|
||||
hooks: MapBox
|
||||
|
||||
register(event, handler) {
|
||||
if not me.hooks.has(event) {
|
||||
me.hooks.set(event, new ArrayBox())
|
||||
}
|
||||
me.hooks.get(event).push(handler)
|
||||
}
|
||||
|
||||
trigger(event, data) {
|
||||
if me.hooks.has(event) {
|
||||
for handler in me.hooks.get(event) {
|
||||
handler(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用例:自動フォーマッター
|
||||
box AutoFormatter from CodeDBPlugin {
|
||||
birth() {
|
||||
me.register("before_save", me.formatCode)
|
||||
}
|
||||
|
||||
formatCode(data) {
|
||||
if data.entity_type == "method" {
|
||||
data.body = Formatter.format(data.body)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AI統合の準備
|
||||
```sql
|
||||
-- ベクトル埋め込み保存
|
||||
CREATE TABLE embeddings (
|
||||
id INTEGER PRIMARY KEY,
|
||||
entity_type TEXT,
|
||||
entity_id INTEGER,
|
||||
embedding BLOB, -- float配列をBLOBで保存
|
||||
model_version TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- 類似性検索用の仮想テーブル(将来的にベクトル検索エンジンと統合)
|
||||
CREATE VIRTUAL TABLE vector_search USING vector_index(
|
||||
embedding FLOAT[768]
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
これらの技術的考慮事項を踏まえて、段階的に実装を進めることで、
|
||||
安全で高性能なデータベース駆動開発環境を実現できるにゃ!
|
||||
Reference in New Issue
Block a user