diff --git a/tremor-cli/tests/stdlib/std/all.tremor b/tremor-cli/tests/stdlib/std/all.tremor index 1283170253..8e97a31709 100644 --- a/tremor-cli/tests/stdlib/std/all.tremor +++ b/tremor-cli/tests/stdlib/std/all.tremor @@ -865,4 +865,47 @@ test::suite({ ] }); +test::suite({ + "name": "URL Construct and Modification tests", + "tags": [ "url", "construct", "modify" ], + "tests": [ + test::test({ + "name": "Test construct function", + "test": test::assert("url::construct", + url::construct("http", "www.example.com", "/path", "query=test", "fragment"), + "http://www.example.com/path?query=test#fragment"), + }), + test::test({ + "name": "Test set_scheme function", + "test": test::assert("url::set_scheme", + url::set_scheme("http://www.example.com", "https"), + "https://www.example.com"), + }), + test::test({ + "name": "Test set_host function", + "test": test::assert("url::set_host", + url::set_host("http://www.example.com", "www.example2.com"), + "http://www.example2.com"), + }), + test::test({ + "name": "Test set_path function", + "test": test::assert("url::set_path", + url::set_path("http://www.example.com", "/newpath"), + "http://www.example.com/newpath"), + }), + test::test({ + "name": "Test set_query function", + "test": test::assert("url::set_query", + url::set_query("http://www.example.com?query=test", "newquery=test2"), + "http://www.example.com?newquery=test2"), + }), + test::test({ + "name": "Test set_fragment function", + "test": test::assert("url::set_fragment", + url::set_fragment("http://www.example.com#fragment", "newfragment"), + "http://www.example.com#newfragment"), + }), + ], +}); + "snot badger"; diff --git a/tremor-script/lib/std/url.tremor b/tremor-script/lib/std/url.tremor index d384c6eaa9..38ea3150fc 100644 --- a/tremor-script/lib/std/url.tremor +++ b/tremor-script/lib/std/url.tremor @@ -19,3 +19,59 @@ intrinsic fn encode(str) as url::encode; ## ## Returns a `string` intrinsic fn decode(str) as url::decode; + +## Constructs a url from the provided scheme, host, path, query and fragment +## +## > ```tremor +## > use std::url; +## > +## > "https://example.com/path?query=1#fragment" == url::construct("https","example.com","/path","query=1","fragment") +## > ``` +## +## Returns a `string` +intrinsic fn construct(scheme:str,host:str,path:str,query:str,fragment:str) as url::construct; + +## Returns a new URL string with the specified scheme +## +## > ```tremor +## > "https://example.com" == url::set_scheme("http://example.com", "https") +## > ``` +## +## Returns a `string` +intrinsic fn set_scheme(url:str, scheme:str) as url::set_scheme; + +## Returns a new URL string with the specified host +## +## > ```tremor +## > "http://newhost.com" == url::set_host("http://example.com", "newhost.com") +## > ``` +## +## Returns a `string` +intrinsic fn set_host(url:str, host:str) as url::set_host; + +## Returns a new URL string with the specified path +## +## > ```tremor +## > "http://example.com/newpath" == url::set_path("http://example.com/oldpath", "/newpath") +## > ``` +## +## Returns a `string` +intrinsic fn set_path(url:str, path:str) as url::set_path; + +## Returns a new URL string with the specified query +## +## > ```tremor +## > "http://example.com?newquery=value" == url::set_query("http://example.com", "newquery=value") +## > ``` +## +## Returns a `string` +intrinsic fn set_query(url:str, query:str) as url::set_query; + +## Returns a new URL string with the specified fragment +## +## > ```tremor +## > "http://example.com#newfragment" == url::set_fragment("http://example.com", "newfragment") +## > ``` +## +## Returns a `string` +intrinsic fn set_fragment(url:str, fragment:str) as url::set_fragment; \ No newline at end of file diff --git a/tremor-script/src/std_lib/url.rs b/tremor-script/src/std_lib/url.rs index 7f7bae8210..ef05f2c4cd 100644 --- a/tremor-script/src/std_lib/url.rs +++ b/tremor-script/src/std_lib/url.rs @@ -15,6 +15,7 @@ use crate::registry::Registry; use crate::tremor_fn; use percent_encoding::{percent_decode_str, utf8_percent_encode, NON_ALPHANUMERIC}; +use url::Url; pub fn load(registry: &mut Registry) { registry @@ -29,6 +30,69 @@ pub fn load(registry: &mut Registry) { .insert(tremor_fn! (url|encode(ctx, s: String) { Ok(Value::from(utf8_percent_encode(s, NON_ALPHANUMERIC).to_string())) })); + .insert(tremor_fn!(url|construct(ctx, scheme: String, host: String, path: String, query: String, fragment: String) { + let url = Url::build(|b| { + b.scheme(scheme) + .host(host) + .path(path) + .query(query) + .fragment(fragment) + }); + match url { + Ok(url) => Ok(Value::from(url.as_str().to_owned())), + Err(e) => Err(to_runtime_error(format!("Error building URL: {}", e))), + } + })) + .insert(tremor_fn!(url|set_scheme(ctx, url: String, scheme: String) { + let parsed_url = Url::parse(&url); + match parsed_url { + Ok(mut parsed_url) => { + parsed_url.set_scheme(scheme).unwrap(); + Ok(Value::from(parsed_url.as_str().to_owned())) + } + Err(e) => Err(to_runtime_error(format!("Error parsing URL: {}", e))), + } + })) + .insert(tremor_fn!(url|set_host(ctx, url: String, host: String) { + let parsed_url = Url::parse(&url); + match parsed_url { + Ok(mut parsed_url) => { + parsed_url.set_host(Some(host)).unwrap(); + Ok(Value::from(parsed_url.as_str().to_owned())) + } + Err(e) => Err(to_runtime_error(format!("Error parsing URL: {}", e))), + } + })) + .insert(tremor_fn!(url|set_path(ctx, url: String, path: String) { + let parsed_url = Url::parse(&url); + match parsed_url { + Ok(mut parsed_url) => { + parsed_url.set_path(path); + Ok(Value::from(parsed_url.as_str().to_owned())) + } + Err(e) => Err(to_runtime_error(format!("Error parsing URL: {}", e))), + } + })) + .insert(tremor_fn!(url|set_query(ctx, url: String, query: String) { + let parsed_url = Url::parse(&url); + match parsed_url { + Ok(mut parsed_url) => { + parsed_url.set_query(Some(query)); + Ok(Value::from(parsed_url.as_str().to_owned())) + } + Err(e) => Err(to_runtime_error(format!("Error parsing URL: {}", e))), + } + })) + .insert(tremor_fn! (url|set_fragment(url: String, fragment: String) { + let parsed_url = Url::parse(&url); + match parsed_url { + Ok(mut parsed_url) => { + parsed_url.set_fragment(Some(&fragment)); + Ok(Value::from(parsed_url.into_string())) + } + Err(e) => Err(to_runtime_error(format!("Error parsing URL: {}", e))) + } + })) } #[cfg(test)] @@ -53,4 +117,41 @@ mod test { let v = Value::from("%22snot%20badger%22"); assert_val!(d(&[&v]), r#""snot badger""#); } -} + + #[test] + fn url_construct_smoke_test() { + let c = fun("url", "construct"); + assert_val!(c(&[Value::from("http"), Value::from("example.com"), Value::from("/path"), Value::from("query"), Value::from("fragment")]), "http://example.com/path?query#fragment"); + } + + #[test] + fn url_set_scheme_smoke_test() { + let c = fun("url", "set_scheme"); + assert_val!(c(&[Value::from("http://example.com"), Value::from("https")]), "https://example.com"); + } + + #[test] + fn url_set_host_smoke_test() { + let c = fun("url", "set_host"); + assert_val!(c(&[Value::from("http://example.com"), Value::from("newexample.com")]), "http://newexample.com"); + } + + #[test] + fn url_set_path_smoke_test() { + let c = fun("url", "set_path"); + assert_val!(c(&[Value::from("http://example.com"), Value::from("/newpath")]), "http://example.com/newpath"); + } + + #[test] + fn url_set_query_smoke_test() { + let c = fun("url", "set_query"); + assert_val!(c(&[Value::from("http://example.com"), Value::from("newquery")]), "http://example.com?newquery"); + } + + #[test] + fn url_set_fragment_smoke_test() { + let c = fun("url", "set_fragment"); + assert_val!(c(&[Value::from("http://example.com"), Value::from("newfragment")]), "http://example.com#newfragment"); + } + +} \ No newline at end of file