refactor(server): 切换 SQLite 并重建设备/任务表结构
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,6 +9,11 @@
|
|||||||
# Bun build
|
# Bun build
|
||||||
*.bun-build
|
*.bun-build
|
||||||
|
|
||||||
|
# SQLite database files
|
||||||
|
*.db
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
|
|
||||||
# Turborepo
|
# Turborepo
|
||||||
.turbo/
|
.turbo/
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
DATABASE_URL=postgres://postgres:postgres@localhost:5432/postgres
|
DATABASE_PATH=data.db
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { env } from '@/env'
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
out: './drizzle',
|
out: './drizzle',
|
||||||
schema: './src/server/db/schema/index.ts',
|
schema: './src/server/db/schema/index.ts',
|
||||||
dialect: 'postgresql',
|
dialect: 'sqlite',
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: env.DATABASE_URL,
|
url: env.DATABASE_PATH,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { z } from 'zod'
|
|||||||
|
|
||||||
export const env = createEnv({
|
export const env = createEnv({
|
||||||
server: {
|
server: {
|
||||||
DATABASE_URL: z.url(),
|
DATABASE_PATH: z.string().min(1).default('data.db'),
|
||||||
},
|
},
|
||||||
clientPrefix: 'VITE_',
|
clientPrefix: 'VITE_',
|
||||||
client: {
|
client: {
|
||||||
|
|||||||
@@ -1,47 +1,28 @@
|
|||||||
import { sql } from 'drizzle-orm'
|
import { integer, text } from 'drizzle-orm/sqlite-core'
|
||||||
import { timestamp, uuid } from 'drizzle-orm/pg-core'
|
|
||||||
import { v7 as uuidv7 } from 'uuid'
|
import { v7 as uuidv7 } from 'uuid'
|
||||||
|
|
||||||
// id
|
export const pk = (name = 'id') =>
|
||||||
|
text(name)
|
||||||
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()
|
.primaryKey()
|
||||||
.$defaultFn(() => uuidv7())
|
.$defaultFn(() => uuidv7())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// timestamp
|
export const createdAt = (name = 'created_at') =>
|
||||||
|
integer(name, { mode: 'timestamp_ms' })
|
||||||
export const createdAt = (name = 'created_at') => timestamp(name, { withTimezone: true }).notNull().defaultNow()
|
.notNull()
|
||||||
|
.$defaultFn(() => new Date())
|
||||||
|
|
||||||
export const updatedAt = (name = 'updated_at') =>
|
export const updatedAt = (name = 'updated_at') =>
|
||||||
timestamp(name, { withTimezone: true })
|
integer(name, { mode: 'timestamp_ms' })
|
||||||
.notNull()
|
.notNull()
|
||||||
.defaultNow()
|
.$defaultFn(() => new Date())
|
||||||
.$onUpdateFn(() => new Date())
|
.$onUpdateFn(() => new Date())
|
||||||
|
|
||||||
// generated fields
|
|
||||||
|
|
||||||
export const generatedFields = {
|
export const generatedFields = {
|
||||||
id: pk('id'),
|
id: pk('id'),
|
||||||
createdAt: createdAt('created_at'),
|
createdAt: createdAt('created_at'),
|
||||||
updatedAt: updatedAt('updated_at'),
|
updatedAt: updatedAt('updated_at'),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to create omit keys from generatedFields
|
|
||||||
const createGeneratedFieldKeys = <T extends Record<string, unknown>>(fields: T): Record<keyof T, true> => {
|
const createGeneratedFieldKeys = <T extends Record<string, unknown>>(fields: T): Record<keyof T, true> => {
|
||||||
return Object.keys(fields).reduce(
|
return Object.keys(fields).reduce(
|
||||||
(acc, key) => {
|
(acc, key) => {
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { drizzle } from 'drizzle-orm/postgres-js'
|
import { Database } from 'bun:sqlite'
|
||||||
|
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
||||||
import { env } from '@/env'
|
import { env } from '@/env'
|
||||||
import { relations } from '@/server/db/relations'
|
import { relations } from '@/server/db/relations'
|
||||||
|
|
||||||
export const createDB = () =>
|
export const createDB = () => {
|
||||||
drizzle({
|
const sqlite = new Database(env.DATABASE_PATH)
|
||||||
connection: env.DATABASE_URL,
|
sqlite.exec('PRAGMA journal_mode = WAL')
|
||||||
relations,
|
sqlite.exec('PRAGMA foreign_keys = ON')
|
||||||
})
|
return drizzle({ client: sqlite, relations })
|
||||||
|
}
|
||||||
|
|
||||||
export type DB = ReturnType<typeof createDB>
|
export type DB = ReturnType<typeof createDB>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
import { defineRelations } from 'drizzle-orm'
|
import { defineRelations } from 'drizzle-orm'
|
||||||
import * as schema from './schema'
|
import * as schema from './schema'
|
||||||
|
|
||||||
export const relations = defineRelations(schema, (_r) => ({}))
|
export const relations = defineRelations(schema, (r) => ({
|
||||||
|
deviceTable: {
|
||||||
|
tasks: r.many.taskTable(),
|
||||||
|
},
|
||||||
|
taskTable: {
|
||||||
|
device: r.one.deviceTable({
|
||||||
|
from: r.taskTable.deviceId,
|
||||||
|
to: r.deviceTable.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|||||||
11
apps/server/src/server/db/schema/device.ts
Normal file
11
apps/server/src/server/db/schema/device.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||||
|
import { generatedFields } from '../fields'
|
||||||
|
|
||||||
|
export const deviceTable = sqliteTable('device', {
|
||||||
|
...generatedFields,
|
||||||
|
licence: text('licence').notNull().unique(),
|
||||||
|
fingerprint: text('fingerprint').notNull(),
|
||||||
|
platformPublicKey: text('platform_public_key').notNull(),
|
||||||
|
pgpPrivateKey: text('pgp_private_key'),
|
||||||
|
pgpPublicKey: text('pgp_public_key'),
|
||||||
|
})
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './todo'
|
export * from './device'
|
||||||
|
export * from './task'
|
||||||
|
|||||||
16
apps/server/src/server/db/schema/task.ts
Normal file
16
apps/server/src/server/db/schema/task.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'
|
||||||
|
import { generatedFields } from '../fields'
|
||||||
|
|
||||||
|
export const taskTable = sqliteTable('task', {
|
||||||
|
...generatedFields,
|
||||||
|
deviceId: text('device_id').notNull(),
|
||||||
|
taskId: text('task_id').notNull(),
|
||||||
|
enterpriseId: text('enterprise_id'),
|
||||||
|
orgName: text('org_name'),
|
||||||
|
inspectionId: text('inspection_id'),
|
||||||
|
inspectionPerson: text('inspection_person'),
|
||||||
|
issuedAt: integer('issued_at', { mode: 'timestamp_ms' }),
|
||||||
|
status: text('status', { enum: ['pending', 'in_progress', 'done'] })
|
||||||
|
.notNull()
|
||||||
|
.default('pending'),
|
||||||
|
})
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { boolean, pgTable, text } from 'drizzle-orm/pg-core'
|
|
||||||
import { generatedFields } from '../fields'
|
|
||||||
|
|
||||||
export const todoTable = pgTable('todo', {
|
|
||||||
...generatedFields,
|
|
||||||
title: text('title').notNull(),
|
|
||||||
completed: boolean('completed').notNull().default(false),
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user