import { integer, sqliteTable, text, real } from "drizzle-orm/sqlite-core"; import { sql } from "drizzle-orm"; // ─── 分类表 ─────────────────────────────────────────── export const categories = sqliteTable("categories", { id: integer().primaryKey({ autoIncrement: true }), name: text().notNull(), icon: text().notNull().default("📁"), color: text().default("#6B7280"), parentId: integer("parent_id").references(() => categories.id, { onDelete: "set null" }), sortOrder: integer("sort_order").notNull().default(0), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .$onUpdate(() => new Date()) .notNull(), }); // ─── 标签表 ─────────────────────────────────────────── export const tags = sqliteTable("tags", { id: integer().primaryKey({ autoIncrement: true }), name: text().notNull().unique(), color: text().default("#6B7280"), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .notNull(), }); // ─── 收藏主表 ───────────────────────────────────────── export const items = sqliteTable("items", { id: integer().primaryKey({ autoIncrement: true }), userId: integer("user_id").notNull(), type: text({ enum: ["web", "text", "image", "file", "video"] }).notNull(), title: text().notNull(), description: text(), content: text(), // 完整正文(FTS 用) url: text(), // 原始链接 coverUrl: text("cover_url"), faviconUrl: text("favicon_url"), sourceHost: text("source_host"), filePath: text("file_path"), fileSize: integer("file_size"), fileMime: text("file_mime"), categoryId: integer("category_id").references(() => categories.id, { onDelete: "set null" }), note: text(), // 个人备注 rating: integer(), // 1-5 starred: integer({ mode: "boolean" }).notNull().default(false), isArchived: integer("is_archived", { mode: "boolean" }).notNull().default(false), aiSummary: text("ai_summary"), publishedAt: text("published_at"), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .$onUpdate(() => new Date()) .notNull(), }); // ─── 收藏-标签 多对多 ───────────────────────────────── export const itemTags = sqliteTable("item_tags", { itemId: integer("item_id").notNull().references(() => items.id, { onDelete: "cascade" }), tagId: integer("tag_id").notNull().references(() => tags.id, { onDelete: "cascade" }), }); // ─── 文章表 ─────────────────────────────────────────── export const articles = sqliteTable("articles", { id: integer().primaryKey({ autoIncrement: true }), userId: integer("user_id").notNull(), title: text().notNull().default("无标题文章"), content: text().notNull().default(""), coverUrl: text("cover_url"), status: text({ enum: ["draft", "published"] }).notNull().default("draft"), wordCount: integer("word_count").notNull().default(0), shareToken: text("share_token").unique(), shareExpiresAt: text("share_expires_at"), createdAt: integer("created_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .notNull(), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .$onUpdate(() => new Date()) .notNull(), }); // ─── 文章-收藏 关联表 ───────────────────────────────── export const articleItems = sqliteTable("article_items", { articleId: integer("article_id").notNull().references(() => articles.id, { onDelete: "cascade" }), itemId: integer("item_id").notNull().references(() => items.id, { onDelete: "cascade" }), sortOrder: integer("sort_order").notNull().default(0), }); // ─── 设置表 ─────────────────────────────────────────── export const settings = sqliteTable("settings", { key: text().primaryKey(), value: text({ mode: "json" }), updatedAt: integer("updated_at", { mode: "timestamp_ms" }) .default(sql`(cast((julianday('now') - 2440587.5)*86400000 as integer))`) .notNull(), });