sled_web/
request.rs

1//! Functions to simplify the construction of requests along with request types that can be
2//! serialized to and from the JSON body.
3
4use http::uri::PathAndQuery;
5use hyper::{Body, Method, Request, Uri};
6use serde::Serialize;
7use serde_json;
8
9/// Types that represent a request being made to the server.
10pub trait RequestType {
11    /// The HTTP method included with the header.
12    const METHOD: Method;
13    /// The component of the URI following the domain.
14    const PATH_AND_QUERY: &'static str;
15}
16
17/// Types that may be converted into a serialized JSON body for a hyper request.
18pub trait IntoBody {
19    /// The body of the request, capable of being serialized to JSON.
20    type Body: Serialize;
21    /// Convert `self` into the serializable `Body` type.
22    fn into_body(self) -> Self::Body;
23}
24
25/// Types that may be directly converted into a hyper Request.
26pub trait IntoRequest: RequestType + IntoBody {
27    /// The `base_uri` should include only the scheme and host - the path and query will be
28    /// retrieved via `RequestType::PATH_AND_QUERY`.
29    fn into_request(self, base_uri: Uri) -> Request<Body>;
30}
31
32/// The vector of bytes used as a key into a `sled::Tree`.
33type Key = Vec<u8>;
34/// The vector of bytes representing a value within a `sled::Tree`.
35type Value = Vec<u8>;
36
37/// Get a single entry from the DB, identified by the given unique key.
38#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
39pub struct Get {
40    pub key: Key,
41}
42
43/// Delete the entry at the given key.
44#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
45pub struct Del {
46    pub key: Key,
47}
48
49/// Set the entry with the given key and value, replacing the original if one exists.
50#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
51pub struct Set {
52    pub key: Key,
53    pub value: Value,
54}
55
56/// Compare and swap. Capable of unique creation, conditional modification, or deletion.
57///
58/// If old is None, this will only set the value if it doesn't exist yet. If new is None, will
59/// delete the value if old is correct. If both old and new are Some, will modify the value if old
60/// is correct.
61///
62/// If Tree is read-only, will do nothing.
63#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
64pub struct Cas {
65    pub key: Key,
66    pub old: Option<Value>,
67    pub new: Option<Value>,
68}
69
70/// Merge a new value into the total state for a key.
71#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
72pub struct Merge {
73    pub key: Key,
74    pub value: Value,
75}
76
77/// Flushes any pending IO buffers to disk to ensure durability.
78#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
79pub struct Flush;
80
81/// Iterate over all entries within the `Tree`.
82#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
83pub struct Iter;
84
85/// Iterate over all entries within the `Tree` that start at or follow the given key.
86#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
87pub struct Scan {
88    pub key: Key,
89}
90
91/// Iterate over all entries within the `Tree` within the given key range.
92///
93/// The given range is non-inclusive of the `end` key.
94#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
95pub struct ScanRange {
96    pub start: Key,
97    pub end: Key,
98}
99
100/// Retrieve the entry with the greatest `Key` in the `Tree`.
101#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
102pub struct Max;
103
104/// Retrieve the entry that precedes the `Key`.
105#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
106pub struct Pred {
107    pub key: Key,
108}
109
110/// Retrieve the entry that precedes or includes the `Key`.
111#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
112pub struct PredIncl {
113    pub key: Key,
114}
115
116/// Retrieve the entry that follows the `Key`.
117#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
118pub struct Succ {
119    pub key: Key,
120}
121
122/// Retrieve the entry that follows or includes the `Key`.
123#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
124pub struct SuccIncl {
125    pub key: Key,
126}
127
128impl RequestType for Get {
129    const METHOD: Method = Method::GET;
130    const PATH_AND_QUERY: &'static str = "/tree/entries/get";
131}
132
133impl RequestType for Del {
134    const METHOD: Method = Method::DELETE;
135    const PATH_AND_QUERY: &'static str = "/tree/entries/delete";
136}
137
138impl RequestType for Set {
139    const METHOD: Method = Method::POST;
140    const PATH_AND_QUERY: &'static str = "/tree/entries/set";
141}
142
143impl RequestType for Cas {
144    const METHOD: Method = Method::PUT;
145    const PATH_AND_QUERY: &'static str = "/tree/entries/cas";
146}
147
148impl RequestType for Merge {
149    const METHOD: Method = Method::POST;
150    const PATH_AND_QUERY: &'static str = "/tree/entries/merge";
151}
152
153impl RequestType for Flush {
154    const METHOD: Method = Method::PUT;
155    const PATH_AND_QUERY: &'static str = "/tree/entries/flush";
156}
157
158impl RequestType for Iter {
159    const METHOD: Method = Method::GET;
160    const PATH_AND_QUERY: &'static str = "/tree/entries/iter";
161}
162
163impl RequestType for Scan {
164    const METHOD: Method = Method::GET;
165    const PATH_AND_QUERY: &'static str = "/tree/entries/scan";
166}
167
168impl RequestType for ScanRange {
169    const METHOD: Method = Method::GET;
170    const PATH_AND_QUERY: &'static str = "/tree/entries/scan_range";
171}
172
173impl RequestType for Max {
174    const METHOD: Method = Method::GET;
175    const PATH_AND_QUERY: &'static str = "/tree/entries/max";
176}
177
178impl RequestType for Pred {
179    const METHOD: Method = Method::GET;
180    const PATH_AND_QUERY: &'static str = "/tree/entries/pred";
181}
182
183impl RequestType for PredIncl {
184    const METHOD: Method = Method::GET;
185    const PATH_AND_QUERY: &'static str = "/tree/entries/pred_incl";
186}
187
188impl RequestType for Succ {
189    const METHOD: Method = Method::GET;
190    const PATH_AND_QUERY: &'static str = "/tree/entries/succ";
191}
192
193impl RequestType for SuccIncl {
194    const METHOD: Method = Method::GET;
195    const PATH_AND_QUERY: &'static str = "/tree/entries/succ_incl";
196}
197
198impl IntoBody for Get {
199    type Body = Self;
200    fn into_body(self) -> Self::Body { self }
201}
202
203impl IntoBody for Del {
204    type Body = Self;
205    fn into_body(self) -> Self::Body { self }
206}
207
208impl IntoBody for Set {
209    type Body = Self;
210    fn into_body(self) -> Self::Body { self }
211}
212
213impl IntoBody for Cas {
214    type Body = Self;
215    fn into_body(self) -> Self::Body { self }
216}
217
218impl IntoBody for Merge {
219    type Body = Self;
220    fn into_body(self) -> Self::Body { self }
221}
222
223impl IntoBody for Flush {
224    type Body = Self;
225    fn into_body(self) -> Self::Body { self }
226}
227
228impl IntoBody for Iter {
229    type Body = Self;
230    fn into_body(self) -> Self::Body { self }
231}
232
233impl IntoBody for Scan {
234    type Body = Self;
235    fn into_body(self) -> Self::Body { self }
236}
237
238impl IntoBody for ScanRange {
239    type Body = Self;
240    fn into_body(self) -> Self::Body { self }
241}
242
243impl IntoBody for Max {
244    type Body = Self;
245    fn into_body(self) -> Self::Body { self }
246}
247
248impl IntoBody for Pred {
249    type Body = Self;
250    fn into_body(self) -> Self::Body { self }
251}
252
253impl IntoBody for PredIncl {
254    type Body = Self;
255    fn into_body(self) -> Self::Body { self }
256}
257
258impl IntoBody for Succ {
259    type Body = Self;
260    fn into_body(self) -> Self::Body { self }
261}
262
263impl IntoBody for SuccIncl {
264    type Body = Self;
265    fn into_body(self) -> Self::Body { self }
266}
267
268impl<T> IntoRequest for T
269where
270    T: RequestType + IntoBody,
271{
272    fn into_request(self, base_uri: Uri) -> Request<Body> {
273        let method = T::METHOD;
274        let uri = uri_with_path(base_uri, T::PATH_AND_QUERY);
275        let body = self.into_body();
276        let body_json = serde_json::to_vec(&body).expect("failed to serialize request body");
277        Request::builder()
278            .method(method)
279            .uri(uri)
280            .body(body_json.into())
281            .expect("attempted to construct invalid request")
282    }
283}
284
285/// Append the given path to the given `Uri`.
286///
287/// Assumes the `Uri` already contains the scheme and authority parts.
288fn uri_with_path(uri: Uri, path: &str) -> Uri {
289    let mut parts = uri.into_parts();
290    let path_and_query = path
291        .parse::<PathAndQuery>()
292        .expect("failed to parse path and query for request URI");
293    parts.path_and_query = Some(path_and_query);
294    Uri::from_parts(parts)
295        .expect("failed to construct request URI from parts")
296}
297
298/// A request to download the entire tree.
299///
300/// The body of the returned key is a `Get` serialized to JSON form.
301pub fn from<T>(base_uri: Uri, req: T) -> Request<Body>
302where
303    T: IntoRequest,
304{
305    req.into_request(base_uri)
306}
307
308/// Shorthand for `from(base_uri, Get { key })`.
309pub fn get(base_uri: Uri, key: Key) -> Request<Body> {
310    from(base_uri, Get { key })
311}
312
313/// Shorthand for `from(base_uri, Del { key })`.
314pub fn del(base_uri: Uri, key: Key) -> Request<Body> {
315    from(base_uri, Del { key })
316}
317
318/// Shorthand for `from(base_uri, Set { key, value })`.
319pub fn set(base_uri: Uri, key: Key, value: Value) -> Request<Body> {
320    from(base_uri, Set { key, value })
321}
322
323/// Shorthand for `from(base_uri, Iter)`.
324pub fn iter(base_uri: Uri) -> Request<Body> {
325    from(base_uri, Iter)
326}
327
328/// Shorthand for `from(base_uri, Scan { key })`.
329pub fn scan(base_uri: Uri, key: Key) -> Request<Body> {
330    from(base_uri, Scan { key })
331}
332
333/// Shorthand for `from(base_uri, ScanRange { start, end })`.
334pub fn scan_range(base_uri: Uri, start: Key, end: Key) -> Request<Body> {
335    from(base_uri, ScanRange { start, end })
336}
337
338/// Shorthand for `from(base_uri, Max)`.
339pub fn max(base_uri: Uri) -> Request<Body> {
340    from(base_uri, Max)
341}
342
343/// Shorthand for `from(base_uri, Pred { key })`.
344pub fn pred(base_uri: Uri, key: Key) -> Request<Body> {
345    from(base_uri, Pred { key })
346}
347
348/// Shorthand for `from(base_uri, PredIncl { key })`.
349pub fn pred_incl(base_uri: Uri, key: Key) -> Request<Body> {
350    from(base_uri, PredIncl { key })
351}
352
353/// Shorthand for `from(base_uri, Succ { key })`.
354pub fn succ(base_uri: Uri, key: Key) -> Request<Body> {
355    from(base_uri, Succ { key })
356}
357
358/// Shorthand for `from(base_uri, SuccIncl { key })`.
359pub fn succ_incl(base_uri: Uri, key: Key) -> Request<Body> {
360    from(base_uri, SuccIncl { key })
361}
362
363/// Shorthand for `from(base_uri, Cas { key, old, new })`.
364pub fn cas(base_uri: Uri, key: Key, old: Option<Value>, new: Option<Value>) -> Request<Body> {
365    from(base_uri, Cas { key, old, new })
366}
367
368/// Shorthand for `from(base_uri, Merge { key, value })`.
369pub fn merge(base_uri: Uri, key: Key, value: Value) -> Request<Body> {
370    from(base_uri, Merge { key, value })
371}
372
373/// Shorthand for `from(base_uri, Flush)`.
374pub fn flush(base_uri: Uri) -> Request<Body> {
375    from(base_uri, Flush)
376}