Botanica/apps/server/src/schema.ts

99 lines
3.4 KiB
TypeScript

import {
pgTable,
text,
integer,
boolean,
uuid,
jsonb,
timestamp,
index,
unique,
type AnyPgColumn,
} from "drizzle-orm/pg-core";
export const species = pgTable("species", {
id: text().primaryKey(),
name: text().notNull(),
compatibilityGroup: text("compatibility_group").notNull(),
catalogVersion: integer("catalog_version").notNull(),
config: jsonb("config_jsonb").notNull(),
});
export const players = pgTable("players", {
id: uuid().primaryKey(),
displayName: text("display_name").notNull(),
normalizedUsername: text("normalized_username").unique(),
passwordHash: text("password_hash"),
coinBalance: integer("coin_balance").notNull().default(0),
xp: integer("xp").notNull().default(0),
gameStats: jsonb("game_stats").notNull().default({}),
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
});
export const plants = pgTable(
"plants",
{
id: uuid().primaryKey(),
name: text().notNull().default("Velvetleaf"),
creationSource: text("creation_source").notNull().default("designed"),
rarityReasons: jsonb("rarity_reasons").notNull().default([]),
gameEligible: boolean("game_eligible").notNull().default(false),
isFavorite: boolean("is_favorite").notNull().default(false),
isProtected: boolean("is_protected").notNull().default(false),
firstDiscovery: boolean("first_discovery").notNull().default(false),
soldAt: timestamp("sold_at", { withTimezone: true }),
ownerId: uuid("owner_id")
.notNull()
.references(() => players.id),
speciesId: text("species_id")
.notNull()
.references(() => species.id),
genomeVersion: integer("genome_version").notNull(),
genome: jsonb().notNull(),
mutations: jsonb().notNull(),
visualSeed: integer("visual_seed").notNull(),
rendererVersion: integer("renderer_version").notNull(),
rarityPolicyVersion: integer("rarity_policy_version").notNull(),
rarityScore: integer("rarity_score").notNull(),
rarityTier: text("rarity_tier").notNull(),
generation: integer().notNull(),
parentAId: uuid("parent_a_id").references((): AnyPgColumn => plants.id),
parentBId: uuid("parent_b_id").references((): AnyPgColumn => plants.id),
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
index("plants_owner_created").on(t.ownerId, t.createdAt.desc()),
index("plants_species_rarity").on(t.speciesId, t.rarityTier),
],
);
export const breedingEvents = pgTable(
"breeding_events",
{
id: uuid().primaryKey(),
ownerId: uuid("owner_id")
.notNull()
.references(() => players.id),
parentAId: uuid("parent_a_id")
.notNull()
.references(() => plants.id),
parentBId: uuid("parent_b_id")
.notNull()
.references(() => plants.id),
childId: uuid("child_id")
.notNull()
.references(() => plants.id),
rngSeed: integer("rng_seed").notNull(),
engineVersion: integer("engine_version").notNull(),
mutationEvents: jsonb("mutation_events").notNull(),
idempotencyKey: text("idempotency_key").notNull(),
createdAt: timestamp("created_at", { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
unique().on(t.childId),
unique("breeding_owner_request").on(t.ownerId, t.idempotencyKey),
index("breeding_owner_created").on(t.ownerId, t.createdAt.desc()),
],
);