機能

機能の一覧ではなく、ひとつの作業として見てください

接続を作り、クエリを実行し、結果を編集し、ステータスバーを確認するまでを8つの場面でたどります。8枚とも実際の画面で、拡大も縮小もしていません。

01接続

まず接続を作ります

DB の種類を選び、ホスト、ポート、ユーザーを入力します。この時点で2つのことが決まります。パスワードをどこに保存するかと、この接続が本番サーバーかどうかです。

新しい接続のフォーム(General タブ)。Name 欄に「New Connection」、DB Type のドロップダウンに「MySQL / MariaDB」、その横に「Mark as a production server (red tab and status bar)」のチェックボックス。その下に Host localhost、Port 3306、User root、空の Password 欄とその説明、Default Database scratch。
パスワード欄の下に保存先が書かれています。Stored only in the OS keychain (never written to the profile file)、つまり「OS のキーチェーンにだけ保存され、プロファイルファイルには書き込まれない」という意味です。上のチェックボックス Mark as a production server は、この接続を本番サーバーとして扱う設定です。

パスワードは OS のキーチェーンにだけ保存されます

macOS では Keychain、Windows では資格情報マネージャーに保存されます。平文で保存されることはありません。プロファイルファイルを開いても、パスワードは入っていません。

本番サーバーはひと目で区別できます

本番サーバーとして設定した接続は、タブとステータスバーの表示が変わります。いまどこに接続しているかを記憶に頼らずに済みます。

接続したまま放置しても切れません

サーバーの wait_timeout と interactive_timeout を読み取り、その半分の間隔で ping を送ります(15〜60秒の範囲)。ただし、自動再接続はあえて行いません。切れた接続を黙って復活させると、開いていたトランザクションが知らないうちに消えてしまうからです。SSH トンネルが必要なら、同じフォームの2番目のタブで設定します。

SSH トンネルは同じフォームの2番目のタブで

踏み台サーバーを経由する接続も、別のツールを使わずに同じ画面で設定できます。このタブの説明文も、何を入力するかより何がどこに保存されるかを伝えている点で接続フォームと同じです。

接続フォームの SSH Tunnel タブ。「Open this connection through a jump server」のチェックボックス、SSH Host bastion.example.com、SSH Port 22、SSH User deploy、Authentication「Key file」、Private Key File の選択ボタン、Key passphrase、Host Key Fingerprint の各欄とそれぞれの説明。
鍵ファイル欄には Only absolute paths are stored、パスフレーズ欄には Stored in the OS keychain as an entry separate from the DB password とあります。パスフレーズは DB のパスワードとは別の項目としてキーチェーンに保存されます。フィンガープリントは The fingerprint is checked and stored on the first connect のとおり、初回接続時に受け取って保存し、次回からはそれと照合します。手で入力する欄ではありません。

02capability

接続すると、画面がその DB に合わせて変わります

4種類の DB をひとつの画面に詰め込んでいるわけではありません。アダプターが接続するとこの DB で何ができるかを確認し、その結果に応じて画面の要素を表示したり隠したりします。そのため Redis ではクエリエディターではなくキーブラウザーが開きます。Redis は SQL ではなく KV だからです。

DB 種類 画面が変わるところ
MySQL · MariaDBSQL基準となる画面
PostgreSQLSQLDDL をトランザクション内でロールバックできます
SQLiteSQLカラムの型変更はテーブルの作り直しになり、ユーザーと権限の画面はありません
RedisKVキーブラウザー、TTL、値の型ごとのビュー。クエリエディターはありません
Redis に接続した DBerio のウィンドウ。クエリエディターはなく、左にキーパターンの入力欄と db0 の下のフォルダーツリー(bulk、tags、text、user、stream、leaderboard、queue、counter、big、session)、user:3 の下に name string と profile hash。右には「user:3:profile hash · TTL Permanent · Set expiry」のヘッダーと field/value の表。一番下のステータスバーに Key ≈10,026 · hash TTL Permanent · Transaction Interactive transactions not supported。
同じアプリですが、クエリエディターがありません。キーツリーには値の型がバッジで付き(string、hash)、ヘッダーには TTL Permanent と有効期限を設定するボタンが並びます。ステータスバーの右側はさらに具体的で、Transaction: Interactive transactions not supported と表示されます。トランザクションの UI をグレーアウトしているのではなく、この DB では成り立たないことをはっきり書いています。

