Skip to content

Release 2.2.2: PostHog, Railway and faster far databases - #94

Merged
broisnischal merged 12 commits into
masterfrom
feat/posthog
Sep 29, 2026
Merged

broisnischal merged 12 commits into
masterfrom
feat/posthog

Conversation

@broisnischal

Copy link
Copy Markdown
Collaborator

Releases 2.2.2 (release:patch, master is at 2.2.1).

What's in it

  • PostHog: sign in with a personal API key, browse tables and query with HogQL, read-only.
  • Railway in the provider picker, and sturdier provider sign-in.
  • Right-click a Docker database to restart, stop or copy its URL.
  • A full connecting screen in the connection dialog.
  • MySQL 8/9 empty tables show their columns; inserts appear without a refresh.
  • The expanded row JSON and row panel update after an edit.

Speed, measured against my Neon, Supabase, Nile and Prisma databases

  • Connect pays one handshake, not two: Prisma 6.2s to 0.6s.
  • Far hosts keep a pool warmed in parallel, so a table open never waits on new handshakes.
  • Vendored sqlx-postgres / sqlx-mysql 0.8.6 skip the on-release ping for a clean connection: 5 sequential queries went from 2.7-3.0s to 1.6-1.9s, and Nile stops dropping its connection after every query. Live tests cover a dropped transaction and a half-read stream.
  • A table's first open is one round trip instead of two.
  • Provider APIs are warmed when the dialog opens; PlanetScale lists and connects in fewer calls.

Checks

  • 174 Rust tests, 685 frontend tests, svelte-check 0 errors, clippy clean, vite build OK.
  • Live: PostHog against a real project, MySQL against a local MySQL 9 container, Postgres patch tests against Neon, Supabase and Nile.

- MySQL 8 and later can type information_schema text as VARBINARY, and plain
  String decodes dropped those values silently: an empty table had no
  columns, AUTO_INCREMENT was lost on insert, foreign keys vanished and a
  backup could miss a CREATE statement. They all use my_text now.
- The grid falls back to the table's structure when a fetch returns no
  columns, and reloads the page after an insert when splicing the row in
  would be wrong ("All" mode, a sort, or an incomplete row).
- A table open ran columns, count + rows, primary key and foreign keys one
  after another. Keys now load with the rows, and a plain open is one stage.
- Provider connections are titled by their name, not a generic database
  name like Railway's `railway`.
- Railway signs in as its registered native app, on the 127.0.0.1 redirect
  it was registered with, and connects through a TCP proxy when the template
  has no public URL variable. A service without public access says so, with
  an Open in Railway button.
- The sign-in callback answers on IPv6 loopback too, and a browser that
  won't open no longer ends the sign-in: the waiting panel offers Open again
  and Copy link. Cloudflare uses the same shared callback.
PostHog keeps its data in ClickHouse, but Cloud gives no direct access, so
this is a new engine over PostHog's query API: HogQL SELECTs in, columns and
rows out, the schema from a DatabaseSchemaQuery (cached, since the API allows
240 requests a minute).

- Sign in from the provider picker with the PostHog URL (US, EU or
  self-hosted) and a personal API key, then pick a project.
- Browse events, persons, sessions and warehouse tables in the grid, with
  search, filters and sort. Events open newest first.
- Run HogQL in the SQL console and chart the results. The MCP tools query it
  too, so agents can read the same analytics.
- Always read-only: writes, imports, backups and transactions say so.
Start, stop and restart go through one command that only accepts those three and validates the container name, so it can't be read as a docker flag. Stopping drops the card from the running list, so its toast offers Start again.
PostHog rejects OFFSET on personal-API-key queries, even OFFSET 0, so every table failed to open. A page now asks for rows up to its end and drops the ones before it, within PostHog's 50,000-row ceiling.
Checked against a live PostHog project:
- The grid's "All" mode takes its total from the background count, which
  returned unknown for PostHog. It counts now.
- Nested tables (system.information_schema.columns) are quoted per part;
  quoted whole, PostHog answered HTTP 500.
- Columns are no longer all marked required, and ClickHouse types read as
  short labels (Int64, DateTime64, Enum8, String).
- PostHog's 400s no longer dump the generated query; a listed table that
  can't be queried, or a 5xx on an internal table, says so in one line.
A saved cell swaps one row in place and bumps dataVersion, since rows is
$state.raw. The expanded row JSON and the row detail panel read rows
without watching dataVersion, so both kept showing the old value until a
refresh. Both now rebuild on it, and the expanded row shows staged edits
the same way the grid paints them.
Measured against Neon, Supabase, Nile and Prisma Postgres: a handshake
costs 1.8-3.4s and a query 265-535ms, so every avoidable handshake or
round trip is most of what a far database feels like.

- Open pools lazily and wait for one connection. sqlx's connect_with
  opens every min_connections connection in a row first, so each connect
  paid two handshakes (Prisma: 6.2s, now 0.6s).
- Remember each host's handshake cost. A host over 1.2s keeps a pool the
  size of a table open's burst, warmed in parallel right after connect,
  so the burst never waits on fresh handshakes.
- Vendor sqlx-postgres and sqlx-mysql 0.8.6 with one change each: skip
  the on-release ping when the connection has nothing pending. It cost a
  round trip after every query, and Nile's proxy rejects it, so every
  Nile query threw its connection away. Five sequential queries: 2.7-3.0s
  before, 1.6-1.9s after. Live tests cover a dropped transaction and a
  half-read stream.
- Decide which columns are wide for the whole schema when the table list
  loads, and keep a "nothing wide" answer on first open, so a table's
  first page is one round trip instead of two.
- Open the HTTPS connection to each signed-in provider's API when the
  connect dialog opens, so the first listing or connect skips DNS, TCP
  and TLS. Unauthenticated HEAD, nothing sent.
- Start building a Neon, Supabase, Railway or Upstash connection when the
  pointer rests on a database, so it is usually ready by the click.
  Providers that mint credentials on connect never prefetch.
- PlanetScale: re-check organizations and fetch their databases in one
  round trip, and connect with the default branch the listing already
  returned instead of looking the database up first.
- Log how long each provider's listing and connect take.
Connecting from the dialog only had a 12px footer spinner beside the
form's host, which was not the host being dialled for a provider pick or
a saved row ("127.0.0.1:-/" while connecting to Supabase), and Resume
spun whenever the connection being dialled was the last one.

The launch reconnect screen is now ConnectOverlay, used for both: the
database's own mark in a ring, its name and host, seconds elapsed from
2s, and Cancel. Only the control that started a connect shows progress,
and the footer names the real target. The DNS prewarm also resolves the
hostname inside a PostHog base URL instead of the URL itself.
@broisnischal broisnischal added the release:patch Bump patch version (0.0.x) label Sep 29, 2026
@broisnischal broisnischal self-assigned this Sep 29, 2026
@broisnischal
broisnischal merged commit 5db98e8 into master Sep 29, 2026
1 check passed
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release:patch Bump patch version (0.0.x)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant