<p>There's a particular kind of joy in software that just gets out of your way. You open it, it does the thing, and you go back to what you were actually trying to build. That's the feeling I keep chasing with Elyra Grove, and these two releases are all about smoothing over the little papercuts between you and that feeling.</p><p>Two small features, both living in a brand-new Tools panel: a one-click Restart daemon button, and a full database converter that moves whole databases between MySQL, PostgreSQL and SQLite.</p><h2>0.2.7 — "Restart daemon", because nobody enjoys typing that command</h2><p>Grove runs as a tiny background service so it can hold on to ports 53, 80 and 443 and quietly serve your <code>*.test</code> sites. That's great — until you update the app. The freshly downloaded binary is on disk, but the running daemon is still the old one.</p><p>Until now, the fix was a trip to the terminal:</p><pre><code class="language-bash">$ sudo launchctl kickstart -k system/com.elyra.grove
Password:
</code></pre><p>It works, but it asks for your password and it's easy to fat-finger. So Grove learned to restart itself. There's now a Restart daemon button in Tools:</p><pre><code class="language-text">🛠  Tools
┌─────────────────────────────────────────────────────────────┐
│  Restart daemon                                    ↻ Service  │
│  Restarts Grove's background service. Use this after          │
│  updating the app so the running daemon picks up the new      │
│  version. No password needed.                                 │
│                                          [ Restart daemon ]   │
└─────────────────────────────────────────────────────────────┘
</code></pre><p>Click it and that's it — no password, no terminal. The daemon already runs as root (that's how it binds the privileged ports), so it can re-exec itself through launchctl without asking you for anything:</p><pre><code class="language-text">$ grove status | head -1
Grove 0.2.7
</code></pre><p>The whole update loop is now: update the app → Tools → Restart daemon → done.</p><h2>0.2.8 — Convert a database between MySQL, PostgreSQL and SQLite</h2><p>This is the one I'm most excited about.</p><p>We've all been there. You've got a MySQL database full of lovingly seeded dev data, and you want a SQLite copy — for a fast test suite, a self-contained file to hand a colleague, or just to poke at on a plane. Or the other direction, promoting a SQLite prototype into MySQL.</p><p>Open Tools → Convert database, pick a source and target, press Convert:</p><pre><code class="language-text">🛠  Tools → Convert database
  Source                          →        Target
  ┌───────────────────────┐                ┌───────────────────────┐
  │ Type   [ MySQL     ▾] │                │ Type   [ SQLite    ▾] │
  │ Host   127.0.0.1      │                │ File   ~/shop.sqlite  │
  │ Port   3306           │                │                       │
  │ User   root           │                │                       │
  │ DB     shop           │                │                       │
  └───────────────────────┘                └───────────────────────┘
                         [ Convert ]
  ✅ Converted 14 table(s) and 3,481 row(s) into the sqlite database.
</code></pre><p>And there's your file, ready to go:</p><pre><code class="language-text">$ sqlite3 ~/shop.sqlite '.tables'
cache            jobs             products         sessions
categories       migrations       order_items      users
failed_jobs      orders           products_index   ...
$ sqlite3 ~/shop.sqlite 'SELECT name, price FROM products LIMIT 3;'
Widget|9.99
Gadget|19.50
Sprocket|4.25
</code></pre><p>It works in every direction that matters — MySQL → SQLite, SQLite → MySQL, and the same for PostgreSQL. It recreates tables, columns and primary keys, then copies every row.</p><h3>The interesting bit: making values survive the trip</h3><p>The hard part isn't the tables — it's the values. Every dialect has its own opinions about dates, decimals, booleans and binary data. Grove sidesteps most of that by transferring values as text (blobs as raw bytes) and letting each database cast them back on the way in. A MySQL DATETIME lands in SQLite as <code>2024-01-02 03:04:05</code>, a DECIMAL keeps its digits, and JSON and UUID columns come through intact.</p><p>Getting there meant fixing a few genuinely gnarly things — MySQL and PostgreSQL hand back their <code>information_schema</code> type names as binary strings, and a LONGTEXT column can come back as bytes rather than a tidy String. Grove now reads all of that robustly, with a bytes-to-UTF-8 fallback. (There's an end-to-end test that spins up a real MySQL, round-trips a table with dates, decimals and NULLs through SQLite and back, and checks every value. It's green. 🟢)</p><p>Scope for this first version: it copies tables, columns, primary keys and data. Views, stored routines, triggers and foreign keys aren't recreated yet — but for "I just want my data over there," it's exactly enough</p><h2>Getting the update</h2><p>Grove auto-updates. After it relaunches:</p><ul><li><p>On 0.2.7+: just hit Tools → Restart daemon.</p></li><li><p>Coming from an older build one last time: <code>sudo launchctl kickstart -k system/com.elyra.grove</code></p></li></ul><pre><code class="language-text">$ grove status | head -1
Grove 0.2.8
</code></pre><hr><p>Two small buttons, but they each remove a real bit of friction — one from updating, one from wrangling databases. That's the whole idea: a local dev environment that quietly handles the plumbing so you can get back to building.</p><p>Happy building. 🌳</p>