feat(api): NestJS standalone 骨架 + Drizzle/postgres.js 接入
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import './src/db/env.js'
|
||||
import { defineConfig } from 'drizzle-kit'
|
||||
|
||||
export default defineConfig({
|
||||
dialect: 'postgresql',
|
||||
schema: './src/db/schema.ts',
|
||||
out: './drizzle',
|
||||
dbCredentials: { url: process.env.DATABASE_URL! },
|
||||
})
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "@sf/api",
|
||||
"version": "0.1.0",
|
||||
"description": "SiteForge API:NestJS 模块化单体骨架(本切片以 standalone context 供 CLI 使用,不监听端口)+ Drizzle/postgres.js 接入",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"db:generate": "drizzle-kit generate",
|
||||
"db:migrate": "drizzle-kit migrate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.4.22",
|
||||
"@nestjs/core": "^10.4.22",
|
||||
"drizzle-orm": "^0.45.4",
|
||||
"postgres": "^3.4.9",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^26.6.5",
|
||||
"dotenv": "^18.0.8",
|
||||
"drizzle-kit": "^0.31.11",
|
||||
"typescript": "^5.6.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { Module } from '@nestjs/common'
|
||||
|
||||
@Module({ imports: [] })
|
||||
export class AppModule {}
|
||||
@@ -0,0 +1,13 @@
|
||||
import './env.js'
|
||||
import { drizzle } from 'drizzle-orm/postgres-js'
|
||||
import postgres from 'postgres'
|
||||
import * as schema from './schema.js'
|
||||
|
||||
// DATABASE_URL_TEST ?? DATABASE_URL 的回退链是 Task 13 集成测试的接线:
|
||||
// 测试临时库优先,开发库兜底。env 加载见 ./env.ts(向上查找仓库根 .env)。
|
||||
export function getDb(
|
||||
connectionString = process.env.DATABASE_URL_TEST ?? process.env.DATABASE_URL!,
|
||||
) {
|
||||
const sql = postgres(connectionString, { max: 5 })
|
||||
return drizzle(sql, { schema })
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { dirname, join } from 'node:path'
|
||||
import { config } from 'dotenv'
|
||||
|
||||
// dotenv 默认只读 cwd 下的 .env:从仓库根跑 `pnpm test` 时 cwd 是仓库根,能读到根 .env;
|
||||
// 但在 apps/api 内跑 drizzle-kit(db:generate / db:migrate)时 cwd 是包目录,默认读不到。
|
||||
// 因此这里从 cwd 逐级向上查找 .env(就近优先,找到即停),两种场景都能稳定读到仓库根 .env。
|
||||
let dir = process.cwd()
|
||||
for (;;) {
|
||||
const candidate = join(dir, '.env')
|
||||
if (existsSync(candidate)) {
|
||||
config({ path: candidate })
|
||||
break
|
||||
}
|
||||
const parent = dirname(dir)
|
||||
if (parent === dir) break
|
||||
dir = parent
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// 聚合导出:后续任务(6-12)按域追加 pgTable 定义
|
||||
export {}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { getDb } from '../src/db/client.js'
|
||||
|
||||
describe('数据库连接', () => {
|
||||
it('连接本项目 PG(5434)并响应 select 1', async () => {
|
||||
const db = getDb()
|
||||
// postgres.js 驱动下 drizzle 的 execute 返回 RowList(行数组),
|
||||
// 不是 node-postgres 风格的 { rows: [...] },故直接取 r[0]
|
||||
const r = (await db.execute('select 1 as ok')) as any
|
||||
expect(Number(r[0].ok)).toBe(1)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"include": ["src", "test"]
|
||||
}
|
||||
Reference in New Issue
Block a user