cassandra_protocol/frame/
message_prepare.rs

1use crate::error;
2use crate::frame::{Direction, Envelope, Flags, FromCursor, Opcode, Serialize, Version};
3use crate::query::PrepareFlags;
4use crate::types::{
5    from_cursor_str, from_cursor_str_long, serialize_str, serialize_str_long, INT_LEN, SHORT_LEN,
6};
7use std::io::Cursor;
8
9/// Struct that represents a body of a envelope of type `prepare`
10#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Default)]
11pub struct BodyReqPrepare {
12    pub query: String,
13    pub keyspace: Option<String>,
14}
15
16impl BodyReqPrepare {
17    /// Creates new body of a envelope of type `prepare` that prepares query `query`.
18    #[inline]
19    pub fn new(query: String, keyspace: Option<String>) -> BodyReqPrepare {
20        BodyReqPrepare { query, keyspace }
21    }
22}
23
24impl Serialize for BodyReqPrepare {
25    #[inline]
26    fn serialize(&self, cursor: &mut Cursor<&mut Vec<u8>>, version: Version) {
27        serialize_str_long(cursor, &self.query, version);
28
29        if version >= Version::V5 {
30            if let Some(keyspace) = &self.keyspace {
31                PrepareFlags::WITH_KEYSPACE.serialize(cursor, version);
32                serialize_str(cursor, keyspace.as_str(), version);
33            } else {
34                PrepareFlags::empty().serialize(cursor, version);
35            }
36        }
37    }
38
39    #[inline]
40    fn serialize_to_vec(&self, version: Version) -> Vec<u8> {
41        let mut buf = if version >= Version::V5 {
42            Vec::with_capacity(
43                INT_LEN * 2
44                    + self.query.len()
45                    + self
46                        .keyspace
47                        .as_ref()
48                        .map(|keyspace| SHORT_LEN + keyspace.len())
49                        .unwrap_or(0),
50            )
51        } else {
52            Vec::with_capacity(INT_LEN + self.query.len())
53        };
54
55        self.serialize(&mut Cursor::new(&mut buf), version);
56        buf
57    }
58}
59
60impl FromCursor for BodyReqPrepare {
61    #[inline]
62    fn from_cursor(cursor: &mut Cursor<&[u8]>, version: Version) -> error::Result<Self> {
63        if version >= Version::V5 {
64            from_cursor_str_long(cursor)
65                .and_then(|query| {
66                    PrepareFlags::from_cursor(cursor, version).map(|flags| (query, flags))
67                })
68                .and_then(|(query, flags)| {
69                    if flags.contains(PrepareFlags::WITH_KEYSPACE) {
70                        from_cursor_str(cursor).map(|keyspace| {
71                            BodyReqPrepare::new(query.into(), Some(keyspace.into()))
72                        })
73                    } else {
74                        Ok(BodyReqPrepare::new(query.into(), None))
75                    }
76                })
77        } else {
78            from_cursor_str_long(cursor).map(|query| BodyReqPrepare::new(query.into(), None))
79        }
80    }
81}
82
83impl Envelope {
84    pub fn new_req_prepare(
85        query: String,
86        keyspace: Option<String>,
87        flags: Flags,
88        version: Version,
89    ) -> Envelope {
90        let direction = Direction::Request;
91        let opcode = Opcode::Prepare;
92        let body = BodyReqPrepare::new(query, keyspace);
93
94        Envelope::new(
95            version,
96            direction,
97            flags,
98            opcode,
99            0,
100            body.serialize_to_vec(version),
101            None,
102            vec![],
103        )
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use crate::frame::message_prepare::BodyReqPrepare;
110    use crate::frame::{FromCursor, Serialize, Version};
111    use std::io::Cursor;
112
113    #[test]
114    fn should_deserialize_body() {
115        let data = [0, 0, 0, 3, 102, 111, 111, 0];
116        let mut cursor = Cursor::new(data.as_slice());
117
118        let body = BodyReqPrepare::from_cursor(&mut cursor, Version::V4).unwrap();
119        assert_eq!(body.query, "foo");
120    }
121
122    #[test]
123    fn should_support_keyspace() {
124        let keyspace = "abc";
125        let query = "test";
126
127        let body = BodyReqPrepare::new(query.into(), Some(keyspace.into()));
128
129        let data_v4 = body.serialize_to_vec(Version::V4);
130        let body_v4 =
131            BodyReqPrepare::from_cursor(&mut Cursor::new(data_v4.as_slice()), Version::V4).unwrap();
132        assert_eq!(body_v4.query, query);
133        assert_eq!(body_v4.keyspace, None);
134
135        let data_v5 = body.serialize_to_vec(Version::V5);
136        let body_v5 =
137            BodyReqPrepare::from_cursor(&mut Cursor::new(data_v5.as_slice()), Version::V5).unwrap();
138        assert_eq!(body_v5.query, query);
139        assert_eq!(body_v5.keyspace, Some(keyspace.to_string()));
140    }
141}