valence_core/
record_id.rs1use serde::de::{self, MapAccess, Visitor};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use std::fmt;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub struct RecordId {
9 table: String,
10 id: String,
11}
12
13impl RecordId {
14 pub fn new(table: impl Into<String>, id: impl Into<String>) -> Self {
15 Self {
16 table: table.into(),
17 id: id.into(),
18 }
19 }
20
21 pub fn table(&self) -> &str {
22 &self.table
23 }
24
25 pub fn id(&self) -> &str {
26 &self.id
27 }
28
29 pub fn parse(s: &str) -> Option<Self> {
31 let (table, id) = s.split_once(':')?;
32 if table.is_empty() || id.is_empty() {
33 return None;
34 }
35 Some(Self::new(table, id))
36 }
37}
38
39impl fmt::Display for RecordId {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 write!(f, "{}:{}", self.table, self.id)
42 }
43}
44
45impl Serialize for RecordId {
46 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47 where
48 S: Serializer,
49 {
50 use serde::ser::SerializeStruct;
51 let mut state = serializer.serialize_struct("RecordId", 2)?;
52 state.serialize_field("table", &self.table)?;
53 state.serialize_field("id", &self.id)?;
54 state.end()
55 }
56}
57
58impl<'de> Deserialize<'de> for RecordId {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: Deserializer<'de>,
62 {
63 struct RecordIdVisitor;
64
65 impl<'de> Visitor<'de> for RecordIdVisitor {
66 type Value = RecordId;
67
68 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 f.write_str("RecordId object or \"table:id\" string")
70 }
71
72 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
73 where
74 E: de::Error,
75 {
76 RecordId::parse(v).ok_or_else(|| E::custom(format!("invalid RecordId string: {v}")))
77 }
78
79 fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
80 where
81 E: de::Error,
82 {
83 self.visit_str(&v)
84 }
85
86 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
87 where
88 A: MapAccess<'de>,
89 {
90 let mut table: Option<String> = None;
91 let mut id: Option<String> = None;
92 while let Some(key) = map.next_key::<String>()? {
93 match key.as_str() {
94 "table" | "tb" => table = Some(map.next_value::<String>()?),
95 "id" => id = Some(map.next_value::<String>()?),
96 _ => {
97 let _: de::IgnoredAny = map.next_value()?;
98 }
99 }
100 }
101 let table = table.ok_or_else(|| de::Error::missing_field("table"))?;
102 let id = id.ok_or_else(|| de::Error::missing_field("id"))?;
103 Ok(RecordId::new(table, id))
104 }
105 }
106
107 deserializer.deserialize_any(RecordIdVisitor)
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn deserializes_object_and_colon_string() {
117 let obj: RecordId = serde_json::from_str(r#"{"table":"task","id":"1"}"#).expect("object");
118 assert_eq!(obj.table(), "task");
119 assert_eq!(obj.id(), "1");
120
121 let s: RecordId = serde_json::from_str(r#""task:1""#).expect("string");
122 assert_eq!(s.table(), "task");
123 assert_eq!(s.id(), "1");
124 }
125}