Skip to main content

systemprompt_cli/commands/core/content/analytics/
journey.rs

1use crate::cli_settings::CliConfig;
2use crate::commands::core::content::types::{JourneyNode, JourneyOutput};
3use crate::shared::CommandResult;
4use anyhow::Result;
5use clap::Args;
6use systemprompt_content::LinkAnalyticsService;
7use systemprompt_database::DbPool;
8use systemprompt_runtime::AppContext;
9
10#[derive(Debug, Clone, Copy, Args)]
11pub struct JourneyArgs {
12    #[arg(long, default_value = "20")]
13    pub limit: i64,
14
15    #[arg(long, default_value = "0")]
16    pub offset: i64,
17}
18
19pub async fn execute(
20    args: JourneyArgs,
21    config: &CliConfig,
22) -> Result<CommandResult<JourneyOutput>> {
23    let ctx = AppContext::new().await?;
24    execute_with_pool(args, ctx.db_pool(), config).await
25}
26
27pub async fn execute_with_pool(
28    args: JourneyArgs,
29    pool: &DbPool,
30    _config: &CliConfig,
31) -> Result<CommandResult<JourneyOutput>> {
32    let service = LinkAnalyticsService::new(pool)?;
33
34    let nodes = service
35        .get_content_journey_map(Some(args.limit), Some(args.offset))
36        .await?;
37
38    let journey_nodes: Vec<JourneyNode> = nodes
39        .into_iter()
40        .map(|node| JourneyNode {
41            source_content_id: node.source_content_id,
42            target_url: node.target_url,
43            click_count: node.click_count,
44        })
45        .collect();
46
47    let output = JourneyOutput {
48        nodes: journey_nodes,
49    };
50
51    Ok(CommandResult::table(output)
52        .with_title("Content Journey")
53        .with_columns(vec![
54            "source_content_id".to_string(),
55            "target_url".to_string(),
56            "click_count".to_string(),
57        ]))
58}