From 566ae58fb9910666f29bb219f9aa975698f8704a Mon Sep 17 00:00:00 2001 From: Teajey <21069848+Teajey@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:54:01 +1200 Subject: [PATCH] feat: collate strings with frontmatter query --- src/main.rs | 38 +----------------- src/route/collate_strings.rs | 78 ++++++++++++++++++++++++++++++++++++ src/route/mod.rs | 1 + 3 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 src/route/collate_strings.rs diff --git a/src/main.rs b/src/main.rs index 7d66531..c2527f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,44 +5,10 @@ mod markup; mod route; use anyhow::{anyhow, Result}; -use axum::{ - extract::{Path, State}, - http::StatusCode, - routing, Json, Router, -}; +use axum::{routing, Router}; use camino::Utf8PathBuf; use notify::{RecursiveMode, Watcher}; -async fn frontmatter_collate_strings_get( - State(markdown_files): State, - Path(key): Path, -) -> Result>, StatusCode> { - let keeper = markdown_files.lock().map_err(|err| { - eprintln!("Failed to lock data on a get_collate_strings request: {err}"); - StatusCode::INTERNAL_SERVER_ERROR - })?; - let mut values = keeper - .files() - .filter_map(|fmf| fmf.frontmatter()) - .filter_map(|fm| fm.get(&key)) - .filter_map(|v| match v { - serde_yaml::Value::String(v) => Some(vec![v.clone()]), - serde_yaml::Value::Sequence(seq) => seq - .iter() - .map(|v| match v { - serde_yaml::Value::String(v) => Some(v.clone()), - _ => None, - }) - .collect(), - _ => None, - }) - .flatten() - .collect::>(); - values.sort(); - values.dedup(); - Ok(Json(values)) -} - async fn run() -> Result<()> { let mut args = std::env::args(); let port = args @@ -74,7 +40,7 @@ async fn run() -> Result<()> { ) .route( "/frontmatter/collate_strings/:key", - routing::get(frontmatter_collate_strings_get), + routing::post(route::collate_strings::post).get(route::collate_strings::get), ) .with_state(markdown_files); diff --git a/src/route/collate_strings.rs b/src/route/collate_strings.rs new file mode 100644 index 0000000..487a3bc --- /dev/null +++ b/src/route/collate_strings.rs @@ -0,0 +1,78 @@ +use std::collections::HashMap; +use std::str::FromStr; + +use axum::{ + extract::{Path, Query, State}, + http::StatusCode, + Json, +}; + +use super::{lock_keeper, query_files}; + +use crate::{ + frontmatter_file::{self, FrontmatterFile}, + frontmatter_query::FrontmatterQuery, +}; + +fn collate_strings_from_files<'a>( + files: impl Iterator, + key: &str, +) -> Vec { + files + .filter_map(|fmf| fmf.frontmatter()) + .filter_map(|fm| fm.get(key)) + .filter_map(|v| match v { + serde_yaml::Value::String(v) => Some(vec![v.clone()]), + serde_yaml::Value::Sequence(seq) => seq + .iter() + .map(|v| match v { + serde_yaml::Value::String(v) => Some(v.clone()), + _ => None, + }) + .collect(), + _ => None, + }) + .flatten() + .collect() +} + +pub async fn get( + State(markdown_files): State, + Path(key): Path, +) -> Result>, StatusCode> { + let keeper = lock_keeper(&markdown_files)?; + let files = keeper.files(); + + let mut values = collate_strings_from_files(files, &key); + + values.sort(); + values.dedup(); + + Ok(Json(values)) +} + +pub async fn post( + State(markdown_files): State, + params: Query>, + Path(key): Path, + Json(query): Json, +) -> Result>, StatusCode> { + let keeper = lock_keeper(&markdown_files)?; + let files = keeper.files(); + + let intersect = params + .get("intersect") + .map(|p| bool::from_str(p)) + .transpose() + .map_err(|_| StatusCode::BAD_REQUEST)? + .unwrap_or_default(); + + let files = query_files(files, &query, None, intersect); + + let mut values = collate_strings_from_files(files, &key); + + values.sort(); + values.dedup(); + + Ok(Json(values)) +} diff --git a/src/route/mod.rs b/src/route/mod.rs index 309b60e..0083934 100644 --- a/src/route/mod.rs +++ b/src/route/mod.rs @@ -1,3 +1,4 @@ +pub mod collate_strings; pub mod frontmatter_file; pub mod frontmatter_list;