From ef7245b716299f16c6f60bfbc50e729004c12458 Mon Sep 17 00:00:00 2001 From: ryan Date: Thu, 27 Mar 2025 15:31:58 +0300 Subject: [PATCH] fix(labels): add property cache and refactor fetch_item_properties function to use it --- src/components/items_list.rs | 96 +++++++++++++++++++++++++++++------- 1 file changed, 77 insertions(+), 19 deletions(-) diff --git a/src/components/items_list.rs b/src/components/items_list.rs index 2a6a766..76a2677 100644 --- a/src/components/items_list.rs +++ b/src/components/items_list.rs @@ -141,6 +141,8 @@ pub fn ItemsList( // Signal to store the fetched property labels let (property_labels, set_property_labels) = create_signal(HashMap::::new()); + // State to manage property cache + let (property_cache, set_property_cache) = create_signal(HashMap::>::new()); #[cfg(feature = "ssr")] fn get_current_url() -> String { use leptos::use_context; @@ -381,7 +383,19 @@ pub fn ItemsList( }; //function to fetch properties - async fn fetch_item_properties(wikidata_id: &str, set_property_labels: WriteSignal>) -> HashMap { + async fn fetch_item_properties( + wikidata_id: &str, + set_property_labels: WriteSignal>, + property_cache: ReadSignal>>, + set_property_cache: WriteSignal>>, + property_labels: ReadSignal>, + ) -> HashMap { + + // Check cache first + if let Some(cached) = property_cache.get().get(wikidata_id) { + return cached.clone(); + } + let sparql_query = format!( r#" SELECT ?propLabel ?value ?valueLabel WHERE {{ @@ -408,28 +422,56 @@ pub fn ItemsList( Ok(response) => { if let Ok(data) = response.json::().await { let mut result = HashMap::new(); + let mut prop_ids = Vec::new(); + + // First pass: collect unique property IDs if let Some(bindings) = data["results"]["bindings"].as_array() { for binding in bindings { - let prop = binding["propLabel"]["value"].as_str().unwrap_or("").to_string(); - let prop_id = prop.replace("http://www.wikidata.org/prop/", ""); - let value_label = binding["valueLabel"]["value"].as_str().unwrap_or("").to_string(); - - // Fetch property labels - let prop_label_map = fetch_property_labels(vec![prop_id]).await; - set_property_labels.update(|labels_map| { - for (key, value) in &prop_label_map { - labels_map.insert(key.clone(), value.clone()); + if let Some(prop) = binding["propLabel"]["value"].as_str() { + let prop_id = prop.replace("http://www.wikidata.org/prop/", ""); + if !prop_ids.contains(&prop_id) { + prop_ids.push(prop_id.clone()); } - }); - - if let Some(prop_label) = prop_label_map.values().next() { - result.insert(prop_label.clone(), value_label); } - log!("result: {:?}", result); } } + + // Batch fetch missing labels + let existing_labels = property_labels.get(); + let missing_ids: Vec = prop_ids + .iter() + .filter(|id| !existing_labels.contains_key(*id)) + .cloned() + .collect(); + + if !missing_ids.is_empty() { + let new_labels = fetch_property_labels(missing_ids).await; + set_property_labels.update(|labels| { + labels.extend(new_labels.clone()); + }); + } + + // Second pass: build results + if let Some(bindings) = data["results"]["bindings"].as_array() { + for binding in bindings { + if let (Some(prop), Some(value_label)) = ( + binding["propLabel"]["value"].as_str(), + binding["valueLabel"]["value"].as_str() + ) { + let prop_id = prop.replace("http://www.wikidata.org/prop/", ""); + if let Some(label) = property_labels.get().get(&prop_id).cloned() { + result.insert(label.clone(), value_label.to_string()); + } + } + } + } + + // Update cache + set_property_cache.update(|cache| { + cache.insert(wikidata_id.to_string(), result.clone()); + }); + result - } else { HashMap::new() } @@ -527,11 +569,27 @@ pub fn ItemsList( let current_url = Rc::clone(¤t_url); let set_items = set_items.clone(); let set_property_labels = set_property_labels.clone(); + let property_cache = property_cache.clone(); + let set_property_cache = set_property_cache.clone(); Arc::new(move |property: String| { // Normalize the property ID let normalized_property = property.replace("http://www.wikidata.org/prop/", ""); let normalized_property_clone = normalized_property.clone(); + // Check if label already exists + if !property_labels.get().contains_key(&normalized_property) { + spawn_local({ + let normalized_property = normalized_property.clone(); + let set_property_labels = set_property_labels.clone(); + async move { + let labels = fetch_property_labels(vec![normalized_property.clone()]).await; + set_property_labels.update(|map| { + map.extend(labels); + }); + } + }); + } + // Check if property is already selected if !selected_properties.get().contains_key(&normalized_property) && !normalized_property.is_empty() { // Add property to selected properties @@ -608,7 +666,7 @@ pub fn ItemsList( let set_property_labels = set_property_labels.clone(); let property_clone = property.clone(); spawn_local(async move { - let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone()).await; + let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone(), property_cache.clone(), set_property_cache.clone(), property_labels.clone()).await; // Update fetched properties and property labels set_fetched_properties.update(|fp| { fp.insert(wikidata_id.clone(), properties.clone()); @@ -650,7 +708,7 @@ pub fn ItemsList( if let Some(wikidata_id) = &item.wikidata_id { let wikidata_id = wikidata_id.clone(); spawn_local(async move { - let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone()).await; + let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone(), property_cache.clone(), set_property_cache.clone(), property_labels.clone()).await; log!("Fetched properties for index {}: {:?}", index, properties); }); } @@ -799,7 +857,7 @@ pub fn ItemsList( // Fetch additional properties from Wikidata let wikidata_id = id.clone(); spawn_local(async move { - let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone()).await; + let properties = fetch_item_properties(&wikidata_id, set_property_labels.clone(), property_cache.clone(), set_property_cache.clone(), property_labels.clone()).await; // log!("Fetched properties for Wikidata ID {}: {:?}", wikidata_id, properties); // Populate the custom properties for the new item