import { relations, sql } from "drizzle-orm"; import { jsonb, pgTable, primaryKey, text, timestamp, uuid, varchar, } from "drizzle-orm/pg-core"; export const users = pgTable("users", { id: uuid("id").primaryKey().defaultRandom(), hfId: varchar("hf_id", { length: 64 }).notNull().unique(), hfUsername: varchar("hf_username", { length: 128 }).notNull(), email: varchar("email", { length: 256 }), avatarUrl: text("avatar_url"), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); export const profiles = pgTable("profiles", { userId: uuid("user_id") .primaryKey() .references(() => users.id, { onDelete: "cascade" }), nativeLang: varchar("native_lang", { length: 8 }).notNull(), targetLang: varchar("target_lang", { length: 8 }).notNull(), level: varchar("level", { length: 4 }).notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), }); export const stories = pgTable("stories", { id: uuid("id").primaryKey().defaultRandom(), targetLang: varchar("target_lang", { length: 8 }).notNull(), level: varchar("level", { length: 4 }).notNull(), title: text("title").notNull(), content: text("content").notNull(), vocab: jsonb("vocab").$type>().default(sql`'[]'::jsonb`), createdBy: uuid("created_by").references(() => users.id, { onDelete: "set null" }), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); export const storyReads = pgTable( "story_reads", { userId: uuid("user_id") .notNull() .references(() => users.id, { onDelete: "cascade" }), storyId: uuid("story_id") .notNull() .references(() => stories.id, { onDelete: "cascade" }), completedAt: timestamp("completed_at", { withTimezone: true }).notNull().defaultNow(), }, (t) => [primaryKey({ columns: [t.userId, t.storyId] })], ); export const visionJobs = pgTable("vision_jobs", { id: uuid("id").primaryKey().defaultRandom(), userId: uuid("user_id") .notNull() .references(() => users.id, { onDelete: "cascade" }), imageUrl: text("image_url").notNull(), caption: text("caption"), objects: jsonb("objects").$type< Array<{ label: string; translation: string; box: [number, number, number, number]; score: number }> >(), sentences: jsonb("sentences").$type>(), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); export type DialogueOption = { text: string; isCorrect: boolean; feedback: string; }; export type DialogueTurn = { type: "narration" | "character" | "user_choice"; text: string; translation?: string; speakerName?: string; options?: DialogueOption[]; }; export const dialogues = pgTable("dialogues", { id: uuid("id").primaryKey().defaultRandom(), targetLang: varchar("target_lang", { length: 8 }).notNull(), level: varchar("level", { length: 4 }).notNull(), title: text("title").notNull(), scenario: text("scenario").notNull(), turns: jsonb("turns").$type().notNull().default(sql`'[]'::jsonb`), createdBy: uuid("created_by").references(() => users.id, { onDelete: "set null" }), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); export const usersRelations = relations(users, ({ one, many }) => ({ profile: one(profiles, { fields: [users.id], references: [profiles.userId] }), stories: many(stories), reads: many(storyReads), visionJobs: many(visionJobs), dialogues: many(dialogues), })); export const profilesRelations = relations(profiles, ({ one }) => ({ user: one(users, { fields: [profiles.userId], references: [users.id] }), })); export const storiesRelations = relations(stories, ({ one, many }) => ({ author: one(users, { fields: [stories.createdBy], references: [users.id] }), reads: many(storyReads), })); export const storyReadsRelations = relations(storyReads, ({ one }) => ({ user: one(users, { fields: [storyReads.userId], references: [users.id] }), story: one(stories, { fields: [storyReads.storyId], references: [stories.id] }), })); export const dialoguesRelations = relations(dialogues, ({ one }) => ({ author: one(users, { fields: [dialogues.createdBy], references: [users.id] }), }));