diff options
| author | tv <tv@krebsco.de> | 2026-11-01 22:29:54 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-01 22:29:54 +0100 |
| commit | 9b976a6c4add3719b8f9afef53578ff778b50aa1 (patch) | |
| tree | 0a4f7e0ed17817cdee493ede8185fc70c7b8fa7e /src/api/store.rs | |
| parent | b9b54f318a7f7892a9f6e2a4f4fcf2a276492b8c (diff) | |
api: add support for counters
Diffstat (limited to 'src/api/store.rs')
| -rw-r--r-- | src/api/store.rs | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/src/api/store.rs b/src/api/store.rs index 8b09487..7039008 100644 --- a/src/api/store.rs +++ b/src/api/store.rs @@ -78,6 +78,13 @@ macro_rules! read_at { } #[derive(Debug, Deserialize)] +pub(crate) struct PostQuery { + /// Adds this to the counter at the path instead of inserting the body + /// (`store::increment_path`). + increment: Option<i64>, +} + +#[derive(Debug, Deserialize)] pub(crate) struct DeleteQuery { #[serde(default)] prune: bool, @@ -355,11 +362,14 @@ fn body_value(headers: &HeaderMap, body: &Bytes) -> Result<JsonValue, StatusCode /// `POST /store/{key}`: inserts the body into a list, `key` ending in the index it /// goes to (`store::insert_path`: the items from there on move up; the length, or `-1`, /// appends); `201` with where it went (`{"index": n}`). Not a list there, or an index -/// past its end: `409`, saying which. +/// past its end: `409`, saying which. With `?increment=n`, adds `n` to the counter at +/// `key` instead (`store::increment_path`), answering with its value then; not a +/// counter there: `409`. pub(crate) async fn post_store_entry( State(state): State<AppState>, Extension(user): Extension<AuthenticatedUser>, Path(key): Path<String>, + Query(query): Query<PostQuery>, RawQuery(raw_query): RawQuery, headers: HeaderMap, body: Bytes, @@ -368,9 +378,22 @@ pub(crate) async fn post_store_entry( return Err(StatusCode::SERVICE_UNAVAILABLE.into()); } let path = parse_write_path(&state, &user, &key, "POST")?; - if let Some(redirect) = to_positive(&state, &path, true, None, raw_query.as_deref()).await? { + // An increment names an item (`-1`: the last); an insert where it goes (`-1`: the end). + let insertion = query.increment.is_none(); + if let Some(redirect) = + to_positive(&state, &path, insertion, None, raw_query.as_deref()).await? + { return Ok(redirect); } + if let Some(by) = query.increment { + let value = state + .mutate_doc_for(Some(user.0.clone()), move |doc| { + store::increment_path(doc, &path, by) + }) + .await + .map_err(|e| store_status(e, "Failed to increment a counter"))?; + return response_for_value(&JsonValue::from(value), headers.get(ACCEPT)); + } let index = path.last().and_then(|leaf| store::list_index(leaf)); let value = body_value(&headers, &body)?; let inserted = state |
