/通喵千問 →English

HanreiLLM PatentLLM SubsidyDB RAG Eng Apps Live GitHub Inquiry
← 記事一覧に戻る Read in English
開発ツール

SQLite Editorを180行で作り、ブラウザ版を730行で作り直した

2026-03-24 / soy-tuber

はじめに

特許データ、判例PDF、行政データベース——仕事で大量のSQLiteファイルを扱う。テーブルを開いてカラムを選び、フィルタをかけて中身を確認する。それだけの作業に重いIDEは要らない。

最初にStreamlit + pandas + sqlite3で作った。180行、1時間で完成。毎日使った。次に共有しようとして問題に気づいた。

Streamlit版:180行で完成

Streamlitのst.data_editorが仕事の大半をこなす。仮想スクロール、ソート、インライン編集、横長テーブル対応——すべて無料で付いてくる。

主要機能: ・サイドバーにテーブル一覧(行数表示付き) ・カラム選択(multiselect)とピン固定(sticky left) ・WHERE句を直接入力するフィルタ ・ソート、LIMIT、CSV出力 ・セル編集 → PKベースでUPDATE文を自動生成・保存 ・クエリ実行時間の表示 ・PKがないテーブルはリードオンリー

コアのクエリ構築部分:

display = sel_cols or col_names
q = f'SELECT {", ".join(f\'"{c}"\' for c in display)} FROM "{S.tbl}"'
if where.strip():
    q += f" WHERE {where.strip()}"
if order:
    q += f' ORDER BY "{order}" {"DESC" if desc else "ASC"}'
q += f" LIMIT {limit}"
st.data_editorで表示し、編集があればPK列をキーにしてUPDATEを発行する。179行。

共有の壁

Streamlitアプリを公開すると、ユーザーは.dbファイルをサーバーにアップロードすることになる。自分専用なら問題ないが、公開ツールとして他人のデータベースを受け取るのは望ましくない。

解決策:sql.js——SQLiteをWebAssemblyにコンパイルしたライブラリ。すべてブラウザ内で完結する。ファイルはサーバーに送信されない。

WASM版:単一HTMLファイル、730行

代償としてst.data_editorを失い、UIを自前で構築することになった。JS部分は約520行、CSSが124行、HTML構造が約90行。合計731行の単一HTMLファイル。外部フレームワークはゼロ。唯一の依存はsql.js。

実装した機能: ・ドラッグ&ドロップで.dbファイルを開く ・カラム選択ドロップダウン + ピン固定(position: stickyで左端に固定) ・セルのインライン編集 → 変更済みDBをダウンロード ・WHERE句を直接入力(デバウンス付き自動実行) ・ソート、ページネーション(OFFSET/LIMIT)、CSV出力 ・ダーク/ライトモード(localStorage永続化) ・PWA対応(Service Worker + manifest.json)でオフライン動作 ・モバイルレスポンシブ(ハンバーガーメニュー) ・キーボードショートカット(Ctrl+S保存、Ctrl+E CSV出力、Ctrl+Enter再実行)

カラムピン固定の実装

横長テーブルでID列やキー列を見失わないための機能。CSSのposition: stickyを動的に適用する。

function applyPinning() {
  if (!S.pinnedCols.length) return;
  const ths = gridHead.querySelectorAll('th');
  const displayCols = S.result.columns;
  const pinIndices = S.pinnedCols.map(c => displayCols.indexOf(c)).filter(i => i >= 0);

  let cumLeft = 0;
  pinIndices.forEach((colIdx, i) => {
    const th = ths[colIdx];
    const w = th.offsetWidth;
    th.style.position = 'sticky';
    th.style.left = cumLeft + 'px';
    th.style.zIndex = 3;

    gridBody.querySelectorAll('tr').forEach(tr => {
      const td = tr.children[colIdx];
      td.style.position = 'sticky';
      td.style.left = cumLeft + 'px';
      td.style.zIndex = 1;
    });
    cumLeft += w;
  });
}

各ピン列のoffsetWidthを累計し、左からの位置を動的に計算する。ヘッダーはz-index: 3、ボディはz-index: 1で重なりを制御。最後のピン列にはbox-shadowを付けて境界を明示する。

インライン編集とセーブ

contentEditableでセルを編集可能にし、blur時に変更を検知する。PKがないテーブルではcontentEditableを付与しない(リードオンリー)。

const editable = hasPk && !S.pkColumns.includes(columns[ci]);
if (editable) {
  td.contentEditable = true;
  td.dataset.ri = ri;
  td.dataset.col = columns[ci];
  td.dataset.orig = val === null ? '\x00NULL\x00' : String(val);
  td.dataset.pk = JSON.stringify(pkIndices.map(i => row[i]));
}

保存時はpendingEditsをイテレートし、PKベースのUPDATE文を発行する。数値カラムには型強制(coerce関数)を適用し、INTEGERカラムに文字列が入ることを防ぐ。

キーボードショートカット

セル間の移動はTab/Enter/Escapeでスプレッドシートライクに操作できる。ペースト時はプレーンテキストのみに制限し、HTMLタグの混入を防ぐ。

なぜこれが存在しなかったのか

探した限り、カラムピン固定とインライン編集ができる単一ファイルのSQLiteエディタは見つからなかった。既存ツールはフル機能のIDE(DB Browser for SQLiteなど)か、SQL学習用のプレイグラウンドのどちらか。データベースをさっと開いて中身を確認・編集したい人向けの中間地帯が空いていた。

まとめ

Streamlit版とWASM版の両方を維持している。Streamlit版(180行)はローカルワークフロー用、WASM版(730行)はブラウザだけで完結する共有ツール。2回作ることになったが、それぞれの用途に最適化されている。

フレームワークも外部依存もない。右クリック → 名前を付けて保存でオフライン利用可能。

試してみてください:https://media.patentllm.org/static/apps/103-sqlite-editor.html

Daily Tech Digest 海外15サイトから厳選したAI・開発ニュースを毎日配信