feat: 迁移数据库至SQLite并适配嵌入式环境

- 添加SQLite数据库文件及数据目录的忽略规则
- 将数据库连接地址更新为本地SQLite数据库文件路径
- 将数据库从 PostgreSQL 迁移至 SQLite,更新依赖、Drizzle 方言及数据类型映射,确保嵌入式环境兼容性并保持应用层代码不变。
- 将数据库方言从 PostgreSQL 更改为 SQLite。
- 将数据库依赖从 postgres 替换为 better-sqlite3,并添加 better-sqlite3 的类型定义。
- 修改数据库连接字符串验证规则,从URL格式验证改为非空字符串验证。
- 将数据库连接从 PostgreSQL 切换为 Better-SQLite3,并支持创建目录和内存数据库。
- 将 todo 表的 completed 字段从 PostgreSQL 的 boolean 类型改为 SQLite 的 boolean 模式整数类型。
- 将字段定义从 PostgreSQL 适配改为 SQLite 适配,使用文本类型 ID 和时间戳整数类型,并统一使用 UUIDv7 和当前时间作为默认值。
- 添加 better-sqlite3 及其类型定义,并引入相关依赖以支持其功能
- 添加 better-sqlite3 依赖并移除 postgres 依赖
This commit is contained in:
2026-01-26 14:10:25 +08:00
parent a4c44a3fba
commit 5e56383f6f
11 changed files with 245 additions and 54 deletions

View File

@@ -3,7 +3,7 @@ import { z } from 'zod'
export const env = createEnv({
server: {
DATABASE_URL: z.url(),
DATABASE_URL: z.string().min(1),
},
clientPrefix: 'VITE_',
client: {

View File

@@ -1,15 +1,18 @@
import { drizzle } from 'drizzle-orm/postgres-js'
import { mkdirSync } from 'node:fs'
import { dirname } from 'node:path'
import Database from 'better-sqlite3'
import { drizzle } from 'drizzle-orm/better-sqlite3'
import { env } from '@/env'
import * as schema from '@/server/db/schema'
export const createDB = () =>
drizzle({
connection: {
url: env.DATABASE_URL,
prepare: true,
},
schema,
})
export const createDB = () => {
const dbPath = env.DATABASE_URL
if (dbPath !== ':memory:') {
mkdirSync(dirname(dbPath), { recursive: true })
}
const sqlite = new Database(dbPath)
return drizzle(sqlite, { schema })
}
export type DB = ReturnType<typeof createDB>

View File

@@ -1,8 +1,8 @@
import { boolean, pgTable, text } from 'drizzle-orm/pg-core'
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { generatedFields } from './utils/field'
export const todoTable = pgTable('todo', {
export const todoTable = sqliteTable('todo', {
...generatedFields,
title: text('title').notNull(),
completed: boolean('completed').notNull().default(false),
completed: integer('completed', { mode: 'boolean' }).notNull().default(false),
})

View File

@@ -1,37 +1,25 @@
import { sql } from 'drizzle-orm'
import { timestamp, uuid } from 'drizzle-orm/pg-core'
import { integer, text } from 'drizzle-orm/sqlite-core'
import { v7 as uuidv7 } from 'uuid'
// id
export const id = (name: string) => uuid(name)
export const pk = (name: string, strategy?: 'native' | 'extension') => {
switch (strategy) {
// PG 18+
case 'native':
return id(name).primaryKey().default(sql`uuidv7()`)
// PG 13+ with extension
case 'extension':
return id(name).primaryKey().default(sql`uuid_generate_v7()`)
// Any PG version
default:
return id(name)
.primaryKey()
.$defaultFn(() => uuidv7())
}
}
export const id = (name: string) => text(name)
export const pk = (name: string) =>
id(name)
.primaryKey()
.$defaultFn(() => uuidv7())
// timestamp
export const createdAt = (name = 'created_at') =>
timestamp(name, { withTimezone: true }).notNull().defaultNow()
integer(name, { mode: 'timestamp_ms' })
.notNull()
.$defaultFn(() => new Date())
export const updatedAt = (name = 'updated_at') =>
timestamp(name, { withTimezone: true })
integer(name, { mode: 'timestamp_ms' })
.notNull()
.defaultNow()
.$defaultFn(() => new Date())
.$onUpdateFn(() => new Date())
// generated fields