diff --git a/parakeet/src/hydration/embed.rs b/parakeet/src/hydration/embed.rs index 65c28266..3017ecce 100644 --- a/parakeet/src/hydration/embed.rs +++ b/parakeet/src/hydration/embed.rs @@ -140,83 +140,88 @@ fn build_embed(embed: EmbedLoaderRet, did: &str, cdn: &BskyCdn) -> Option } } +/// Helper function to convert a HydratedPost's embed fields to EmbedLoaderRet +/// This consolidates the logic used by both single and batch embed hydration +fn extract_embed_from_post(post: &crate::loaders::HydratedPost) -> Option { + let embed_type = post.post.embed_type.as_ref()?; + + match embed_type { + parakeet_db::types::EmbedType::Images => { + let images = extract_post_images(post); + if !images.is_empty() { + Some(EmbedLoaderRet::Images(images)) + } else { + None + } + } + parakeet_db::types::EmbedType::Video => { + extract_post_video(post).map(EmbedLoaderRet::Video) + } + parakeet_db::types::EmbedType::External => { + extract_post_external(post).map(EmbedLoaderRet::External) + } + parakeet_db::types::EmbedType::Record => { + post.embedded_rkey.and_then(|embedded_rkey_bigint| { + let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); + let emb_uri = format!( + "at://{}/{}/{}", + post.embedded_did.as_ref()?, + post.embedded_collection.as_ref()?, + encoded_embedded_rkey + ); + + Some(EmbedLoaderRet::Record(EnrichedPostEmbedRecord { + uri: emb_uri, + record_type: post.embedded_collection.clone()?, + detached: post.record_detached.unwrap_or(false), + })) + }) + } + parakeet_db::types::EmbedType::RecordWithMedia => { + post.embedded_rkey.and_then(|embedded_rkey_bigint| { + let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); + let emb_uri = format!( + "at://{}/{}/{}", + post.embedded_did.as_ref()?, + post.embedded_collection.as_ref()?, + encoded_embedded_rkey + ); + + let record = EnrichedPostEmbedRecord { + uri: emb_uri, + record_type: post.embedded_collection.clone()?, + detached: post.record_detached.unwrap_or(false), + }; + + let media = match post.post.embed_subtype.as_ref()? { + parakeet_db::types::EmbedType::Images => { + let images = extract_post_images(post); + if !images.is_empty() { + Some(EmbedLoaderRet::Images(images)) + } else { + None + } + } + parakeet_db::types::EmbedType::Video => { + extract_post_video(post).map(EmbedLoaderRet::Video) + } + parakeet_db::types::EmbedType::External => { + extract_post_external(post).map(EmbedLoaderRet::External) + } + _ => None, + }?; + + Some(EmbedLoaderRet::RecordWithMedia(record, Box::new(media))) + }) + } + } +} + impl StatefulHydrator<'_> { /// Extract embed from a HydratedPost (no database query needed) /// This replaces the slow EmbedLoader path that was querying the posts table again pub async fn hydrate_embed_from_post(&self, post: &crate::loaders::HydratedPost) -> Option { - - let embed_type = post.post.embed_type.as_ref()?; - - let embed_ret = match embed_type { - parakeet_db::types::EmbedType::Images => { - let images = extract_post_images(post); - if !images.is_empty() { - Some(EmbedLoaderRet::Images(images)) - } else { - None - } - } - parakeet_db::types::EmbedType::Video => { - extract_post_video(post).map(EmbedLoaderRet::Video) - } - parakeet_db::types::EmbedType::External => { - extract_post_external(post).map(EmbedLoaderRet::External) - } - parakeet_db::types::EmbedType::Record => { - post.embedded_rkey.and_then(|embedded_rkey_bigint| { - let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); - let emb_uri = format!( - "at://{}/{}/{}", - post.embedded_did.as_ref()?, - post.embedded_collection.as_ref()?, - encoded_embedded_rkey - ); - - Some(EmbedLoaderRet::Record(EnrichedPostEmbedRecord { - uri: emb_uri, - record_type: post.embedded_collection.clone()?, - detached: post.record_detached.unwrap_or(false), - })) - }) - } - parakeet_db::types::EmbedType::RecordWithMedia => { - post.embedded_rkey.and_then(|embedded_rkey_bigint| { - let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); - let emb_uri = format!( - "at://{}/{}/{}", - post.embedded_did.as_ref()?, - post.embedded_collection.as_ref()?, - encoded_embedded_rkey - ); - - let record = EnrichedPostEmbedRecord { - uri: emb_uri, - record_type: post.embedded_collection.clone()?, - detached: post.record_detached.unwrap_or(false), - }; - - let media = match post.post.embed_subtype.as_ref()? { - parakeet_db::types::EmbedType::Images => { - let images = extract_post_images(post); - if !images.is_empty() { - Some(EmbedLoaderRet::Images(images)) - } else { - None - } - } - parakeet_db::types::EmbedType::Video => { - extract_post_video(post).map(EmbedLoaderRet::Video) - } - parakeet_db::types::EmbedType::External => { - extract_post_external(post).map(EmbedLoaderRet::External) - } - _ => None, - }?; - - Some(EmbedLoaderRet::RecordWithMedia(record, Box::new(media))) - }) - } - }?; + let embed_ret = extract_embed_from_post(post)?; // Now hydrate the EmbedLoaderRet into an Embed match embed_ret { @@ -410,79 +415,11 @@ impl StatefulHydrator<'_> { let conversion_start = std::time::Instant::now(); - // Convert HydratedPost embed fields to EmbedLoaderRet format + // Convert HydratedPost embed fields to EmbedLoaderRet format using the shared helper let embeds: HashMap = posts .iter() .filter_map(|(uri, (post, _, _))| { - let embed_type = post.post.embed_type.as_ref()?; - - let embed_ret = match embed_type { - parakeet_db::types::EmbedType::Images => { - let images = extract_post_images(post); - if !images.is_empty() { - Some(EmbedLoaderRet::Images(images)) - } else { - None - } - } - parakeet_db::types::EmbedType::Video => { - extract_post_video(post).map(EmbedLoaderRet::Video) - } - parakeet_db::types::EmbedType::External => { - extract_post_external(post).map(EmbedLoaderRet::External) - } - parakeet_db::types::EmbedType::Record => { - post.embedded_rkey.and_then(|embedded_rkey_bigint| { - let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); - let emb_uri = format!( - "at://{}/{}/{}", - post.embedded_did.as_ref()?, - post.embedded_collection.as_ref()?, - encoded_embedded_rkey - ); - - Some(EmbedLoaderRet::Record(EnrichedPostEmbedRecord { - uri: emb_uri, - record_type: post.embedded_collection.clone()?, - detached: post.record_detached.unwrap_or(false), - })) - }) - } - parakeet_db::types::EmbedType::RecordWithMedia => { - post.embedded_rkey.and_then(|embedded_rkey_bigint| { - let encoded_embedded_rkey = parakeet_db::tid_util::encode_tid(embedded_rkey_bigint); - let emb_uri = format!( - "at://{}/{}/{}", - post.embedded_did.as_ref()?, - post.embedded_collection.as_ref()?, - encoded_embedded_rkey - ); - - let record = EnrichedPostEmbedRecord { - uri: emb_uri, - record_type: post.embedded_collection.clone()?, - detached: post.record_detached.unwrap_or(false), - }; - - let media = match post.post.embed_subtype.as_ref()? { - parakeet_db::types::EmbedType::Images => { - let images = extract_post_images(post); - (!images.is_empty()).then_some(EmbedLoaderRet::Images(images)) - } - parakeet_db::types::EmbedType::Video => { - extract_post_video(post).map(EmbedLoaderRet::Video) - } - parakeet_db::types::EmbedType::External => { - extract_post_external(post).map(EmbedLoaderRet::External) - } - _ => None, - }?; - - Some(EmbedLoaderRet::RecordWithMedia(record, Box::new(media))) - }) - } - }?; - + let embed_ret = extract_embed_from_post(post)?; Some((uri.clone(), (embed_ret, post.did.clone()))) }) .collect();