diff --git a/parakeet/src/db/posts.rs b/parakeet/src/db/posts.rs index 7f45f659..ea1cdb1a 100644 --- a/parakeet/src/db/posts.rs +++ b/parakeet/src/db/posts.rs @@ -148,9 +148,6 @@ pub async fn get_threadgate_hiddens( } } -// NOTE: get_post_id_by_uri removed - posts table no longer has id column -// Use natural keys (actor_id, rkey) directly instead - /// Batch lookup post IDs from AT URIs /// /// Returns HashMap mapping AT URI to internal post ID @@ -183,8 +180,7 @@ pub async fn get_post_ids_by_uris( return Ok(HashMap::new()); } - // TODO: Update cache to use PostKey instead of i64 - // For now, skip cache and query all URIs + // Cache currently uses i64 IDs, querying directly for now let mut result = HashMap::new(); let uris_to_query = uris.to_vec(); @@ -357,11 +353,6 @@ pub async fn get_post_ids_by_uris( }) .collect(); - // TODO: Populate cache with new results (cache needs to be updated to use PostKey) - // if let Some(cache) = cache { - // cache.set_post_ids(&db_results).await; - // } - // Return database results result.extend(db_results); diff --git a/parakeet/src/db/search.rs b/parakeet/src/db/search.rs index 175f32a7..c863c890 100644 --- a/parakeet/src/db/search.rs +++ b/parakeet/src/db/search.rs @@ -205,7 +205,7 @@ pub async fn search_posts( tags: &[String], since: Option, until: Option, - _sort: &str, // TODO: Implement BM25 ranking for "top" sort + _sort: &str, // TODO: BM25 ranking for "top" sort limit: i64, cursor: Option, ) -> QueryResult> { @@ -235,9 +235,7 @@ pub async fn search_posts( micros << 10 }); - // For token-based search, "top" sort doesn't have a good relevance metric yet - // So we'll just use chronological order (latest) for both modes - // TODO: Implement BM25 or similar for relevance ranking + // Using chronological order for now - "top" sort requires relevance ranking if has_text { // Search with text tokens @@ -359,7 +357,7 @@ pub async fn search_posts_by_ids( tags: &[String], since: Option, until: Option, - _sort: &str, // TODO: Implement BM25 ranking for "top" sort + _sort: &str, // TODO: BM25 ranking for "top" sort limit: i64, cursor: Option, ) -> QueryResult> { diff --git a/parakeet/src/hydration/profile/builders.rs b/parakeet/src/hydration/profile/builders.rs index 0b8e2ce4..0f1d6dd0 100644 --- a/parakeet/src/hydration/profile/builders.rs +++ b/parakeet/src/hydration/profile/builders.rs @@ -64,7 +64,7 @@ pub(super) fn build_viewer( ProfileViewerState { muted: data.muting.unwrap_or_default(), muted_by_list: list_mute, - blocked_by: data.blocked.unwrap_or_default(), // TODO: this doesn't factor for blocklists atm + blocked_by: data.blocked.unwrap_or_default(), // TODO: Include blocklist memberships blocking, blocking_by_list: list_block, following, diff --git a/parakeet/src/hydration/profile/verification.rs b/parakeet/src/hydration/profile/verification.rs index 26dde66f..5c943a87 100644 --- a/parakeet/src/hydration/profile/verification.rs +++ b/parakeet/src/hydration/profile/verification.rs @@ -38,10 +38,7 @@ pub(super) fn build_verification( // Return None if profile doesn't exist let profile = profile.as_ref()?; - // Why says there's a way for the client to configure which verifiers to trust (explicitly - // mentioning the deer.social client which doesn't run an AppView) - except I can't see any - // parameters or headers in requests, or anywhere in social-app where one would configure that. - // Presuming this means that this will be an option eventually (or I'm missing something) + // Use configured trusted verifiers. let accept_verifiers = TRUSTED_VERIFIERS.get().unwrap(); let is_trusted_verifier = accept_verifiers.iter().any(|v| v == did); diff --git a/parakeet/src/hydration/starter_packs.rs b/parakeet/src/hydration/starter_packs.rs index d7b82471..91b3419c 100644 --- a/parakeet/src/hydration/starter_packs.rs +++ b/parakeet/src/hydration/starter_packs.rs @@ -40,7 +40,7 @@ fn build_spview( record: enriched.record, creator, list, - list_items_sample: vec![], // TODO: we should do this, but the app seems to be okay without? + list_items_sample: vec![], feeds, list_item_count, joined_week_count: 0, diff --git a/parakeet/src/loaders/embed.rs b/parakeet/src/loaders/embed.rs index 8d775119..84ef5aea 100644 --- a/parakeet/src/loaders/embed.rs +++ b/parakeet/src/loaders/embed.rs @@ -1,7 +1,6 @@ use serde::{Deserialize, Serialize}; -// EmbedLoader removed - now using hydrate_embed_from_post() instead -// This file now only contains type definitions used by hydration code +// Type definitions used by embed hydration code // Enriched PostEmbedRecord with reconstructed URI #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/parakeet/src/loaders/mod.rs b/parakeet/src/loaders/mod.rs index 4b89202d..8da75258 100644 --- a/parakeet/src/loaders/mod.rs +++ b/parakeet/src/loaders/mod.rs @@ -12,7 +12,7 @@ use dataloader::BatchFn; use diesel_async::pooled_connection::deadpool::Pool; use diesel_async::AsyncPgConnection; -// Re-export public types (EmbedLoader removed - now using hydrate_embed_from_post() instead) +// Re-export public types pub use embed::{EmbedLoaderRet, EnrichedPostEmbedRecord, PostEmbedImage, PostEmbedVideo, PostEmbedExt}; pub use feed::{EnrichedFeedGen, FeedGenKey, FeedGenLoader, LikeRecordLoader}; pub use labeler::{EnrichedLabeler, LabelLoader, LabelServiceLoader, LabelServiceLoaderRet}; diff --git a/parakeet/src/loaders/post.rs b/parakeet/src/loaders/post.rs index f69b5fbf..077e4312 100644 --- a/parakeet/src/loaders/post.rs +++ b/parakeet/src/loaders/post.rs @@ -4,8 +4,7 @@ use diesel_async::AsyncPgConnection; use parakeet_db::models::{self, array_helpers}; use std::collections::HashMap; -/// Extended Post model with computed fields from the old schema -/// (parent_uri, root_uri, did, cid, at_uri reconstructed from FKs) +/// Post model with computed fields (URIs reconstructed from natural keys) #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct HydratedPost { pub post: models::Post, @@ -176,11 +175,8 @@ pub struct PostWithComputed { /// Tests can call this to validate SQL syntax without duplicating the query. /// Build SQL query for batch loading posts by natural keys (actor_id, rkey) /// -/// OPTIMIZED: No tid_timestamp() function call, no actors JOIN -/// - Timestamp computed in Rust via tid_to_datetime(rkey) -/// - Natural keys (actor_id, rkey) passed directly from parsed URIs -/// - DIDs already available from parsing, no JOIN needed -/// - Uses ANY array for 26x better index usage vs IN subquery (0.7ms vs 5.6ms for 30 posts) +/// Uses natural keys directly avoiding actor table joins. +/// Timestamps computed in Rust via tid_to_datetime(rkey). /// /// This function is public for testing purposes. pub fn build_posts_batch_query() -> &'static str { @@ -969,7 +965,6 @@ impl BatchFn for PostLoader { .collect(); let post_processing_time = post_processing_start.elapsed().as_secs_f64() * 1000.0; - // OPTIMIZED: Facets are now loaded inline with posts (no separate query needed) // Collect all mention actor IDs from facets to batch lookup DIDs let facets_start = std::time::Instant::now(); let mut mention_actor_ids: Vec = Vec::new(); @@ -1030,11 +1025,9 @@ impl BatchFn for PostLoader { } use parakeet_db::models::array_helpers::ThreadgateRuleArray; - // Generate synthetic CID for threadgate (deterministic based on post natural key) - // Since we no longer store the real threadgate CID, we create a consistent placeholder + // Generate deterministic CID for threadgate based on post natural key let synthetic_cid = parakeet_db::cid_util::post_cid_string(post.actor_id, post.rkey); - // TODO: Load allowed_lists from threadgate_allowed_lists junction table if needed let allowed_lists = None; // Store hidden replies as (actor_id, rkey) pairs - URI construction deferred to hydration @@ -1154,7 +1147,7 @@ impl BatchFn for PostLoader { _threadgate_hidden_rkeys, labels, )| { - // OPTIMIZED: Process facets from inline composite fields (no separate query) + // Process facets from inline composite fields let facet_vec = vec![facet_1, facet_2, facet_3, facet_4, facet_5, facet_6, facet_7, facet_8]; let facets: Vec = facet_vec .into_iter() diff --git a/parakeet/src/timeline_cache.rs b/parakeet/src/timeline_cache.rs index d8f0a579..1b098f4a 100644 --- a/parakeet/src/timeline_cache.rs +++ b/parakeet/src/timeline_cache.rs @@ -109,7 +109,7 @@ impl TimelineCache { let prefix = format!("timeline:{}:", actor_id); // Invalidate all entries matching the prefix - // Note: We can't count deletions with moka's Fn closure API + // Deletion metrics not tracked in current implementation drop(self.cache.invalidate_entries_if(move |key, _| { key.starts_with(&prefix) })); @@ -219,7 +219,7 @@ impl AuthorFeedCache { let prefix = format!("authorfeed:{}:", actor_id); // Invalidate all entries matching the prefix - // Note: We can't count deletions with moka's Fn closure API + // Deletion metrics not tracked in current implementation drop(self.cache.invalidate_entries_if(move |key, _| { key.starts_with(&prefix) })); @@ -336,7 +336,6 @@ mod tests { // Invalidate let _deleted = cache.invalidate_by_actor_id(actor_id).await; - // Note: moka's API doesn't allow counting deletions // Verify cache cleared assert!(cache.get(actor_id, None).await.is_none()); diff --git a/parakeet/src/xrpc/app_bsky/feed/feedgen.rs b/parakeet/src/xrpc/app_bsky/feed/feedgen.rs index 3f28e121..a0afa231 100644 --- a/parakeet/src/xrpc/app_bsky/feed/feedgen.rs +++ b/parakeet/src/xrpc/app_bsky/feed/feedgen.rs @@ -197,8 +197,7 @@ pub async fn get_suggested_feeds( .and_then(|c| c.parse::().ok()) .unwrap_or(0); - // Fetch and rank feeds - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - feed rankings let mut conn = state.pool.get().await?; // Fetch all feedgens ordered by like count (uses idx_feedgens_like_count_desc index) diff --git a/parakeet/src/xrpc/app_bsky/feed/posts/helpers.rs b/parakeet/src/xrpc/app_bsky/feed/posts/helpers.rs index 09c4e4ea..15f54229 100644 --- a/parakeet/src/xrpc/app_bsky/feed/posts/helpers.rs +++ b/parakeet/src/xrpc/app_bsky/feed/posts/helpers.rs @@ -14,9 +14,6 @@ use crate::xrpc::error::{Error, XrpcResult}; #[expect(dead_code)] const FEEDGEN_SERVICE_ID: &str = "#bsky_fg"; -// Note: embed_type filtering is now done in SQL string interpolation in feed queries -// The old diesel-based embed_type_filter function has been removed - pub(super) async fn get_feed_skeleton( client: &reqwest::Client, feed: &str, diff --git a/parakeet/src/xrpc/app_bsky/graph/suggestions.rs b/parakeet/src/xrpc/app_bsky/graph/suggestions.rs index 82023c0c..1e01f1b5 100644 --- a/parakeet/src/xrpc/app_bsky/graph/suggestions.rs +++ b/parakeet/src/xrpc/app_bsky/graph/suggestions.rs @@ -42,8 +42,7 @@ pub async fn get_suggested_follows_by_actor( &actor_did, ).await?; - // Compute suggestions - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - similarity suggestions // Get input actor's follower count for similarity ranking let input_stats = state diff --git a/parakeet/src/xrpc/app_bsky/unspecced/mod.rs b/parakeet/src/xrpc/app_bsky/unspecced/mod.rs index 6a0141e9..21b02d0e 100644 --- a/parakeet/src/xrpc/app_bsky/unspecced/mod.rs +++ b/parakeet/src/xrpc/app_bsky/unspecced/mod.rs @@ -155,8 +155,7 @@ pub async fn get_suggested_feeds( ) -> XrpcResult> { let limit = query.limit.unwrap_or(50).clamp(1, 100) as usize; - // Fetch and rank feeds (no caching - recalculated each time) - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - feed rankings let mut conn = state.pool.get().await?; // Fetch all feedgens ordered by like count (uses idx_feedgens_like_count_desc index) @@ -234,8 +233,7 @@ pub async fn get_suggested_users( let limit = query.limit.unwrap_or(25).clamp(1, 100) as usize; // Category parameter is accepted but ignored for now - // Compute global suggestions (no caching - recalculated each time) - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - actor suggestions let mut conn = state.pool.get().await?; // Get top 1000 most-followed DIDs by counting follows in our database @@ -333,8 +331,7 @@ pub async fn get_popular_feed_generators( .and_then(|c| c.parse::().ok()) .unwrap_or(0); - // Fetch and rank feeds (no caching - recalculated each time) - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - feed rankings let mut conn = state.pool.get().await?; // Fetch all feedgens ordered by like count (uses idx_feedgens_like_count_desc index) @@ -462,7 +459,7 @@ pub async fn get_suggested_starter_packs( let limit = query.limit.unwrap_or(25).clamp(1, 100) as usize; // Compute rankings (no caching - recalculated each time) - // TODO: Consider adding moka cache if this becomes a bottleneck + // TODO: Cache opportunity - starter pack rankings let mut conn = state.pool.get().await?; // Get all starter packs with their owners