refactor(db): 统一数据库 schema — 软删除、命名规范、约束标准化
- 全表新增 deleted_at 列,统一软删除替代硬删除+archived_at - models.model_id 重命名为 external_id,消除语义混淆 - conversations.model_id 改为可空(模型为建议而非绑定) - messages 新增 updated_at,移除 CASCADE 改为 DAO 层级联 - 移除 DB 层 UNIQUE 约束,改为应用层检查(配合软删除) - 新增 helpers.ts(baseColumns + 构造层防御)、ESLint 规则、契约测试 - 迁移 0004 补全 CHECK 约束(providers.type/materials.status/messages.role) - DAO 层全面重写:级联软删除、应用层唯一、provider 删除保护 - 路由/前端/测试全量适配 externalId 重命名及类型变更
This commit is contained in:
109
drizzle/0004_db_schema_standardization.sql
Normal file
109
drizzle/0004_db_schema_standardization.sql
Normal file
@@ -0,0 +1,109 @@
|
||||
-- DB schema standardization migration
|
||||
-- 1. Rename columns
|
||||
ALTER TABLE `projects` RENAME COLUMN `archived_at` TO `deleted_at`;
|
||||
ALTER TABLE `models` RENAME COLUMN `model_id` TO `external_id`;
|
||||
|
||||
-- 2. Add deleted_at to remaining tables
|
||||
ALTER TABLE `providers` ADD COLUMN `deleted_at` text;
|
||||
ALTER TABLE `models` ADD COLUMN `deleted_at` text;
|
||||
ALTER TABLE `conversations` ADD COLUMN `deleted_at` text;
|
||||
ALTER TABLE `materials` ADD COLUMN `deleted_at` text;
|
||||
ALTER TABLE `messages` ADD COLUMN `deleted_at` text;
|
||||
|
||||
-- 3. Add updated_at to messages
|
||||
ALTER TABLE `messages` ADD COLUMN `updated_at` text NOT NULL DEFAULT '';
|
||||
|
||||
-- 4. Drop unique indexes (enforcement moves to app layer)
|
||||
DROP INDEX IF EXISTS `projects_name_unique`;
|
||||
DROP INDEX IF EXISTS `providers_name_unique`;
|
||||
DROP INDEX IF EXISTS `models_provider_id_model_id_unique`;
|
||||
|
||||
-- 5. Rebuild messages table (FK cascade → no action, add updated_at + deleted_at in-table, add CHECK on role)
|
||||
CREATE TABLE `messages_new` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`conversation_id` text NOT NULL,
|
||||
`role` text NOT NULL CHECK (`role` IN ('assistant', 'system', 'user')),
|
||||
`content` text NOT NULL DEFAULT '',
|
||||
`parts` text,
|
||||
`created_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL DEFAULT '',
|
||||
`deleted_at` text,
|
||||
FOREIGN KEY (`conversation_id`) REFERENCES `conversations`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `messages_new` (`id`, `conversation_id`, `role`, `content`, `parts`, `created_at`, `updated_at`, `deleted_at`)
|
||||
SELECT `id`, `conversation_id`, `role`, `content`, `parts`, `created_at`, '', NULL FROM `messages`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE `messages`;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `messages_new` RENAME TO `messages`;
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `messages_conversation_id_idx` ON `messages` (`conversation_id`);
|
||||
--> statement-breakpoint
|
||||
|
||||
-- 6. Rebuild conversations table (model_id nullable, add deleted_at in-table)
|
||||
CREATE TABLE `conversations_new` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`project_id` text NOT NULL,
|
||||
`model_id` text,
|
||||
`title` text NOT NULL DEFAULT '新会话',
|
||||
`created_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
`deleted_at` text,
|
||||
FOREIGN KEY (`model_id`) REFERENCES `models`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `conversations_new` (`id`, `project_id`, `model_id`, `title`, `created_at`, `updated_at`, `deleted_at`)
|
||||
SELECT `id`, `project_id`, `model_id`, `title`, `created_at`, `updated_at`, NULL FROM `conversations`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE `conversations`;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `conversations_new` RENAME TO `conversations`;
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `conversations_project_id_idx` ON `conversations` (`project_id`);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `conversations_model_id_idx` ON `conversations` (`model_id`);
|
||||
--> statement-breakpoint
|
||||
|
||||
-- 7. Rebuild providers table (add deleted_at in-table, add CHECK on type)
|
||||
CREATE TABLE `providers_new` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`type` text NOT NULL DEFAULT 'openai-compatible' CHECK (`type` IN ('anthropic', 'openai', 'openai-compatible')),
|
||||
`api_key` text NOT NULL,
|
||||
`base_url` text NOT NULL,
|
||||
`created_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
`deleted_at` text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `providers_new` (`id`, `name`, `type`, `api_key`, `base_url`, `created_at`, `updated_at`, `deleted_at`)
|
||||
SELECT `id`, `name`, `type`, `api_key`, `base_url`, `created_at`, `updated_at`, NULL FROM `providers`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE `providers`;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `providers_new` RENAME TO `providers`;
|
||||
--> statement-breakpoint
|
||||
|
||||
-- 8. Rebuild materials table (add deleted_at in-table, add CHECK on status)
|
||||
CREATE TABLE `materials_new` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`project_id` text NOT NULL,
|
||||
`associated_date` text NOT NULL,
|
||||
`description` text NOT NULL,
|
||||
`status` text NOT NULL DEFAULT 'pending' CHECK (`status` IN ('pending', 'approved', 'discarded')),
|
||||
`created_at` text NOT NULL,
|
||||
`updated_at` text NOT NULL,
|
||||
`deleted_at` text,
|
||||
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
INSERT INTO `materials_new` (`id`, `project_id`, `associated_date`, `description`, `status`, `created_at`, `updated_at`, `deleted_at`)
|
||||
SELECT `id`, `project_id`, `associated_date`, `description`, `status`, `created_at`, `updated_at`, NULL FROM `materials`;
|
||||
--> statement-breakpoint
|
||||
DROP TABLE `materials`;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE `materials_new` RENAME TO `materials`;
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `materials_project_id_idx` ON `materials` (`project_id`);
|
||||
Reference in New Issue
Block a user