portable-schema-generator

$npx mdskill add Tibsfox/gsd-skill-creator/portable-schema-generator

Generate Postgres and SQLite DDL from a single schema spec.

  • Eliminates manual sync between two migration files.
  • Depends on a schema spec and translation rules for each driver.
  • Maps each schema element to driver-specific syntax using a rule table.
  • Outputs ready-to-use .sql files for Postgres and SQLite.

SKILL.md

.github/skills/portable-schema-generatorView on GitHub ↗
---
name: portable-schema-generator
description: "Emit Postgres.sql and SQLite.sql from a single schema spec so tools work across both drivers without duplicating DDL by hand. Use when designing a schema that needs to support both shared Postgres deployments and zero-config SQLite. Reduces two-file sync burden to a single source edit."
format: 2025-10-02
version: 1.0.0
status: stable
updated: 2026-04-17
type: skill
category: gsd-meta
origin: tibsfox
modified: false
first_seen: 2026-04-17
first_path: examples/skills/gsd-meta/portable-schema-generator/SKILL.md
superseded_by: null
---

# Portable Schema Generator

Two-driver schemas mean two migration files. Hand-keeping them in sync
drifts fast. This skill captures the translation rules and the minimal
tooling that keeps them aligned.

## When to Use

- Your tool needs to work on **both** Postgres and SQLite
- You want fresh-project onboarding to be zero-config (SQLite default)
  while shared-infra deployments keep Postgres
- A single schema change should land in both driver files with no manual
  diff-copying

## Core Differences

| Concern | Postgres | SQLite |
|---------|----------|--------|
| Schemas | `CREATE SCHEMA foo; SET search_path TO foo` | Namespace-flat — prefix names instead |
| Autoincrement | `BIGSERIAL PRIMARY KEY` | `INTEGER PRIMARY KEY AUTOINCREMENT` |
| Timestamps | `TIMESTAMPTZ DEFAULT now()` | `TEXT DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))` |
| Booleans | `BOOLEAN` | `INTEGER` (0/1) |
| Enums via CHECK | `CHECK (col IN ('a','b'))` | Same — both support inline CHECK |
| Foreign keys | On by default | `PRAGMA foreign_keys = ON` required at connect |
| Updated-at trigger | `CREATE TRIGGER ... EXECUTE FUNCTION touch_updated_at()` | `CREATE TRIGGER ... BEGIN UPDATE ... END` |
| Cascading drops | `ON DELETE CASCADE` | Same, but only enforced with `foreign_keys = ON` |
| Reserved-word casing | Case-insensitive | Case-insensitive, but be consistent |

## Translation Rules

When authoring the Postgres version first:

1. **Strip schema prefix** for SQLite — `CREATE SCHEMA IF NOT EXISTS foo;`
   and `SET search_path` are removed. Keep bare table names.
2. **Replace `BIGSERIAL`** with `INTEGER PRIMARY KEY AUTOINCREMENT`.
3. **Replace `TIMESTAMPTZ`** with `TEXT`; default becomes
   `(strftime('%Y-%m-%dT%H:%M:%fZ','now'))`.
4. **Replace `BOOLEAN`** with `INTEGER` (values 0/1 at insert time — use an
   adapter coercion).
5. **Drop `RESTART IDENTITY`** on truncates (SQLite uses
   `DELETE FROM sqlite_sequence WHERE name = 'table'` instead).
6. **Rewrite function-style triggers** to inline `BEGIN ... END` trigger
   bodies.

## File Layout

```
migrations/<feature>/
  001-init.postgres.sql
  001-init.sqlite.sql
  002-next.postgres.sql
  002-next.sqlite.sql
```

Numbered pairs. The adapter picks the right one based on `cfg.db.driver`.

## Adapter Runtime Responsibilities

The query adapter at runtime should:

- Rewrite `$N` placeholders → `?` for SQLite
- Strip `release_history.` schema prefix for SQLite
- Translate `now()` → `strftime(...)`, `::type` casts → drop
- Coerce JS booleans → 0/1 on param bindings
- Provide a portable `truncate(table)` helper

Reference implementation: `tools/release-history/db.mjs` in this repo.

## Workflow

1. Author the Postgres version first (richer type system reduces ambiguity).
2. Translate row-by-row using the rules above into the SQLite version.
3. Test both: apply each migration to a disposable DB, run schema-check
   script against the adapter.
