feat: 添加数据库同步功能,创建版本表并处理版本迁移
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
"import-data": "bun run scripts/import-data.ts",
|
"import-data": "bun run scripts/import-data.ts",
|
||||||
"studio": "npx drizzle-kit studio",
|
"studio": "npx drizzle-kit studio",
|
||||||
"drizzle:migrate": "npx drizzle-kit migrate",
|
"drizzle:migrate": "npx drizzle-kit migrate",
|
||||||
|
"drizzle:generate": "npx drizzle-kit generate",
|
||||||
"drizzle:push": "npx drizzle-kit push",
|
"drizzle:push": "npx drizzle-kit push",
|
||||||
"pub": "envision pack -p -u -c"
|
"pub": "envision pack -p -u -c"
|
||||||
},
|
},
|
||||||
|
|||||||
24
src/db/drizzle/0003_shiny_venus.sql
Normal file
24
src/db/drizzle/0003_shiny_venus.sql
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
CREATE TABLE "cf_user_activity" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"userId" uuid,
|
||||||
|
"lastLoginAt" timestamp with time zone,
|
||||||
|
"lastActivityAt" timestamp with time zone,
|
||||||
|
"lastUsedAt" timestamp with time zone,
|
||||||
|
"createdAt" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updatedAt" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "mark_pod" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"title" text DEFAULT '',
|
||||||
|
"tags" jsonb DEFAULT '[]'::jsonb,
|
||||||
|
"link" text DEFAULT '',
|
||||||
|
"summary" text DEFAULT '',
|
||||||
|
"description" text DEFAULT '',
|
||||||
|
"data" jsonb DEFAULT '{}'::jsonb,
|
||||||
|
"uid" uuid,
|
||||||
|
"createdAt" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updatedAt" timestamp with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "kv_app" ALTER COLUMN "proxy" SET DEFAULT true;
|
||||||
3619
src/db/drizzle/meta/0003_snapshot.json
Normal file
3619
src/db/drizzle/meta/0003_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,13 @@
|
|||||||
"when": 1773148571509,
|
"when": 1773148571509,
|
||||||
"tag": "0002_loving_lyja",
|
"tag": "0002_loving_lyja",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 3,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1774808985686,
|
||||||
|
"tag": "0003_shiny_venus",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,2 @@
|
|||||||
import { relations } from "drizzle-orm/relations";
|
import { relations } from "drizzle-orm/relations";
|
||||||
import { } from "./schema";
|
|
||||||
|
|
||||||
|
|||||||
@@ -281,53 +281,7 @@ export const microAppsUpload = pgTable("micro_apps_upload", {
|
|||||||
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const microMark = pgTable("micro_mark", {
|
|
||||||
id: uuid().primaryKey().defaultRandom(),
|
|
||||||
title: text().default(''),
|
|
||||||
tags: jsonb().default([]),
|
|
||||||
link: text().default(''),
|
|
||||||
summary: text().default(''),
|
|
||||||
description: text().default(''),
|
|
||||||
|
|
||||||
data: jsonb().default({}),
|
|
||||||
uname: varchar({ length: 255 }).default(''),
|
|
||||||
uid: uuid(),
|
|
||||||
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
|
||||||
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
|
||||||
cover: text().default(''),
|
|
||||||
thumbnail: text().default(''),
|
|
||||||
|
|
||||||
markType: text().default('md'),
|
|
||||||
config: jsonb().default({}),
|
|
||||||
puid: uuid(),
|
|
||||||
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
|
||||||
version: integer().default(1),
|
|
||||||
fileList: jsonb().default([]),
|
|
||||||
key: text().default(''),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const workShareMark = pgTable("work_share_mark", {
|
|
||||||
id: uuid().primaryKey().defaultRandom(),
|
|
||||||
title: text().default(''),
|
|
||||||
key: text().default(''),
|
|
||||||
markType: text().default('md'),
|
|
||||||
description: text().default(''),
|
|
||||||
cover: text().default(''),
|
|
||||||
link: text().default(''),
|
|
||||||
tags: jsonb().default([]),
|
|
||||||
summary: text().default(''),
|
|
||||||
config: jsonb().default({}),
|
|
||||||
data: jsonb().default({}),
|
|
||||||
fileList: jsonb().default([]),
|
|
||||||
uname: varchar({ length: 255 }).default(''),
|
|
||||||
version: integer().default(1),
|
|
||||||
markedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
|
||||||
uid: uuid(),
|
|
||||||
puid: uuid(),
|
|
||||||
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
|
||||||
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
|
||||||
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
export const prompts = pgTable('cf_prompts', {
|
export const prompts = pgTable('cf_prompts', {
|
||||||
|
|||||||
@@ -7,3 +7,5 @@ export * from './schemas/n-code-schema.ts'
|
|||||||
export * from './schemas/life-schema.ts'
|
export * from './schemas/life-schema.ts'
|
||||||
|
|
||||||
export * from './schemas/user.ts'
|
export * from './schemas/user.ts'
|
||||||
|
|
||||||
|
export * from './schemas/mark.ts'
|
||||||
65
src/db/schemas/mark.ts
Normal file
65
src/db/schemas/mark.ts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { pgTable, serial, text, jsonb, varchar, timestamp, unique, uuid, doublePrecision, json, integer, boolean, index, uniqueIndex, pgEnum } from "drizzle-orm/pg-core"
|
||||||
|
import { sql, sum } from "drizzle-orm"
|
||||||
|
|
||||||
|
export const microMark = pgTable("micro_mark", {
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
title: text().default(''),
|
||||||
|
tags: jsonb().default([]),
|
||||||
|
link: text().default(''),
|
||||||
|
summary: text().default(''),
|
||||||
|
description: text().default(''),
|
||||||
|
|
||||||
|
data: jsonb().default({}),
|
||||||
|
uname: varchar({ length: 255 }).default(''),
|
||||||
|
uid: uuid(),
|
||||||
|
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
cover: text().default(''),
|
||||||
|
thumbnail: text().default(''),
|
||||||
|
|
||||||
|
markType: text().default('md'),
|
||||||
|
config: jsonb().default({}),
|
||||||
|
puid: uuid(),
|
||||||
|
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
||||||
|
version: integer().default(1),
|
||||||
|
fileList: jsonb().default([]),
|
||||||
|
key: text().default(''),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const workShareMark = pgTable("work_share_mark", {
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
title: text().default(''),
|
||||||
|
key: text().default(''),
|
||||||
|
markType: text().default('md'),
|
||||||
|
description: text().default(''),
|
||||||
|
cover: text().default(''),
|
||||||
|
link: text().default(''),
|
||||||
|
tags: jsonb().default([]),
|
||||||
|
summary: text().default(''),
|
||||||
|
config: jsonb().default({}),
|
||||||
|
data: jsonb().default({}),
|
||||||
|
fileList: jsonb().default([]),
|
||||||
|
uname: varchar({ length: 255 }).default(''),
|
||||||
|
version: integer().default(1),
|
||||||
|
markedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
||||||
|
uid: uuid(),
|
||||||
|
puid: uuid(),
|
||||||
|
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
deletedAt: timestamp({ withTimezone: true, mode: 'string' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const markPod = pgTable("mark_pod", {
|
||||||
|
id: uuid().primaryKey().defaultRandom(),
|
||||||
|
title: text().default(''),
|
||||||
|
tags: jsonb().default([]),
|
||||||
|
link: text().default(''),
|
||||||
|
summary: text().default(''),
|
||||||
|
description: text().default(''),
|
||||||
|
data: jsonb().default({}),
|
||||||
|
|
||||||
|
uid: uuid(),
|
||||||
|
createdAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
updatedAt: timestamp({ withTimezone: true, mode: 'string' }).notNull().defaultNow(),
|
||||||
|
});
|
||||||
60
src/db/sync.ts
Normal file
60
src/db/sync.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||||
|
import { sql } from 'drizzle-orm';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import { config } from '../modules/config.ts';
|
||||||
|
|
||||||
|
const VERSION_TABLE = '__db_version';
|
||||||
|
const CURRENT_VERSION = '0.1.0';
|
||||||
|
|
||||||
|
function getDb() {
|
||||||
|
return drizzle(config.DATABASE_URL || '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function syncDatabase() {
|
||||||
|
const database = getDb();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 确保版本表存在
|
||||||
|
await database.execute(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS ${VERSION_TABLE} (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
version VARCHAR(255) NOT NULL,
|
||||||
|
applied_at TIMESTAMP DEFAULT NOW()
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
|
||||||
|
// 2. 获取当前数据库版本
|
||||||
|
const result = await database.execute(sql`
|
||||||
|
SELECT version FROM ${VERSION_TABLE} ORDER BY id DESC LIMIT 1
|
||||||
|
`);
|
||||||
|
const dbVersion = result.rows[0]?.version;
|
||||||
|
|
||||||
|
// 3. 版本对比
|
||||||
|
if (dbVersion === CURRENT_VERSION) {
|
||||||
|
console.log('[DB Sync] Version up to date:', CURRENT_VERSION);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[DB Sync] Version mismatch: DB=${dbVersion}, Code=${CURRENT_VERSION}`);
|
||||||
|
console.log('[DB Sync] Running drizzle-kit push...');
|
||||||
|
|
||||||
|
// 4. 执行 drizzle-kit push
|
||||||
|
execSync('npx drizzle-kit push --force', {
|
||||||
|
cwd: process.cwd(),
|
||||||
|
stdio: 'inherit',
|
||||||
|
env: { ...process.env, DATABASE_URL: config.DATABASE_URL },
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5. 更新版本记录
|
||||||
|
await database.execute(sql`
|
||||||
|
INSERT INTO ${VERSION_TABLE} (version) VALUES (${CURRENT_VERSION})
|
||||||
|
`);
|
||||||
|
|
||||||
|
console.log('[DB Sync] Migration completed, version updated to:', CURRENT_VERSION);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[DB Sync] Migration failed:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sync = syncDatabase;
|
||||||
Reference in New Issue
Block a user