Skip to content

Commit

Permalink
pagination added #14
Browse files Browse the repository at this point in the history
  • Loading branch information
serayuzgur committed Aug 16, 2017
1 parent 440d49d commit 788c472
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/database/query_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub mod filter;
pub mod q;
pub mod sort;
pub mod fields;
pub mod paginate;

// TODO:
// Get the result
// If it is List than do the ops
Expand Down
145 changes: 145 additions & 0 deletions src/database/query_api/paginate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//! # fields
//! All necessery functions for appliying fields to json results.
use serde_json::Value;
use service::query_api::Queries;
use service::query_api::Page;
use std::vec::Vec;

/// let only named fields array according to the query api
pub fn apply(obj: &mut Value, queries: &Queries) {
let ref _offset = queries.paginate.0;
let ref _limit = queries.paginate.1;

match obj {
&mut Value::Array(ref mut arr) => {
let offset = match _offset {
&Page::OFFSET(ref index) => index.clone(),
_ => 0u8,
};
let limit = match _limit {
&Page::LIMIT(ref index) => index.clone(),
_ => arr.len().clone() as u8,
};
let o: usize = offset.clone() as usize;
let l: usize = limit.clone() as usize;

let mut temp = clone_slice(arr, o, l);

arr.clear();
arr.append(&mut temp);
}
_ => {
//No need to handle other types
}
}
}
/// copies array within the given indexes.
fn clone_slice(arr: &mut Vec<Value>, offset: usize, limit: usize) -> Vec<Value> {
let mut temp = Vec::<Value>::new();
let mut i = 0;
let upperlimit = offset + limit;
for val in arr {
if i >= offset && i < upperlimit {
temp.push(val.clone());
}
i += 1;
}
temp
}

#[cfg(test)]
mod tests {
use super::*;
use serde_json;

fn get_json() -> Value {
let json_string = r#"[
{
"name":"seray",
"age":31,
"active":true,
"password":"123"
},
{
"name":"kamil",
"age":900,
"active":false,
"password":"333"
},
{
"name":"hasan",
"age":25,
"active":true,
"password":"321"
}
]"#;
serde_json::from_str(&json_string).unwrap()
}