ウィンドウ全体です(1440×892)。一番下のステータスバーまで見せたいので切り取っていません。画像は等倍です。画面が狭いときは画像の中を横にスクロールしてください。

確認するのはラベルではなく画面の要素です

「SQL か KV か」のような大きな分類で決めることはしません。UI が知る必要があるのはこの画面要素が成り立つかどうかだけなので、capability もその単位で定義しています。

capability 確認する内容
transactional_ddlDDL をトランザクション内でロールバックできるか
supports_interactive_transactionautocommit / commit / rollback に意味があるか
supports_ttlTTL の概念があるか
supports_column_modify既存カラムの型を変更できるか
supports_editable_resultsetF8(編集できる結果)を使えるか
supports_multiple_result_sets複数の結果セットを返せるか
supports_user_adminユーザーと権限の画面が成り立つか
supports_schema_syncスキーマ同期ツールが成り立つか
value_typesKV の値の型。String、Hash、List、Set、ZSet、Stream

このページに載っている画面は MySQL と Redis の2つだけです。PostgreSQL と SQLite の画面は、まだ実際のキャプチャがないため載せていません。ない画面を描いたり、ほかの画面にその名前を付けたりはせず、この2つについては上の表の文章だけで説明しています。

03実行

実行キーは3つあり、それぞれ意味が違います

大事なのはキーが3つあることではありません。同じクエリをどんな結果として受け取るかを3通りから選べることです。そしてその約束は、マニュアルではなくボタンの下の小さな文字に書いてあります。

実行ツールバーの3つのボタン。左から「Execute — One query at the cursor · read-only」、「Execute (Editable) — Same query · asks for an editable result」、「Execute Selection — Selection only · does nothing without one」。
3つのボタンが、それぞれの動作をボタンの下に書いています。押してみなくてもわかります。
  • F9 ExecuteOne query at the cursor · read-only
  • F8 Execute (Editable)Same query · asks for an editable result
  • Ctrl+F9 Execute SelectionSelection only · does nothing without one

既定は安全な側です

F9 はカーソルのある文をひとつだけ実行し、結果は読み取り専用です。既定で LIMIT 1000 が付き、1行多く読んで「続きがあるか」を判定します。1,000万行をうっかり読み込むことはありません。間違えて実行しても、セッションを切らずに止められます。クエリのキャンセルは、すべてのアダプターに必須の項目です。

範囲を選択すると、3つ目のボタンがそれを伝えます

範囲を選択した状態の実行ツールバーとエディターの3行。3つ目のボタンの説明が「Selection only · 3 lines right now」に変わり、下のエディターでは SELECT … FROM scratch.orders ORDER BY placed_at DESC の3行が選択されている。右側には autocommit ON のトグルと Commit、Rollback ボタン。
ドラッグで選択すると、3つ目のボタンの説明が Selection only · 3 lines right now(いま3行)に変わります。何が実行されるかを押す前に確認できます。選択がなければ何も実行しません(does nothing without one)。知らないうちに全体を実行することはありません。

上の画像は元のサイズのままです(1044×112)。画面が狭いときは画像の中を横にスクロールしてください。

タブが増えません

F9 と F8 は同じ結果タブを上書きします。実行するたびにタブが増えていくことはありません。

04結果

結果が自分の状態を表示します

F9 で実行した結果です。ヘッダーにはすでに Read-only (F9) · F8 to edit(読み取り専用、編集するなら F8)と表示されています。編集系の操作も同じ理由で無効になっています。押してみて「なぜできないのか」と迷うことはありません。

