Skip to content

feat(datatables): datatable migrations (GIT-890)#9495

Draft
diegoimbert wants to merge 6 commits into
mainfrom
diego/git-890-datatable-migrations
Draft

feat(datatables): datatable migrations (GIT-890)#9495
diegoimbert wants to merge 6 commits into
mainfrom
diego/git-890-datatable-migrations

Conversation

@diegoimbert

@diegoimbert diegoimbert commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements datatable migrations (Fixes GIT-890): schema changes to datatables are recorded as versioned SQL migration scripts that are tracked per datatable, synced to git as plain .sql files, applied by a migration runner, and carried across workspace forks — replacing the previous best-effort schema-diff generation on fork.

How it works

Storage & runner (backend)

  • New datatable_migration table: versioned SQL scripts per (workspace, datatable) with name, content, checksum.
  • Applied state is tracked inside the datatable's backing database in a _windmill_datatable_migrations table (like sqlx/flyway). Since a fork copies the database, the fork automatically sees the same migrations as applied — no state reconstruction needed.
  • Runner applies pending migrations in version order; each migration runs in its own transaction together with its tracking insert (all-or-nothing per migration).
  • Workspaced API under /datatable_migrations/{datatable}: list (with applied/drifted status), create, upsert, delete, run — declared in openapi.yaml, consumed via generated clients (frontend + CLI).

REPL warning modal (frontend)

  • Running a query containing DDL (CREATE/ALTER/DROP/TRUNCATE/…) against a datatable in the SQL REPL surfaces a "Schema change detected" modal.
  • Primary action "Save as migration" records the query as a migration (optional name) and applies pending migrations. "Run once without saving" remains as an escape hatch.
  • Detection lives in a unit-tested sqlDdl.ts helper (leading-verb match only — SELECT 'create table' is not flagged).

Schema change detected modal

CLI sync (_datatable_migrations/ folder)

  • Migrations round-trip through git as _datatable_migrations/{datatable}/{version}_{name}.sql.
  • wmill sync pull writes them from the workspace tarball export; wmill sync push upserts added/edited files by version and deletes removed ones.
  • Run on git merge: after a push that touches migration files, pending migrations are applied to each affected datatable — so merging new migration files into a git-synced branch runs them on the target workspace.
  • Migration files are excluded from the script push path and lockfile metadata generation (plain .sql is not a script language).

Fork behavior (replaces best-effort diff)

  • create_workspace_fork no longer snapshots the parent datatable schema; the DatatableSchemaDiff three-way diff + generated ALTER/CREATE SQL component is removed.
  • Migration scripts are cloned to the fork; the Compare & Deploy page now shows a Datatable migrations panel listing each datatable's migrations with applied/pending/drifted status and a "Run pending migrations" action.

Datatable migrations panel on Compare & Deploy

Edit-after-apply warning (secondary requirement)

  • Checksums detect when a stored migration was edited after having been applied (drifted). The UI shows an "edited after apply" badge (visible in the screenshot above), and wmill sync push logs a warning that the edited content will NOT be re-run. Checksums ignore trailing whitespace so editor-appended final newlines don't count as drift.

Validation

  • cargo check (windmill-api, windmill-api-workspaces) — clean; SQLX_OFFLINE=true build passes (cache updated via the safe procedure, zero EE-cache deletions).
  • Frontend npm run check0 errors; vitest sqlDdl tests pass; svelte-autofixer applied (keyed each blocks).
  • CLI bun test unit suite — 815/815 pass (incl. new path-parsing tests); tsc introduces no new errors (pre-existing baseline verified by stash-diff).
  • End-to-end in a real browser + real Postgres:
    • REPL: CREATE TABLE → modal → "Save as migration" → migration stored, runner applied it, tracking row written; "Run once without saving" executes without recording; SELECT unaffected.
    • CLI: sync pull writes the .sql file; adding a file + sync push upserts and auto-applies it (table created); deleting the file + push removes the remote migration; editing an applied migration + push logs the drift warning; re-push after workspace-side row loss correctly reports "no pending migrations" (applied state survives in the datatable DB).
    • Fork: created via API → migration rows cloned; Compare & Deploy renders the migrations panel with correct status badges.