#[test]
fn apply_test_middle() {
let mut queries = Queries::new();
{
let paginate = &mut queries.paginate;
paginate.0 = Page::OFFSET(1);
paginate.1 = Page::LIMIT(1);
}
let expected: Value = serde_json::from_str(
&r#"[
{
"name":"kamil",
"age":900,
"active":false,
"password":"333"
}
]"#,
).unwrap();
let json = &mut get_json();
apply(json, &queries);
assert_eq!(json.clone(), expected);
}
#[test]
fn apply_test_start() {
let mut queries = Queries::new();
{
let paginate = &mut queries.paginate;
paginate.0 = Page::OFFSET(0);
paginate.1 = Page::LIMIT(1);
}
let expected: Value = serde_json::from_str(
&r#"[
{
"name":"seray",
"age":31,
"active":true,
"password":"123"
}
]"#,
).unwrap();
let json = &mut get_json();
apply(json, &queries);
assert_eq!(json.clone(), expected);
}
#[test]
fn apply_test_end() {
let mut queries = Queries::new();
{
let paginate = &mut queries.paginate;
paginate.0 = Page::OFFSET(2);
paginate.1 = Page::LIMIT(1);
}
let expected: Value = serde_json::from_str(
&r#"[
{
"name":"hasan",
"age":25,
"active":true,
"password":"321"
}
]"#,
).unwrap();
let json = &mut get_json();
apply(json, &queries);
assert_eq!(json.clone(), expected);
}
}
16 changes: 9 additions & 7 deletions src/database/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@ use database::query_api;
impl Database {
/// Retuns the list of the tables (outmost keys) from the database.
pub fn tables(&self) -> Vec<&String> {
let map: &serde_json::Map<String, Value> = self.data
.as_object()
.expect("Database is invalid. You can't mock API with it. Terminating...");
let map: &serde_json::Map<String, Value> = self.data.as_object().expect(
"Database is invalid. You can't mock API with it. Terminating...",
);
let mut keys = Vec::new();
keys.extend(map.keys());
keys
}

/// Reads the desired result with the given path.
pub fn read(&mut self,
keys: &mut Vec<String>,
queries: Option<Queries>)
-> Result<Value, Errors> {
pub fn read(
&mut self,
keys: &mut Vec<String>,
queries: Option<Queries>,
) -> Result<Value, Errors> {
let mut data = &mut self.data;
match Self::get_object(keys, data) {
Ok(obj) => {
Expand All @@ -32,6 +33,7 @@ impl Database {
query_api::q::apply(clone, &q);
query_api::sort::apply(clone, &q);
query_api::fields::apply(clone, &q);
query_api::paginate::apply(clone, &q);
return Ok(clone.clone());
}
return Ok(obj.clone());
Expand Down
28 changes: 18 additions & 10 deletions src/service/query_api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod page;

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

/// parse query params. For duplicate parameters only last one will be used.
pub fn parse(query: Option<&str>) -> Option<Queries> {
Expand All @@ -26,12 +27,14 @@ pub fn parse(query: Option<&str>) -> Option<Queries> {
let value = parts.get(1).unwrap().to_string();
if key.starts_with("_") {
// fields,offset,limit,sort,filter,q
set_where_it_belongs(&mut queries,
Query {
key: key,
value: value,
op: "=".to_string(),
});
set_where_it_belongs(
&mut queries,
Query {
key: key,
value: value,
op: "=".to_string(),
},
);
}
}
Some(queries)
Expand All @@ -44,7 +47,12 @@ fn set_where_it_belongs(queries: &mut Queries, q: Query) {
match q.key.as_str() {
"_fields" => {
let mut fields_vec = &mut queries.fields;
fields_vec.extend(q.value.split(",").map(String::from).collect::<Vec<String>>());
fields_vec.extend(
q.value
.split(",")
.map(String::from)
.collect::<Vec<String>>(),
);
}
"_offset" | "_limit" => {
if let Some(page) = page::parse(q) {
Expand Down Expand Up @@ -75,7 +83,7 @@ fn set_where_it_belongs(queries: &mut Queries, q: Query) {
}

/// A simple struct to hold query parameters well structured.
#[derive(Debug,Clone)]
#[derive(Debug, Clone)]
pub struct Queries {
/// field names to return
pub fields: Vec<String>,
Expand Down Expand Up @@ -109,8 +117,8 @@ impl PartialEq for Queries {
#[inline]
fn eq(&self, other: &Queries) -> bool {
self.fields == other.fields && self.filter == other.filter && self.q == other.q &&
self.paginate == other.paginate && self.slice == other.slice &&
self.sort == other.sort
self.paginate == other.paginate && self.slice == other.slice &&
self.sort == other.sort
}
}

Expand Down
30 changes: 19 additions & 11 deletions src/service/query_api/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
//! All paging related codes contained under this module.
use service::query_api::query::Query;
/// An enum to hold sort parameters with the direction.
#[derive(Debug,Copy,Clone)]
#[derive(Debug, Copy, Clone)]
pub enum Page {
/// Ascending sorting.
OFFSET(u8),
/// Descendinf sorting.
/// Descending sorting.
LIMIT(u8),
}

Expand Down Expand Up @@ -57,14 +57,22 @@ mod tests {
assert_eq!(parse(Query::new("Abc", "=", "123")), None);
assert_eq!(parse(Query::new("_offset", "=", "")), None);
assert_eq!(parse(Query::new("_limit", "=", "")), None);
assert_eq!(parse(Query::new("_offset", "=", "123")),
Some(Page::OFFSET(123)));
assert_eq!(parse(Query::new("_limit", "=", "123")),
Some(Page::LIMIT(123)));

assert_ne!(parse(Query::new("_offset", "=", "123")),
Some(Page::LIMIT(123)));
assert_ne!(parse(Query::new("_offset", "=", "123")),
Some(Page::LIMIT(123)));
assert_eq!(
parse(Query::new("_offset", "=", "123")),
Some(Page::OFFSET(123))
);
assert_eq!(
parse(Query::new("_limit", "=", "123")),
Some(Page::LIMIT(123))
);

assert_ne!(
parse(Query::new("_offset", "=", "123")),
Some(Page::LIMIT(123))
);
assert_ne!(
parse(Query::new("_offset", "=", "123")),
Some(Page::LIMIT(123))
);
}
}

0 comments on commit 788c472

Please sign in to comment.