use std::marker::PhantomData;
use futures::{Future, Poll};
use serde::de::DeserializeOwned;
use error::{Error, Result};
use client::{AsyncSender, Client, Sender, SyncSender};
use client::requests::{empty_body, DefaultBody, RequestBuilder};
use client::requests::params::{Index, Type};
use client::requests::endpoints::SearchRequest;
use client::requests::raw::RawRequestInner;
use client::responses::SearchResponse;
pub type SearchRequestBuilder<TSender, TDocument, TBody> = RequestBuilder<TSender, SearchRequestInner<TDocument, TBody>>;
#[doc(hidden)]
pub struct SearchRequestInner<TDocument, TBody> {
index: Option<Index<'static>>,
ty: Option<Type<'static>>,
body: TBody,
_marker: PhantomData<TDocument>,
}
impl<TSender> Client<TSender>
where
TSender: Sender,
{
pub fn search<TDocument>(&self) -> SearchRequestBuilder<TSender, TDocument, DefaultBody>
where
TDocument: DeserializeOwned,
{
RequestBuilder::new(self.clone(), None, SearchRequestInner::new(empty_body()))
}
}
impl<TDocument, TBody> SearchRequestInner<TDocument, TBody>
where
TDocument: DeserializeOwned,
{
fn new(body: TBody) -> Self {
SearchRequestInner {
index: None,
ty: None,
body: body,
_marker: PhantomData,
}
}
fn into_request(self) -> SearchRequest<'static, TBody> {
let index = self.index.unwrap_or_else(|| "_all".into());
match self.ty {
Some(ty) => SearchRequest::for_index_ty(index, ty, self.body),
None => SearchRequest::for_index(index, self.body),
}
}
}
impl<TSender, TDocument, TBody> SearchRequestBuilder<TSender, TDocument, TBody>
where
TSender: Sender,
{
pub fn index<I>(mut self, index: I) -> Self
where
I: Into<Index<'static>>,
{
self.inner.index = Some(index.into());
self
}
pub fn ty<I>(mut self, ty: Option<I>) -> Self
where
I: Into<Type<'static>>,
{
self.inner.ty = ty.map(Into::into);
self
}
pub fn body<TNewBody>(self, body: TNewBody) -> SearchRequestBuilder<TSender, TDocument, TNewBody>
where
TNewBody: Into<TSender::Body>,
{
RequestBuilder::new(
self.client,
self.params,
SearchRequestInner {
body: body,
index: self.inner.index,
ty: self.inner.ty,
_marker: PhantomData,
},
)
}
}
impl<TDocument, TBody> SearchRequestBuilder<SyncSender, TDocument, TBody>
where
TDocument: DeserializeOwned,
TBody: Into<<SyncSender as Sender>::Body>,
{
pub fn send(self) -> Result<SearchResponse<TDocument>> {
let req = self.inner.into_request();
RequestBuilder::new(self.client, self.params, RawRequestInner::new(req))
.send()?
.into_response()
}
}
impl<TDocument, TBody> SearchRequestBuilder<AsyncSender, TDocument, TBody>
where
TDocument: DeserializeOwned + Send + 'static,
TBody: Into<<AsyncSender as Sender>::Body>,
{
pub fn send(self) -> Pending<TDocument> {
let req = self.inner.into_request();
let res_future = RequestBuilder::new(self.client, self.params, RawRequestInner::new(req))
.send()
.and_then(|res| res.into_response());
Pending::new(res_future)
}
}
pub struct Pending<TDocument> {
inner: Box<Future<Item = SearchResponse<TDocument>, Error = Error>>,
}
impl<TDocument> Pending<TDocument> {
fn new<F>(fut: F) -> Self
where
F: Future<Item = SearchResponse<TDocument>, Error = Error> + 'static,
{
Pending {
inner: Box::new(fut),
}
}
}
impl<TDocument> Future for Pending<TDocument>
where
TDocument: DeserializeOwned + Send + 'static,
{
type Item = SearchResponse<TDocument>;
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.inner.poll()
}
}
#[cfg(test)]
mod tests {
use serde_json::Value;
use prelude::*;
#[test]
fn default_request() {
let client = SyncClientBuilder::new().build().unwrap();
let req = client.search::<Value>().inner.into_request();
assert_eq!("/_all/_search", req.url.as_ref());
}
#[test]
fn specify_index() {
let client = SyncClientBuilder::new().build().unwrap();
let req = client
.search::<Value>()
.index("new-idx")
.inner
.into_request();
assert_eq!("/new-idx/_search", req.url.as_ref());
}
#[test]
fn specify_ty() {
let client = SyncClientBuilder::new().build().unwrap();
let req = client
.search::<Value>()
.ty(Some("new-ty"))
.inner
.into_request();
assert_eq!("/_all/new-ty/_search", req.url.as_ref());
}
#[test]
fn specify_body() {
let client = SyncClientBuilder::new().build().unwrap();
let req = client.search::<Value>().body("{}").inner.into_request();
assert_eq!("{}", req.body);
}
}