use super::{Error, Params, Path};
use regex::Regex;
use std::collections::HashMap;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct PathWithRegex {
path: Path,
params: Arc<Params>,
path_type: PathType,
}
#[derive(PartialEq, Debug, Clone)]
pub enum PathType {
Rest,
Wildcard,
Route,
}
impl PathWithRegex {
pub(crate) fn new(path: Path, path_type: PathType) -> Result<Self, Error> {
let mut params = HashMap::new();
let mut i = 1;
let mut iter = path.base().split("/");
let mut regex = Vec::new();
while let Some(part) = iter.next() {
let re = if part.starts_with(":") {
params.insert(part[1..].to_owned(), i);
i += 1;
"([a-zA-Z0-9_-]+)"
} else {
part
};
regex.push(re);
}
let regex =
"^".to_string() +
®ex.join(r#"\/"#) +
match path_type {
PathType::Rest => {
r#"(\/[a-zA-Z0-9_-]+)?"#
}
PathType::Route => "",
PathType::Wildcard => ".*",
}
+
if path.base().ends_with("/") { "$" } else { r#"\/?$"# };
if path_type == PathType::Rest {
params.insert("id".to_string(), i);
}
let regex = Regex::new(®ex)?;
Ok(Self {
path,
params: Arc::new(Params::new(regex, params)),
path_type,
})
}
pub(crate) fn route(path: Path) -> Result<Self, Error> {
Self::new(path, PathType::Route)
}
pub(crate) fn rest(path: Path) -> Result<Self, Error> {
Self::new(path, PathType::Rest)
}
pub(crate) fn wildcard(path: Path) -> Result<Self, Error> {
Self::new(path, PathType::Wildcard)
}
pub fn params(&self) -> Arc<Params> {
self.params.clone()
}
pub fn regex(&self) -> &Regex {
self.params.regex()
}
pub fn path_type(&self) -> &PathType {
&self.path_type
}
}
impl std::ops::Deref for PathWithRegex {
type Target = Path;
fn deref(&self) -> &Self::Target {
&self.path
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_paramters() {
let path = Path::parse("/api/orders/:name/receipt").unwrap();
let with_regex = PathWithRegex::rest(path).unwrap();
assert_eq!(
r#"^\/api\/orders\/([a-zA-Z0-9_-]+)\/receipt(\/[a-zA-Z0-9_-]+)?\/?$"#,
with_regex.regex().as_str()
);
let params = with_regex.params();
let url = "/api/orders/apple_bees/receipt/5";
let name = params.parameter(url, "name");
assert_eq!(name, Some("apple_bees"));
let name = params.parameter(url, "id");
assert_eq!(name, Some("5"));
let url = "/api/orders/hello-world/receipt/";
let name = params.parameter(url, "name");
assert_eq!(name, Some("hello-world"));
}
}