読み取り専用の結果グリッド。カラム見出しに id bigint unsigned、customer_id int unsigned、amount decimal(10,2)、status varchar、placed_at timestamp、その下に placed_at の降順で12行。
カラム見出しには名前と型が一緒に表示されます。たとえば amount decimal(10,2) です。小数点以下が2桁か4桁かを数える必要はありません。並び順が id ではなく placed_at に従っていることもそのまま見えます。F9 で実行したので、結果は読み取り専用です。

上の画像は元のサイズのままです(1030×246)。画面が狭いときは画像の中を横にスクロールしてください。

編集が無効になる理由は型で決まっています

画面があいまいな表示をしない理由がここにあります。無効なときは次の5つのどれかで、その理由がそのまま表示されます。

理由 どんな状況か
リクエストなしF9 で実行しました。編集できる結果をリクエストしていません
アダプター未対応この DB のアダプターが編集できる結果セットに対応していません
元のテーブルなし式や集計だけなので、書き戻す先がありません
複数のテーブルJOIN の結果なので、どのテーブルを更新するか決められません
同じ元カラムが2回自己結合です。違う行が知らないうちに更新されるのを防ぎます

エクスポートは画面の行ではなく、クエリを再実行します

この違いは大切です。通常の実行には行数の上限があるので、画面の行をそのまま保存すると途中までの行だけがファイルになります。そのため、同じ文を上限なしで実行し直して書き出します。

「Export Result Set — scratch-mysql」ダイアログ。Target は「Query result (12 rows shown)」でその下に説明、Format は CSV、TSV、JSON のうち CSV を選択、Save file はファイル選択ボタンでのみ指定、Delimiter はカンマ、「Write column names on the first line」にチェック、Encoding は UTF-8 で改行は CRLF。一番下に「Export is read-only — it does not change the source data.」。
説明文にその理由が書いてあります。Writes the result of re-running the same statement with no row limit, not the rows on screen、つまり「画面の行ではなく、同じ文を上限なしで実行し直した結果を書き出す」という意味です。一番下の Export is read-only — it does not change the source data. は、エクスポートが元のデータを変更しないことを示しています。(この画面は結果セットのエクスポートなので形式は3つです。テーブルデータのエクスポートでは SQL と Excel も選べます。)

グリッドは見えている行だけを描画し(仮想化レンダリング)、大きな結果は一度に渡さずチャンクに分けて送ります。保存先のパスを直接入力できないようにしているのも同じ考え方で、ファイルダイアログが返した絶対パスだけを使います。

05編集

編集するつもりのときだけ F8 を押します

同じ文を F8 で実行し直すと、結果のモードが変わります。ヘッダーの表示も変わります。

編集できる結果グリッド。ヘッダーに「完了 3行 · 47ms · 最初のチャンク 36ms · 編集可能。セルを編集して行を離れると保存されます (Esc でキャンセル)」。行選択のチェックボックスが有効になっている。
ヘッダーのバッジが Editable — edit a cell and leave the row to save (Esc to discard)(セルを編集して行を離れると保存、Esc でキャンセル)に変わります。いつ保存されるかをバッジがそのまま伝えるので、推測する必要はありません。

上の画像は元のサイズのままです(1030×298)。画面が狭いときは画像の中を横にスクロールしてください。

このひと手間が、この製品の考え方です

編集するには別のキーを押す必要があるので、うっかり本番データを変更してしまう操作が既定にはありません。毎日使う人にとって大事なのは、機能の数よりこうした既定値です。

06ステータスバー

残りはステータスバーに表示されます

結果のヘッダーが「この実行」についての表示なら、ステータスバーは「いまのウィンドウ」についての表示です。接続状態、選択範囲、カーソル位置、エンコーディングが表示されます。

ステータスバーの右側。「Connected to scratch-mysql · Selection 3 lines · 98 chars · Cursor Ln 3, Col 27 · UTF-8」。
接続名、選択範囲(3 lines · 98 chars)、カーソル位置、エンコーディングが表示されています。左側にはサーバーのバージョン、負荷、トランザクションモードがあり、場面 08 で一緒に見られます。