4. Commit both files together; never commit one without the other.

## Anti-patterns to avoid

- Single mixed-syntax file — both drivers will try to parse it and one or
  both will fail.
- Runtime translation of whole migration files — too many edge cases.
- Letting the Postgres file diverge "just for now" — alignment rots quickly.

## Example (from this repo)

See `migrations/release-history/001-init.postgres.sql` and
`migrations/release-history/001-init.sqlite.sql`. Six tables (release,
feature, metric, retrospective, lesson, publish_target). Same semantics,
driver-idiomatic DDL.

## Related

- `env-setup` — database credentials and `.env` conventions
- `file-operation-patterns` — migration file naming discipline

More from Tibsfox/gsd-skill-creator

SkillDescription
3d-interaction-designDesign heuristics for three-dimensional interaction — input modalities (6DoF controllers, gaze, gesture, voice), selection and manipulation techniques (ray-cast, virtual hand, go-go, world-in-miniature), navigation (teleport, continuous, redirected walking), and feedback loops (haptic, audio, visual). Covers Fitts' law in 3D, discoverability vs affordance, safe-zone design, and comfort/simulator sickness mitigation. Use when designing VR/AR interactions, immersive walkthroughs, or any input system where the user's body is the controller.
accessibility-patternsProvides web accessibility best practices for semantic HTML, ARIA, keyboard navigation, color contrast, and screen reader patterns. Use when building UI components, reviewing accessibility, or when user mentions 'a11y', 'accessibility', 'ARIA', 'screen reader', 'keyboard navigation', 'WCAG'.
active-listeningActive listening techniques for effective communication. Covers attending behaviors, paraphrasing, reflective listening, clarifying questions, empathic response, barriers to listening, listening in conflict, and cross-cultural listening. Use when building listening skills, improving understanding in conversation, mediating disputes, or analyzing communication breakdowns.
adversarial-pr-reviewAdversarial spec-compliance PR review — cross-references diffs against approved specs, verifies runtime claims against source, detects competing PRs, audits scope/convention compliance. Use before merging.
agile-methodsAgile and Lean software development methodologies for iterative, adaptive project execution. Covers Scrum (roles, ceremonies, artifacts), Kanban (WIP limits, flow metrics), XP (TDD, pair programming, CI), SAFe overview, Lean Software Development (Poppendieck's 7 principles), user stories (INVEST criteria), estimation via story points and velocity, and the Agile Manifesto's values and principles. Includes Cynefin framework for methodology selection and GSD's relationship to Agile as a structured Lean variant.
algebraic-reasoningSymbolic manipulation, equation solving, and algebraic structures for mathematical reasoning. Covers distributive law, factoring, completing the square, linear through polynomial equation solving, systems of equations (substitution, elimination, Gaussian elimination, matrix methods), algebraic structures (groups, rings, fields), modular arithmetic, polynomial theory, and inequalities. Use when solving equations, simplifying expressions, working with algebraic structures, or performing symbolic manipulation.
algorithmic-awarenessUnderstanding how algorithmic systems shape what users see, know, and do -- from recommendation feeds to search ranking to credit scoring to hiring software. Covers the mechanics of recommendation systems, algorithmic bias and its sources, personalization's effects on information diets, opacity and accountability, AI limitations (hallucination, confident wrongness), and the human-in-the-loop question. Use when a learner needs to think critically about why particular content reached them.
algorithms-data-structuresAlgorithms and data structures from first principles through advanced analysis. Covers sorting (bubble, insertion, selection, merge, quick, heap, radix), searching (linear, binary, BFS, DFS, Dijkstra, A*), fundamental data structures (arrays, linked lists, stacks, queues, hash tables, trees, heaps, graphs, tries), complexity analysis (Big-O, Big-Omega, Big-Theta, amortized), recurrence relations, and algorithm design paradigms (divide-and-conquer, greedy, dynamic programming, backtracking). Use when analyzing, selecting, implementing, or comparing algorithms and data structures.
aminet-browserAminet search and browse: full-text search, category tree navigation, architecture filtering, package detail, and curated collections. Use when searching, browsing, or managing package collections.
aminet-emulatorFS-UAE emulator configuration and launch: hardware profiles, ROM management, WHDLoad integration, config generation, and state snapshots. Use when configuring emulation, managing ROMs, or launching Amiga software.