Spaces:
Sleeping
Sleeping
| import { sqliteTable, text, integer, real, uniqueIndex } from "drizzle-orm/sqlite-core"; | |
| import { relations } from "drizzle-orm"; | |
| // ============================================================================= | |
| // ENUMS (stored as TEXT with application-level validation) | |
| // ============================================================================= | |
| export const userRoleEnum = ["MAINTAINER", "CONTRIBUTOR"] as const; | |
| export const classificationEnum = [ | |
| "CRITICAL_BUG", "BUG", "FEATURE_REQUEST", "QUESTION", | |
| "DOCS", "DUPLICATE", "NEEDS_INFO", "SPAM" | |
| ] as const; | |
| export const sentimentEnum = ["POSITIVE", "NEUTRAL", "NEGATIVE", "FRUSTRATED"] as const; | |
| export const profileVisibilityEnum = ["public", "private", "connections_only"] as const; | |
| export const expertiseLevelEnum = ["beginner", "intermediate", "advanced", "expert"] as const; | |
| export const sessionTypeEnum = ["one_on_one", "group", "issue_help"] as const; | |
| export const sessionStatusEnum = ["active", "paused", "completed", "cancelled"] as const; | |
| export const resourceTypeEnum = [ | |
| "link", "code_snippet", "documentation", "tutorial", "tool", "example", "answer" | |
| ] as const; | |
| export const trophyTypeEnum = [ | |
| "first_pr", "pr_master", "pr_legend", "bug_hunter", "bug_slayer", | |
| "first_mentor", "master_mentor", "streak_starter", "streak_warrior", "streak_legend", | |
| "triage_helper", "triage_hero", "first_review", "review_guru", | |
| "welcome_committee", "documentation_hero", "early_adopter", "top_contributor" | |
| ] as const; | |
| export const trophyRarityEnum = ["common", "uncommon", "rare", "legendary"] as const; | |
| // ============================================================================= | |
| // CORE TABLES | |
| // ============================================================================= | |
| // ---- Users ---- | |
| export const users = sqliteTable("users", { | |
| id: text("id").primaryKey(), | |
| githubId: integer("github_id").unique().notNull(), | |
| username: text("username").notNull(), | |
| avatarUrl: text("avatar_url").notNull(), | |
| role: text("role"), // email: text("email"), | |
| githubAccessToken: text("github_access_token"), | |
| // Sync status tracking (Phase 2) - DISABLED until Turso migration is applied | |
| // Run: turso db shell <db-name> < src/db/migrations/add_sync_status.sql | |
| // syncStatus: text("sync_status").default("IDLE"), // IDLE | PENDING | SYNCING | COMPLETED | FAILED | |
| // lastSyncAt: text("last_sync_at"), // ISO timestamp | |
| // syncError: text("sync_error"), // Error message if failed | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ---- Repositories ---- | |
| export const repositories = sqliteTable("repositories", { | |
| id: text("id").primaryKey(), | |
| githubRepoId: integer("github_repo_id").notNull(), | |
| name: text("name").notNull(), | |
| owner: text("owner").notNull(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| addedByUser: integer("added_by_user", { mode: "boolean" }).default(false), // true if explicitly added by user (maintainer) | |
| etag: text("etag"), // GitHub ETag for conditional requests | |
| lastSyncedAt: text("last_synced_at"), // When the repo was last synced | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ---- Issues ---- | |
| export const issues = sqliteTable("issues", { | |
| id: text("id").primaryKey(), | |
| githubIssueId: integer("github_issue_id").notNull(), | |
| number: integer("number").notNull(), | |
| title: text("title").notNull(), | |
| body: text("body"), // Full body fetched on-demand via /api/issues/:id/details | |
| bodySummary: text("body_summary"), // First 200 chars of body for display optimization | |
| authorName: text("author_name").notNull(), | |
| repoId: text("repo_id").notNull().references(() => repositories.id), | |
| repoName: text("repo_name").notNull(), | |
| owner: text("owner"), | |
| repo: text("repo"), | |
| htmlUrl: text("html_url"), | |
| state: text("state").notNull().default("open"), | |
| isPR: integer("is_pr", { mode: "boolean" }).notNull().default(false), | |
| authorAssociation: text("author_association"), // OWNER, MEMBER, COLLABORATOR, etc. | |
| headSha: text("head_sha"), // For PRs: track the commit SHA to detect force-pushes | |
| updatedAt: text("updated_at"), // Track last GitHub update time for efficient syncing | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ---- Triage Data ---- | |
| export const triageData = sqliteTable("triage_data", { | |
| id: text("id").primaryKey(), | |
| issueId: text("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }), | |
| classification: text("classification").notNull(), // Classification enum | |
| summary: text("summary").notNull(), | |
| suggestedLabel: text("suggested_label").notNull(), | |
| sentiment: text("sentiment").notNull(), // Sentiment enum | |
| bugRiskScore: integer("bug_risk_score"), // 0-10 risk from Quality Assessment | |
| toxicityFlag: integer("toxicity_flag", { mode: "boolean" }).default(false), // From Bilingual Moderation | |
| analyzedAt: text("analyzed_at").notNull(), | |
| }); | |
| // ---- Templates ---- | |
| export const templates = sqliteTable("templates", { | |
| id: text("id").primaryKey(), | |
| name: text("name").notNull(), | |
| body: text("body").notNull(), | |
| ownerId: text("owner_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| triggerClassification: text("trigger_classification"), | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ============================================================================= | |
| // PROFILE & MENTORSHIP TABLES | |
| // ============================================================================= | |
| // ---- User Profiles ---- | |
| export const profiles = sqliteTable("profiles", { | |
| userId: text("user_id").primaryKey().references(() => users.id, { onDelete: "cascade" }), | |
| username: text("username").notNull(), | |
| avatarUrl: text("avatar_url"), | |
| bio: text("bio"), | |
| location: text("location"), | |
| website: text("website"), | |
| twitter: text("twitter"), | |
| availableForMentoring: integer("available_for_mentoring", { mode: "boolean" }).default(false), | |
| profileVisibility: text("profile_visibility").default("public"), | |
| showEmail: integer("show_email", { mode: "boolean" }).default(false), | |
| githubStats: text("github_stats"), // JSON string | |
| statsUpdatedAt: text("stats_updated_at"), | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ---- Mentor Profiles ---- | |
| export const mentors = sqliteTable("mentors", { | |
| id: text("id").primaryKey(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| username: text("username").notNull(), | |
| expertiseLevel: text("expertise_level").default("intermediate"), | |
| availabilityHoursPerWeek: integer("availability_hours_per_week").default(5), | |
| timezone: text("timezone"), | |
| isActive: integer("is_active", { mode: "boolean" }).default(true), | |
| bio: text("bio"), | |
| avatarUrl: text("avatar_url"), | |
| menteeCount: integer("mentee_count").default(0), | |
| sessionsCompleted: integer("sessions_completed").default(0), | |
| avgRating: real("avg_rating").default(0.0), | |
| totalRatings: integer("total_ratings").default(0), | |
| maxMentees: integer("max_mentees").default(3), | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ---- Mentor Matches ---- | |
| export const mentorMatches = sqliteTable("mentor_matches", { | |
| id: text("id").primaryKey(), | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| mentorUsername: text("mentor_username").notNull(), | |
| menteeId: text("mentee_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| menteeUsername: text("mentee_username").notNull(), | |
| compatibilityScore: real("compatibility_score").notNull(), | |
| matchReason: text("match_reason"), | |
| issueId: text("issue_id"), | |
| repoName: text("repo_name"), | |
| status: text("status").default("suggested"), // suggested, accepted, declined, completed | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ---- Mentorship Requests ---- | |
| export const mentorshipRequests = sqliteTable("mentorship_requests", { | |
| id: text("id").primaryKey(), | |
| menteeId: text("mentee_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| menteeUsername: text("mentee_username"), | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| mentorUsername: text("mentor_username"), | |
| issueId: text("issue_id"), | |
| message: text("message"), | |
| status: text("status").default("pending"), // pending, accepted, declined | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ---- Mentor Ratings ---- | |
| export const mentorRatings = sqliteTable("mentor_ratings", { | |
| id: text("id").primaryKey(), | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| menteeId: text("mentee_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| sessionId: text("session_id"), | |
| rating: integer("rating").notNull(), // 1-5 | |
| feedback: text("feedback"), | |
| createdAt: text("created_at").notNull(), | |
| }); | |
| // ============================================================================= | |
| // CHAT & MESSAGING TABLES | |
| // ============================================================================= | |
| // ---- Chat Sessions ---- | |
| export const chatSessions = sqliteTable("chat_sessions", { | |
| id: text("id").primaryKey(), | |
| mentorId: text("mentor_id").notNull().references(() => users.id), | |
| mentorUsername: text("mentor_username").notNull(), | |
| sessionType: text("session_type").default("one_on_one"), | |
| issueId: text("issue_id"), | |
| repoName: text("repo_name"), | |
| topic: text("topic"), | |
| status: text("status").default("active"), | |
| startedAt: text("started_at").notNull(), | |
| endedAt: text("ended_at"), | |
| lastActivityAt: text("last_activity_at").notNull(), | |
| summary: text("summary"), | |
| messageCount: integer("message_count").default(0), | |
| durationMinutes: integer("duration_minutes").default(0), | |
| }); | |
| // ---- Chat Messages ---- | |
| export const chatMessages = sqliteTable("chat_messages", { | |
| id: text("id").primaryKey(), | |
| sessionId: text("session_id").notNull().references(() => chatSessions.id, { onDelete: "cascade" }), | |
| senderId: text("sender_id").notNull().references(() => users.id), | |
| senderUsername: text("sender_username").notNull(), | |
| isMentor: integer("is_mentor", { mode: "boolean" }).default(false), | |
| content: text("content").notNull(), | |
| messageType: text("message_type").default("text"), // text, code, link, file | |
| language: text("language"), // for code blocks | |
| isAiGenerated: integer("is_ai_generated", { mode: "boolean" }).default(false), | |
| containsResource: integer("contains_resource", { mode: "boolean" }).default(false), | |
| extractedResourceId: text("extracted_resource_id"), | |
| timestamp: text("timestamp").notNull(), | |
| editedAt: text("edited_at"), | |
| }); | |
| // ---- Chat History (DEPRECATED - AI chat uses ephemeral history from frontend) ---- | |
| // This table stored AI chat history but was never read. Kept for reference. | |
| // To be removed in a future migration after verifying no data loss impact. | |
| // export const chatHistory = sqliteTable("chat_history", { | |
| // id: text("id").primaryKey(), | |
| // userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| // sessionId: text("session_id").notNull(), | |
| // createdAt: text("created_at").notNull(), | |
| // }); | |
| // ---- Issue Chats ---- | |
| export const issueChats = sqliteTable("issue_chats", { | |
| id: text("id").primaryKey(), | |
| issueId: text("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| sessionId: text("session_id").notNull(), | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ---- Direct Messages ---- | |
| export const messages = sqliteTable("messages", { | |
| id: text("id").primaryKey(), | |
| senderId: text("sender_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| receiverId: text("receiver_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| content: text("content").notNull(), | |
| read: integer("read", { mode: "boolean" }).default(false), | |
| timestamp: text("timestamp").notNull(), | |
| editedAt: text("edited_at"), | |
| }); | |
| // ---- Global Chat Messages (Ably persistence) ---- | |
| export const globalChatMessages = sqliteTable("global_chat_messages", { | |
| id: text("id").primaryKey(), | |
| senderId: text("sender_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| senderUsername: text("sender_username").notNull(), | |
| senderAvatarUrl: text("sender_avatar_url"), | |
| content: text("content").notNull(), | |
| timestamp: text("timestamp").notNull(), | |
| }); | |
| // ============================================================================= | |
| // GAMIFICATION TABLES | |
| // ============================================================================= | |
| // ---- Trophies ---- | |
| export const trophies = sqliteTable("trophies", { | |
| id: text("id").primaryKey(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| username: text("username").notNull(), | |
| trophyType: text("trophy_type").notNull(), // TrophyType enum | |
| name: text("name").notNull(), | |
| description: text("description").notNull(), | |
| icon: text("icon").notNull(), | |
| color: text("color").notNull(), | |
| rarity: text("rarity").notNull(), // common, uncommon, rare, legendary | |
| svgData: text("svg_data"), | |
| isPublic: integer("is_public", { mode: "boolean" }).default(true), | |
| shareUrl: text("share_url"), | |
| earnedFor: text("earned_for"), // e.g., "owner/repo" | |
| milestoneValue: integer("milestone_value"), | |
| awardedAt: text("awarded_at").notNull(), | |
| }); | |
| // ---- Resources ---- | |
| export const resources = sqliteTable("resources", { | |
| id: text("id").primaryKey(), | |
| repoName: text("repo_name").notNull(), | |
| sourceType: text("source_type").default("chat"), | |
| sourceId: text("source_id"), | |
| resourceType: text("resource_type").notNull(), // ResourceType enum | |
| title: text("title").notNull(), | |
| content: text("content").notNull(), | |
| description: text("description"), | |
| language: text("language"), | |
| sharedBy: text("shared_by").notNull(), | |
| sharedById: text("shared_by_id").notNull().references(() => users.id), | |
| saveCount: integer("save_count").default(0), | |
| helpfulCount: integer("helpful_count").default(0), | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ---- User Saved Resources ---- | |
| export const userSavedResources = sqliteTable("user_saved_resources", { | |
| id: text("id").primaryKey(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| resourceId: text("resource_id").notNull().references(() => resources.id, { onDelete: "cascade" }), | |
| notes: text("notes"), | |
| savedAt: text("saved_at").notNull(), | |
| }); | |
| // ============================================================================= | |
| // JUNCTION TABLES (Normalized Arrays) | |
| // ============================================================================= | |
| // ---- User Repositories (User.repositories array) ---- | |
| export const userRepositories = sqliteTable("user_repositories", { | |
| id: text("id").primaryKey(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| repoFullName: text("repo_full_name").notNull(), | |
| addedAt: text("added_at").notNull(), | |
| }, (table) => ({ | |
| // Unique constraint on userId + repoFullName to prevent duplicate tracking | |
| userRepoUnique: uniqueIndex("user_repo_unique").on(table.userId, table.repoFullName), | |
| })); | |
| // ---- Profile Skills ---- | |
| export const profileSkills = sqliteTable("profile_skills", { | |
| profileId: text("profile_id").notNull().references(() => profiles.userId, { onDelete: "cascade" }), | |
| skill: text("skill").notNull(), | |
| }); | |
| // ---- Profile Mentoring Topics ---- | |
| export const profileMentoringTopics = sqliteTable("profile_mentoring_topics", { | |
| profileId: text("profile_id").notNull().references(() => profiles.userId, { onDelete: "cascade" }), | |
| topic: text("topic").notNull(), | |
| }); | |
| // ---- Profile Connected Repos ---- | |
| export const profileConnectedRepos = sqliteTable("profile_connected_repos", { | |
| profileId: text("profile_id").notNull().references(() => profiles.userId, { onDelete: "cascade" }), | |
| repoName: text("repo_name").notNull(), | |
| }); | |
| // ---- Mentor Tech Stack ---- | |
| export const mentorTechStack = sqliteTable("mentor_tech_stack", { | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| tech: text("tech").notNull(), | |
| }); | |
| // ---- Mentor Languages ---- | |
| export const mentorLanguages = sqliteTable("mentor_languages", { | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| language: text("language").notNull(), | |
| }); | |
| // ---- Mentor Frameworks ---- | |
| export const mentorFrameworks = sqliteTable("mentor_frameworks", { | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| framework: text("framework").notNull(), | |
| }); | |
| // ---- Mentor Preferred Topics ---- | |
| export const mentorPreferredTopics = sqliteTable("mentor_preferred_topics", { | |
| mentorId: text("mentor_id").notNull().references(() => mentors.id, { onDelete: "cascade" }), | |
| topic: text("topic").notNull(), | |
| }); | |
| // ---- Mentor Match Matched Skills ---- | |
| export const mentorMatchSkills = sqliteTable("mentor_match_skills", { | |
| matchId: text("match_id").notNull().references(() => mentorMatches.id, { onDelete: "cascade" }), | |
| skill: text("skill").notNull(), | |
| }); | |
| // ---- Chat Session Mentees ---- | |
| export const chatSessionMentees = sqliteTable("chat_session_mentees", { | |
| sessionId: text("session_id").notNull().references(() => chatSessions.id, { onDelete: "cascade" }), | |
| menteeId: text("mentee_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| menteeUsername: text("mentee_username").notNull(), | |
| }); | |
| // ---- Chat Session Key Points ---- | |
| export const chatSessionKeyPoints = sqliteTable("chat_session_key_points", { | |
| id: text("id").primaryKey(), | |
| sessionId: text("session_id").notNull().references(() => chatSessions.id, { onDelete: "cascade" }), | |
| keyPoint: text("key_point").notNull(), | |
| sortOrder: integer("sort_order").default(0), | |
| }); | |
| // ---- Chat Session Resources Shared ---- | |
| export const chatSessionResources = sqliteTable("chat_session_resources", { | |
| sessionId: text("session_id").notNull().references(() => chatSessions.id, { onDelete: "cascade" }), | |
| resourceId: text("resource_id").notNull().references(() => resources.id, { onDelete: "cascade" }), | |
| }); | |
| // ---- Chat History Messages (DEPRECATED - see chatHistory above) ---- | |
| // export const chatHistoryMessages = sqliteTable("chat_history_messages", { | |
| // id: text("id").primaryKey(), | |
| // chatHistoryId: text("chat_history_id").notNull().references(() => chatHistory.id, { onDelete: "cascade" }), | |
| // role: text("role").notNull(), // 'user' | 'assistant' | |
| // content: text("content").notNull(), | |
| // timestamp: text("timestamp").notNull(), | |
| // githubCommentId: text("github_comment_id"), | |
| // githubCommentUrl: text("github_comment_url"), | |
| // }); | |
| // ---- Issue Chat Messages ---- | |
| export const issueChatMessages = sqliteTable("issue_chat_messages", { | |
| id: text("id").primaryKey(), | |
| issueChatId: text("issue_chat_id").notNull().references(() => issueChats.id, { onDelete: "cascade" }), | |
| role: text("role").notNull(), | |
| content: text("content").notNull(), | |
| timestamp: text("timestamp").notNull(), | |
| githubCommentId: text("github_comment_id"), | |
| githubCommentUrl: text("github_comment_url"), | |
| }); | |
| // ---- Chat Message Attachments ---- | |
| export const chatMessageAttachments = sqliteTable("chat_message_attachments", { | |
| messageId: text("message_id").notNull().references(() => chatMessages.id, { onDelete: "cascade" }), | |
| attachment: text("attachment").notNull(), | |
| }); | |
| // ---- Chat Message Reactions ---- | |
| export const chatMessageReactions = sqliteTable("chat_message_reactions", { | |
| messageId: text("message_id").notNull().references(() => chatMessages.id, { onDelete: "cascade" }), | |
| emoji: text("emoji").notNull(), | |
| userId: text("user_id").notNull().references(() => users.id, { onDelete: "cascade" }), | |
| }); | |
| // ---- Resource Tags ---- | |
| export const resourceTags = sqliteTable("resource_tags", { | |
| resourceId: text("resource_id").notNull().references(() => resources.id, { onDelete: "cascade" }), | |
| tag: text("tag").notNull(), | |
| }); | |
| // ---- Private Resources (Mentor-Contributor Tunnel) ---- | |
| // These resources are only visible to the repo owner (mentor) and the specific PR/issue author | |
| export const privateResources = sqliteTable("private_resources", { | |
| id: text("id").primaryKey(), | |
| issueId: text("issue_id").notNull().references(() => issues.id, { onDelete: "cascade" }), | |
| repoOwner: text("repo_owner").notNull(), // The repository owner (mentor) who can see this | |
| prAuthor: text("pr_author").notNull(), // The PR/issue author (contributor) who can see this | |
| resourceType: text("resource_type").notNull(), // link, code_snippet, documentation, tutorial, etc. | |
| title: text("title").notNull(), | |
| content: text("content").notNull(), | |
| description: text("description"), | |
| language: text("language"), // For code snippets | |
| sharedBy: text("shared_by").notNull(), // Username who shared | |
| sharedById: text("shared_by_id").notNull().references(() => users.id), | |
| createdAt: text("created_at").notNull(), | |
| updatedAt: text("updated_at").notNull(), | |
| }); | |
| // ============================================================================= | |
| // RELATIONS (for Drizzle Query API) | |
| // ============================================================================= | |
| export const usersRelations = relations(users, ({ many, one }) => ({ | |
| repositories: many(repositories), | |
| issues: many(issues), | |
| profile: one(profiles), | |
| trophies: many(trophies), | |
| sentMessages: many(messages, { relationName: "sender" }), | |
| receivedMessages: many(messages, { relationName: "receiver" }), | |
| })); | |
| export const repositoriesRelations = relations(repositories, ({ one, many }) => ({ | |
| user: one(users, { fields: [repositories.userId], references: [users.id] }), | |
| issues: many(issues), | |
| })); | |
| export const issuesRelations = relations(issues, ({ one, many }) => ({ | |
| repository: one(repositories, { fields: [issues.repoId], references: [repositories.id] }), | |
| triageData: one(triageData), | |
| issueChats: many(issueChats), | |
| })); | |
| export const triageDataRelations = relations(triageData, ({ one }) => ({ | |
| issue: one(issues, { fields: [triageData.issueId], references: [issues.id] }), | |
| })); | |
| export const profilesRelations = relations(profiles, ({ one, many }) => ({ | |
| user: one(users, { fields: [profiles.userId], references: [users.id] }), | |
| skills: many(profileSkills), | |
| mentoringTopics: many(profileMentoringTopics), | |
| connectedRepos: many(profileConnectedRepos), | |
| })); | |
| export const mentorsRelations = relations(mentors, ({ one, many }) => ({ | |
| user: one(users, { fields: [mentors.userId], references: [users.id] }), | |
| matches: many(mentorMatches), | |
| requests: many(mentorshipRequests), | |
| ratings: many(mentorRatings), | |
| techStack: many(mentorTechStack), | |
| languages: many(mentorLanguages), | |
| frameworks: many(mentorFrameworks), | |
| preferredTopics: many(mentorPreferredTopics), | |
| })); | |
| export const chatSessionsRelations = relations(chatSessions, ({ one, many }) => ({ | |
| mentor: one(users, { fields: [chatSessions.mentorId], references: [users.id] }), | |
| messages: many(chatMessages), | |
| mentees: many(chatSessionMentees), | |
| keyPoints: many(chatSessionKeyPoints), | |
| sharedResources: many(chatSessionResources), | |
| })); | |
| export const trophiesRelations = relations(trophies, ({ one }) => ({ | |
| user: one(users, { fields: [trophies.userId], references: [users.id] }), | |
| })); | |
| export const resourcesRelations = relations(resources, ({ one, many }) => ({ | |
| sharer: one(users, { fields: [resources.sharedById], references: [users.id] }), | |
| tags: many(resourceTags), | |
| savedBy: many(userSavedResources), | |
| })); | |