cassandra_protocol/frame/
message_prepare.rs1use 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#[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 #[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}