[
  {
    "path": ".cargo/config",
    "content": "[alias]\r\nt = \"test -- --nocapture\"\r\n"
  },
  {
    "path": ".gitignore",
    "content": "/target\r\n.idea"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\r\nname = \"firebase-rs\"\r\nedition = \"2021\"\r\nversion = \"2.2.5\"\r\ndescription = \"Rust based Firebase library\"\r\nreadme = \"README.md\"\r\nrepository = \"https://github.com/emreyalvac/firebase-rs\"\r\ndocumentation = \"https://docs.rs/firebase-rs/2.2.5/firebase_rs/\"\r\nlicense = \"MIT\"\r\nauthors = [\"Emre YALVAÇ <emre.yalvac@outlook.com>\"]\r\nexclude = [\"examples/*\", \"tests/*\"]\r\nkeywords = [\"firebase\", \"rest\", \"api\", \"web\", \"database\"]\r\n\r\n[dependencies]\r\nurl = \"2.2.3\"\r\nreqwest = { version = \"0.12.12\", features = [\"json\"] }\r\nserde_json = \"1.0.137\"\r\nserde = { version = \"1.0.217\", features = [\"derive\"] }\r\nitertools = \"0.14.0\"\r\neventsource-client = \"0.13.0\"\r\nfutures-util = \"0.3.31\"\r\n\r\n[dev-dependencies]\r\ntokio = { version = \"1.43.0\", features = [\"rt\", \"macros\", \"rt-multi-thread\"] }"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\r\n\r\nCopyright (c) 2020 Emre YALVAÇ\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in all\r\ncopies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r\nSOFTWARE.\r\n"
  },
  {
    "path": "README.md",
    "content": "# firebase-rs\n\n[![Crates.io](https://img.shields.io/crates/v/firebase-rs.svg)](https://crates.io/crates/firebase-rs) [![docs.rs](https://docs.rs/firebase-rs/badge.svg)](https://docs.rs/firebase-rs) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n\nRust based Firebase library.\n---\n![firebase](https://firebase.google.com/downloads/brand-guidelines/SVG/logo-logomark.svg 'Firebase')\n\n# Full Documentation\n\n[Documentation](https://docs.rs/firebase-rs/2.2.5/firebase_rs/)\n\n# Features\n\n- Server-Sent Events (a.k.a stream) (https://github.com/emreyalvac/firebase-rs#read-data-as-stream)\n- Generic Payload\n\n# How to use\n\n### Load library\n\n````rust\nuse firebase_rs::*;\n````\n\n### Without Auth\n\n````rust\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap();\n````\n\n### With Auth\n\n````rust\nlet firebase = Firebase::auth(\"https://myfirebase.firebaseio.com\", \"AUTH_KEY\").unwrap();\n````\n\n---\n\n### At usage for nested objects\n\n````rust\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\").at(...);\n````\n\n---\n\n### Read Data as Stream\n\n### With Real Time Events\n\n````rust\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").at(\"users\").unwrap();\nlet stream = firebase.with_realtime_events().unwrap();\nstream\n.listen( | event_type, data| {\nprintln ! (\"Type: {:?} Data: {:?}\", event_type, data);\n}, | err| println!(\"{:?}\", err), false).await;\n````\n\n### Read Data\n\n#### Read data as string\n\n````rust\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\nlet users = firebase.get_as_string().await;\n````\n\n#### Read data with generic type (All)\n\n````rust\n#[derive(Serialize, Deserialize, Debug)]\nstruct User {\n    name: String\n}\n\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\nlet user = firebase.get::<HashMap<String, User>> ().await;\n````\n\n#### Read data with generic type (Single record)\n\n````rust\n#[derive(Serialize, Deserialize, Debug)]\nstruct User {\n    name: String\n}\n\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\");\nlet user = firebase.get::<User>().await;\n````\n\n---\n\n### Set Data with Custom Key\n\n````rust\n#[derive(Serialize, Deserialize, Debug)]\nstruct User {\n    name: String\n}\n\nlet user = User { name: String::default () };\nlet mut firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\nfirebase.set_with_key(\"myKey\", &user).await;\n````\n_Output_\n```json\n{\n  \"users\": {\n    \"myKey\": {\n      \"name\": \"\"\n    }\n  }\n}\n```\n\n### Set Data\n\n````rust\n#[derive(Serialize, Deserialize, Debug)]\nstruct User {\n    name: String\n}\n\nlet user = User { name: String::default () };\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\nfirebase.set(&user).await;\n````\n_Output_\n```json\n{\n  \"users\": {\n    \"-OC9mYIUIdY3JygkmsFQ\": {\n      \"name\": \"\"\n    }\n  }\n}\n```\n\n---\n\n### Update Data\n\n````rust\n#[derive(Serialize, Deserialize, Debug)]\nstruct User {\n    name: String\n}\n\nlet user = User { name: String::default () };\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\");\nfirebase.update( &user).await;\n````\n\n---\n\n### With Params\n\n````rust\nlet firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().with_params().start_at(1).order_by(\"name\").equal_to(5).finish();\nlet result = firebase.get().await;\n````\n\n## Contributors\n\nThanks goes to these wonderful people ✨\n\n<a href=\"https://github.com/emreyalvac/firebase-rs/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=emreyalvac/firebase-rs\" />\n</a>\n\n"
  },
  {
    "path": "src/constants.rs",
    "content": "pub const AUTH: &str = \"auth\";\npub const ORDER_BY: &str = \"orderBy\";\npub const LIMIT_TO_FIRST: &str = \"limitToFirst\";\npub const LIMIT_TO_LAST: &str = \"limitToLast\";\npub const START_AT: &str = \"startAt\";\npub const END_AT: &str = \"endAt\";\npub const EQUAL_TO: &str = \"equalTo\";\npub const SHALLOW: &str = \"shallow\";\npub const FORMAT: &str = \"format\";\npub const EXPORT: &str = \"export\";\n\n#[derive(Debug, PartialEq)]\npub enum Method {\n    GET,\n    POST,\n    DELETE,\n    PATCH,\n    PUT,\n}\n\n#[derive(Debug)]\npub struct Response {\n    pub data: String,\n}\n\nimpl Response {\n    pub fn new() -> Self {\n        Self {\n            data: String::default(),\n        }\n    }\n}\n"
  },
  {
    "path": "src/errors.rs",
    "content": "use std::{\n    error::Error,\n    fmt::{Display, Formatter},\n};\n\npub type UrlParseResult<T> = Result<T, UrlParseError>;\n\n#[derive(Debug)]\n#[non_exhaustive]\npub enum UrlParseError {\n    NoPath,\n    NotHttps,\n    Parser(url::ParseError),\n}\n\nimpl Error for UrlParseError {}\n\nimpl Display for UrlParseError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            UrlParseError::NoPath => write!(f, \"URL path is missing.\"),\n            UrlParseError::NotHttps => write!(f, \"The URL protocol should be https.\"),\n            UrlParseError::Parser(e) => write!(f, \"Error while parsing the URL: {}\", e),\n        }\n    }\n}\n\npub type RequestResult<T> = Result<T, RequestError>;\n\n#[derive(Debug)]\n#[non_exhaustive]\npub enum RequestError {\n    NotJSON,\n    NoUTF8,\n    NetworkError,\n    SerializeError(serde_json::Error),\n    DeserializeError(serde_json::Error),\n    NotFoundOrNullBody,\n    Unauthorized,\n}\n\nimpl Error for RequestError {}\n\nimpl Display for RequestError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            RequestError::NotJSON => write!(f, \"Invalid JSON\"),\n            RequestError::NoUTF8 => write!(f, \"Utf8 error\"),\n            RequestError::NetworkError => write!(f, \"Network error\"),\n            RequestError::SerializeError(e) => write!(f, \"Failed to serialize request: {}\", e),\n            RequestError::DeserializeError(e) => write!(f, \"Failed to deserialize response: {}\", e),\n            RequestError::NotFoundOrNullBody => write!(f, \"Body is null or record is not found\"),\n            RequestError::Unauthorized => write!(f, \"Unauthorized\"),\n        }\n    }\n}\n\n#[derive(Debug)]\n#[non_exhaustive]\npub enum ServerEventError {\n    ConnectionError,\n}\n\nimpl Error for ServerEventError {}\n\nimpl Display for ServerEventError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            ServerEventError::ConnectionError => write!(f, \"Connection error for server events\"),\n        }\n    }\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "use constants::{Method, Response, AUTH};\nuse errors::{RequestResult, UrlParseResult};\nuse params::Params;\nuse reqwest::StatusCode;\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\nuse serde_json::Value;\nuse std::fmt::Debug;\nuse url::Url;\nuse utils::check_uri;\n\nuse crate::sse::ServerEvents;\n\npub use errors::{RequestError, ServerEventError, UrlParseError};\n\nmod constants;\nmod errors;\nmod params;\nmod sse;\nmod utils;\n\n#[derive(Debug)]\npub struct Firebase {\n    uri: Url,\n}\n\nimpl Firebase {\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    ///\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap();\n    /// ```\n    pub fn new(uri: &str) -> UrlParseResult<Self>\n    where\n        Self: Sized,\n    {\n        match check_uri(&uri) {\n            Ok(uri) => Ok(Self { uri }),\n            Err(err) => Err(err),\n        }\n    }\n\n    /// ```rust\n    /// const URI: &str = \"...\";\n    /// const AUTH_KEY: &str = \"...\";\n    ///\n    /// use firebase_rs::Firebase;\n    ///\n    /// let firebase = Firebase::auth(\"https://myfirebase.firebaseio.com\", AUTH_KEY).unwrap();\n    /// ```\n    pub fn auth(uri: &str, auth_key: &str) -> UrlParseResult<Self>\n    where\n        Self: Sized,\n    {\n        match check_uri(&uri) {\n            Ok(mut uri) => {\n                uri.set_query(Some(&format!(\"{}={}\", AUTH, auth_key)));\n                Ok(Self { uri })\n            }\n            Err(err) => Err(err),\n        }\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    ///\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().with_params().start_at(1).order_by(\"name\").equal_to(5).finish();\n    /// let result = firebase.get::<String>().await;\n    /// # }\n    /// ```\n    pub fn with_params(&self) -> Params {\n        let uri = self.uri.clone();\n        Params::new(uri)\n    }\n\n    /// To use simple interface with synchronous callbacks, pair with `.listen()`:\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let stream = firebase.with_realtime_events().unwrap();\n    /// stream.listen(|event_type, data| {\n    ///                     println!(\"{:?} {:?}\" ,event_type, data);\n    ///                 }, |err| println!(\"{:?}\" ,err), false).await;\n    /// # }\n    /// ```\n    ///\n    /// To use streaming interface for async code, pair with `.stream()`:\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    /// use futures_util::StreamExt;\n    ///\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let stream = firebase.with_realtime_events()\n    ///              .unwrap()\n    ///              .stream(true);\n    /// stream.for_each(|event| {\n    ///           match event {\n    ///               Ok((event_type, maybe_data)) => println!(\"{:?} {:?}\" ,event_type, maybe_data),\n    ///               Err(err) => println!(\"{:?}\" ,err),\n    ///           }\n    ///           futures_util::future::ready(())\n    ///        }).await;\n    /// # }\n    /// ```\n    pub fn with_realtime_events(&self) -> Option<ServerEvents> {\n        ServerEvents::new(self.uri.as_str())\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    ///\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\").at(\"f69111a8a5258c15286d3d0bd4688c55\");\n    /// ```\n    pub fn at(&self, path: &str) -> Self {\n        let uri = self.build_uri(path);\n\n        Firebase { uri }\n    }\n\n    fn build_uri(&self, path: &str) -> Url {\n        let mut new_path = String::new();\n\n        if let Some(segments) = self.uri.path_segments() {\n            for segment in segments {\n                let clean_segment = segment.trim_end_matches(\".json\");\n                new_path.push_str(clean_segment);\n                new_path.push('/');\n            }\n        }\n\n        new_path.push_str(path);\n\n        let final_path = if new_path.ends_with(\".json\") {\n            new_path.trim_end_matches(\".json\").to_string()\n        } else {\n            new_path\n        };\n\n        let mut uri = self.uri.clone();\n        uri.set_path(&format!(\"{}.json\", final_path));\n\n        uri\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    ///\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let uri = firebase.get_uri();\n    /// ```\n    pub fn get_uri(&self) -> String {\n        self.uri.to_string()\n    }\n\n    async fn request(&self, method: Method, data: Option<Value>) -> RequestResult<Response> {\n        let client = reqwest::Client::new();\n        let request = match method {\n            Method::GET => client.get(self.uri.to_string()).send().await,\n            Method::PUT | Method::PATCH | Method::POST => {\n                if data.is_none() {\n                    return Err(RequestError::NotFoundOrNullBody);\n                }\n                let builder = if method == Method::PUT {\n                    client.put(self.uri.to_string())\n                } else if method == Method::POST {\n                    client.post(self.uri.to_string())\n                } else {\n                    client.patch(self.uri.to_string())\n                };\n                builder.json(&data).send().await\n            }\n            Method::DELETE => client.delete(self.uri.to_string()).send().await,\n        };\n\n        match request {\n            Ok(response) => match response.status() {\n                StatusCode::OK | StatusCode::NO_CONTENT => {\n                    let response_text = response.text().await.unwrap_or_default();\n                    Ok(Response {\n                        data: response_text,\n                    })\n                }\n                StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => Err(RequestError::Unauthorized),\n                StatusCode::NOT_FOUND => Err(RequestError::NotFoundOrNullBody),\n                _ => Err(RequestError::NetworkError),\n            },\n            Err(_) => Err(RequestError::NetworkError),\n        }\n    }\n\n    async fn request_generic<T>(&self, method: Method) -> RequestResult<T>\n    where\n        T: DeserializeOwned + Debug,\n    {\n        let request = self.request(method, None).await;\n\n        match request {\n            Ok(response) => {\n                let value: serde_json::Value = serde_json::from_str(response.data.as_str())\n                    .map_err(|_| RequestError::NotJSON)?;\n\n                let data: T = serde_json::from_value(value)\n                    .map_err(RequestError::DeserializeError)?;\n\n                Ok(data)\n            }\n            Err(err) => Err(err),\n        }\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    /// use serde::{Serialize, Deserialize};\n    ///\n    /// #[derive(Serialize, Deserialize, Debug)]\n    /// struct User {\n    ///    name: String\n    /// }\n    ///\n    /// # async fn run() {\n    /// let user = User { name: String::default() };\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let users = firebase.set(&user).await;\n    /// # }\n    /// ```\n    pub async fn set<T>(&self, data: &T) -> RequestResult<Response>\n    where\n        T: Serialize + Debug,\n    {\n        let data = serde_json::to_value(&data).map_err(RequestError::SerializeError)?;\n        self.request(Method::POST, Some(data)).await\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    /// use serde::{Serialize, Deserialize};\n    ///\n    /// #[derive(Serialize, Deserialize, Debug)]\n    /// struct User {\n    ///    name: String\n    /// }\n    ///\n    /// # async fn run() {\n    /// let user = User { name: String::default() };\n    /// let mut firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let users = firebase.set_with_key(\"myKey\", &user).await;\n    /// # }\n    /// ```\n    pub async fn set_with_key<T>(&mut self, key: &str, data: &T) -> RequestResult<Response>\n    where\n        T: Serialize + Debug,\n    {\n        self.uri = self.build_uri(key);\n        let data = serde_json::to_value(&data).map_err(RequestError::SerializeError)?;\n\n        self.request(Method::PUT, Some(data)).await\n    }\n\n    /// ```rust\n    /// use std::collections::HashMap;\n    /// use firebase_rs::Firebase;\n    /// use serde::{Serialize, Deserialize};\n    ///\n    /// #[derive(Serialize, Deserialize, Debug)]\n    /// struct User {\n    ///    name: String\n    /// }\n    ///\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let users = firebase.get::<HashMap<String, User>>().await;\n    /// # }\n    /// ```\n    pub async fn get_as_string(&self) -> RequestResult<Response> {\n        self.request(Method::GET, None).await\n    }\n\n    /// ```rust\n    /// use std::collections::HashMap;\n    /// use firebase_rs::Firebase;\n    /// use serde::{Serialize, Deserialize};\n    ///\n    /// #[derive(Serialize, Deserialize, Debug)]\n    /// struct User {\n    ///     name: String\n    /// }\n    ///\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\");\n    /// let user = firebase.get::<User>().await;\n    ///\n    ///  // OR\n    ///\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\");\n    /// let user = firebase.get::<HashMap<String, User>>().await;\n    /// # }\n    /// ```\n    pub async fn get<T>(&self) -> RequestResult<T>\n    where\n        T: DeserializeOwned + Debug,\n    {\n        self.request_generic::<T>(Method::GET).await\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    ///\n    /// # async fn run() {\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\");\n    /// firebase.delete().await;\n    /// # }\n    /// ```\n    pub async fn delete(&self) -> RequestResult<Response> {\n        self.request(Method::DELETE, None).await\n    }\n\n    /// ```rust\n    /// use firebase_rs::Firebase;\n    /// use serde::{Serialize, Deserialize};\n    ///\n    /// #[derive(Serialize, Deserialize, Debug)]\n    /// struct User {\n    ///     name: String\n    /// }\n    ///\n    /// # async fn run() {\n    /// let user = User { name: String::default() };\n    /// let firebase = Firebase::new(\"https://myfirebase.firebaseio.com\").unwrap().at(\"users\").at(\"USER_ID\");\n    /// let users = firebase.update(&user).await;\n    /// # }\n    /// ```\n    pub async fn update<T>(&self, data: &T) -> RequestResult<Response>\n    where\n        T: Serialize + Debug,\n    {\n        let value = serde_json::to_value(&data).map_err(RequestError::SerializeError)?;\n        self.request(Method::PATCH, Some(value)).await\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::{Firebase, UrlParseError};\n\n    const URI: &str = \"https://firebase_id.firebaseio.com\";\n    const URI_WITH_SLASH: &str = \"https://firebase_id.firebaseio.com/\";\n    const URI_NON_HTTPS: &str = \"http://firebase_id.firebaseio.com/\";\n\n    #[tokio::test]\n    async fn simple() {\n        let firebase = Firebase::new(URI).unwrap();\n        assert_eq!(URI_WITH_SLASH.to_string(), firebase.get_uri());\n    }\n\n    #[tokio::test]\n    async fn non_https() {\n        let firebase = Firebase::new(URI_NON_HTTPS).map_err(|e| e.to_string());\n        assert_eq!(\n            firebase.err(),\n            Some(String::from(UrlParseError::NotHttps.to_string()))\n        );\n    }\n\n    #[tokio::test]\n    async fn with_auth() {\n        let firebase = Firebase::auth(URI, \"auth_key\").unwrap();\n        assert_eq!(\n            format!(\"{}/?auth=auth_key\", URI.to_string()),\n            firebase.get_uri()\n        );\n    }\n\n    #[tokio::test]\n    async fn with_sse_events() {\n        // TODO: SSE Events Test\n    }\n}\n"
  },
  {
    "path": "src/params.rs",
    "content": "use crate::constants::{\n    END_AT, EQUAL_TO, EXPORT, FORMAT, LIMIT_TO_FIRST, LIMIT_TO_LAST, ORDER_BY, SHALLOW, START_AT,\n};\nuse crate::Firebase;\nuse itertools::Itertools;\nuse std::collections::HashMap;\nuse url::Url;\n\n#[derive(Debug)]\npub struct Params {\n    pub uri: Url,\n    pub params: HashMap<String, String>,\n}\n\nimpl Params {\n    pub fn new(uri: Url) -> Self {\n        Self {\n            uri,\n            params: Default::default(),\n        }\n    }\n\n    pub fn set_params(&mut self) -> () {\n        for (k, v) in self.params.iter().sorted() {\n            self.uri.query_pairs_mut().append_pair(k, v);\n        }\n    }\n\n    pub fn add_param<T>(&mut self, key: &str, value: T) -> &mut Self\n    where\n        T: ToString,\n    {\n        self.params.insert(key.to_string(), value.to_string());\n        self.set_params();\n\n        self\n    }\n\n    pub fn order_by(&mut self, key: &str) -> &mut Params {\n        self.add_param(ORDER_BY, key)\n    }\n\n    pub fn limit_to_first(&mut self, count: u32) -> &mut Params {\n        self.add_param(LIMIT_TO_FIRST, count)\n    }\n\n    pub fn limit_to_last(&mut self, count: u32) -> &mut Params {\n        self.add_param(LIMIT_TO_LAST, count)\n    }\n\n    pub fn start_at(&mut self, index: u32) -> &mut Params {\n        self.add_param(START_AT, index)\n    }\n\n    pub fn end_at(&mut self, index: u32) -> &mut Params {\n        self.add_param(END_AT, index)\n    }\n\n    pub fn equal_to(&mut self, value: u32) -> &mut Params {\n        self.add_param(EQUAL_TO, value)\n    }\n\n    pub fn shallow(&mut self, flag: bool) -> &mut Params {\n        self.add_param(SHALLOW, flag)\n    }\n\n    pub fn format(&mut self) -> &mut Params {\n        self.add_param(FORMAT, EXPORT)\n    }\n\n    pub fn finish(&self) -> Firebase {\n        Firebase::new(self.uri.as_str()).unwrap()\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::params::Params;\n    use std::collections::HashMap;\n    use url::Url;\n\n    #[test]\n    fn check_params() {\n        let mut params: HashMap<String, String> = HashMap::new();\n        params.insert(\"param_1\".to_owned(), \"value_1\".to_owned());\n        params.insert(\"param_2\".to_owned(), \"value_2\".to_owned());\n        let mut param = Params {\n            uri: Url::parse(\"https://github.com/emreyalvac\").unwrap(),\n            params,\n        };\n        param.set_params();\n\n        assert_eq!(\n            param.uri.as_str(),\n            \"https://github.com/emreyalvac?param_1=value_1&param_2=value_2\"\n        )\n    }\n}\n"
  },
  {
    "path": "src/sse.rs",
    "content": "use eventsource_client::*;\r\nuse futures_util::StreamExt;\r\n\r\npub struct ServerEvents {\r\n    client: ClientBuilder,\r\n}\r\n\r\nimpl ServerEvents {\r\n    pub fn new(url: &str) -> Option<Self> {\r\n        let client = ClientBuilder::for_url(url);\r\n\r\n        match client {\r\n            Ok(stream_connection) => Some(ServerEvents {\r\n                client: stream_connection,\r\n            }),\r\n            Err(_) => None,\r\n        }\r\n    }\r\n\r\n    pub async fn listen(\r\n        self,\r\n        stream_event: impl Fn(String, Option<String>),\r\n        stream_err: impl Fn(Error),\r\n        keep_alive_friendly: bool,\r\n    ) {\r\n        self.stream(keep_alive_friendly)\r\n            .for_each(|event| {\r\n                match event {\r\n                    Ok((event_type, maybe_data)) => stream_event(event_type, maybe_data),\r\n                    Err(x) => stream_err(x),\r\n                }\r\n                futures_util::future::ready(())\r\n            })\r\n            .await\r\n    }\r\n\r\n    pub fn stream(\r\n        self,\r\n        keep_alive_friendly: bool,\r\n    ) -> std::pin::Pin<Box<dyn futures_util::Stream<Item = Result<(String, Option<String>)>> + Send>>\r\n    {\r\n        Box::pin(\r\n            self.client\r\n                .build()\r\n                .stream()\r\n                .filter_map(move |event| async move {\r\n                    match event {\r\n                        Ok(SSE::Event(ev)) => {\r\n                            if ev.event_type == \"keep-alive\" && !keep_alive_friendly {\r\n                                return None;\r\n                            }\r\n\r\n                            if ev.data == \"null\" {\r\n                                return Some(Ok((ev.event_type, None)));\r\n                            }\r\n\r\n                            return Some(Ok((ev.event_type, Some(ev.data))));\r\n                        }\r\n                        Ok(SSE::Comment(_)) | Ok(SSE::Connected(_)) => return None,\r\n                        Err(x) => Some(Err(x)),\r\n                    }\r\n                }),\r\n        )\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/utils.rs",
    "content": "use crate::errors::UrlParseResult;\nuse crate::UrlParseError;\nuse url::Url;\n\npub fn check_uri(uri: &str) -> UrlParseResult<Url> {\n    let uri = Url::parse(uri);\n\n    let uri = match uri {\n        Ok(res) => res,\n        Err(err) => return Err(UrlParseError::Parser(err)),\n    };\n\n    if uri.scheme() != \"https\" {\n        return Err(UrlParseError::NotHttps);\n    }\n\n    Ok(uri)\n}\n"
  }
]