From 0153b2e22f6cee84fd54b1d015250c4a1d1a4f5d Mon Sep 17 00:00:00 2001 From: Dominic Date: Sun, 13 Oct 2019 17:43:42 +0200 Subject: [PATCH] add search method --- example/Cargo.toml | 2 ++ example/src/main.rs | 19 ++++++++--------- gotham_restful/src/lib.rs | 1 + gotham_restful/src/openapi/router.rs | 18 ++++++++++++++++ gotham_restful/src/resource.rs | 15 ++++++++++++-- gotham_restful/src/routing.rs | 31 +++++++++++++++++++++++++++- gotham_restful_derive/src/lib.rs | 7 +++++++ gotham_restful_derive/src/method.rs | 4 ++++ 8 files changed, 84 insertions(+), 13 deletions(-) diff --git a/example/Cargo.toml b/example/Cargo.toml index 2601ef9..06ade0c 100644 --- a/example/Cargo.toml +++ b/example/Cargo.toml @@ -16,7 +16,9 @@ gitlab = { repository = "msrd0/gotham-restful", branch = "master" } [dependencies] fake = "2.2" gotham = "0.4" +gotham_derive = "0.4" gotham_restful = { path = "../gotham_restful", features = ["openapi"] } +hyper = "0.12" log = "0.4" log4rs = { version = "0.8", features = ["console_appender"], default-features = false } serde = "1" diff --git a/example/src/main.rs b/example/src/main.rs index fb291ff..69b99b3 100644 --- a/example/src/main.rs +++ b/example/src/main.rs @@ -1,3 +1,4 @@ +#[macro_use] extern crate gotham_derive; #[macro_use] extern crate log; use fake::{faker::internet::en::Username, Fake}; @@ -17,20 +18,12 @@ use log4rs::{ use serde::{Deserialize, Serialize}; #[derive(Resource)] -#[rest_resource(ReadAll, Read, Create, DeleteAll, Delete, Update, UpdateAll)] +#[rest_resource(ReadAll, Read, Search, Create, DeleteAll, Delete, Update, UpdateAll)] struct Users { } -// rest_resource!{Users, route => { -// route.read_all::(); -// route.read::(); -// route.create::(); -// route.update_all::(); -// route.update::(); -// }} - -#[derive(Deserialize, OpenapiType, Serialize)] +#[derive(Deserialize, OpenapiType, Serialize, StateData, StaticResponseExtender)] struct User { username : String @@ -53,6 +46,12 @@ fn read(_state : &mut State, id : u64) -> Success User { username: format!("{}{}", username, id) }.into() } +#[rest_search(Users)] +fn search(_state : &mut State, query : User) -> Success +{ + query.into() +} + #[rest_create(Users)] fn create(_state : &mut State, body : User) { diff --git a/gotham_restful/src/lib.rs b/gotham_restful/src/lib.rs index 9204f42..3a37cd1 100644 --- a/gotham_restful/src/lib.rs +++ b/gotham_restful/src/lib.rs @@ -30,6 +30,7 @@ pub use resource::{ Resource, ResourceReadAll, ResourceRead, + ResourceSearch, ResourceCreate, ResourceUpdateAll, ResourceUpdate, diff --git a/gotham_restful/src/openapi/router.rs b/gotham_restful/src/openapi/router.rs index 1d89eb9..bcc86f7 100644 --- a/gotham_restful/src/openapi/router.rs +++ b/gotham_restful/src/openapi/router.rs @@ -8,12 +8,14 @@ use crate::{ }; use futures::future::ok; use gotham::{ + extractor::QueryStringExtractor, handler::{Handler, HandlerFuture, NewHandler}, helpers::http::response::create_response, pipeline::chain::PipelineHandleChain, router::builder::*, state::State }; +use hyper::Body; use indexmap::IndexMap; use log::error; use mime::{APPLICATION_JSON, TEXT_PLAIN}; @@ -292,6 +294,22 @@ macro_rules! implOpenapiRouter { (&mut *(self.0).0, self.1.to_string()).read::() } + fn search(&mut self) + where + Query : ResourceType + QueryStringExtractor + Send + Sync + 'static, + Res : ResourceResult, + Handler : ResourceSearch + { + let schema = (self.0).1.add_schema::(); + + let path = format!("/{}/search", &self.1); + let mut item = (self.0).1.remove_path(&self.1); + item.get = Some(new_operation(Res::default_status(), schema, vec![], None)); // TODO + (self.0).1.add_path(path, item); + + (&mut *(self.0).0, self.1.to_string()).search::() + } + fn create(&mut self) where Body : ResourceType, diff --git a/gotham_restful/src/resource.rs b/gotham_restful/src/resource.rs index d05594f..8b04159 100644 --- a/gotham_restful/src/resource.rs +++ b/gotham_restful/src/resource.rs @@ -1,5 +1,8 @@ use crate::{DrawResourceRoutes, ResourceResult, ResourceType}; -use gotham::state::State; +use gotham::{ + router::response::extender::StaticResponseExtender, + state::{State, StateData} +}; use serde::de::DeserializeOwned; use std::panic::RefUnwindSafe; @@ -29,6 +32,14 @@ where fn read(state : &mut State, id : ID) -> R; } +/// Handle a GET request on the Resource with additional search parameters. +pub trait ResourceSearch +where + Query : ResourceType + StateData + StaticResponseExtender +{ + fn search(state : &mut State, query : Query) -> R; +} + /// Handle a POST request on the Resource root. pub trait ResourceCreate { @@ -36,7 +47,7 @@ pub trait ResourceCreate } /// Handle a PUT request on the Resource root. -pub trait ResourceUpdateAll +pub trait ResourceUpdateAll { fn update_all(state : &mut State, body : Body) -> R; } diff --git a/gotham_restful/src/routing.rs b/gotham_restful/src/routing.rs index 5d720b2..12ef4f0 100644 --- a/gotham_restful/src/routing.rs +++ b/gotham_restful/src/routing.rs @@ -12,12 +12,14 @@ use futures::{ stream::Stream }; use gotham::{ + extractor::QueryStringExtractor, handler::{HandlerFuture, IntoHandlerError}, helpers::http::response::create_response, pipeline::chain::PipelineHandleChain, router::builder::*, state::{FromState, State} }; +use hyper::Body; use mime::APPLICATION_JSON; use serde::de::DeserializeOwned; use std::panic::RefUnwindSafe; @@ -65,6 +67,12 @@ pub trait DrawResourceRoutes Res : ResourceResult, Handler : ResourceRead; + fn search(&mut self) + where + Query : ResourceType + QueryStringExtractor + Send + Sync + 'static, + Res : ResourceResult, + Handler : ResourceSearch; + fn create(&mut self) where Body : ResourceType, @@ -175,6 +183,16 @@ where to_handler_future(state, |state| Handler::read(state, id)) } +fn search_handler(mut state : State) -> Box +where + Query : ResourceType + QueryStringExtractor + Send + Sync + 'static, + Res : ResourceResult, + Handler : ResourceSearch +{ + let query = Query::take_from(&mut state); + to_handler_future(state, |state| Handler::search(state, query)) +} + fn create_handler(state : State) -> Box where Body : ResourceType, @@ -284,7 +302,18 @@ macro_rules! implDrawResourceRoutes { .with_path_extractor::>() .to(|state| read_handler::(state)); } - + + fn search(&mut self) + where + Query : ResourceType + QueryStringExtractor + Send + Sync + 'static, + Res : ResourceResult, + Handler : ResourceSearch + { + self.0.get(&format!("{}/search", self.1)) + .with_query_string_extractor::() + .to(|state| search_handler::(state)); + } + fn create(&mut self) where Body : ResourceType, diff --git a/gotham_restful_derive/src/lib.rs b/gotham_restful_derive/src/lib.rs index 29d3106..5a25f32 100644 --- a/gotham_restful_derive/src/lib.rs +++ b/gotham_restful_derive/src/lib.rs @@ -36,6 +36,13 @@ pub fn rest_read(attr : TokenStream, item : TokenStream) -> TokenStream output } +#[proc_macro_attribute] +pub fn rest_search(attr : TokenStream, item : TokenStream) -> TokenStream +{ + let output = expand_method(Method::Search, attr, item); + output +} + #[proc_macro_attribute] pub fn rest_create(attr : TokenStream, item : TokenStream) -> TokenStream { diff --git a/gotham_restful_derive/src/method.rs b/gotham_restful_derive/src/method.rs index b4fcc4c..801f985 100644 --- a/gotham_restful_derive/src/method.rs +++ b/gotham_restful_derive/src/method.rs @@ -13,6 +13,7 @@ pub enum Method { ReadAll, Read, + Search, Create, UpdateAll, Update, @@ -28,6 +29,7 @@ impl FromStr for Method match str { "ReadAll" | "read_all" => Ok(Self::ReadAll), "Read" | "read" => Ok(Self::Read), + "Search" | "search" => Ok(Self::Search), "Create" | "create" => Ok(Self::Create), "UpdateAll" | "update_all" => Ok(Self::UpdateAll), "Update" | "update" => Ok(Self::Update), @@ -47,6 +49,7 @@ impl Method let name = match self { ReadAll => "ReadAll", Read => "Read", + Search => "Search", Create => "Create", UpdateAll => "UpdateAll", Update => "Update", @@ -63,6 +66,7 @@ impl Method let name = match self { ReadAll => "read_all", Read => "read", + Search => "search", Create => "create", UpdateAll => "update_all", Update => "update",