a cache for slack profile pictures and emojis
1import type { Database } from "bun:sqlite";
2import type { Migration } from "./types";
3
4/**
5 * Migration to group request logs that aren't already grouped
6 * This migration normalizes request_analytics data to use consistent endpoint grouping
7 */
8export const logGroupingMigration: Migration = {
9 version: "0.3.2",
10 description: "Group request logs that aren't already grouped",
11
12 async up(db: Database): Promise<void> {
13 console.log("Running log grouping migration...");
14
15 // Get all request_analytics entries with specific URLs that need grouping
16 const results = db
17 .query(`
18 SELECT id, endpoint FROM request_analytics
19 WHERE
20 endpoint NOT LIKE '/users/%/r' AND
21 endpoint NOT LIKE '/users/%' AND
22 endpoint NOT LIKE '/emojis/%/r' AND
23 endpoint NOT LIKE '/emojis/%' AND
24 endpoint NOT LIKE '/health' AND
25 endpoint NOT LIKE '/dashboard' AND
26 endpoint NOT LIKE '/swagger%' AND
27 endpoint NOT LIKE '/reset' AND
28 endpoint NOT LIKE '/stats' AND
29 endpoint NOT LIKE '/'
30 `)
31 .all() as Array<{ id: string; endpoint: string }>;
32
33 console.log(`Found ${results.length} entries to update`);
34
35 // Process each entry and update with the correct grouping
36 for (const entry of results) {
37 let newEndpoint = entry.endpoint;
38
39 // Apply grouping logic
40 if (
41 entry.endpoint.includes("localhost") ||
42 entry.endpoint.includes("http")
43 ) {
44 // Extract the path from URLs
45 try {
46 const url = new URL(entry.endpoint);
47 newEndpoint = url.pathname;
48 } catch (_e) {
49 // If URL parsing fails, try to extract the path manually
50 const pathMatch = entry.endpoint.match(/https?:\/\/[^/]+(\/.*)/);
51 if (pathMatch?.[1]) {
52 newEndpoint = pathMatch[1];
53 }
54 }
55 }
56
57 // Now apply the same grouping logic to the extracted path
58 if (newEndpoint.match(/^\/users\/[^/]+$/)) {
59 newEndpoint = "/users/USER_ID";
60 } else if (newEndpoint.match(/^\/users\/[^/]+\/r$/)) {
61 newEndpoint = "/users/USER_ID/r";
62 } else if (newEndpoint.match(/^\/emojis\/[^/]+$/)) {
63 newEndpoint = "/emojis/EMOJI_NAME";
64 } else if (newEndpoint.match(/^\/emojis\/[^/]+\/r$/)) {
65 newEndpoint = "/emojis/EMOJI_NAME/r";
66 } else if (
67 newEndpoint.includes("/users/") &&
68 newEndpoint.includes("/r")
69 ) {
70 newEndpoint = "/users/USER_ID/r";
71 } else if (newEndpoint.includes("/users/")) {
72 newEndpoint = "/users/USER_ID";
73 } else if (
74 newEndpoint.includes("/emojis/") &&
75 newEndpoint.includes("/r")
76 ) {
77 newEndpoint = "/emojis/EMOJI_NAME/r";
78 } else if (newEndpoint.includes("/emojis/")) {
79 newEndpoint = "/emojis/EMOJI_NAME";
80 } else if (newEndpoint === "/") {
81 newEndpoint = "/";
82 } else if (newEndpoint === "/health") {
83 newEndpoint = "/health";
84 } else if (newEndpoint === "/dashboard") {
85 newEndpoint = "/dashboard";
86 } else if (newEndpoint.startsWith("/swagger")) {
87 newEndpoint = "/swagger";
88 } else if (newEndpoint === "/reset") {
89 newEndpoint = "/reset";
90 } else if (newEndpoint === "/stats") {
91 newEndpoint = "/stats";
92 } else {
93 newEndpoint = "/other";
94 }
95
96 // Only update if the endpoint has changed
97 if (newEndpoint !== entry.endpoint) {
98 db.run(
99 `
100 UPDATE request_analytics
101 SET endpoint = ?
102 WHERE id = ?
103 `,
104 [newEndpoint, entry.id],
105 );
106 }
107 }
108
109 console.log("Log grouping migration completed");
110 },
111};