QoreDB LogoQoreDB
Back to blog
ProduitTechnical journal

Sandbox Mode: Testing Changes Without Touching the Database

When working on an existing database, you often need to test a series of changes before applying them. Fixing inconsistent data, restructuring a set of rows, preparing an import. The usual instinct is to write the SQL by hand, test it on a copy, then run it in production. This…

Raphaël – Creator of QoreDBRaphaël – Creator of QoreDB
5 min readUpdated Jul 18, 2026
Sandbox Mode: Testing Changes Without Touching the Database

When working on an existing database, you often need to test a series of changes before applying them. Fixing inconsistent data, restructuring a set of rows, preparing an import. The usual instinct is to write the SQL by hand, test it on a copy, then run it in production. This workflow works, but it separates two moments that are naturally linked: exploring the data in the grid, and producing the migration that modifies it.

QoreDB's Sandbox Mode shortens this path. You enable the mode, edit cells in the data grid as usual, but nothing is sent to the server. Changes accumulate locally, you review them, and apply them in one block by generating the corresponding SQL script. It's a direct product choice: turn the grid into a staging area, without reinventing a migration editor.

Editing Without Applying

The principle of the sandbox is to decouple intent from commit. When the mode is active, every cell edit, every insertion, every deletion becomes a change recorded on the client side. The frontend store (sandboxStore.ts) keeps the list of operations in localStorage, grouped by connection session. Three types of changes are supported: insert, update, delete. Each one keeps the original primary key, the before and after values, and the table involved.

The grid displays these changes visually: a modified cell takes on a distinct shade, an inserted row is marked, a deleted row is struck through or hidden depending on preferences. The Changes panel groups everything by table, with a counter per operation type. At no point is the database touched. You can quit QoreDB and come back; the sandbox persists as long as you don't purge it.

Generating the Migration Script

When you want to see what these changes will produce, the frontend sends the whole set to the backend through the Tauri command generate_migration_sql. The Rust generator receives the list of SandboxChangeDto items and produces a MigrationScript object: the textual SQL, the statement count, and any warnings. This script is specific to the active driver. PostgreSQL, MySQL, SQLite and SQL Server generate syntax suited to their dialect, while MongoDB emits native operations on collections.

The goal is not to hide the target. The generated SQL is readable, copyable, executable elsewhere if needed. A developer can inspect it, paste it into a migration file in their project, or hand it to a DBA for review. This transparency is deliberate: the sandbox prepares a change, it doesn't disguise it.

Per-Environment Visual Indicator

A production change doesn't carry the same weight as a development change. The SandboxIndicator component reflects this difference visually. When the mode is active, a badge appears in the top bar with a color code tied to the session's environment: blue for development, orange for staging, red for production. The pending-changes counter is visible directly in the badge.

This detail matters because the sandbox can be enabled on any connection, including a production database. Cutting off the confusion between "I'm playing on a local copy" and "I have 12 pending changes on the payroll database" was necessary. Color doesn't replace attention, but it reduces the margin of error when juggling several tabs.

Transactional Application

Applying the changes goes through the apply_sandbox_changes command, which takes the session, the list of changes, and a use_transaction flag. The backend first checks that the session is not read-only and that the driver supports mutations. Without both conditions, the operation is refused with an explicit message.

When use_transaction is true and the driver supports transactions, a BEGIN is issued before the first operation. Each change is applied through the insert_row, update_row or delete_row methods of the DataEngine trait. If an operation fails (primary key conflict, violated constraint, vanished row), the backend triggers an automatic rollback and returns the index of the offending change. The frontend sandbox stays intact: you can fix the offending change and re-run the apply.

If the driver doesn't support multi-statement transactions, the changes are applied sequentially and each failure is recorded in failed_changes. The frontend shows which operations went through and which failed. It's less clean than a global rollback, but it's honest: the target engine dictates its own rules, and the sandbox doesn't contradict them.

A Concrete Workflow

The typical usage starts by enabling the sandbox on the current connection. You open the table to modify, change a dozen values, add two rows, delete an obsolete entry. The Changes panel shows 13 operations grouped by table. Before applying, you request the preview: the generated SQL appears in a dedicated view. You check the UPDATEs, spot a fragile WHERE clause, and go back to the grid to adjust.

When the script is satisfactory, an Apply button triggers the backend command. If the transaction is enabled, everything goes through or nothing does. The database has seen only a single commit, containing the 13 changes. The panel empties, the indicator disappears, and the sandbox becomes inactive again. In case of an error, the details are shown and you can iterate without starting over.

For cases where you don't want to apply but simply export, copying the SQL is enough: you grab the script, commit it into the migrations repo, and hand it to CI or the DBA. The sandbox has done its staging work without imposing a single application channel.

Why This Design

Sandbox Mode is a local staging area that makes visible and atomic a task that is often done blind. It doesn't replace a versioned-migrations tool; that's not its role. It fills the gap between "I edit a cell by hand" and "I write a separate SQL script": a place where you can compose a series of changes, review them, and commit them in a single commit. For a developer working alone or in a small team on a shared database, this shortcut changes the nature of small data corrections: they become traceable, transactional, and readable before execution.

Newsletter

Stay updated on new releases

Subscribe to get product releases, new drivers notifications, and technical tutorials.

🎁 Bonus: Get our free SQL Performance Cheat Sheet — 9 pages, PostgreSQL / MySQL / SQLite (PDF)!
Share
Sandbox Mode: Testing Changes Without Touching the Database - Blog - QoreDB