The SQL editor
An AppKit text view with highlighting, alias-aware autocomplete and a formatter that keeps every token. Each tab carries its own session.
⌘⇧↩. Each produced its own result tab; the status line under the panes shows the SQL that made the rows on screen.Writing
- Line-number gutter, current-line highlight, bracket matching, auto-indent,
⌘/to toggle comments,⌘Dto duplicate a line. - Highlighting comes from Tinker’s own SQL tokenizer (
DBSQL), which also drives the statement splitter and the formatter, so all three agree on where a statement begins and ends. - Autocomplete opens after one character or on
⌃Space: keywords, tables in the current schema, functions, and the columns of tables referenced in the statement. It knows your aliases: afterFROM users u, typingu.lists the columns of users. - Functions come from a catalog per engine — 281 on MySQL, 291 on PostgreSQL, 128 on SQLite — grouped the way each engine’s own documentation groups them. Typing
DAoffersDATE,DATE_FORMAT,DAY,DAYNAME…, each with its argument list and its category; choosing one insertsDATE()with the caret between the parentheses, while a function that takes none, such asCURRENT_TIMESTAMP, is inserted bare. Known function names are coloured in the editor. ⌘⇧Iformats conservatively: uppercase keywords, one clause per line, indented sub-selects. Every token survives.- A server error with a known position becomes a red squiggle under the offending token until the text changes.
The tab’s session
Two pickers in the tab toolbar choose the connection and the database (MySQL) or schema (PostgreSQL). Statements run in that session, so you write SELECT * FROM t, not SELECT * FROM db.t. Changing the picker issues the engine’s own switch: USE db on MySQL, SET search_path on PostgreSQL. The pickers show what the session actually holds after the switch; a failed switch leaves the previous choice selected and reports the server’s words.
Running
⌘↩runs the selection, or the statement under the cursor when nothing is selected.⌘⇧↩runs every statement in order.- Each statement produces its own result tab. A non-SELECT produces a message such as “UPDATE 3 rows in 12 ms”.
- The splitter handles MySQL
DELIMITER $$procedures, dollar-quoted PostgreSQL bodies and a 2,000-statement dump pasted in one go. ⌘.cancels on the server (pg_cancel_backend,KILL QUERY) and returns within a second. The connection remains usable afterwards.- Auto-commit is a toggle in the toolbar. With it off, the status bar shows “Transaction open” in orange and Commit and Rollback become active. Closing the tab with an open transaction asks what to do. On a production connection there is no toggle at all: the toolbar carries a MANUAL COMMIT mark, and every write waits for Commit or Rollback.
Result panes
Profile and Status are read when their pane is opened, not after every statement. Both cost a round trip, and a pane nobody looks at should cost nothing.
Errors
Server errors appear in a non-modal banner above the results: red left border, monospaced message, a Copy button. The message is the server’s, verbatim, with its SQLSTATE. When the position is known the editor jumps to the token. Tinker never rewrites, summarises or retries an error on your behalf.
History and snippets
Every executed statement is recorded with its connection, database, timestamp, duration and row count or error, capped at 10,000 entries and searchable from ⌘Y. Double-click puts one back in the editor. Snippets (⌘⇧K) hold the statements you type every week.