feat: refactor database connection handling and add legacy map loading functionality

- Updated check-connections.mts to use Prisma with PostgreSQL adapter.
- Introduced databaseUrl.ts for resolving database URLs from environment variables.
- Added legacyMapLoader.ts to load and parse legacy map data.
- Implemented scenarioSeeder.ts to seed scenario data into the database.
- Created tests for scenario seeding in scenarioSeeder.test.ts.
- Configured Prisma datasource in prisma.config.ts to support dynamic database URLs.
This commit is contained in:
2025-12-29 05:49:25 +00:00
parent 7124483001
commit 9fe4c8f96c
12 changed files with 1863 additions and 81 deletions
+5 -2
View File
@@ -13,11 +13,14 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@prisma/client": "^5.18.0",
"@prisma/adapter-pg": "^7.2.0",
"@prisma/client": "^7.2.0",
"pg": "^8.16.3",
"redis": "^4.7.0"
},
"devDependencies": {
"prisma": "^5.18.0",
"dotenv": "^17.2.3",
"prisma": "^7.2.0",
"tsdown": "^0.18.3"
}
}
+22
View File
@@ -0,0 +1,22 @@
import 'dotenv/config';
import { defineConfig } from 'prisma/config';
const buildDatabaseUrlFromEnv = (): string => {
const host = process.env.POSTGRES_HOST ?? '127.0.0.1';
const port = process.env.POSTGRES_PORT ?? '15432';
const user = process.env.POSTGRES_USER ?? 'sammo';
const password = process.env.POSTGRES_PASSWORD ?? '';
const dbName = process.env.POSTGRES_DB ?? 'sammo';
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
};
const databaseUrl =
process.env.DATABASE_URL ?? buildDatabaseUrlFromEnv();
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: databaseUrl,
},
});
+127 -2
View File
@@ -4,7 +4,132 @@ generator client {
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// TODO: Translate docs/architecture/postgres-schema.md into Prisma models.
model WorldState {
id Int @id @default(autoincrement())
scenarioCode String @map("scenario_code")
currentYear Int @map("current_year")
currentMonth Int @map("current_month")
tickSeconds Int @map("tick_seconds")
config Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
updatedAt DateTime @updatedAt @map("updated_at")
@@map("world_state")
}
model Nation {
id Int @id
name String
color String
capitalCityId Int? @map("capital_city_id")
gold Int @default(0)
rice Int @default(0)
tech Float @default(0)
level Int @default(0)
typeCode String @default("che_중립") @map("type_code")
meta Json @default(dbgenerated("'{}'::jsonb"))
@@map("nation")
}
model City {
id Int @id
name String
level Int
nationId Int @default(0) @map("nation_id")
supplyState Int @default(1) @map("supply_state")
frontState Int @default(0) @map("front_state")
population Int @map("pop")
populationMax Int @map("pop_max")
agriculture Int @map("agri")
agricultureMax Int @map("agri_max")
commerce Int @map("comm")
commerceMax Int @map("comm_max")
security Int @map("secu")
securityMax Int @map("secu_max")
trust Int @default(0)
trade Int @default(100)
defence Int @map("def")
defenceMax Int @map("def_max")
wall Int @map("wall")
wallMax Int @map("wall_max")
region Int
conflict Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
@@map("city")
}
model General {
id Int @id
name String
nationId Int @default(0) @map("nation_id")
cityId Int @default(0) @map("city_id")
troopId Int @default(0) @map("troop_id")
npcState Int @default(0) @map("npc_state")
affinity Int?
bornYear Int @default(180) @map("born_year")
deadYear Int @default(300) @map("dead_year")
picture String?
imageServer Int @default(0) @map("image_server")
leadership Int @default(50)
strength Int @default(50)
intel Int @default(50)
injury Int @default(0)
experience Int @default(0)
dedication Int @default(0)
officerLevel Int @default(0) @map("officer_level")
gold Int @default(1000)
rice Int @default(1000)
crew Int @default(0)
crewTypeId Int @default(0) @map("crew_type_id")
train Int @default(0)
atmos Int @default(0)
weaponCode String @default("None") @map("weapon_code")
bookCode String @default("None") @map("book_code")
horseCode String @default("None") @map("horse_code")
itemCode String @default("None") @map("item_code")
turnTime DateTime @map("turn_time")
recentWarTime DateTime? @map("recent_war_time")
age Int @default(20)
startAge Int @default(20) @map("start_age")
personalCode String @default("None") @map("personal_code")
specialCode String @default("None") @map("special_code")
special2Code String @default("None") @map("special2_code")
lastTurn Json @default(dbgenerated("'{}'::jsonb")) @map("last_turn")
meta Json @default(dbgenerated("'{}'::jsonb"))
penalty Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @map("updated_at")
@@map("general")
}
model Diplomacy {
id Int @id @default(autoincrement())
srcNationId Int @map("src_nation_id")
destNationId Int @map("dest_nation_id")
stateCode Int @map("state_code")
term Int @default(0)
isDead Boolean @default(false) @map("is_dead")
isShowing Boolean @default(true) @map("is_showing")
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
@@unique([srcNationId, destNationId])
@@map("diplomacy")
}
model Event {
id Int @id @default(autoincrement())
targetCode String @map("target_code")
priority Int @default(0)
condition Json @default(dbgenerated("'{}'::jsonb"))
action Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
@@map("event")
}
+23 -7
View File
@@ -1,4 +1,6 @@
import { Prisma, PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { Pool } from 'pg';
export interface PostgresConfig {
url: string;
@@ -11,10 +13,21 @@ export interface PostgresConnector {
disconnect(): Promise<void>;
}
const buildDatabaseUrlFromEnv = (
env: NodeJS.ProcessEnv
): string => {
const host = env.POSTGRES_HOST ?? '127.0.0.1';
const port = env.POSTGRES_PORT ?? '15432';
const user = env.POSTGRES_USER ?? 'sammo';
const password = env.POSTGRES_PASSWORD ?? '';
const dbName = env.POSTGRES_DB ?? 'sammo';
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
};
export const resolvePostgresConfigFromEnv = (
env: NodeJS.ProcessEnv = process.env
): PostgresConfig => {
const url = env.DATABASE_URL ?? '';
const url = env.DATABASE_URL ?? buildDatabaseUrlFromEnv(env);
if (!url) {
throw new Error('DATABASE_URL is required to create a Postgres client.');
}
@@ -25,18 +38,21 @@ export const resolvePostgresConfigFromEnv = (
export const createPostgresConnector = (
config: PostgresConfig
): PostgresConnector => {
const pool = new Pool({
connectionString: config.url,
});
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({
datasources: {
db: {
url: config.url,
},
},
adapter,
log: config.log,
});
return {
prisma,
connect: () => prisma.$connect(),
disconnect: () => prisma.$disconnect(),
disconnect: async () => {
await prisma.$disconnect();
await pool.end();
},
};
};