Skip to content

Latest commit

 

History

History
63 lines (42 loc) · 4.23 KB

File metadata and controls

63 lines (42 loc) · 4.23 KB

SQL Guild

Learn SQL by playing through a fantasy RPG. Instead of querying tables of employees and orders, you write real SQL against a game world of characters, quests, creatures, and items — clearing narrative levels as your queries get you further into the story.

Status: in active development. The core engine works today — real query execution, the first levels, and a free practice mode are all functional. Visual polish and persistent progress are in progress and called out explicitly below.


Why

Most people learn SQL against dry sample databases and forget it a week later. SQL Guild wraps the same concepts — SELECT, JOIN, filtering, aggregation — in a game world you actually want to explore. You learn by writing queries that do something: find the character, uncover the quest, count the creatures. The querying is real; only the dataset is fun.

What it does today

All functional now:

  • Narrative levels — progress through story-driven levels (three built so far) with characters and dialogue, solving a SQL challenge to advance
  • Live SQL sandbox — write a query, run it, and see the results in a table. Queries execute for real against the game database, not a fake preview
  • Practice mode — a separate free-drill mode with tagged exercises and practice sessions, for reps outside the story
  • Query validation — submitted SQL is normalised and validated before execution
  • A full fantasy game-world schema — races, professions, characters, locations, items, skills, quests, creatures and more, with seed data, so there's a rich world to query from the first level

How it works

app/api/query/route.ts   ← receives the player's SQL
        │
        ▼
lib/db.ts  createSeededDb()  ← fresh in-memory SQLite (:memory:)
        │                        schema (lib/schema.ts) + seed (lib/seed.ts)
        ▼
better-sqlite3 executes the query
        │
        ▼
QueryResultTable  ← results rendered back to the player

Built on Next.js (App Router) with React 19 and TypeScript. The database is better-sqlite3 running in-memory: createSeededDb() builds the schema and loads seed data on demand, so every query runs against a clean, fully-populated world.

Levels live in lib/levels/ (world background, characters, dialogue, per-level definitions, and validation); the practice system lives in lib/practice/ (exercises, sessions, tags). Domain types are modelled in lib/models/.

Design decisions

Why an in-memory, per-request database? Letting learners run arbitrary SQL is the whole point — and also the risk. Seeding a throwaway :memory: database means a player can run anything, including a bad query, without corrupting shared state: every request starts from a clean world. It's safe by construction.

The trade-off — and the current gap. Because the query database is ephemeral by design, player progress isn't persisted yet: which levels you've cleared and your practice history don't survive a reload. Separating "safe, resettable query execution" from "durable progress tracking" is deliberate — they're different layers — and the progress layer is the main build-out remaining (see roadmap).

Tech stack

Next.js 16 (App Router) · React 19 · TypeScript · better-sqlite3 · Tailwind CSS v4

Roadmap (planned — not yet complete)

  • Visual polish — a proper design pass on levels, the sandbox, and results
  • Persistent progress — save cleared levels and practice history across sessions (durable store + player identity)
  • More levels — extend beyond the current three, covering joins, aggregation, and subqueries in sequence
  • Hardened execution for shared data — if any query ever runs against persistent shared data, enforce read-only access and statement limits (arbitrary SQL against a durable DB is a real risk; the current ephemeral model sidesteps it)
  • Hint system and per-level solution checking

Status

In active development. Core query engine, the first levels, and practice mode are working; visual polish and progress persistence are underway. Personal / portfolio project.

Source-available for review and contribution; not licensed for reuse or redistribution.