テーブルのオプションも同じ考え方です。サーバーの実際の値を読み込むので、AUTO_INCREMENT は実際の次の番号で、エンジンはそのテーブルの実際のエンジンです。

07ショートカット

ここまでのキーは、すべて1つの定義ファイルから来ています

キー割り当ての元は docs/keymap-contract.json(v0.7)ひとつだけです。コンポーネントにショートカットを直接書くことは禁止されていて、定義と実装が一致しているかを機械的に照合しています。手作業で合わせたものではありません。

使う人にとっての結果は3つです。どの OS でも同じで、すべて変更でき(JSON でのエクスポートも可能)、バージョンが上がっても変わりません。

項目 値
アクション102個(操作の数)
ショートカットの組み合わせWindows 114、macOS 126
有効な範囲global 66 · editor 19 · grid 9 · browser 6 · dialog 2
分類editor 18 · schema 18 · result 12 · connection 9 · common 9 · browser 6 · powertool 5 · tools 5 · statement 4 · query 3 · format 3 · panel 3 · user 3 · app 3 · favorites 1

macOS で変わるのはこれだけです

原則は「Ctrl の組み合わせを macOS でもそのまま使えるようにする」ことです。OS の予約キーとぶつかるところは、Windows のキーを消さずに代わりのキーを1つ追加しました。102個のアクションのうち macOS でキーが変わるのは13個で、そのうち12個は Windows のキーを残したまま Cmd の組み合わせを追加したものです。Windows のキーがなくなったのは終了の1つだけで、Alt+F4 は macOS にないため Cmd+Q にしました。

操作 Windows macOS 理由
入力補完 Ctrl+SpaceCtrl+Space · Option+EscmacOS では Ctrl+Space が入力ソースの切り替えに使われています
Insert/Update ダイアログ F11F11 · Cmd+F11F11 はシステムの「デスクトップを表示」に使われています
タブを閉じる Alt+LAlt+L · Cmd+WmacOS の慣例に合わせ、接続の切断と区別しています
コピー、貼り付け、保存、検索、取り消し Ctrl+…Ctrl+… · Cmd+…一般的な編集操作は Cmd の組み合わせも受け付けます
終了 Alt+F4Cmd+QWindows のキーを置き換えた唯一の項目です

あらかじめお伝えしておきたいことがひとつあります。macOS では F1〜F12 が初期設定でメディアキーになっています。F9、F8、F12 を使うには、システム設定で「F1、F2 などのキーを標準のファンクションキーとして使用」をオンにしてください。

初回起動時の案内でこの設定をお知らせし、Fn との組み合わせにも対応しています。

メニューも同じ定義ファイルから作られます。macOS ではネイティブのメニューバー、Windows ではウィンドウ内のメニューバーで、メニューにキーを手で書く箇所はありません。

08ひとつのウィンドウ

ここまでの画面は、ひとつのウィンドウの一部です

結果のヘッダー(04)、グリッド(05)、ステータスバー(06)は別々の画面ではありません。下の画像は、メインウィンドウの下半分を元の画像からそのまま切り出したものです。3つはこのようにつながっています。

メインウィンドウの下半分。左はオブジェクトブラウザーパネルの空いた下部、右は Result 1、Profiler、Messages、Table Data、Info、History のタブと結果ヘッダー「Done 12 rows · 59ms First chunk 51ms · Read-only (F9) · F8 to edit」、その下に結果グリッド、そしてウィンドウの一番下を横切るステータスバー。
ウィンドウの下半分です。一番下のステータスバーの左側に Load 0.6 q/s · 2 / 151 · 2 とサーバーのバージョン、トランザクションモードがあり、右端には 場面 06 で見たカーソル位置がそのまま表示されています。

元の画像(1440×892)の y=562 から下を切り出しています。エディターと結果パネルの境目で切っているので、行の途中ではなくパネルの境目で終わっています。画像は等倍です。画面が狭いときは画像の中を横にスクロールしてください。

