diff --git a/app/game-engine/package.json b/app/game-engine/package.json index 31d8507f..e309009a 100644 --- a/app/game-engine/package.json +++ b/app/game-engine/package.json @@ -12,7 +12,6 @@ "typecheck": "tsc -b" }, "dependencies": { - "@prisma/client": "^7.2.0", "@sammo-ts/common": "workspace:*", "@sammo-ts/infra": "workspace:*", "@sammo-ts/logic": "workspace:*", diff --git a/app/game-engine/src/scenario/scenarioSeeder.ts b/app/game-engine/src/scenario/scenarioSeeder.ts index 87d43069..3c8de401 100644 --- a/app/game-engine/src/scenario/scenarioSeeder.ts +++ b/app/game-engine/src/scenario/scenarioSeeder.ts @@ -1,6 +1,9 @@ -import type { Prisma } from '@prisma/client'; - -import { createPostgresConnector } from '@sammo-ts/infra'; +import { + createPostgresConnector, + type InputJsonValue, + type TurnEngineDatabaseClient, + type TurnEngineEventCreateManyInput, +} from '@sammo-ts/infra'; import { buildScenarioBootstrap, type ScenarioBootstrapWarning, @@ -37,8 +40,7 @@ export interface ScenarioSeedResult { warnings: ScenarioBootstrapWarning[]; } -const asJson = (value: unknown): Prisma.InputJsonValue => - value as Prisma.InputJsonValue; +const asJson = (value: unknown): InputJsonValue => value as InputJsonValue; const resolveGeneralAge = ( startYear: number | null, @@ -53,8 +55,8 @@ const resolveGeneralAge = ( const buildEventRows = ( rows: unknown[], targetOverride?: string -): Prisma.EventCreateManyInput[] => { - const result: Prisma.EventCreateManyInput[] = []; +): TurnEngineEventCreateManyInput[] => { + const result: TurnEngineEventCreateManyInput[] = []; for (const row of rows) { if (!Array.isArray(row)) { @@ -123,7 +125,7 @@ export const seedScenarioToDatabase = async ( await connector.connect(); try { - const prisma = connector.prisma; + const prisma = connector.prisma as TurnEngineDatabaseClient; if (options.resetTables ?? true) { await prisma.event.deleteMany(); diff --git a/app/game-engine/src/turn/databaseHooks.ts b/app/game-engine/src/turn/databaseHooks.ts index fbc06e39..fca58cb0 100644 --- a/app/game-engine/src/turn/databaseHooks.ts +++ b/app/game-engine/src/turn/databaseHooks.ts @@ -1,6 +1,16 @@ -import type { Prisma } from '@prisma/client'; - -import { createPostgresConnector } from '@sammo-ts/infra'; +import { + createPostgresConnector, + type InputJsonValue, + type TurnEngineCityUpdateInput, + type TurnEngineDatabaseClient, + type TurnEngineGeneralCreateManyInput, + type TurnEngineGeneralUpdateInput, + type TurnEngineLogEntryCreateManyInput, + type TurnEngineNationUpdateInput, + type TurnEngineTroopCreateManyInput, + type TurnEngineTroopUpdateInput, + type TurnEngineWorldStateUpdateInput, +} from '@sammo-ts/infra'; import { finalizeLogEntry, type LogEntryDraft } from '@sammo-ts/logic'; import type { TurnDaemonHooks } from '../lifecycle/types.js'; @@ -12,8 +22,7 @@ export interface DatabaseTurnHooks { close(): Promise; } -const asJson = (value: unknown): Prisma.InputJsonValue => - value as Prisma.InputJsonValue; +const asJson = (value: unknown): InputJsonValue => value as InputJsonValue; const toCode = (value: string | null | undefined): string => value && value !== 'None' ? value : 'None'; @@ -28,7 +37,7 @@ const readMetaNumber = ( const buildGeneralUpdate = ( general: ReturnType['generals'][number] -): Prisma.GeneralUpdateInput => ({ +): TurnEngineGeneralUpdateInput => ({ name: general.name, nationId: general.nationId, cityId: general.cityId, @@ -62,7 +71,7 @@ const buildGeneralUpdate = ( const buildGeneralCreate = ( general: ReturnType['generals'][number] -): Prisma.GeneralCreateManyInput => ({ +): TurnEngineGeneralCreateManyInput => ({ id: general.id, name: general.name, nationId: general.nationId, @@ -97,13 +106,13 @@ const buildGeneralCreate = ( const buildCityUpdate = ( city: ReturnType['cities'][number] -): Prisma.CityUpdateInput => { +): TurnEngineCityUpdateInput => { const meta = city.meta as Record; const trust = readMetaNumber(meta, 'trust'); const trade = readMetaNumber(meta, 'trade'); const region = readMetaNumber(meta, 'region'); - const data: Prisma.CityUpdateInput = { + const data: TurnEngineCityUpdateInput = { name: city.name, nationId: city.nationId, level: city.level, @@ -139,7 +148,7 @@ const buildCityUpdate = ( const buildNationUpdate = ( nation: ReturnType['nations'][number] -): Prisma.NationUpdateInput => ({ +): TurnEngineNationUpdateInput => ({ name: nation.name, color: nation.color, capitalCityId: nation.capitalCityId, @@ -152,14 +161,14 @@ const buildNationUpdate = ( const buildTroopUpdate = ( troop: ReturnType['troops'][number] -): Prisma.TroopUpdateInput => ({ +): TurnEngineTroopUpdateInput => ({ nationId: troop.nationId, name: troop.name, }); const buildTroopCreate = ( troop: ReturnType['troops'][number] -): Prisma.TroopCreateManyInput => ({ +): TurnEngineTroopCreateManyInput => ({ troopLeaderId: troop.id, nationId: troop.nationId, name: troop.name, @@ -168,7 +177,7 @@ const buildTroopCreate = ( const buildLogCreateData = ( entry: LogEntryDraft, context: { year: number; month: number; at: Date } -): Prisma.LogEntryCreateManyInput | null => { +): TurnEngineLogEntryCreateManyInput | null => { const record = finalizeLogEntry(entry, { year: context.year, month: context.month, @@ -201,6 +210,7 @@ export const createDatabaseTurnHooks = async ( // 턴 처리 결과를 DB에 반영하는 훅을 만든다. const connector = createPostgresConnector({ url: databaseUrl }); await connector.connect(); + const prisma = connector.prisma as TurnEngineDatabaseClient; const hooks: TurnDaemonHooks = { flushChanges: async () => { @@ -215,14 +225,15 @@ export const createDatabaseTurnHooks = async ( createdTroops, } = world.consumeDirtyState(); - await connector.prisma.worldState.update({ + const worldStateUpdate: TurnEngineWorldStateUpdateInput = { + currentYear: state.currentYear, + currentMonth: state.currentMonth, + tickSeconds: state.tickSeconds, + meta: asJson(state.meta), + }; + await prisma.worldState.update({ where: { id: state.id }, - data: { - currentYear: state.currentYear, - currentMonth: state.currentMonth, - tickSeconds: state.tickSeconds, - meta: asJson(state.meta), - }, + data: worldStateUpdate, }); const createdIds = new Set( @@ -233,12 +244,12 @@ export const createDatabaseTurnHooks = async ( ); if (createdGenerals.length > 0) { - await connector.prisma.general.createMany({ + await prisma.general.createMany({ data: createdGenerals.map(buildGeneralCreate), }); } if (createdTroops.length > 0) { - await connector.prisma.troop.createMany({ + await prisma.troop.createMany({ data: createdTroops.map(buildTroopCreate), }); } @@ -247,19 +258,19 @@ export const createDatabaseTurnHooks = async ( ...generals .filter((general) => !createdIds.has(general.id)) .map((general) => - connector.prisma.general.update({ + prisma.general.update({ where: { id: general.id }, data: buildGeneralUpdate(general), }) ), ...cities.map((city) => - connector.prisma.city.update({ + prisma.city.update({ where: { id: city.id }, data: buildCityUpdate(city), }) ), ...nations.map((nation) => - connector.prisma.nation.update({ + prisma.nation.update({ where: { id: nation.id }, data: buildNationUpdate(nation), }) @@ -267,7 +278,7 @@ export const createDatabaseTurnHooks = async ( ...troops .filter((troop) => !createdTroopIds.has(troop.id)) .map((troop) => - connector.prisma.troop.update({ + prisma.troop.update({ where: { troopLeaderId: troop.id }, data: buildTroopUpdate(troop), }) @@ -283,11 +294,13 @@ export const createDatabaseTurnHooks = async ( const payload = logs .map((entry) => buildLogCreateData(entry, logContext)) .filter( - (entry): entry is Prisma.LogEntryCreateManyInput => + ( + entry + ): entry is TurnEngineLogEntryCreateManyInput => Boolean(entry) ); if (payload.length > 0) { - await connector.prisma.logEntry.createMany({ + await prisma.logEntry.createMany({ data: payload, }); } diff --git a/app/game-engine/src/turn/reservedTurnStore.ts b/app/game-engine/src/turn/reservedTurnStore.ts index 71129abf..90f90fa0 100644 --- a/app/game-engine/src/turn/reservedTurnStore.ts +++ b/app/game-engine/src/turn/reservedTurnStore.ts @@ -1,6 +1,8 @@ -import type { Prisma } from '@prisma/client'; - -import { createPostgresConnector } from '@sammo-ts/infra'; +import { + createPostgresConnector, + type InputJsonValue, + type TurnEngineDatabaseClient, +} from '@sammo-ts/infra'; export interface ReservedTurnEntry { action: string; @@ -22,8 +24,7 @@ const DEFAULT_TURN_ACTION = '휴식'; const DEFAULT_GENERAL_TURNS = 30; const DEFAULT_NATION_TURNS = 12; -const asJson = (value: unknown): Prisma.InputJsonValue => - value as Prisma.InputJsonValue; +const asJson = (value: unknown): InputJsonValue => value as InputJsonValue; const isRecord = (value: unknown): value is Record => value !== null && typeof value === 'object' && !Array.isArray(value); @@ -81,50 +82,10 @@ const buildTurnListFromRows = ( const buildNationKey = (nationId: number, officerLevel: number): string => `${nationId}:${officerLevel}`; -interface PrismaReservedTurnClient { - generalTurn: { - findMany(args?: unknown): Promise< - Array<{ - generalId: number; - turnIdx: number; - actionCode: string; - arg: unknown; - }> - >; - deleteMany(args: { where: { generalId: number } }): Promise; - createMany(args: { - data: Array<{ - generalId: number; - turnIdx: number; - actionCode: string; - arg: Prisma.InputJsonValue; - }>; - }): Promise; - }; - nationTurn: { - findMany(args?: unknown): Promise< - Array<{ - nationId: number; - officerLevel: number; - turnIdx: number; - actionCode: string; - arg: unknown; - }> - >; - deleteMany(args: { - where: { nationId: number; officerLevel: number }; - }): Promise; - createMany(args: { - data: Array<{ - nationId: number; - officerLevel: number; - turnIdx: number; - actionCode: string; - arg: Prisma.InputJsonValue; - }>; - }): Promise; - }; -} +type ReservedTurnDatabaseClient = Pick< + TurnEngineDatabaseClient, + 'generalTurn' | 'nationTurn' +>; export class InMemoryReservedTurnStore { private readonly generalTurns = new Map(); @@ -135,7 +96,7 @@ export class InMemoryReservedTurnStore { private readonly maxNationTurns: number; constructor( - private readonly prisma: PrismaClientOrAdapter, + private readonly prisma: ReservedTurnDatabaseClient, options: { maxGeneralTurns: number; maxNationTurns: number } ) { this.maxGeneralTurns = options.maxGeneralTurns; @@ -305,18 +266,13 @@ export class InMemoryReservedTurnStore { } } -type PrismaClientOrAdapter = ReturnType< - typeof createPostgresConnector ->['prisma'] & - PrismaReservedTurnClient; - export const createReservedTurnStore = async ( options: ReservedTurnStoreOptions ): Promise => { const connector = createPostgresConnector({ url: options.databaseUrl }); await connector.connect(); const store = new InMemoryReservedTurnStore( - connector.prisma as PrismaClientOrAdapter, + connector.prisma as ReservedTurnDatabaseClient, { maxGeneralTurns: options.maxGeneralTurns ?? DEFAULT_GENERAL_TURNS, maxNationTurns: options.maxNationTurns ?? DEFAULT_NATION_TURNS, diff --git a/app/game-engine/src/turn/worldLoader.ts b/app/game-engine/src/turn/worldLoader.ts index 28307d2f..3d1a4ac3 100644 --- a/app/game-engine/src/turn/worldLoader.ts +++ b/app/game-engine/src/turn/worldLoader.ts @@ -1,13 +1,13 @@ -import type { - City as PrismaCity, - Diplomacy as PrismaDiplomacy, - General as PrismaGeneral, - Nation as PrismaNation, - Prisma, - Troop as PrismaTroop, -} from '@prisma/client'; - -import { createPostgresConnector } from '@sammo-ts/infra'; +import { + createPostgresConnector, + type JsonValue, + type TurnEngineCityRow, + type TurnEngineDatabaseClient, + type TurnEngineDiplomacyRow, + type TurnEngineGeneralRow, + type TurnEngineNationRow, + type TurnEngineTroopRow, +} from '@sammo-ts/infra'; import type { City, Nation, @@ -126,7 +126,7 @@ const alignToPreviousTick = (base: Date, tickMinutes: number): Date => { return new Date(nextTick.getTime() - tickMinutes * 60_000); }; -const mapScenarioConfig = (raw: Prisma.JsonValue): ScenarioConfig => { +const mapScenarioConfig = (raw: JsonValue): ScenarioConfig => { const parsed = zScenarioConfig.safeParse(raw); if (!parsed.success) { throw new Error(`world_state.config is invalid: ${parsed.error.message}`); @@ -134,7 +134,7 @@ const mapScenarioConfig = (raw: Prisma.JsonValue): ScenarioConfig => { return parsed.data; }; -const mapGeneralRow = (row: PrismaGeneral): TurnGeneral => ({ +const mapGeneralRow = (row: TurnEngineGeneralRow): TurnGeneral => ({ id: row.id, name: row.name, nationId: row.nationId, @@ -179,7 +179,7 @@ const mapGeneralRow = (row: PrismaGeneral): TurnGeneral => ({ recentWarTime: row.recentWarTime ?? null, }); -const mapCityRow = (row: PrismaCity): City => ({ +const mapCityRow = (row: TurnEngineCityRow): City => ({ id: row.id, name: row.name, nationId: row.nationId, @@ -206,7 +206,7 @@ const mapCityRow = (row: PrismaCity): City => ({ }, }); -const mapNationRow = (row: PrismaNation): Nation => ({ +const mapNationRow = (row: TurnEngineNationRow): Nation => ({ id: row.id, name: row.name, color: row.color, @@ -223,14 +223,14 @@ const mapNationRow = (row: PrismaNation): Nation => ({ }, }); -const mapDiplomacyRow = (row: PrismaDiplomacy): ScenarioDiplomacy => ({ +const mapDiplomacyRow = (row: TurnEngineDiplomacyRow): ScenarioDiplomacy => ({ fromNationId: row.srcNationId, toNationId: row.destNationId, state: row.stateCode, durationMonths: row.term, }); -const mapTroopRow = (row: PrismaTroop): Troop => ({ +const mapTroopRow = (row: TurnEngineTroopRow): Troop => ({ id: row.troopLeaderId, nationId: row.nationId, name: row.name, @@ -242,7 +242,7 @@ export const loadTurnWorldFromDatabase = async ( const connector = createPostgresConnector({ url: options.databaseUrl }); await connector.connect(); try { - const prisma = connector.prisma; + const prisma = connector.prisma as TurnEngineDatabaseClient; const worldState = await prisma.worldState.findFirst(); if (!worldState) { throw new Error('world_state row is required to start turn daemon.'); diff --git a/app/game-engine/test/scenarioSeeder.test.ts b/app/game-engine/test/scenarioSeeder.test.ts index 6742ccfe..7b267abb 100644 --- a/app/game-engine/test/scenarioSeeder.test.ts +++ b/app/game-engine/test/scenarioSeeder.test.ts @@ -6,11 +6,31 @@ import { seedScenarioToDatabase } from '../src/scenario/scenarioSeeder.js'; const scenarioId = 1010; const databaseUrl = await resolveDatabaseUrl(); +type ScenarioSeederPrismaClient = { + $queryRawUnsafe(query: string): Promise; + nation: { + count(): Promise; + }; + city: { + count(): Promise; + }; + general: { + count(): Promise; + }; + diplomacy: { + count(): Promise; + findFirst(args: { + where: { srcNationId: number; destNationId: number }; + }): Promise<{ stateCode: string } | null>; + }; +}; + const canConnectToDatabase = async (url: string): Promise => { const connector = createPostgresConnector({ url }); try { await connector.connect(); - await connector.prisma.$queryRawUnsafe('SELECT 1'); + const prisma = connector.prisma as ScenarioSeederPrismaClient; + await prisma.$queryRawUnsafe('SELECT 1'); return true; } catch { return false; @@ -32,7 +52,7 @@ describeDb('scenario database seed', () => { const connector = createPostgresConnector({ url: databaseUrl }); await connector.connect(); try { - const prisma = connector.prisma; + const prisma = connector.prisma as ScenarioSeederPrismaClient; const [ nationCount, cityCount, diff --git a/app/gateway-api/src/server.ts b/app/gateway-api/src/server.ts index 92aa9a82..0dcc5ab1 100644 --- a/app/gateway-api/src/server.ts +++ b/app/gateway-api/src/server.ts @@ -1,6 +1,7 @@ import fastify from 'fastify'; import cors from '@fastify/cors'; import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify'; +import type { PrismaClient } from '@prisma/client'; import { createPostgresConnector, createRedisConnector, @@ -24,7 +25,9 @@ export const createGatewayApiServer = async () => { await postgres.connect(); await redis.connect(); - const users = createPostgresUserRepository(postgres.prisma); + const users = createPostgresUserRepository( + postgres.prisma as PrismaClient + ); const sessions = new RedisGatewaySessionService(redis.client, { keyPrefix: config.redisKeyPrefix, sessionTtlSeconds: config.sessionTtlSeconds, diff --git a/packages/infra/src/index.ts b/packages/infra/src/index.ts index 1d804de7..99c14c3d 100644 --- a/packages/infra/src/index.ts +++ b/packages/infra/src/index.ts @@ -2,3 +2,4 @@ export * from './postgres.js'; export * from './db.js'; export * from './logRepository.js'; export * from './redis.js'; +export * from './turnEngineDb.js'; diff --git a/packages/infra/src/postgres.ts b/packages/infra/src/postgres.ts index d7e8c4e0..404d3d6f 100644 --- a/packages/infra/src/postgres.ts +++ b/packages/infra/src/postgres.ts @@ -1,14 +1,23 @@ -import { Prisma, PrismaClient } from '@prisma/client'; +import { PrismaClient } from '@prisma/client'; import { PrismaPg } from '@prisma/adapter-pg'; import { Pool } from 'pg'; +export type PostgresLogLevel = 'query' | 'info' | 'warn' | 'error'; + +export type PostgresLogOption = + | PostgresLogLevel + | { + emit: 'stdout' | 'event'; + level: PostgresLogLevel; + }; + export interface PostgresConfig { url: string; - log?: Prisma.PrismaClientOptions['log']; + log?: PostgresLogOption[]; } -export interface PostgresConnector { - readonly prisma: PrismaClient; +export interface PostgresConnector { + readonly prisma: TClient; connect(): Promise; disconnect(): Promise; } diff --git a/packages/infra/src/turnEngineDb.ts b/packages/infra/src/turnEngineDb.ts new file mode 100644 index 00000000..454d1971 --- /dev/null +++ b/packages/infra/src/turnEngineDb.ts @@ -0,0 +1,440 @@ +export type JsonValue = + | null + | boolean + | number + | string + | JsonValue[] + | { [key: string]: JsonValue }; + +export type InputJsonValue = JsonValue; + +export interface TurnEngineWorldStateRow { + id: number; + scenarioCode: string; + currentYear: number; + currentMonth: number; + tickSeconds: number; + config: JsonValue; + meta: JsonValue; + updatedAt?: Date | null; +} + +export interface TurnEngineGeneralRow { + id: number; + name: string; + nationId: number; + cityId: number; + troopId: number; + leadership: number; + strength: number; + intel: number; + experience: number; + dedication: number; + officerLevel: number; + personalCode: string | null; + specialCode: string | null; + special2Code: string | null; + horseCode: string | null; + weaponCode: string | null; + bookCode: string | null; + itemCode: string | null; + injury: number; + gold: number; + rice: number; + crew: number; + crewTypeId: number; + train: number; + atmos: number; + age: number; + npcState: number; + meta: JsonValue; + turnTime: Date; + recentWarTime: Date | null; +} + +export interface TurnEngineCityRow { + id: number; + name: string; + nationId: number; + level: number; + population: number; + populationMax: number; + agriculture: number; + agricultureMax: number; + commerce: number; + commerceMax: number; + security: number; + securityMax: number; + supplyState: number; + frontState: number; + defence: number; + defenceMax: number; + wall: number; + wallMax: number; + meta: JsonValue; + trust: number; + trade: number; + region: number; +} + +export interface TurnEngineNationRow { + id: number; + name: string; + color: string; + capitalCityId: number | null; + gold: number; + rice: number; + tech: number; + level: number; + typeCode: string; + meta: JsonValue; +} + +export interface TurnEngineDiplomacyRow { + srcNationId: number; + destNationId: number; + stateCode: number; + term: number; +} + +export interface TurnEngineTroopRow { + troopLeaderId: number; + nationId: number; + name: string; +} + +export interface TurnEngineEventRow { + id: number; + targetCode: string; + priority: number; + condition: JsonValue; + action: JsonValue; + meta: JsonValue; +} + +export interface TurnEngineGeneralTurnRow { + generalId: number; + turnIdx: number; + actionCode: string; + arg: JsonValue; +} + +export interface TurnEngineNationTurnRow { + nationId: number; + officerLevel: number; + turnIdx: number; + actionCode: string; + arg: JsonValue; +} + +export interface TurnEngineWorldStateUpdateInput { + currentYear: number; + currentMonth: number; + tickSeconds: number; + meta: InputJsonValue; +} + +export interface TurnEngineWorldStateCreateInput { + scenarioCode: string; + currentYear: number; + currentMonth: number; + tickSeconds: number; + config: InputJsonValue; + meta: InputJsonValue; +} + +export interface TurnEngineGeneralUpdateInput { + name: string; + nationId: number; + cityId: number; + troopId: number | null; + leadership: number; + strength: number; + intel: number; + experience: number; + dedication: number; + officerLevel: number; + injury: number; + gold: number; + rice: number; + crew: number; + crewTypeId: number; + train: number; + atmos: number; + age: number; + npcState: number; + horseCode: string; + weaponCode: string; + bookCode: string; + itemCode: string; + personalCode: string; + specialCode: string; + special2Code: string; + meta: InputJsonValue; + turnTime: Date; + recentWarTime: Date | null; +} + +export interface TurnEngineGeneralCreateManyInput { + id: number; + name: string; + nationId: number; + cityId: number; + troopId?: number | null; + npcState: number; + leadership: number; + strength: number; + intel: number; + experience?: number; + dedication?: number; + officerLevel: number; + injury?: number; + gold: number; + rice: number; + crew?: number; + crewTypeId: number; + train?: number; + atmos?: number; + age: number; + horseCode: string; + weaponCode: string; + bookCode: string; + itemCode: string; + personalCode: string; + specialCode: string; + special2Code: string; + meta: InputJsonValue; + turnTime: Date; + recentWarTime?: Date | null; + affinity?: number | null; + bornYear?: number; + deadYear?: number; + picture?: string | null; + lastTurn?: InputJsonValue; + penalty?: InputJsonValue; +} + +export interface TurnEngineCityUpdateInput { + name: string; + nationId: number; + level: number; + population: number; + populationMax: number; + agriculture: number; + agricultureMax: number; + commerce: number; + commerceMax: number; + security: number; + securityMax: number; + supplyState: number; + frontState: number; + defence: number; + defenceMax: number; + wall: number; + wallMax: number; + meta: InputJsonValue; + trust?: number; + trade?: number; + region?: number; +} + +export interface TurnEngineCityCreateManyInput { + id: number; + name: string; + level: number; + nationId: number; + supplyState: number; + frontState: number; + population: number; + populationMax: number; + agriculture: number; + agricultureMax: number; + commerce: number; + commerceMax: number; + security: number; + securityMax: number; + trust: number; + trade: number; + defence: number; + defenceMax: number; + wall: number; + wallMax: number; + region: number; + conflict: InputJsonValue; + meta: InputJsonValue; +} + +export interface TurnEngineNationUpdateInput { + name: string; + color: string; + capitalCityId: number | null; + gold: number; + rice: number; + level: number; + typeCode: string; + meta: InputJsonValue; +} + +export interface TurnEngineNationCreateManyInput { + id: number; + name: string; + color: string; + capitalCityId: number | null; + gold: number; + rice: number; + tech: number; + level: number; + typeCode: string; + meta: InputJsonValue; +} + +export interface TurnEngineTroopUpdateInput { + nationId: number; + name: string; +} + +export interface TurnEngineTroopCreateManyInput { + troopLeaderId: number; + nationId: number; + name: string; +} + +export interface TurnEngineDiplomacyCreateManyInput { + srcNationId: number; + destNationId: number; + stateCode: number; + term: number; + meta: InputJsonValue; +} + +export interface TurnEngineEventCreateManyInput { + targetCode: string; + priority: number; + condition: InputJsonValue; + action: InputJsonValue; + meta: InputJsonValue; +} + +export interface TurnEngineLogEntryCreateManyInput { + scope: string; + category: string; + subType: string | null; + year: number; + month: number; + text: string; + generalId: number | null; + nationId: number | null; + userId: number | null; + meta: InputJsonValue; + createdAt?: Date; +} + +export interface TurnEngineDatabaseClient { + worldState: { + findFirst(args?: unknown): Promise; + update(args: { + where: { id: number }; + data: TurnEngineWorldStateUpdateInput; + }): Promise; + create(args: { + data: TurnEngineWorldStateCreateInput; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + general: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineGeneralCreateManyInput[]; + }): Promise; + update(args: { + where: { id: number }; + data: TurnEngineGeneralUpdateInput; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + city: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineCityCreateManyInput[]; + }): Promise; + update(args: { + where: { id: number }; + data: TurnEngineCityUpdateInput; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + nation: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineNationCreateManyInput[]; + }): Promise; + update(args: { + where: { id: number }; + data: TurnEngineNationUpdateInput; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + diplomacy: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineDiplomacyCreateManyInput[]; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + troop: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineTroopCreateManyInput[]; + }): Promise; + update(args: { + where: { troopLeaderId: number }; + data: TurnEngineTroopUpdateInput; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + event: { + findMany(args?: unknown): Promise; + createMany(args: { + data: TurnEngineEventCreateManyInput[]; + }): Promise; + deleteMany(args?: unknown): Promise; + }; + logEntry: { + createMany(args: { + data: TurnEngineLogEntryCreateManyInput[]; + }): Promise; + }; + generalTurn: { + findMany(args?: { + where?: { generalId?: number }; + orderBy?: { turnIdx: 'asc' | 'desc' }[]; + }): Promise; + deleteMany(args: { where: { generalId: number } }): Promise; + createMany(args: { + data: Array<{ + generalId: number; + turnIdx: number; + actionCode: string; + arg: InputJsonValue; + }>; + }): Promise; + }; + nationTurn: { + findMany(args?: { + where?: { nationId?: number; officerLevel?: number }; + orderBy?: { turnIdx: 'asc' | 'desc' }[]; + }): Promise; + deleteMany(args: { + where: { nationId: number; officerLevel: number }; + }): Promise; + createMany(args: { + data: Array<{ + nationId: number; + officerLevel: number; + turnIdx: number; + actionCode: string; + arg: InputJsonValue; + }>; + }): Promise; + }; +}