Skip to content

Repository files navigation

Omatable logo

Omatable

A native database client for Omarchy.
A connection manager, a schema browser, a paged result grid with staged edits and a SQL editor, for MySQL/MariaDB, PostgreSQL and Redis — over a direct socket or through an SSH tunnel.

MIT license Qt 6 Made for Omarchy

Omatable browsing a MariaDB table: the schema tree on the left, a paged result grid with a real row count, and the console log showing every statement the app issued — the connection bar filled red because this connection is tagged production

A production MariaDB connection: the bar is the theme's red, the footer says 1-300 of 10,559 rows and means it, and the console log shows the exact SQL omatable just ran — timestamps and duration included.

One binary. Qt 6 Widgets straight over the vendor client libraries — MariaDB Connector/C, libpq, hiredis — painted live in whatever Omarchy theme you are running, at whatever text size you have set. No Electron, no Java, no Python runtime, no subscription.

Highlights

  • A 200,000-row table opens as fast as an empty one. Nothing ever loads a whole table: every result is a page — 300 rows, with a real count beside it — so memory is bounded by construction, not by luck.
  • The grid never writes as you type. Edits, inserts and deletions accumulate visibly, show you the exact SQL they will send (Ctrl+Shift+P), and go to the server as one transaction (Ctrl+S). No "are you sure" on every cell — one deliberate commit instead.
  • Production is read-only until you say otherwise. Protection follows the connection's environment, not a toolbar control you have to remember to arm — and the connection bar is filled with the environment's colour, so which server am I about to change is answered before you ask it.
  • Every statement is inspectable, including ours. The console log shows the SQL omatable itself issues, introspection queries included. If the app sends it, you can read it.
  • The tunnel is OpenSSH. A real ssh child process, so ~/.ssh/config, ProxyJump, known_hosts, certificates, FIDO keys and the 1Password agent all just work — omatable implements no SSH at all.
  • Arrive without retyping. Omatable reads Sequel Ace's and DBeaver's connection files, so a connection set built elsewhere arrives working.
  • Omarchy through and through. Colours from the live theme, text size from omarchy display text size, both applied the instant they change — and row heights, indents and paddings all derive from the text size, because a grid is mostly rows.

Install

On Omarchy:

git clone https://github.com/omacom-io/omatable
cd omatable
./install-omarchy      # deps through omarchy-pkg-add, installs into ~/.local

As an Arch package:

cd pkgbuild && makepkg -fsi

Runtime dependencies: qt6-base, mariadb-libs, postgresql-libs, hiredis, libsecret, openssl, openssh. Optional: mariadb-clients and postgresql, for database backup and restore. Without them those two actions say which package to install; everything else works.

Omatable also registers as the handler for database URLs: xdg-open postgres://user@host/db opens it as an ad-hoc connection that is never saved and never touches the keyring.

Connections

A connection is created in one form that carries its own driver selector, so there is no separate chooser step. Host and port are prefilled, and the name is derived from user@host/database when left empty. Launch to first row of data is ten interactions, and that number is a budget the test suite holds.

Every connection has an environment, and it drives both the colour of the connection bar and what the connection permits:

Environment Colour Writes
Development theme accent permitted
Staging theme orange / yellow confirmed first
Production theme red refused until unlocked for the session

The three colours come from your theme's own palette, and are pulled apart automatically on a theme whose accent, orange and red are three shades of the same warm colour — so red still means production under all 22 shipped themes, without a hex literal fighting your colours.

An unlock is explicit, lasts only that session, and is shown in the connection bar for as long as it lasts. Whether a statement is a read is decided conservatively and syntactically: anything that is not plainly a SELECT/EXPLAIN/SHOW/DESCRIBE — a DELETE inside a CTE, a SELECT … FOR UPDATE, a batch with one write in it — is a write. And no dialog ever stands between you and a statement you typed: a production refusal is a line in the message pane with an Unlock control beside it.

The tunnel forwards to a unix socket, not a loopback port, in a mode-0700 directory under $XDG_RUNTIME_DIR — a forwarded TCP port is reachable by every process on the machine while it is up, and a socket in a private directory is not. When a jump host restarts underneath it, the tunnel is rebuilt silently on next use. When it cannot be, the error names the cause — refused forwarding, unknown host key, auth rejected, no agent, host unreachable — rather than a bare Failed to create tunnel, and the ssh child's stderr is kept and shown on request.

The grid

Double-click a table and you get its first page, with 1-300 of 200,000 and page controls in the footer. Filter, sort and page compose into one statement, and the count is the filtered count.