左側はフィルター1つですべて絞り込めます

切り出した部分の上、左側にはオブジェクトブラウザーがあります。フィルターはテーブルだけを絞り込むのではありません。同じ文字でビュー、プロシージャ、トリガーまでまとめて絞り込めます。

オブジェクトブラウザーのパネル。root@127.0.0.1:33107 の下のフィルター欄に「ord」が入力され、scratch utf8mb4 の下に Tables(order_items、orders)、Views(v_customer_orders)、Stored Procedures(sp_count_orders)、Triggers(trg_orders_ai AFTER INSERT · orders、trg_orders_bi BEFORE INSERT · orders)が表示されている。
ord の3文字で、テーブル、ビュー、プロシージャ、トリガーがまとめて見つかりました。トリガーには AFTER INSERT · orders のように、いつどのテーブルで動くかまで表示されます。種類を先に選んでから探すのではなく、名前がわかればすぐに見つかります。

ウィンドウのそのほかの構成

タブは3段階です。接続タブ、クエリタブ、結果タブの順に分かれています。このほかに接続マネージャー、テーブル構造エディター(カラム、インデックス、外部キー、オプション、SQL プレビュー)、ユーザーと権限の画面があります。

最後につくり

エラーメッセージまで日本語で表示されます

アプリの表示言語は韓国語、English、日本語の3つで、アプリ内で Alt+Shift+L を押して切り替えます。翻訳する文言は、どの言語も 1,499件で同じです。

多くのツールは画面だけを翻訳し、サーバーやエンジンのエラーは英語のまま表示します。DBerio はバックエンドが値を埋め込んだ文ではなく文の型と値を送るので、エラー文そのものが使う人の言語で組み立てられます。ただし、サーバーから返された原文(MySQL や PostgreSQL 固有のメッセージ)はそのまま表示します。それは私たちが翻訳すべき文ではないからです。

使っている技術

レイヤー 内容
シェルTauri 2 で作っていて、Electron ではなく OS の WebView を使います。Windows では WebView2、macOS では WKWebView です。
バックエンドRust(mysql_async、tokio-postgres、russh、keyring)
フロントエンドReact 19、TypeScript、Monaco エディター、Glide Data Grid、Zustand
IPC の型Rust の定義から TypeScript を生成します。手作業では合わせていません

エディターは Monaco です。スキーマを読み込んで入力補完に使い、エディター内のキーも同じキーマップに合わせています。エクスポートはどこから実行するかで形式が違います。テーブルデータは CSV、TSV、JSON、SQL、Excel(xlsx)、結果セットは CSV、TSV、JSON です。DB への接続とライセンスの確認はコンパイル済みの Rust バイナリの中で行い、フロントエンドの JS には確認の処理を置いていません。

「Export Table Data — scratch-mysql」ダイアログ。Target は scratch.orders で、Format の行に CSV、TSV、JSON、SQL、Excel (xlsx) の5つが並んでいる。
テーブルデータのエクスポートでは、CSV、TSV、JSON、SQL、Excel (xlsx) の5つの形式が1行に並びます。結果セットのエクスポートと形式が違うのは、実行する場所が違うためです。
エディターの2行。「SELECT id, customer_id, amount, status」の下に「FROM scratch.or」まで入力した状態で入力補完の一覧が開き、order_items、orders、sp_count_orders、v_customer_orders の4つの候補で「or」の部分が太字になっている。候補ごとにテーブル、プロシージャ、ビューを示すアイコンが違う。
スキーマから読み込んだ候補なので、テーブルだけでなくビューやプロシージャも一緒に表示され、アイコンで種類を見分けられます。入力した or が候補のどこに一致したかも太字で示されるので、名前の途中で一致した場合もわかります。

「何倍速い」といった数字を書いていないのは、測ったことがないからです。メモリ使用量も、起動時間も、クエリの速度も測定していません。いま言えるのは、OS の WebView を使うネイティブアプリだという構造上の事実までです。