diff options
| author | tv <tv@krebsco.de> | 2026-10-31 04:50:53 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-31 04:50:53 +0100 |
| commit | 5a20a8448a9c0b33174e2490dbde6e12749dd140 (patch) | |
| tree | e2716b8ed19b71b0ae93aae35b90de99fbbadfd2 /src | |
| parent | aaeb05c716cb746ee7c746f4eefa75ebba3f703e (diff) | |
api: unify store reads
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/store.rs | 58 |
1 files changed, 22 insertions, 36 deletions
diff --git a/src/api/store.rs b/src/api/store.rs index bc43824..a74d968 100644 --- a/src/api/store.rs +++ b/src/api/store.rs @@ -59,36 +59,7 @@ pub(crate) async fn get_store_root( headers: HeaderMap, Query(query): Query<ReadQuery>, ) -> Result<Response, StatusCode> { - if query.shallow { - return shallow(&state, Vec::new(), true, &query).await; - } - let accept = headers.get(ACCEPT).cloned(); - let want_conflicts = query.conflicts; - - let (response, source, heads) = state - .render_read( - true, - query.heads, - move |doc| { - if want_conflicts { - store::read_path_with_conflicts(doc, &Vec::new()) - .map(|found| found.map(|(value, conflicts)| (value, Some(conflicts)))) - } else { - store::read_path(doc, &Vec::new()).map(|found| found.map(|value| (value, None))) - } - }, - move |result| { - let (value, conflicts) = result - .map_err(|e| store_status(e, "Failed to read store path"))? - .unwrap_or_else(|| (JsonValue::Object(Default::default()), Some(Vec::new()))); - match conflicts { - Some(conflicts) => conflicts_response(value, conflicts), - None => response_for_value(&value, accept.as_ref()), - } - }, - ) - .await?; - mark_source(response, source, heads) + read(&state, Vec::new(), &headers, &query).await } /// `GET /store/{key}`. @@ -103,16 +74,28 @@ pub(crate) async fn get_store_entry( if let Some(redirect) = to_positive(&state, &path, false, raw_query.as_deref()).await? { return Ok(redirect); } + read(&state, path, &headers, &query).await +} + +/// A read of `path` as `query` asks (the empty path: the whole store). The root is read +/// while not ready too (`render_read`'s `unready_live`), and is never missing: an empty +/// store is an empty map. +async fn read( + state: &AppState, + path: Vec<String>, + headers: &HeaderMap, + query: &ReadQuery, +) -> Result<Response, StatusCode> { + let root = path.is_empty(); if query.shallow { - return shallow(&state, path, false, &query).await; + return shallow(state, path, root, query).await; } - let accept = headers.get(ACCEPT).cloned(); let want_conflicts = query.conflicts; let (response, source, heads) = state .render_read( - false, + root, query.heads, move |doc| { if want_conflicts { @@ -123,9 +106,12 @@ pub(crate) async fn get_store_entry( } }, move |result| { - let (value, conflicts) = result - .map_err(|e| store_status(e, "Failed to read store path"))? - .ok_or(StatusCode::NOT_FOUND)?; + let found = result.map_err(|e| store_status(e, "Failed to read store path"))?; + let (value, conflicts) = match found { + Some(found) => found, + None if root => (JsonValue::Object(Default::default()), Some(Vec::new())), + None => return Err(StatusCode::NOT_FOUND), + }; match conflicts { Some(conflicts) => conflicts_response(value, conflicts), None => response_for_value(&value, accept.as_ref()), |
