systemprompt_cli/commands/core/content/analytics/
journey.rs1use crate::cli_settings::CliConfig;
2use crate::commands::core::content::types::{JourneyNode, JourneyOutput};
3use crate::shared::CommandOutput;
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(args: JourneyArgs, config: &CliConfig) -> Result<CommandOutput> {
20 let ctx = AppContext::new().await?;
21 execute_with_pool(args, ctx.db_pool(), config).await
22}
23
24pub async fn execute_with_pool(
25 args: JourneyArgs,
26 pool: &DbPool,
27 _config: &CliConfig,
28) -> Result<CommandOutput> {
29 let service = LinkAnalyticsService::new(pool)?;
30
31 let nodes = service
32 .get_content_journey_map(Some(args.limit), Some(args.offset))
33 .await?;
34
35 let journey_nodes: Vec<JourneyNode> = nodes
36 .into_iter()
37 .map(|node| JourneyNode {
38 source_content_id: node.source_content_id,
39 target_url: node.target_url,
40 click_count: node.click_count,
41 })
42 .collect();
43
44 let output = JourneyOutput {
45 nodes: journey_nodes,
46 };
47
48 Ok(CommandOutput::table_of(
49 vec!["source_content_id", "target_url", "click_count"],
50 &output.nodes,
51 )
52 .with_title("Content Journey"))
53}