1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
pub mod page;
pub mod sort;

use percent_encoding::percent_decode;
use serde_qs;

use self::sort::Direction;
use builder;
use error::Error;
use value::{Map, Set, Value};
use value::key::{Key, Path};

pub use self::page::Page;
pub use self::sort::Sort;

#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct Query {
    #[serde(default, skip_serializing_if = "Map::is_empty")]
    pub fields: Map<Key, Set<Key>>,
    #[serde(default, skip_serializing_if = "Map::is_empty")]
    pub filter: Map<Path, Value>,
    #[serde(default, skip_serializing_if = "Set::is_empty")]
    pub include: Set<Path>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub page: Option<Page>,
    #[serde(default, skip_serializing_if = "Set::is_empty")]
    pub sort: Set<Sort>,
    /// Private field for backwards compatibility.
    #[serde(skip)]
    _ext: (),
}

impl Query {
    pub fn build() -> QueryBuilder {
        Default::default()
    }
}

#[derive(Default)]
pub struct QueryBuilder {
    fields: Vec<(String, Vec<String>)>,
    filter: Vec<(String, Value)>,
    include: Vec<String>,
    page: Option<Page>,
    sort: Vec<(String, Direction)>,
}

impl QueryBuilder {
    pub fn finalize(&mut self) -> Result<Query, Error> {
        Ok(Query {
            fields: builder::iter(&mut self.fields, |(key, mut fields)| {
                let key = key.parse()?;
                let fields = fields
                    .drain(..)
                    .map(|item| item.parse())
                    .collect::<Result<_, _>>()?;

                Ok((key, fields))
            })?,
            filter: builder::iter(&mut self.filter, |(key, value)| Ok((key.parse()?, value)))?,
            include: builder::iter(&mut self.include, |key| key.parse())?,
            page: builder::optional(&mut self.page),
            sort: builder::iter(&mut self.sort, |(field, direction)| {
                Ok(Sort::new(field.parse()?, direction))
            })?,
            _ext: (),
        })
    }

    pub fn fields<I, K, V>(&mut self, key: K, iter: I) -> &mut Self
    where
        I: IntoIterator<Item = V>,
        K: Into<String>,
        V: Into<String>,
    {
        let key = key.into();
        let value = iter.into_iter().map(|i| i.into()).collect();

        self.fields.push((key, value));
        self
    }

    pub fn filter<K, V>(&mut self, key: K, value: V) -> &mut Self
    where
        K: Into<String>,
        V: Into<Value>,
    {
        let key = key.into();
        let value = value.into();

        self.filter.push((key, value));
        self
    }

    pub fn include<V>(&mut self, value: V) -> &mut Self
    where
        V: Into<String>,
    {
        self.include.push(value.into());
        self
    }

    pub fn page(&mut self, number: u64, size: Option<u64>) -> &mut Self {
        self.page = Some(Page::new(number, size));
        self
    }

    pub fn sort<F>(&mut self, field: F, direction: Direction) -> &mut Self
    where
        F: Into<String>,
    {
        self.sort.push((field.into(), direction));
        self
    }
}

pub fn from_slice(data: &[u8]) -> Result<Query, Error> {
    let value = percent_decode(data).decode_utf8()?;
    Ok(serde_qs::from_bytes(value.as_bytes())?)
}

pub fn from_str(data: &str) -> Result<Query, Error> {
    from_slice(data.as_bytes())
}

pub fn to_string(query: &Query) -> Result<String, Error> {
    use percent_encoding::{percent_encode, QUERY_ENCODE_SET};

    let value = serde_qs::to_string(query)?;
    let data = value.as_bytes();

    Ok(percent_encode(data, QUERY_ENCODE_SET).collect())
}

pub fn to_vec(query: &Query) -> Result<Vec<u8>, Error> {
    to_string(query).map(Vec::from)
}