feat(server): database migration

This commit is contained in:
RainbowBird
2026-02-26 15:01:06 +08:00
parent 3a107b7465
commit ea05075550
10 changed files with 588 additions and 383 deletions
+2
View File
@@ -16,6 +16,8 @@
"@electric-sql/pglite": "catalog:",
"@guiiai/logg": "catalog:",
"@hono/node-server": "^1.19.9",
"@proj-airi/drizzle-orm-browser-migrator": "^0.1.4",
"@proj-airi/server-schema": "workspace:*",
"better-auth": "^1.4.16",
"drizzle-orm": "^0.45.1",
"drizzle-valibot": "catalog:",
+11 -13
View File
@@ -1,6 +1,6 @@
import type { HonoEnv } from './types/hono'
import process, { exit } from 'node:process'
import process from 'node:process'
import { initLogger, LoggerFormat, LoggerLevel, useLogger } from '@guiiai/logg'
import { serve } from '@hono/node-server'
@@ -16,14 +16,12 @@ import { createProviderRoutes } from './routes/providers'
import { createAuth } from './services/auth'
import { createCharacterService } from './services/characters'
import { createChatService } from './services/chats'
import { createDrizzle } from './services/db'
import { createDrizzle, migrateDatabase } from './services/db'
import { parsedEnv } from './services/env'
import { createProviderService } from './services/providers'
import { ApiError, createInternalError } from './utils/error'
import { getTrustedOrigin } from './utils/origin'
import * as schema from './schemas'
type AuthService = ReturnType<typeof createAuth>
type CharacterService = ReturnType<typeof createCharacterService>
type ChatService = ReturnType<typeof createChatService>
@@ -93,17 +91,17 @@ export type AppType = ReturnType<typeof buildApp>
async function createApp() {
initLogger(LoggerLevel.Debug, LoggerFormat.Pretty)
injeca.setLogger(createLoggLogger(useLogger('injeca').useGlobalConfig()))
const logger = useLogger('app').useGlobalConfig()
const db = injeca.provide('services:db', {
dependsOn: { env: parsedEnv },
build: ({ dependsOn }) => {
const dbInstance = createDrizzle(dependsOn.env.DATABASE_URL, schema)
dbInstance.execute('SELECT 1')
.then(() => useLogger('app').useGlobalConfig().log('Connected to database'))
.catch((err) => {
useLogger('app').useGlobalConfig().withError(err).error('Failed to connect to database')
exit(1)
})
build: async ({ dependsOn }) => {
const dbInstance = createDrizzle(dependsOn.env.DATABASE_URL)
await dbInstance.execute('SELECT 1')
logger.log('Connected to database')
await migrateDatabase(dbInstance)
logger.log('Applied schema')
return dbInstance
},
})
@@ -137,7 +135,7 @@ async function createApp() {
providerService: resolved.providerService,
})
useLogger('app').useGlobalConfig().withFields({ port: 3000 }).log('Server started')
logger.withFields({ port: 3000 }).log('Server started')
return app
}
+9 -3
View File
@@ -1,9 +1,15 @@
import postgres from 'postgres'
import { migrate } from '@proj-airi/drizzle-orm-browser-migrator/pg'
import { migrations } from '@proj-airi/server-schema'
import { drizzle } from 'drizzle-orm/postgres-js'
export type Database<TSchema extends Record<string, unknown>> = ReturnType<typeof createDrizzle<TSchema>>
export type Database = ReturnType<typeof createDrizzle>
export function createDrizzle<TSchema extends Record<string, unknown>>(dsn: string, schema?: TSchema) {
return drizzle(postgres(dsn), { schema })
export function createDrizzle(dsn: string) {
return drizzle(postgres(dsn))
}
export function migrateDatabase(db: Database) {
return migrate(db, migrations)
}
+36
View File
@@ -0,0 +1,36 @@
{
"name": "@proj-airi/server-schema",
"type": "module",
"version": "0.8.4",
"description": "Server schema for AIRI",
"author": {
"name": "Moeru AI Project AIRI Team",
"email": "airi@moeru.ai",
"url": "https://github.com/moeru-ai"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/moeru-ai/airi.git",
"directory": "packages/server-schema"
},
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
}
},
"main": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"files": [
"README.md",
"dist",
"package.json"
],
"scripts": {
"build": "tsdown"
},
"devDependencies": {
"@proj-airi/unplugin-drizzle-orm-migrations": "^0.1.4"
}
}
+1
View File
@@ -0,0 +1 @@
export { default as migrations } from 'virtual:drizzle-migrations.sql'
+21
View File
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": [
"ESNext"
],
"module": "ESNext",
"moduleResolution": "bundler",
"types": [
"@proj-airi/unplugin-drizzle-orm-migrations/types"
],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
]
}
+18
View File
@@ -0,0 +1,18 @@
import DrizzleORMMigrations from '@proj-airi/unplugin-drizzle-orm-migrations/rolldown'
import { defineConfig } from 'tsdown'
export default defineConfig({
entry: [
'src/index.ts',
],
dts: true,
sourcemap: true,
unused: true,
fixedExtension: true,
plugins: [
DrizzleORMMigrations({
root: '../../apps/server',
}),
],
})
+7
View File
@@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
include: ['src/**/*.test.ts'],
},
})
+482 -366
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -85,7 +85,7 @@ catalog:
splitpanes: ^4.0.4
std-env: ^3.10.0
superjson: ^2.2.6
tsdown: ^0.17.4
tsdown: ^0.20.1
tsx: ^4.21.0
uncrypto: ^0.1.3
unplugin-info: ^1.2.4