The grid never writes as you type. Double-click a cell and type, + Row or Ctrl+I for a new row, Delete row from the grid's menu for an old one — all three accumulate, visibly, and none of them has touched the server. An edited cell is tinted in place, an inserted row appears under the page with its untouched cells reading DEFAULT, and a row staged for deletion is tinted across its full width.

Ctrl+Shift+P previews the SQL. Ctrl+S applies it as one transaction: a batch that fails at any statement rolls back whole. Values are sent as bound parameters, so a numeric shown as 128.40 is written back as 128.40. Ctrl+Shift+Delete discards everything staged.

A row that changed underneath you is detected, not overwritten — every update is preceded, inside the same transaction, by a locking check that the row still holds what the page read. A table with no primary or unique key cannot be edited here, and the footer says so rather than generating a WHERE that would match more rows than you selected.

Filters

Ctrl+F over an open table, and filtering to one row is five interactions: Ctrl+F, type the column name, Tab, type the value, Ctrl+Return. The column field is a typeahead and the operator defaults from the column's type, so in the common case it is never touched.

Operators follow the type — contains and begins with on text, between on numbers and timestamps, an enum's own labels as a picker, containment on JSON, and is null only on a column that can be null. Conditions combine with AND and each can be turned off (Ctrl+B) without losing what was typed into it. When the builder runs out, Raw SQL sits in the same column list and is appended to the WHERE as written.

Values are bound parameters, so a filter value of '; DROP TABLE customers; -- matches nothing and drops nothing.

The structure editor

Ctrl+Alt+] over an open table, and its shape is editable: columns, indexes and foreign keys, staged exactly like the grid — the same three keys, the same three tints, the same one transaction. Adding a column is eight interactions.

The preview says which kind of apply you are getting: PostgreSQL wraps DDL in the transaction and rolls a failed batch back whole, MariaDB commits each statement as it runs, and neither pretends to be the other. Destructive changes are named above their statement rather than blocked.

The SQL editor

Ctrl+E from anywhere opens the editor on the current connection — no feature in this app is allowed to stand between you and writing SQL. Ctrl+Return runs the selection or the statement under the cursor; Ctrl+. cancels. Several statements produce several result tabs. The server's own error text is shown unchanged, with the line it came from. Completion knows your schema — tables, columns behind a dot, and the keywords of the engine you are on.

Every statement you run is kept in the sidebar's History tab across restarts, and Save query… puts one in Queries.

Redis

A driver, not a second application. db0 opens as a grid whose columns are key, value, type and ttl, filtered with the same filter bar as any table and paged over SCAN rather than LIMIT — so browsing a keyspace feels exactly like browsing a table, because it is the same grid.

Tabs and sessions

Tabs belong to a connection, not to the window: switching connection switches the whole set, and switching back finds it where you left it. Ctrl+Shift+D splits the pane, once.

Omatable always opens on the connection list. It does not reconnect to whatever you were last looking at — opening a server is a click you make on purpose, and there is no environment for which that is the wrong rule.

The window writes ~/.local/state/omatable/session.json when it closes, and it holds a window layout — geometry, the sidebar width, whether the console was showing. Nothing in that file is a secret and nothing in it names a connection, and a missing or corrupt one starts clean rather than failing to launch.

Arriving from another client

Omatable reads Sequel Ace's Favorites.plist and DBeaver's data-sources.json (with the passwords beside it), so a connection set built elsewhere arrives without retyping. Each import is best-effort and says what it could not read rather than failing whole.

Backup and restore

Two different things, deliberately named differently:

  • Your connections go into one sealed file through ... beside New connection. The backup carries the passwords, pulled out of the keyring at export time and put back on restore, so a connection set that moves machine arrives working. The passphrase is not optional, and SSH keys are never included — only the path to them.
  • A database is dumped and restored through Back up database... and Restore database..., which shell out to mariadb-dump / mysqldump and pg_dump / pg_restore — the vendor tools, not a re-implementation. Whole-database granularity, --no-data for schema-only, and no scheduling. Each job opens its own tunnel; the password travels in the child's environment, never on its command line.

Where secrets live — and where they do not

This is a database client, so you should be able to check this before trusting it.

Secret Where it lives
Database passwords, SSH passwords, key passphrases The Secret Service keyring, keyed by connection id
Hosts, ports, users, SSH options, environment tags, the path to a private key ~/.config/omatable/connections.json
Private keys Never read, never copied, never exported. Only the path travels
A connection backup's passwords Inside the sealed envelope, under PBKDF2-HMAC-SHA256 at 600,000 rounds and AES-256-GCM