Notes

  • The _windmill_datatable_migrations tracking table is visible in the DB manager like any other table (same as flyway/sqlx conventions).
  • DataTableForkedFrom.schema is kept as a legacy optional field so existing settings JSON still round-trips; it is no longer written.
  • Migration create/upsert/delete/run require workspace admin.

🤖 Generated with Claude Code

When a datatable is selected in the SQL REPL, detect schema-changing (DDL)
statements (CREATE/ALTER/DROP/TRUNCATE/...) on run and surface a confirmation
modal recommending that schema changes be recorded as migrations rather than
run ad-hoc. The user can still proceed with "Run anyway". Non-datatable
inputs and pure read/DML queries are unaffected.

DDL detection is extracted into a small, unit-tested `sqlDdl.ts` helper.

First stage of the datatable migrations feature (GIT-890).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploying windmill with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5856435
Status: ✅  Deploy successful!
Preview URL: https://3fc7b62a.windmill.pages.dev
Branch Preview URL: https://diego-git-890-datatable-migr.windmill.pages.dev

View logs

diegoimbert and others added 5 commits June 9, 2026 19:30
Add a `datatable_migration` table storing versioned SQL scripts per datatable,
and a runner that applies pending migrations to the datatable's backing
Postgres database. Applied state is tracked inside that database in a
`_windmill_datatable_migrations` table, so it survives forks (the table is
copied with the rest of the database).

New workspaced API under /datatable_migrations/{datatable}:
- list   — migrations + applied/drifted status (drifted = edited after apply)
- create — store a new migration (version auto-generated from timestamp)
- upsert — create-or-update by version (used by the CLI push)
- delete — remove a migration
- run    — apply all not-yet-applied migrations in version order

Each migration runs in its own transaction together with its tracking insert.

Part of GIT-890.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The REPL's DDL warning modal now offers "Save as migration" as the primary
action: it records the query as a datatable migration and applies pending
migrations via the runner. "Run once without saving" remains as an escape
hatch. The new endpoints are declared in openapi.yaml and consumed through
the generated client.

Remove the best-effort migration generation on fork:
- create_workspace_fork no longer snapshots the parent datatable schema
  (forked_from is now just a marker object)
- DatatableSchemaDiff (original/parent/fork three-way diff + generated
  ALTER/CREATE SQL) is replaced in CompareWorkspaces by DatatableMigrations,
  which lists each datatable's migrations with applied/pending/drifted status
  and a "Run pending migrations" action. Applied state lives inside the
  datatable database itself, so it survives forks.

Part of GIT-890.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Datatable migrations now round-trip through git as plain SQL files under
_datatable_migrations/{datatable}/{version}_{name}.sql:

- The workspace tarball export includes them, so `wmill sync pull` writes
  them to disk (identifiers that are not file-path safe are skipped with a
  warning rather than producing unparseable filenames).
- `wmill sync push` upserts added/edited files by version and deletes
  removed ones. They are excluded from the script push path and from
  lockfile metadata generation (plain .sql is not a script language).
- After a push that touches migration files, pending migrations are applied
  to each affected datatable — so merging new migration files into a
  git-synced branch runs them on the target workspace.
- Pushing an edit to an already-applied migration logs a warning that the
  new content will NOT be re-run (drift detection). Checksums ignore
  trailing whitespace so editor-appended final newlines don't count as
  drift.

Part of GIT-890.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Forked workspaces now receive a copy of the parent's datatable migration
scripts. Applied state is tracked inside the datatable database itself, so a
fork that copies the database sees the same migrations as applied; migrations
added to the parent afterwards reach the fork via sync and are applied by the
migration runner.

Part of GIT-890.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@diegoimbert diegoimbert changed the title feat(datatables): warn before running DDL in the SQL REPL (GIT-890, stage 1) feat(datatables): datatable migrations (GIT-890) Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant