Files
website/src/lib/server/db/schema/cs-prices.ts
Stan Runge 64fb8df262 db: Drizzle schemas on domain Postgres schemas, baseline migration, reorg SQL
- pgSchema tables for auth, money, house, ref, games, cs, animaldex, site, meta
  (lists excluded via schemaFilter; runtime list tables are managed by meta.*)
- drizzle/ baseline matches the reorged DB exactly (catalog diff = 0 on rehearsal)
- db/reorg: one-time SQL that moves the flat public schema (rehearsed on a prod copy)
- scripts/db-migrate.ts: migrator with --init to record the baseline and a guard
  against running the baseline on a non-empty, unrecorded database
2026-10-23 22:03:42 +00:00

91 lines
2.5 KiB
TypeScript

import {
index,
integer,
primaryKey,
text,
timestamp,
uniqueIndex,
bigint
} from 'drizzle-orm/pg-core';
import { csSchema } from './schemas';
import { id } from './helpers';
// A Steam market hash name identifies a listing, including wear and special variants.
export const csMarketItems = csSchema.table(
'items',
{
id: id(),
marketHashName: text('market_hash_name').notNull(),
name: text('name').notNull(),
iconUrl: text('icon_url'),
itemType: text('item_type'),
firstSeenAt: timestamp('first_seen_at', { withTimezone: true }).notNull().defaultNow(),
lastSeenAt: timestamp('last_seen_at', { withTimezone: true }).notNull().defaultNow()
},
(table) => [
uniqueIndex('items_hash_idx').on(table.marketHashName),
index('items_name_idx').on(table.name)
]
);
// Keep source observations intact. Aggregation happens only when the chart is requested.
export const csPriceObservations = csSchema.table(
'price_observations',
{
id: bigint('id', { mode: 'number' }).primaryKey().generatedAlwaysAsIdentity(),
itemId: integer('item_id')
.notNull()
.references(() => csMarketItems.id, { onDelete: 'cascade' }),
source: text('source').notNull(),
currency: text('currency').notNull(),
observedAt: timestamp('observed_at', { withTimezone: true }).notNull(),
priceCents: integer('price_cents').notNull(),
volume: integer('volume'),
kind: text('kind').notNull(),
importedAt: timestamp('imported_at', { withTimezone: true }).notNull().defaultNow()
},
(table) => [
uniqueIndex('price_observations_unique_idx').on(
table.itemId,
table.source,
table.currency,
table.observedAt,
table.kind
),
index('price_observations_lookup_idx').on(
table.itemId,
table.source,
table.currency,
table.observedAt
),
index('price_observations_time_idx').on(table.observedAt)
]
);
export const csItemDimensions = csSchema.table(
'item_dimensions',
{
itemId: integer('item_id')
.notNull()
.references(() => csMarketItems.id, { onDelete: 'cascade' }),
key: text('key').notNull(),
value: text('value').notNull()
},
(table) => [
primaryKey({ name: 'item_dimensions_pkey', columns: [table.itemId, table.key] }),
index('item_dimensions_filter_idx').on(table.key, table.value, table.itemId)
]
);
export const csPriceStreams = csSchema.table(
'price_streams',
{
source: text('source').notNull(),
currency: text('currency').notNull(),
kind: text('kind').notNull()
},
(table) => [
primaryKey({ name: 'price_streams_pkey', columns: [table.source, table.currency, table.kind] })
]
);