use crate::db::types::{DbTid, DidKey};
use bytes::Bytes;
use jacquard_common::CowStr;
use jacquard_common::types::cid::IpldCid;
use jacquard_common::types::string::Handle;
use serde::{Deserialize, Serialize};
use smol_str::SmolStr;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum RepoStatus {
Backfilling,
Synced,
Error(SmolStr),
Deactivated,
Takendown,
Suspended,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub(crate) struct Commit {
pub version: i64,
pub rev: DbTid,
pub data: IpldCid,
pub prev: Option<IpldCid>,
#[serde(with = "jacquard_common::serde_bytes_helper")]
pub sig: Bytes,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(bound(deserialize = "'i: 'de"))]
pub(crate) struct RepoState<'i> {
pub status: RepoStatus,
pub root: Option<Commit>,
pub last_message_time: Option<i64>,
pub last_updated_at: i64,
pub tracked: bool,
pub index_id: u64,
#[serde(borrow)]
pub signing_key: Option<DidKey<'i>>,
#[serde(borrow)]
pub pds: Option<CowStr<'i>>,
pub handle: Option<Handle>,
}
#[cfg(test)]
mod tests {
use super::*;
use jacquard_common::types::string::Tid;
#[test]
fn v2_persisted_schema_golden_fixture() {
for (status, golden) in [
(RepoStatus::Backfilling, "ab4261636b66696c6c696e67"),
(RepoStatus::Synced, "a653796e636564"),
(
RepoStatus::Error("stinkpot".into()),
"81a54572726f72a87374696e6b706f74",
),
(RepoStatus::Deactivated, "ab4465616374697661746564"),
(RepoStatus::Takendown, "a954616b656e646f776e"),
(RepoStatus::Suspended, "a953757370656e646564"),
] {
let encoded = rmp_serde::to_vec(&status).unwrap();
assert_eq!(crate::util::hex::encode(&encoded), golden);
assert_eq!(
rmp_serde::from_slice::<RepoStatus>(&encoded).unwrap(),
status
);
}
let state = RepoState {
status: RepoStatus::Error("stinkpot".into()),
root: Some(Commit {
version: 3,
rev: DbTid::from(&Tid::new("3jzfcijpj2z2a").unwrap()),
data: crate::car::compute_cid(b"root"),
prev: None,
sig: Bytes::from_static(b"\x01\x02\x03"),
}),
last_message_time: Some(-1),
last_updated_at: 42,
tracked: true,
index_id: 7,
signing_key: Some(DidKey(std::borrow::Cow::Borrowed(&[0xed, 1, 2, 3]))),
pds: Some("https://pds.example".into()),
handle: Some(Handle::new_static("alice.test").unwrap()),
};
let encoded = rmp_serde::to_vec(&state).unwrap();
assert_eq!(
crate::util::hex::encode(&encoded),
"9981a54572726f72a87374696e6b706f749503c40817fd6873eaf07c06c424017112204813494d137e1631bba301d5acab6e7bb7aa74ce1185d456565ef51d737677b2c0c403010203ff2ac307c404ed010203b368747470733a2f2f7064732e6578616d706c65aa616c6963652e74657374"
);
let decoded: RepoState<'_> = rmp_serde::from_slice(&encoded).unwrap();
assert!(matches!(&decoded.status, RepoStatus::Error(value) if value == "stinkpot"));
let root = decoded.root.unwrap();
assert_eq!(root.version, 3);
assert_eq!(root.rev, DbTid::from(&Tid::new("3jzfcijpj2z2a").unwrap()));
assert_eq!(
root.data,
crate::car::compute_cid(b"root")
);
assert!(root.prev.is_none());
assert_eq!(root.sig.as_ref(), b"\x01\x02\x03");
assert_eq!(decoded.last_message_time, Some(-1));
assert_eq!(decoded.last_updated_at, 42);
assert!(decoded.tracked);
assert_eq!(decoded.index_id, 7);
assert_eq!(
decoded.signing_key.as_ref().map(|key| key.0.as_ref()),
Some([0xed, 1, 2, 3].as_slice())
);
assert_eq!(decoded.pds.as_deref(), Some("https://pds.example"));
assert_eq!(
decoded.handle.as_ref().map(Handle::as_str),
Some("alice.test")
);
}
}