-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(extractors): add query extractor
- Loading branch information
1 parent
364bcfd
commit 9b4dffd
Showing
11 changed files
with
166 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,5 +6,6 @@ members = [ | |
"hitbox-redis", | ||
"hitbox-stretto", | ||
"hitbox-tower", | ||
"hitbox-qs", | ||
"examples", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use async_trait::async_trait; | ||
use hitbox::cache::{Extractor, KeyPart, KeyParts}; | ||
|
||
use crate::CacheableHttpRequest; | ||
|
||
pub struct Query<E> { | ||
inner: E, | ||
name: String, | ||
} | ||
|
||
pub trait QueryExtractor: Sized { | ||
fn query(self, name: String) -> Query<Self>; | ||
} | ||
|
||
impl<E> QueryExtractor for E | ||
where | ||
E: Extractor, | ||
{ | ||
fn query(self, name: String) -> Query<Self> { | ||
Query { inner: self, name } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<ReqBody, E> Extractor for Query<E> | ||
where | ||
ReqBody: Send + 'static, | ||
E: Extractor<Subject = CacheableHttpRequest<ReqBody>> + Send + Sync, | ||
{ | ||
type Subject = E::Subject; | ||
|
||
async fn get(&self, subject: Self::Subject) -> KeyParts<Self::Subject> { | ||
let values = subject | ||
.parts() | ||
.uri | ||
.query() | ||
.map(hitbox_qs::parse) | ||
.map(|m| m.get(&self.name).map(hitbox_qs::Value::inner)) | ||
.flatten() | ||
.unwrap_or_default(); | ||
let mut parts = self.inner.get(subject).await; | ||
for value in values { | ||
parts.push(KeyPart { | ||
key: self.name.clone(), | ||
value: Some(value), | ||
});} | ||
parts | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
mod request; | ||
//mod request; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
mod header; | ||
mod query; | ||
mod method; | ||
mod multiple; | ||
mod path; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
use hitbox::cache::Extractor; | ||
use hitbox_http::extractors::{query::QueryExtractor, NeutralExtractor}; | ||
use hitbox_http::CacheableHttpRequest; | ||
use http::Request; | ||
use hyper::Body; | ||
|
||
#[tokio::test] | ||
async fn test_request_query_extractor_some() { | ||
let uri = http::uri::Uri::builder() | ||
.path_and_query("test-path?key=value") | ||
.build() | ||
.unwrap(); | ||
let request = Request::builder().uri(uri).body(Body::empty()).unwrap(); | ||
let request = CacheableHttpRequest::from_request(request); | ||
let extractor = NeutralExtractor::new().query("key".to_owned()); | ||
let parts = extractor.get(request).await; | ||
dbg!(parts); | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_request_query_extractor_none() { | ||
let uri = http::uri::Uri::builder() | ||
.path_and_query("test-path?key=value") | ||
.build() | ||
.unwrap(); | ||
let request = Request::builder().uri(uri).body(Body::empty()).unwrap(); | ||
let request = CacheableHttpRequest::from_request(request); | ||
let extractor = NeutralExtractor::new().query("non-existent-key".to_owned()); | ||
let parts = extractor.get(request).await; | ||
dbg!(parts); | ||
} | ||
|
||
#[tokio::test] | ||
async fn test_request_query_extractor_multiple() { | ||
let uri = http::uri::Uri::builder() | ||
.path_and_query("test-path?cars[]=Saab&cars[]=Audi") | ||
.build() | ||
.unwrap(); | ||
let request = Request::builder().uri(uri).body(Body::empty()).unwrap(); | ||
let request = CacheableHttpRequest::from_request(request); | ||
let extractor = NeutralExtractor::new().query("cars".to_owned()); | ||
let parts = extractor.get(request).await; | ||
dbg!(parts); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "hitbox-qs" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
serde_qs = "0.12" | ||
serde = { version = "1", features = ["derive"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use std::collections::HashMap; | ||
use serde::Deserialize; | ||
|
||
#[derive(Debug, Deserialize, PartialEq, Eq)] | ||
#[serde(untagged)] | ||
pub enum Value { | ||
Scalar(String), | ||
Array(Vec<String>), | ||
} | ||
|
||
impl Value { | ||
pub fn inner(&self) -> Vec<String> { | ||
match self { | ||
Value::Scalar(value) => vec![value.to_owned()], | ||
Value::Array(values) => values.to_owned(), | ||
} | ||
} | ||
} | ||
|
||
pub fn parse(value: &str) -> HashMap<String, Value> { | ||
serde_qs::from_str(value).expect("Unreachable branch reached") | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_parse_valid_one() { | ||
let hash_map = parse("key=value"); | ||
let value = hash_map.get("key").unwrap(); | ||
assert_eq!(value.inner(), vec!["value"]); | ||
} | ||
|
||
#[test] | ||
fn test_parse_valid_multiple() { | ||
let hash_map = parse("key-one=value-one&key-two=value-two&key-three=value-three"); | ||
let value = hash_map.get("key-one").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-one"]); | ||
let value = hash_map.get("key-two").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-two"]); | ||
let value = hash_map.get("key-three").unwrap(); | ||
assert_eq!(value.inner(), vec!["value-three"]); | ||
} | ||
|
||
#[test] | ||
fn test_parse_not_valid() { | ||
let hash_map = parse(" wrong "); | ||
assert_eq!(hash_map.len(), 1); | ||
} | ||
} |