gremlin_client/
message.rs

1use serde::{Deserialize as SerdeDeserialize, Deserializer};
2use serde_derive::{Deserialize, Serialize};
3use serde_json::Value;
4use uuid::Uuid;
5
6#[derive(Serialize)]
7#[serde(rename_all = "camelCase")]
8pub struct RequestIdV2 {
9    #[serde(rename = "@type")]
10    id_type: String,
11
12    #[serde(rename = "@value")]
13    value: Uuid,
14}
15
16#[derive(Serialize)]
17#[serde(rename_all = "camelCase", untagged)]
18pub enum Message<T> {
19    #[serde(rename_all = "camelCase")]
20    V1 {
21        request_id: Uuid,
22        op: String,
23        processor: String,
24        args: T,
25    },
26    #[serde(rename_all = "camelCase")]
27    V2 {
28        request_id: RequestIdV2,
29        op: String,
30        processor: String,
31        args: T,
32    },
33    #[serde(rename_all = "camelCase")]
34    V3 {
35        request_id: Uuid,
36        op: String,
37        processor: String,
38        args: T,
39    },
40}
41
42impl<T> Message<T> {
43    #[allow(dead_code)]
44    pub fn id(&self) -> &Uuid {
45        match self {
46            Message::V1 { request_id, .. } => request_id,
47            Message::V2 { request_id, .. } => &request_id.value,
48            Message::V3 { request_id, .. } => request_id,
49        }
50    }
51}
52#[derive(Debug, Deserialize)]
53#[serde(rename_all = "camelCase")]
54pub struct Response {
55    pub request_id: Uuid,
56    pub result: ResponseResult,
57    pub status: ReponseStatus,
58}
59
60#[derive(Debug, Deserialize)]
61pub struct ResponseResult {
62    pub data: Value,
63}
64
65#[derive(Debug, Deserialize)]
66pub struct ReponseStatus {
67    pub code: i16,
68    //Sometimes the message is omitted, default to empty string rather than panic
69    #[serde(default, deserialize_with = "map_null_to_default")]
70    pub message: String,
71}
72
73fn map_null_to_default<'de, D, T>(de: D) -> Result<T, D::Error>
74where
75    D: Deserializer<'de>,
76    T: Default + SerdeDeserialize<'de>,
77{
78    Option::<T>::deserialize(de).map(Option::unwrap_or_default)
79}
80
81pub fn message_with_args_v2<T>(op: String, processor: String, args: T) -> Message<T> {
82    message_with_args_and_uuid_v2(op, processor, Uuid::new_v4(), args)
83}
84
85pub fn message_with_args_and_uuid_v2<T>(
86    op: String,
87    processor: String,
88    id: Uuid,
89    args: T,
90) -> Message<T> {
91    Message::V2 {
92        request_id: RequestIdV2 {
93            id_type: "g:UUID".to_string(),
94            value: id,
95        },
96        op,
97        processor,
98        args,
99    }
100}
101
102pub fn message_with_args<T>(op: String, processor: String, args: T) -> Message<T> {
103    message_with_args_and_uuid(op, processor, Uuid::new_v4(), args)
104}
105
106pub fn message_with_args_and_uuid<T>(
107    op: String,
108    processor: String,
109    id: Uuid,
110    args: T,
111) -> Message<T> {
112    Message::V3 {
113        request_id: id,
114        op,
115        processor,
116        args,
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use crate::message::ReponseStatus;
123
124    #[test]
125    fn handle_no_response_status_message() {
126        let parsed: ReponseStatus =
127            serde_json::from_str(r#"{"code": 123}"#).expect("Failed to parse test message");
128        assert_eq!(123, parsed.code);
129        assert_eq!("", parsed.message);
130    }
131
132    #[test]
133    fn handle_null_response_status_message() {
134        let parsed: ReponseStatus = serde_json::from_str(r#"{"code": 123, "message": null}"#)
135            .expect("Failed to parse test message");
136        assert_eq!(123, parsed.code);
137        assert_eq!("", parsed.message);
138    }
139
140    #[test]
141    fn handle_response_status_message() {
142        let parsed: ReponseStatus =
143            serde_json::from_str(r#"{"code": 123, "message": "Hello World"}"#)
144                .expect("Failed to parse test message");
145        assert_eq!(123, parsed.code);
146        assert_eq!("Hello World", parsed.message);
147    }
148}