♻️ refactor: update review-analysis.ts

swadhinbiswas committed 3 months ago
0a09d9d
1 parent d0e310a
commit 0a09d9d
1 file changed
+155 -0
Showing 1 changed file+155-0
▼src/db/schema/review-analysis.ts
+155-0
1
+/**
2
+ * Review Analysis Schema - Drizzle ORM
3
+ * Stores analysis results, summaries, and review data for PRs.
4
+ */
5
+
6
+import { index, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
7
+import { pullRequests } from "./pull-requests";
8
+import { repositories } from "./repositories";
9
+import { users } from "./users";
10
+
11
+/**
12
+ * Stores the full analysis result for a PR review.
13
+ */
14
+export const prReviewAnalyses = pgTable(
15
+ "pr_review_analyses",
16
+ {
17
+ id: text("id").primaryKey(),
18
+ pullRequestId: text("pull_request_id")
19
+ .notNull()
20
+ .references(() => pullRequests.id, { onDelete: "cascade" }),
21
+ repositoryId: text("repository_id")
22
+ .notNull()
23
+ .references(() => repositories.id, { onDelete: "cascade" }),
24
+ status: text("status").notNull().default("pending"), // pending, running, completed, failed
25
+
26
+ // Analysis results (JSON)
27
+ complexityData: jsonb("complexity_data"),
28
+ dependencyGraph: jsonb("dependency_graph"),
29
+ architectureImpact: jsonb("architecture_impact"),
30
+ changeGroups: jsonb("change_groups"),
31
+ blastRadius: jsonb("blast_radius"),
32
+ healthScore: integer("health_score"), // 0-100
33
+ healthGrade: text("health_grade"), // A+, A, B, C, D, F
34
+
35
+ // Summaries (JSON)
36
+ summaries: jsonb("summaries"),
37
+
38
+ // Metadata
39
+ baseSha: text("base_sha"),
40
+ headSha: text("head_sha"),
41
+ filesAnalyzed: integer("files_analyzed"),
42
+ chunksProcessed: integer("chunks_processed"),
43
+ totalAdditions: integer("total_additions"),
44
+ totalDeletions: integer("total_deletions"),
45
+
46
+ // AI review metadata
47
+ model: text("model"),
48
+ provider: text("provider"),
49
+ tokensUsed: integer("tokens_used"),
50
+ costCents: integer("cost_cents"),
51
+ rawAiResponse: jsonb("raw_ai_response"),
52
+
53
+ // Tracking
54
+ triggeredById: text("triggered_by_id").references(() => users.id),
55
+ createdAt: timestamp("created_at").notNull().defaultNow(),
56
+ startedAt: timestamp("started_at"),
57
+ completedAt: timestamp("completed_at"),
58
+ errorMessage: text("error_message"),
59
+ },
60
+ (t) => ({
61
+ pullRequestIdx: index("pr_analysis_pr_idx").on(t.pullRequestId),
62
+ repositoryIdx: index("pr_analysis_repo_idx").on(t.repositoryId),
63
+ statusIdx: index("pr_analysis_status_idx").on(t.status),
64
+ createdIdx: index("pr_analysis_created_idx").on(t.createdAt),
65
+ }),
66
+);
67
+
68
+/**
69
+ * Stores file-level summaries.
70
+ */
71
+export const fileSummaries = pgTable(
72
+ "file_summaries",
73
+ {
74
+ id: text("id").primaryKey(),
75
+ analysisId: text("analysis_id")
76
+ .notNull()
77
+ .references(() => prReviewAnalyses.id, { onDelete: "cascade" }),
78
+ filePath: text("file_path").notNull(),
79
+ language: text("language"),
80
+ summary: text("summary"),
81
+ riskLevel: text("risk_level"), // low, medium, high, critical
82
+ additions: integer("additions"),
83
+ deletions: integer("deletions"),
84
+ complexityScore: integer("complexity_score"),
85
+ createdAt: timestamp("created_at").notNull().defaultNow(),
86
+ },
87
+ (t) => ({
88
+ analysisIdx: index("file_summaries_analysis_idx").on(t.analysisId),
89
+ filePathIdx: index("file_summaries_path_idx").on(t.filePath),
90
+ }),
91
+);
92
+
93
+/**
94
+ * Stores inline AI review comments on specific lines.
95
+ */
96
+export const aiInlineComments = pgTable(
97
+ "ai_inline_comments",
98
+ {
99
+ id: text("id").primaryKey(),
100
+ analysisId: text("analysis_id")
101
+ .notNull()
102
+ .references(() => prReviewAnalyses.id, { onDelete: "cascade" }),
103
+ pullRequestId: text("pull_request_id")
104
+ .notNull()
105
+ .references(() => pullRequests.id, { onDelete: "cascade" }),
106
+ filePath: text("file_path").notNull(),
107
+ line: integer("line").notNull(),
108
+ endLine: integer("end_line"),
109
+ side: text("side").default("right"), // left, right
110
+ severity: text("severity").notNull(), // info, warning, error, critical
111
+ type: text("type").notNull(), // bug, security, performance, style, documentation, suggestion
112
+ category: text("category"), // code-quality, security, performance, architecture, testing
113
+ title: text("title").notNull(),
114
+ message: text("message").notNull(),
115
+ suggestedFix: text("suggested_fix"),
116
+ explanation: text("explanation"),
117
+ confidence: integer("confidence"), // 0-100
118
+ isResolved: integer("is_resolved").default(0), // 0 or 1
119
+ isApplied: integer("is_applied").default(0),
120
+ appliedAt: timestamp("applied_at"),
121
+ dismissedAt: timestamp("dismissed_at"),
122
+ createdAt: timestamp("created_at").notNull().defaultNow(),
123
+ },
124
+ (t) => ({
125
+ analysisIdx: index("ai_inline_comments_analysis_idx").on(t.analysisId),
126
+ pullRequestIdx: index("ai_inline_comments_pr_idx").on(t.pullRequestId),
127
+ filePathIdx: index("ai_inline_comments_path_idx").on(t.filePath),
128
+ severityIdx: index("ai_inline_comments_severity_idx").on(t.severity),
129
+ }),
130
+);
131
+
132
+/**
133
+ * Tracks AI review conversation threads (chat with AI about PR).
134
+ */
135
+export const aiReviewThreads = pgTable(
136
+ "ai_review_threads",
137
+ {
138
+ id: text("id").primaryKey(),
139
+ analysisId: text("analysis_id")
140
+ .notNull()
141
+ .references(() => prReviewAnalyses.id, { onDelete: "cascade" }),
142
+ pullRequestId: text("pull_request_id")
143
+ .notNull()
144
+ .references(() => pullRequests.id, { onDelete: "cascade" }),
145
+ filePath: text("file_path"),
146
+ line: integer("line"),
147
+ messages: jsonb("messages").notNull(), // Array of { role, content, timestamp }
148
+ createdAt: timestamp("created_at").notNull().defaultNow(),
149
+ updatedAt: timestamp("updated_at").notNull().defaultNow(),
150
+ },
151
+ (t) => ({
152
+ analysisIdx: index("ai_thread_analysis_idx").on(t.analysisId),
153
+ pullRequestIdx: index("ai_thread_pr_idx").on(t.pullRequestId),
154
+ }),
155
+);
0
156