use crate::models::field_names;
use anyhow::Result;
use clap::Args;
use serde_json::{Value, json};
use crate::cli::CliOutput;
use crate::storage as db;
#[derive(Args, Debug, Clone)]
pub struct EntityGetByAliasArgs {
#[arg(long, value_name = "ALIAS")]
pub alias: String,
#[arg(long, value_name = "NS")]
pub namespace: Option<String>,
#[arg(long)]
pub json: bool,
}
pub fn cmd_entity_get_by_alias(
db_path: &std::path::Path,
args: &EntityGetByAliasArgs,
out: &mut CliOutput<'_>,
) -> Result<()> {
let conn = db::open(db_path)?;
let mut params = json!({"alias": args.alias});
if let Some(ns) = &args.namespace {
params["namespace"] = json!(ns);
}
let envelope = crate::mcp::handle_entity_get_by_alias(&conn, ¶ms)
.map_err(|e| anyhow::anyhow!("entity-get-by-alias: {e}"))?;
if args.json {
writeln!(out.stdout, "{}", serde_json::to_string(&envelope)?)?;
return Ok(());
}
let found = envelope
.get("found")
.and_then(Value::as_bool)
.unwrap_or(false);
if found {
let id = envelope
.get("entity_id")
.and_then(Value::as_str)
.unwrap_or("?");
let name = envelope
.get(field_names::CANONICAL_NAME)
.and_then(Value::as_str)
.unwrap_or("?");
writeln!(
out.stdout,
"entity-get-by-alias: entity_id={id} canonical_name={name}"
)?;
} else {
writeln!(out.stdout, "entity-get-by-alias: no match")?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::test_utils::TestEnv;
#[test]
fn entity_get_by_alias_cli_unknown_alias_returns_not_found() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
let args = EntityGetByAliasArgs {
alias: "nonexistent-alias".into(),
namespace: None,
json: true,
};
{
let mut out = env.output();
cmd_entity_get_by_alias(&db, &args, &mut out).expect("ok");
}
let stdout = env.stdout_str();
let envelope: Value = serde_json::from_str(stdout.trim()).expect("parse envelope");
assert_eq!(envelope["found"].as_bool(), Some(false));
}
#[test]
fn entity_get_by_alias_cli_round_trip_finds_entity() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
let reg = crate::mcp::handle_entity_register(
&crate::storage::open(&db).unwrap(),
&json!({
"canonical_name": "Bob",
"namespace": "people",
"aliases": ["bobby"],
"agent_id": "ai:tester",
}),
None,
)
.expect("register");
let expected_id = reg["entity_id"].as_str().unwrap().to_string();
let args = EntityGetByAliasArgs {
alias: "bobby".into(),
namespace: Some("people".into()),
json: true,
};
{
let mut out = env.output();
cmd_entity_get_by_alias(&db, &args, &mut out).expect("ok");
}
let stdout = env.stdout_str();
let envelope: Value = serde_json::from_str(stdout.trim()).expect("parse envelope");
assert_eq!(envelope["found"].as_bool(), Some(true));
assert_eq!(envelope["entity_id"].as_str(), Some(expected_id.as_str()));
}
#[test]
fn entity_get_by_alias_cli_text_output_not_found() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
let args = EntityGetByAliasArgs {
alias: "nope".into(),
namespace: None,
json: false,
};
{
let mut out = env.output();
cmd_entity_get_by_alias(&db, &args, &mut out).expect("ok");
}
assert!(env.stdout_str().contains("entity-get-by-alias: no match"));
}
#[test]
fn entity_get_by_alias_cli_text_output_found() {
let mut env = TestEnv::fresh();
let db = env.db_path.clone();
crate::mcp::handle_entity_register(
&crate::storage::open(&db).unwrap(),
&json!({
"canonical_name": "Carol",
"namespace": "people",
"aliases": ["caz"],
"agent_id": "ai:tester",
}),
None,
)
.expect("register");
let args = EntityGetByAliasArgs {
alias: "caz".into(),
namespace: Some("people".into()),
json: false,
};
{
let mut out = env.output();
cmd_entity_get_by_alias(&db, &args, &mut out).expect("ok");
}
let stdout = env.stdout_str();
assert!(stdout.contains("entity_id="), "got: {stdout}");
assert!(stdout.contains("canonical_name=Carol"), "got: {stdout}");
}
}