You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

106 lines
5.0 KiB

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(),
});