gwelle 0.1.0

Lightweight Rust client for the Google Trends API
Documentation
use crate::client::{format_req_param, TrendsClient};
use crate::models::{RelatedItem, RelatedQueries, WidgetToken};
use crate::{Result, TrendsError};

impl TrendsClient {
    pub async fn related_queries(&self, token: &WidgetToken) -> Result<RelatedQueries> {
        let url = "https://trends.google.com/trends/api/widgetdata/relatedsearches";

        let req_str = format_req_param(&token.request)?;

        let tz_str = self.tz.to_string();

        let params = vec![
            ("hl", self.hl.as_str()),
            ("tz", tz_str.as_str()),
            ("req", req_str.as_str()),
            ("token", token.token.as_str()),
        ];

        let result = self.get_json_with_params(url, &params).await?;

        let ranked_list = result
            .pointer("/default/rankedList")
            .and_then(|r| r.as_array())
            .ok_or_else(|| {
                TrendsError::TokenNotFound(
                    "Missing 'default/rankedList' in relatedsearches response".into(),
                )
            })?;

        let mut top_queries = Vec::new();
        let mut rising_queries = Vec::new();

        for (index, list) in ranked_list.iter().enumerate() {
            let Some(items) = list.get("rankedKeyword").and_then(|rk| rk.as_array()) else {
                continue;
            };

            let list_type = list
                .get("rankedListType")
                .and_then(|t| t.as_str())
                .unwrap_or_default()
                .to_ascii_uppercase();

            let target = if list_type == "TOP" {
                &mut top_queries
            } else if list_type == "RISING" {
                &mut rising_queries
            } else if index == 0 {
                &mut top_queries
            } else if index == 1 {
                &mut rising_queries
            } else {
                continue;
            };

            for item in items {
                let value_str = item
                    .get("formattedValue")
                    .and_then(|v| v.as_str())
                    .or_else(|| item.get("value").and_then(|v| v.as_str()))
                    .map(|v| v.to_string())
                    .or_else(|| item.get("value").map(|v| v.to_string()))
                    .unwrap_or_default();

                target.push(RelatedItem {
                    query: item
                        .get("query")
                        .and_then(|v| v.as_str())
                        .unwrap_or("")
                        .to_string(),
                    value: value_str,
                    link: item
                        .get("link")
                        .and_then(|v| v.as_str())
                        .unwrap_or("")
                        .to_string(),
                });
            }
        }

        Ok(RelatedQueries {
            top: top_queries,
            rising: rising_queries,
        })
    }
}