use serde_json::{Map, Value};
pub mod keys {
pub const SESSION_ID: &str = "session_id";
pub const USER_ID: &str = "user_id";
pub const RELEASE: &str = "release";
pub const VERSION: &str = "version";
pub const ENVIRONMENT: &str = "environment";
pub const PUBLIC: &str = "public";
}
pub struct TraceMeta;
impl TraceMeta {
pub fn session(id: impl Into<String>) -> (&'static str, Value) {
(keys::SESSION_ID, Value::String(id.into()))
}
pub fn user(id: impl Into<String>) -> (&'static str, Value) {
(keys::USER_ID, Value::String(id.into()))
}
pub fn release(s: impl Into<String>) -> (&'static str, Value) {
(keys::RELEASE, Value::String(s.into()))
}
pub fn environment(s: impl Into<String>) -> (&'static str, Value) {
(keys::ENVIRONMENT, Value::String(s.into()))
}
pub fn version(s: impl Into<String>) -> (&'static str, Value) {
(keys::VERSION, Value::String(s.into()))
}
pub fn public(b: bool) -> (&'static str, Value) {
(keys::PUBLIC, Value::Bool(b))
}
}
pub fn merge_into(metadata: Value, kv: (&str, Value)) -> Value {
let mut map = match metadata {
Value::Object(m) => m,
_ => Map::new(),
};
map.insert(kv.0.to_string(), kv.1);
Value::Object(map)
}
pub fn read_string(metadata: &Value, key: &str) -> Option<String> {
metadata.as_object()?.get(key)?.as_str().map(str::to_owned)
}
pub fn read_bool(metadata: &Value, key: &str) -> Option<bool> {
metadata.as_object()?.get(key)?.as_bool()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merge_into_null_creates_object() {
let v = merge_into(Value::Null, TraceMeta::session("s1"));
assert_eq!(v.as_object().unwrap()["session_id"], "s1");
}
#[test]
fn merge_into_existing_object_inserts_key() {
let v = merge_into(serde_json::json!({"a": 1}), TraceMeta::user("u1"));
let obj = v.as_object().unwrap();
assert_eq!(obj["a"], 1);
assert_eq!(obj["user_id"], "u1");
}
#[test]
fn merge_into_overwrites_same_key() {
let v = merge_into(Value::Null, TraceMeta::session("first"));
let v = merge_into(v, TraceMeta::session("second"));
assert_eq!(v.as_object().unwrap()["session_id"], "second");
}
#[test]
fn read_string_returns_none_when_missing() {
assert_eq!(read_string(&Value::Null, keys::SESSION_ID), None);
assert_eq!(
read_string(&serde_json::json!({"a": 1}), keys::SESSION_ID),
None
);
}
#[test]
fn read_string_finds_well_known_key() {
let v = merge_into(Value::Null, TraceMeta::release("v1.2.3"));
assert_eq!(read_string(&v, keys::RELEASE).as_deref(), Some("v1.2.3"));
}
#[test]
fn read_bool_finds_public() {
let v = merge_into(Value::Null, TraceMeta::public(true));
assert_eq!(read_bool(&v, keys::PUBLIC), Some(true));
}
}