+42
-5
netlify/functions/db.ts
+42
-5
netlify/functions/db.ts
···
139
139
)
140
140
`;
141
141
142
-
// Create indexes
142
+
// ==================== ENHANCED INDEXES FOR PHASE 2 ====================
143
+
144
+
// Existing indexes
143
145
await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_to_check ON source_accounts(source_platform, match_found, last_checked)`;
144
146
await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_platform ON source_accounts(source_platform)`;
145
147
await sql`CREATE INDEX IF NOT EXISTS idx_user_source_follows_did ON user_source_follows(did)`;
···
148
150
await sql`CREATE INDEX IF NOT EXISTS idx_atproto_matches_did ON atproto_matches(atproto_did)`;
149
151
await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_did_notified ON user_match_status(did, notified, viewed)`;
150
152
await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_did_followed ON user_match_status(did, followed)`;
151
-
await sql`CREATE INDEX IF NOT EXISTS idx_notification_queue_pending ON notification_queue(sent, created_at) WHERE sent = FALSE`;
153
+
await sql`CREATE INDEX IF NOT EXISTS idx_notification_queue_pending ON notification_queue(sent, created_at) WHERE sent = false`;
154
+
155
+
// NEW: Enhanced indexes for common query patterns
156
+
157
+
// For session lookups (most frequent query)
158
+
await sql`CREATE INDEX IF NOT EXISTS idx_user_sessions_did ON user_sessions(did)`;
159
+
await sql`CREATE INDEX IF NOT EXISTS idx_user_sessions_expires ON user_sessions(expires_at)`;
160
+
161
+
// For OAuth state/session cleanup
162
+
await sql`CREATE INDEX IF NOT EXISTS idx_oauth_states_expires ON oauth_states(expires_at)`;
163
+
await sql`CREATE INDEX IF NOT EXISTS idx_oauth_sessions_expires ON oauth_sessions(expires_at)`;
164
+
165
+
// For upload queries by user
166
+
await sql`CREATE INDEX IF NOT EXISTS idx_user_uploads_did_created ON user_uploads(did, created_at DESC)`;
167
+
168
+
// For upload details pagination (composite index for ORDER BY + JOIN)
169
+
await sql`CREATE INDEX IF NOT EXISTS idx_user_source_follows_upload_created ON user_source_follows(upload_id, source_account_id)`;
170
+
171
+
// For match status queries
172
+
await sql`CREATE INDEX IF NOT EXISTS idx_user_match_status_match_id ON user_match_status(atproto_match_id)`;
173
+
174
+
// Composite index for the common join pattern in get-upload-details
175
+
await sql`CREATE INDEX IF NOT EXISTS idx_atproto_matches_source_active ON atproto_matches(source_account_id, is_active) WHERE is_active = true`;
176
+
177
+
// For bulk operations - normalized username lookups
178
+
await sql`CREATE INDEX IF NOT EXISTS idx_source_accounts_normalized ON source_accounts(normalized_username, source_platform)`;
179
+
180
+
console.log('✅ Database indexes created/verified');
152
181
}
153
182
154
183
export async function cleanupExpiredSessions() {
155
184
const sql = getDbClient();
156
-
await sql`DELETE FROM oauth_states WHERE expires_at < NOW()`;
157
-
await sql`DELETE FROM oauth_sessions WHERE expires_at < NOW()`;
158
-
await sql`DELETE FROM user_sessions WHERE expires_at < NOW()`;
185
+
186
+
// Use indexes for efficient cleanup
187
+
const statesDeleted = await sql`DELETE FROM oauth_states WHERE expires_at < NOW()`;
188
+
const sessionsDeleted = await sql`DELETE FROM oauth_sessions WHERE expires_at < NOW()`;
189
+
const userSessionsDeleted = await sql`DELETE FROM user_sessions WHERE expires_at < NOW()`;
190
+
191
+
console.log('🧹 Cleanup:', {
192
+
states: (statesDeleted as any).length,
193
+
sessions: (sessionsDeleted as any).length,
194
+
userSessions: (userSessionsDeleted as any).length
195
+
});
159
196
}
160
197
161
198
export { getDbClient as sql };