extern crate url;
use self::url::form_urlencoded;
use errors::QueryStringParseError;
use sort_order::SortOrder;
use std::collections::HashMap;
use std::fmt::Debug;
use std::str::FromStr;
use try_from::TryFrom;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct JsonApiParams<F, S> {
pub sort: Sort<S>,
pub fieldset: FieldSet<F>,
pub query_params: HashMap<String, String>,
}
impl<F, S> JsonApiParams<F, S> {
fn new(fieldset: Vec<F>,
sort_params: Vec<S>,
query_params: HashMap<String, String>)
-> JsonApiParams<F, S> {
JsonApiParams {
sort: Sort { fields: sort_params },
fieldset: FieldSet { fields: fieldset },
query_params: query_params,
}
}
}
impl<F, S> Default for JsonApiParams<F, S> {
fn default() -> Self {
let query_params: HashMap<String, String> = Default::default();
JsonApiParams::new(vec![], vec![], query_params)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Sort<S> {
pub fields: Vec<S>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FieldSet<F> {
pub fields: Vec<F>,
}
pub trait JsonApiResource: Sized {
type Params: Default;
type SortField;
type FilterField;
type JsonApiIdType: FromStr + Debug;
fn resource_name() -> &'static str;
fn from_str<'a>
(query_string: &'a str)
-> Result<JsonApiParams<Self::FilterField, Self::SortField>, QueryStringParseError>
where Self::SortField: for<'b> TryFrom<(&'b str, SortOrder), Error = QueryStringParseError>,
Self::FilterField: for<'b> TryFrom<(&'b str, Vec<&'b str>),
Error = QueryStringParseError>
{
let mut params: JsonApiParams<Self::FilterField, Self::SortField> = Default::default();
let decoded = form_urlencoded::parse(query_string.as_bytes()).into_owned();
for (key, value) in decoded {
if &key == "sort" {
if !params.sort.fields.is_empty() {
return Err(QueryStringParseError::DuplicateSortKey(value));
}
let fields = value.split(',').filter(|&f| !f.is_empty());
for mut field in fields {
let sort_order = if field.starts_with('-') {
field = field.trim_left_matches('-');
SortOrder::Desc
} else {
SortOrder::Asc
};
match Self::SortField::try_from((field, sort_order)) {
Ok(result) => params.sort.fields.push(result),
Err(err) => return Err(err),
}
}
} else if key.starts_with("fields") {
let mut model = key.trim_left_matches("fields");
if !model.starts_with('[') || !model.ends_with(']') {
return Err(QueryStringParseError::InvalidKeyParam(model.to_string()));
}
model = model.trim_left_matches('[').trim_right_matches(']');
if model.is_empty() {
return Err(QueryStringParseError::EmptyFieldsetKey(key.to_string()));
}
let fields: Vec<_> = value.split(',').filter(|&f| !f.is_empty()).collect();
if fields.is_empty() {
return Err(QueryStringParseError::EmptyFieldsetValue(model.to_string()));
}
match Self::FilterField::try_from((model, fields)) {
Ok(result) => params.fieldset.fields.push(result),
Err(err) => return Err(err),
}
} else {
params.query_params.insert(key, value);
}
}
Ok(params)
}
}