Files
SpaceWanderer/lib/db/schema.ts
T

71 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { integer, primaryKey, real, sqliteTable, text } from 'drizzle-orm/sqlite-core'
// Drizzle schema for game state. Single-player by design: exactly ONE save row ever exists
// (no auth/accounts), so every table hangs off saves.id but only one save is in play.
// Column names/types here are the source of truth; matching CREATE TABLE statements live
// in lib/db/client.ts (DDL) and must stay in sync with this file.
export const saves = sqliteTable('saves', {
id: integer('id').primaryKey({ autoIncrement: true }),
// Seed for the deterministic world generator — same seed always regenerates the same world.
seed: text('seed').notNull(),
turn: integer('turn').notNull().default(0),
createdAt: text('created_at').notNull(),
})
export const solarSystems = sqliteTable('solar_systems', {
id: integer('id').primaryKey({ autoIncrement: true }),
saveId: integer('save_id').notNull().references(() => saves.id),
name: text('name').notNull(),
// 0–100 coordinate space, rendered directly by the NodeGraph component.
x: real('x').notNull(),
y: real('y').notNull(),
discovered: integer('discovered', { mode: 'boolean' }).notNull().default(false),
isCurrent: integer('is_current', { mode: 'boolean' }).notNull().default(false),
})
// Jump routes, stored as directed pairs (both directions of each route) so adjacency and
// "reachable from current" are single-row lookups. Read side dedupes for display.
export const jumpRoutes = sqliteTable(
'jump_routes',
{
fromSystem: integer('from_system').notNull().references(() => solarSystems.id),
toSystem: integer('to_system').notNull().references(() => solarSystems.id),
},
(t) => [primaryKey({ columns: [t.fromSystem, t.toSystem] })],
)
// Bodies of a solar system: planets (parent_id NULL) and moons (parent_id = their planet's
// id). Generated when the system is generated, so every system has 2–5 planets, some with
// 1–3 moons. Insertion order is display order — a moon always follows its parent row.
export const planets = sqliteTable('planets', {
id: integer('id').primaryKey({ autoIncrement: true }),
systemId: integer('system_id').notNull().references(() => solarSystems.id),
parentId: integer('parent_id'), // NULL for a planet, set for a moon
name: text('name').notNull(),
type: text('type').notNull(),
hazard: integer('hazard', { mode: 'boolean' }).notNull().default(false),
explored: integer('explored', { mode: 'boolean' }).notNull().default(false),
})
// Dumb-simple cargo hold on the save: what exploration has found so far. SHIP SYSTEMS (#8)
// will spend parts from here later; nothing consumes it yet.
export const inventoryItems = sqliteTable('inventory_items', {
id: integer('id').primaryKey({ autoIncrement: true }),
saveId: integer('save_id').notNull().references(() => saves.id),
kind: text('kind').notNull(), // 'resource' | 'part'
name: text('name').notNull(),
qty: integer('qty').notNull().default(1),
})
// Append-only game log. Writers so far: new-game + jump events; later issues add more
// writers and a read endpoint.
export const events = sqliteTable('events', {
id: integer('id').primaryKey({ autoIncrement: true }),
saveId: integer('save_id').notNull().references(() => saves.id),
turn: integer('turn').notNull(),
type: text('type').notNull(),
message: text('message').notNull(),
createdAt: text('created_at').notNull(),
})