And where they never go:

  • Never on a command line. mariadb-dump gets the password through MYSQL_PWD or a mode-0600 defaults file and pg_dump through PGPASSWORD, in the child's environment; ssh gets it over a private socket. A test asserts that no child process command line contains a password, because /proc/<pid>/cmdline is readable by every process on the machine.
  • Never in connections.json, and never in plaintext on disk as a fallback. With no keyring available the password is kept for that session only, and the form says so.
  • Never in session.json, which is asserted rather than assumed.
  • Never in the console log, which is the sneaky one — it shows every statement, and a connection string is a statement.

Keyboard shortcuts

F1 shows this table inside the app, and a test fails the build if the two ever disagree — a shortcut with no row and a row with no shortcut are the same bug.

Omatable never binds Super. Super belongs to Hyprland: on stock Omarchy 184 of its 225 bindings use it.

Key
Ctrl+Shift+K / Ctrl+K Switch connection / switch database
Ctrl+Shift+W Disconnect, back to the connection list
Ctrl+P Quick open: any object by name
Ctrl+R Reload what is in front of you
Ctrl+T / Ctrl+W New query tab / close the tab
Ctrl+[ / Ctrl+] Previous / next tab, wrapping
Ctrl+1…Ctrl+9 Jump to a tab
Ctrl+Shift+D Split the pane, and unsplit it
Ctrl+Shift+C Show or hide the console log
Ctrl+Alt+[ / Ctrl+Alt+] Data view / structure view
Space Row detail
Ctrl+I Insert a row, or add a filter condition
Ctrl+F Filter the table, or search the tree
Ctrl+Return Apply the filters, or run the statement
Ctrl+Shift+P / Ctrl+S / Ctrl+Shift+Delete Preview / apply / discard staged changes
Ctrl+E Open a query editor
Ctrl+. Cancel the running statement
F1 These shortcuts

Files omatable writes

Path What
~/.config/omatable/connections.json Connections. No passwords, ever
~/.local/state/omatable/session.json Window geometry, sidebar width, console visibility
~/.config/omatable/history/<id>.json Query history, per connection
~/.config/omatable/queries/ Saved queries
$XDG_RUNTIME_DIR/omatable/<id>/ The tunnel's forward socket, mode 0700
The Secret Service keyring Every password and passphrase

Theme

Omatable follows the live Omarchy theme with no restart: omarchy theme set <name> re-colours the running window and omarchy display text size re-scales it. Row heights, the tree indent and every padding derive from the resolved text size, so the grid stays readable at every setting rather than growing text inside a fixed row. Anything painted in a theme colour picks its own label colour by WCAG contrast rather than assuming white, and light themes are read as light, not assumed away.

On a machine with no Omarchy themes installed at all, omatable falls back to a built-in palette and looks right anyway.

Build

make check      # configure, build, the offscreen suite, then both linters
make build      # build only
make install    # install into ~/.local

Build dependencies (Arch): qt6-base qt6-svg cmake ninja pkgconf mariadb-libs postgresql-libs hiredis libsecret openssl. qt6-svg is needed only by the icon suite, which rasterises the shipped icon; the app itself never renders one.

Tests

The suite runs headless against real servers rather than mocks — a driver test that mocks a server proves the mock:

make containers      # MariaDB, PostgreSQL, Redis and an SSH jump host, on loopback
make smoke           # the suite
make containers-down # destroy them, volumes included

The containers exist to prove what nothing else can: that the SSH tunnel carries a real connection end to end, and that paging over 200,000 rows stays bounded.

Not yet

Engines beyond MySQL/MariaDB, PostgreSQL and Redis; per-table backup granularity; scheduled backups; importing connections from clients other than Sequel Ace and DBeaver.

Contributing

Keep make check green — the suites are the specification, and both linters fail the build on a finding. The client libraries do the protocol and OpenSSH does the tunnelling: never implement a wire format, a handshake or SSH that a vendor library or ssh already provides. Each driver's C headers are included only under its own src/drivers/<name>/, and make contained fails the build on a violation. And never put a secret on a command line — there is a test for that too.

Licence

MIT — see LICENSE.

Built with Qt 6 under the LGPLv3, linked dynamically, over MariaDB Connector/C, libpq and hiredis. Sequel Ace and DBeaver are their respective owners' projects; omatable shares no code with any other database client and interoperates only through file formats.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages