Skip to main content

systemprompt_cli/commands/core/content/
list.rs

1use super::types::{ContentListOutput, ContentSummary};
2use crate::cli_settings::CliConfig;
3use crate::shared::CommandResult;
4use anyhow::Result;
5use clap::Args;
6use systemprompt_content::ContentRepository;
7use systemprompt_database::DbPool;
8use systemprompt_identifiers::SourceId;
9use systemprompt_runtime::AppContext;
10
11#[derive(Debug, Args)]
12pub struct ListArgs {
13    #[arg(long, help = "Filter by source ID")]
14    pub source: Option<String>,
15
16    #[arg(long, help = "Filter by category ID")]
17    pub category: Option<String>,
18
19    #[arg(long, default_value = "20")]
20    pub limit: i64,
21
22    #[arg(long, default_value = "0")]
23    pub offset: i64,
24}
25
26pub async fn execute(
27    args: ListArgs,
28    config: &CliConfig,
29) -> Result<CommandResult<ContentListOutput>> {
30    let ctx = AppContext::new().await?;
31    execute_with_pool(args, ctx.db_pool(), config).await
32}
33
34pub async fn execute_with_pool(
35    args: ListArgs,
36    pool: &DbPool,
37    _config: &CliConfig,
38) -> Result<CommandResult<ContentListOutput>> {
39    let repo = ContentRepository::new(pool)?;
40
41    let items = match &args.source {
42        Some(source_id) => {
43            let source = SourceId::new(source_id.clone());
44            repo.list_by_source(&source).await?
45        },
46        None => repo.list(args.limit, args.offset).await?,
47    };
48
49    let summaries: Vec<ContentSummary> = items
50        .into_iter()
51        .filter(|c| {
52            args.category.as_ref().is_none_or(|cat| {
53                c.category_id
54                    .as_ref()
55                    .is_some_and(|cid| cid.as_str() == cat)
56            })
57        })
58        .map(|c| ContentSummary {
59            id: c.id,
60            slug: c.slug,
61            title: c.title,
62            kind: c.kind,
63            source_id: c.source_id,
64            category_id: c.category_id,
65            published_at: Some(c.published_at),
66        })
67        .collect();
68
69    let total = summaries.len() as i64;
70
71    let output = ContentListOutput {
72        items: summaries,
73        total,
74        limit: args.limit,
75        offset: args.offset,
76    };
77
78    Ok(CommandResult::table(output)
79        .with_title("Content")
80        .with_columns(vec![
81            "id".to_string(),
82            "title".to_string(),
83            "kind".to_string(),
84            "source_id".to_string(),
85            "published_at".to_string(),
86        ]))
87}