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::context::CommandContext;
4use crate::shared::CommandOutput;
5use anyhow::Result;
6use clap::Args;
7use systemprompt_content::LinkAnalyticsService;
8use systemprompt_database::DbPool;
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(args: JourneyArgs, ctx: &CommandContext) -> Result<CommandOutput> {
20    execute_with_pool(args, &ctx.db_pool().await?, &ctx.cli).await
21}
22
23pub async fn execute_with_pool(
24    args: JourneyArgs,
25    pool: &DbPool,
26    _config: &CliConfig,
27) -> Result<CommandOutput> {
28    let service = LinkAnalyticsService::new(pool)?;
29
30    let nodes = service
31        .get_content_journey_map(Some(args.limit), Some(args.offset))
32        .await?;
33
34    let journey_nodes: Vec<JourneyNode> = nodes
35        .into_iter()
36        .map(|node| JourneyNode {
37            source_content_id: node.source_content_id,
38            target_url: node.target_url,
39            click_count: node.click_count,
40        })
41        .collect();
42
43    let output = JourneyOutput {
44        nodes: journey_nodes,
45    };
46
47    Ok(CommandOutput::table_of(
48        vec!["source_content_id", "target_url", "click_count"],
49        &output.nodes,
50    )
51    .with_title("Content Journey"))
52}