use super::DbError;
use crate::db;
use crate::tools::Tool;
use crate::tools::context::ToolContext;
use choreo_keystore::ServiceCredential;
use schemars::JsonSchema;
use serde::Deserialize;
use tracing::{debug, error};
#[derive(Debug, Deserialize, JsonSchema)]
pub struct DbGetArgs {
key: String,
}
pub(crate) struct DbGet;
impl Tool for DbGet {
type Args = DbGetArgs;
type Return = Option<String>;
type Error = DbError;
fn name(&self) -> &'static str {
"db_get"
}
fn group(&self) -> &'static str {
"db"
}
fn description(&self) -> &'static str {
"Retrieve a value by key from the session's database."
}
fn describe_invocation(&self, args: &Self::Args) -> String {
format!("Getting database key `{}`.", args.key)
}
fn return_string(ret: &Self::Return) -> String {
ret.clone().unwrap_or_default()
}
fn output_schema(&self) -> Option<serde_json::Value> {
None
}
fn execute(
&self,
args: Self::Args,
_x_credentials: Option<&ServiceCredential>,
_working_dir: Option<&std::path::Path>,
ctx: Option<&ToolContext>,
) -> Result<Self::Return, Self::Error> {
let ctx = ctx.ok_or(DbError::NoSessionContext)?;
match db::kv_get(ctx.db.as_ref(), ctx.session_id, &args.key) {
Ok(value) => {
let value_len = value.as_ref().map_or(0, Vec::len);
let value_str = value.map(|v| String::from_utf8_lossy(&v).into_owned());
debug!(
session = ctx.session_id,
key = &args.key,
value_len,
"db_get ok"
);
Ok(value_str)
}
Err(e) => {
error!(session = ctx.session_id, key = &args.key, error = %e, "db_get failed");
Err(DbError::Storage(format!("db_get failed: {e}")))
}
}
}
}
#[cfg(test)]
pub(crate) fn get_args(key: &str) -> DbGetArgs {
DbGetArgs {
key: key.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tools::db::tests::test_context;
#[test]
fn db_get_not_found() {
let (_dir, ctx) = test_context();
let result = DbGet.execute(
DbGetArgs {
key: "nonexistent".into(),
},
None,
None,
Some(&ctx),
);
assert_eq!(result.unwrap(), None);
}
#[test]
fn db_get_output_schema_is_none() {
assert!(
DbGet.output_schema().is_none(),
"DbGet returns raw bytes converted lossily to string; no structured JSON schema"
);
}
#[test]
fn describe_db_get_invocation() {
let tool = DbGet;
let args = DbGetArgs {
key: "my_key".into(),
};
let desc = tool.describe_invocation(&args);
assert_eq!(desc, "Getting database key `my_key`.");
}
}