import { randomBytes } from "node:crypto"; import { index, pgSchema, text, timestamp, } from "drizzle-orm/pg-core"; import { uuidv7 } from "uuidv7"; import { users } from "./account"; import { cdn } from "./form"; export const shareSchema = pgSchema("share"); export type ShareSource = "web" | "bot"; const SHARE_ID_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789"; export function createShareId() { let id = ""; while (id.length < 8) { for (const value of randomBytes(8)) { if (value >= 252) continue; id += SHARE_ID_ALPHABET[value % SHARE_ID_ALPHABET.length]; if (id.length === 8) break; } } return id; } export const shareTexts = shareSchema.table( "text", { id: text("id").primaryKey().$defaultFn(createShareId), content: text("content").notNull(), description: text("description"), imageCdnId: text("image_cdn_id").references(() => cdn.id, { onDelete: "set null", }), source: text("source").$type().notNull(), authorId: text("author_id").references(() => users.id, { onDelete: "set null", }), authorDiscordId: text("author_discord_id").notNull(), authorName: text("author_name").notNull(), authorAvatarUrl: text("author_avatar_url"), createdAt: timestamp("created_at", { mode: "date", withTimezone: true }) .defaultNow() .notNull(), }, (share) => [ index("share_text_author_created_idx").on( share.authorDiscordId, share.createdAt ), ] ); export const shareComments = shareSchema.table( "comment", { id: text("id") .primaryKey() .$defaultFn(() => uuidv7()), shareId: text("share_id") .notNull() .references(() => shareTexts.id, { onDelete: "cascade" }), body: text("body").notNull(), authorId: text("author_id").references(() => users.id, { onDelete: "set null", }), authorDiscordId: text("author_discord_id").notNull(), authorName: text("author_name").notNull(), authorAvatarUrl: text("author_avatar_url"), createdAt: timestamp("created_at", { mode: "date", withTimezone: true }) .defaultNow() .notNull(), }, (comment) => [ index("share_comment_share_created_id_idx").on( comment.shareId, comment.createdAt, comment.id ), ] );