rincon_core/api/method.rs
1//! Method Calls as Data
2//!
3//! The REST API of ArangoDB defines operations to be invoked by a client
4//! application. In this driver we speak of a method call for the invocation
5//! of a REST operation. Each operation or method is defined by its input
6//! parameters and its return type. The input parameters may be mandatory or
7//! optional.
8//!
9//! In rincon method calls are represented as structs that implement the
10//! `Method` and the `Prepare` traits. Hence method calls are in fact structs
11//! that hold the data necessary to invoke an operation.
12//!
13//! The big advantage of defining method calls as data types is that instances
14//! of concrete method calls can be easily queued, distributed, repeated, cached
15//! or processed in batches. Further it is very easy to extend the driver with
16//! new operations by simple defining a new struct for each new operation, done.
17
18use std;
19use std::fmt::{self, Debug, Display};
20use std::iter::{ExactSizeIterator, FromIterator, Iterator};
21use std::slice::Iter;
22use std::vec::IntoIter;
23
24use serde::de::DeserializeOwned;
25use serde::ser::Serialize;
26
27use api::types::Value;
28use arango::ErrorCode;
29
30/// A `Method` type can be used to represent method calls.
31///
32/// This trait defines the result type of a method. As the rincon driver uses
33/// the `serde` crate as its serialization framework the return type must
34/// implement the `DeserializeOwned` trait of `serde`.
35pub trait Method {
36 /// The type of the result of a method call.
37 type Result: DeserializeOwned;
38
39 /// Specification of the fields of RPC-like return type.
40 ///
41 /// The design of the ArangoDB REST API is not very type safe friendly as
42 /// different operations use different fields in the top level result type.
43 /// Mainly it does not stick to one RPC-like style of fields returned as
44 /// operation results. Hence this hack is used to overcome this issue and
45 /// allows the driver to always return specific types for each operation.
46 const RETURN_TYPE: RpcReturnType;
47
48 /// Returns the specification of the RPC-like return type.
49 fn return_type(&self) -> RpcReturnType {
50 Self::RETURN_TYPE
51 }
52}
53
54/// A `Prepare` type of a method call is used to convert the method call into
55/// a concrete request that is specific to the protocol used by a `Connector`.
56///
57/// For example the `JsonHttpConnector` converts the `Prepare` type into a
58/// HTTP-request and serializes the content as JSON into the body of the
59/// request.
60///
61/// As the rincon driver uses the `serde` crate as its serialization framework
62/// the content type must implement the `Serialize` trait of `serde`.
63pub trait Prepare {
64 /// The type of the content of a method call.
65 ///
66 /// The content is the part of a request that is sent within the body of a
67 /// REST call.
68 type Content: Serialize;
69
70 /// Returns the type of operation this method is executing.
71 fn operation(&self) -> Operation;
72
73 /// Returns the resource path of a REST operation.
74 fn path(&self) -> String;
75
76 /// Returns the query parameters of this method.
77 ///
78 /// The query parameters are usually part of the URL of a REST call.
79 fn parameters(&self) -> Parameters;
80
81 /// Returns the header parameters of this method.
82 ///
83 /// The header parameters are usually sent with the HTTP header of a REST
84 /// call.
85 fn header(&self) -> Parameters;
86
87 /// Returns the content of this method if any.
88 ///
89 /// The content of a method is usually sent within the body of a REST call.
90 fn content(&self) -> Option<&Self::Content>;
91}
92
93/// Enumeration of the used operation of a REST API.
94///
95/// The operations are defined in a logical sense thus being abstract over the
96/// HTTP operations like POST, GET, PUT, PATCH, etc.
97#[derive(Clone, Copy, Debug)]
98pub enum Operation {
99 /// Create a new entity
100 Create,
101 /// Get an entity or resource
102 Read,
103 /// Modify an existing entity
104 Modify,
105 /// Replace an existing entity
106 Replace,
107 /// Delete an entity
108 Delete,
109 /// Get the header data or short info about an entity
110 ReadHeader,
111}
112
113/// A new type for a set of parameters or name/value pairs.
114///
115/// Each parameter consists of the name of the parameter and its value.
116#[derive(Clone, PartialEq)]
117pub struct Parameters {
118 list: Vec<(String, Value)>,
119}
120
121impl Parameters {
122 /// Creates and empty set of parameters.
123 pub fn empty() -> Self {
124 Parameters {
125 list: Vec::new(),
126 }
127 }
128
129 /// Creates a new set of parameters, which is empty.
130 pub fn new() -> Self {
131 Parameters {
132 list: Vec::new(),
133 }
134 }
135
136 /// Creates a new set of parameters with the given capacity.
137 ///
138 /// When the number of parameters to be inserted in the new parameter set
139 /// is known beforehand using this function can speed up memory allocation.
140 pub fn with_capacity(capacity: usize) -> Self {
141 Parameters {
142 list: Vec::with_capacity(capacity),
143 }
144 }
145
146 /// Returns whether this parameter set is empty.
147 pub fn is_empty(&self) -> bool {
148 self.list.is_empty()
149 }
150
151 /// Returns an `Iterator` over the parameters in this set.
152 pub fn iter(&self) -> ParameterIter {
153 ParameterIter {
154 inner: self.list.iter(),
155 }
156 }
157
158 /// Inserts a name/value pair as a new parameter into this set.
159 pub fn insert<K, V>(&mut self, name: K, value: V)
160 where K: Into<String>, V: Into<Value>
161 {
162 self.list.push((name.into(), value.into()));
163 }
164}
165
166impl Default for Parameters {
167 fn default() -> Self {
168 Parameters {
169 list: Vec::default(),
170 }
171 }
172}
173
174impl Debug for Parameters {
175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176 f.write_str("Parameters")
177 .and_then(|_| f.debug_list().entries(self.iter()).finish())
178 }
179}
180
181impl Display for Parameters {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 let mut display = String::new();
184 display.push_str("Parameters[");
185 if !self.list.is_empty() {
186 for &(ref key, ref value) in &self.list {
187 display.push_str(key);
188 display.push('=');
189 display.push_str(&value.to_string());
190 display.push(',');
191 display.push(' ');
192 }
193 display.pop();
194 display.pop();
195 }
196 display.push(']');
197 f.write_str(&display)
198 }
199}
200
201impl<K, V> From<Vec<(K, V)>> for Parameters
202 where K: Into<String>, V: Into<Value>
203{
204 fn from(list: Vec<(K, V)>) -> Self {
205 Parameters::from_iter(list)
206 }
207}
208
209impl<K, V> FromIterator<(K, V)> for Parameters
210 where K: Into<String>, V: Into<Value>
211{
212 fn from_iter<T: IntoIterator<Item=(K, V)>>(iter: T) -> Parameters {
213 Parameters {
214 list: Vec::from_iter(iter.into_iter().map(|(k, v)| (k.into(), v.into()))),
215 }
216 }
217}
218
219impl<'i, K, V> FromIterator<&'i (K, V)> for Parameters
220 where K: Into<String> + Clone, V: Into<Value> + Clone
221{
222 fn from_iter<T: IntoIterator<Item=&'i (K, V)>>(iter: T) -> Parameters {
223 Parameters {
224 list: Vec::from_iter(iter.into_iter().map(|&(ref k, ref v)|
225 (k.clone().into(), v.clone().into()))),
226 }
227 }
228}
229
230impl<K, V> Extend<(K, V)> for Parameters
231 where K: Into<String>, V: Into<Value>
232{
233 fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
234 self.list.extend(iter.into_iter().map(|(k, v)| (k.into(), v.into())));
235 }
236}
237
238/// An `Iterator` over the references to name/value pairs of a parameter set.
239///
240/// This iterator is created by calling the `Parameters.iter()` function.
241#[derive(Debug)]
242pub struct ParameterIter<'i> {
243 inner: Iter<'i, (String, Value)>,
244}
245
246impl<'i> Iterator for ParameterIter<'i> {
247 type Item = &'i (String, Value);
248
249 fn next(&mut self) -> Option<Self::Item> {
250 self.inner.next()
251 }
252
253 fn size_hint(&self) -> (usize, Option<usize>) {
254 self.inner.size_hint()
255 }
256}
257
258impl<'i> ExactSizeIterator for ParameterIter<'i> {
259 fn len(&self) -> usize {
260 self.inner.len()
261 }
262}
263
264/// Specification of the fields of RPC-like return type.
265///
266/// The design of the ArangoDB REST API is not very type safe friendly as
267/// different operations use different fields in the top level result type.
268/// Mainly it does not stick to one RPC-like style of fields returned as
269/// operation results. Hence this hack is used to overcome this issue and
270/// allows the driver to always return specific types for each operation.
271#[allow(missing_copy_implementations)]
272#[derive(Debug, Clone, PartialEq)]
273pub struct RpcReturnType {
274 /// The name of the result field if any or none if the fields of the result
275 /// type are at the top level returned object.
276 pub result_field: Option<&'static str>,
277
278 /// The name of the code field that contains the error code if there is any
279 /// or none if the result will never contain an error code.
280 pub code_field: Option<&'static str>,
281}
282
283/// A container for entities in the result of a method call, where the result
284/// contains a list of entities and there might be error information for single
285/// results only, not the whole operation.
286#[derive(Debug, Clone, PartialEq)]
287pub enum Result<T> {
288 /// The successful result for one single entity of an operation that has
289 /// been executed for multiple entities.
290 Success(T),
291 /// The error for one single result that occurred during execution of an
292 /// operation for multiple entities.
293 Failed(Error),
294}
295
296impl<T> Result<T> {
297 /// Converts this `Result` into a `::std::result::Result`.
298 pub fn into_std_result(self) -> std::result::Result<T, Error> {
299 use self::Result::*;
300 match self {
301 Success(value) => Ok(value),
302 Failed(error) => Err(error),
303 }
304 }
305
306 /// Returns this `Result` as a `::std::result::Result` to the references
307 /// of the success or error value.
308 pub fn as_std_result(&self) -> std::result::Result<&T, &Error> {
309 use self::Result::*;
310 match *self {
311 Success(ref value) => Ok(value),
312 Failed(ref error) => Err(error),
313 }
314 }
315}
316
317impl<T> From<std::result::Result<T, Error>> for Result<T> {
318 fn from(value: std::result::Result<T, Error>) -> Self {
319 use self::Result::*;
320 match value {
321 Ok(value) => Success(value),
322 Err(error) => Failed(error),
323 }
324 }
325}
326
327/// A container for a list of `Result`s. This type is used as return type for
328/// methods that operate on a list of entities where the result can contain
329/// error information for single entities only, not the whole operation.
330#[derive(Debug, Clone, PartialEq, Deserialize)]
331pub struct ResultList<T>(#[serde(bound(deserialize = "T: DeserializeOwned"))] Vec<Result<T>>);
332
333impl<T> ResultList<T> {
334 /// Returns the result at the given index if available.
335 pub fn get(&self, index: usize) -> Option<std::result::Result<&T, &Error>> {
336 self.0.get(index).map(|x| x.as_std_result())
337 }
338
339 /// Returns an `Iterator` over the result items in this result list.
340 pub fn iter(&self) -> ResultListIter<T> {
341 ResultListIter(self.0.iter())
342 }
343}
344
345impl<T> FromIterator<std::result::Result<T, Error>> for ResultList<T> {
346 fn from_iter<I>(iter: I) -> Self
347 where I: IntoIterator<Item=std::result::Result<T, Error>>
348 {
349 ResultList(Vec::from_iter(iter.into_iter().map(From::from)))
350 }
351}
352
353impl<T> FromIterator<Result<T>> for ResultList<T> {
354 fn from_iter<I>(iter: I) -> Self
355 where I: IntoIterator<Item=Result<T>>
356 {
357 ResultList(Vec::from_iter(iter.into_iter()))
358 }
359}
360
361impl<T> IntoIterator for ResultList<T>
362 where T: DeserializeOwned
363{
364 type Item = std::result::Result<T, Error>;
365 type IntoIter = ResultListIntoIter<T>;
366
367 fn into_iter(self) -> Self::IntoIter {
368 ResultListIntoIter(self.0.into_iter())
369 }
370}
371
372/// An `Iterator` over the result items of a `ResultList`.
373///
374/// This iterator is returned by the `ResultList.into_iter()` function.
375#[derive(Debug)]
376pub struct ResultListIntoIter<T>(IntoIter<Result<T>>);
377
378impl<T> Iterator for ResultListIntoIter<T> {
379 type Item = std::result::Result<T, Error>;
380
381 fn next(&mut self) -> Option<Self::Item> {
382 self.0.next().map(|x| x.into_std_result())
383 }
384}
385
386impl<T> ExactSizeIterator for ResultListIntoIter<T> {}
387
388/// An `Iterator` over references to the result items of a `ResultList`.
389///
390/// This iterator is returned by the `ResulList.iter()` function.
391#[derive(Debug)]
392pub struct ResultListIter<'a, T: 'a>(Iter<'a, Result<T>>);
393
394impl<'a, T> Iterator for ResultListIter<'a, T> {
395 type Item = std::result::Result<&'a T, &'a Error>;
396
397 fn next(&mut self) -> Option<Self::Item> {
398 self.0.next().map(|x| x.as_std_result())
399 }
400}
401
402impl<'a, T> ExactSizeIterator for ResultListIter<'a, T> {}
403
404/// Represents an error that occurs during method execution.
405///
406/// A method `Error` is returned by the ArangoDB server when the execution of
407/// an operation fails.
408#[derive(Clone, PartialEq, Deserialize)]
409pub struct Error {
410 #[serde(rename = "errorNum")]
411 code: ErrorCode,
412 #[serde(rename = "errorMessage")]
413 message: String,
414}
415
416impl Error {
417 /// Contructs a new method `Error` with given code and message.
418 pub fn new<M>(code: ErrorCode, message: M) -> Self
419 where M: Into<String>
420 {
421 Error {
422 code,
423 message: message.into(),
424 }
425 }
426
427 /// Returns the code of this error.
428 ///
429 /// The possible error codes are defined by ArangoDB.
430 pub fn code(&self) -> ErrorCode {
431 self.code
432 }
433
434 /// Returns the message of this error.
435 ///
436 /// The message coming with an error is received from the ArangoDB server.
437 /// The driver transparently copies the error message into this property of
438 /// the `Error` struct.
439 pub fn message(&self) -> &str {
440 &self.message
441 }
442}
443
444impl Debug for Error {
445 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446 f.write_str(&format!("Error {}: {}",
447 &self.code.as_u16(), &self.message))
448 }
449}
450
451impl Display for Error {
452 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
453 f.write_str(&format!("Error {}: {}",
454 &self.code.as_u16(), &self.message))
455 }
456}