fkl-parser 0.4.0

Feakin is a architecture design and visual collaboration tool. This is the parser for Feakin.
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum Datasource {
  MySql(MySqlDatasource),
  Postgres(PostgresDatasource),
}

impl Datasource {
  pub fn from(url: &str) -> Result<Datasource, String> {
    let url = url::Url::parse(url).map_err(|e| e.to_string())?;
    let scheme = url.scheme();
    let host = url.host_str().ok_or("host is required")?.to_string();
    let port = url.port().ok_or("port is required")?;
    let username = url.username().to_string();
    let password = url.password().unwrap_or("").to_string();
    let database = url.path().trim_start_matches('/').to_string();

    match scheme {
      "mysql" => Ok(Datasource::MySql(MySqlDatasource {
        host,
        port,
        username,
        password,
        database,
      })),
      "postgresql" => Ok(Datasource::Postgres(PostgresDatasource {
        host,
        port,
        username,
        password,
        database,
      })),
      _ => Err(format!("unsupported scheme: {}", scheme)),
    }
  }

  #[allow(dead_code)]
  fn url(&self) -> String {
    match self {
      Datasource::MySql(config) => MySqlDatasource::url(config),
      Datasource::Postgres(config) => format!(
        "postgresql://{}:{}@{}:{}/{}",
        config.username, config.password, config.host, config.port, config.database
      ),
    }
  }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct MySqlDatasource {
  pub host: String,
  pub port: u16,
  pub username: String,
  pub password: String,
  pub database: String,
}

impl MySqlDatasource {
  pub fn url(&self) -> String {
    format!(
      "mysql://{}:{}@{}:{}/{}",
      self.username, self.password, self.host, self.port, self.database
    )
  }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PostgresDatasource {
  pub host: String,
  pub port: u16,
  pub username: String,
  pub password: String,
  pub database: String,
}

impl PostgresDatasource {
  pub fn url(&self) -> String {
    format!(
      "postgresql://{}:{}@{}:{}/{}",
      self.username, self.password, self.host, self.port, self.database
    )
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_parse_database_url() {
    let url = "mysql://username:password@localhost:3306/database";
    let datasource = Datasource::from(url).unwrap();
    assert_eq!(
      datasource,
      Datasource::MySql(MySqlDatasource {
        host: "localhost".to_string(),
        port: 3306,
        username: "username".to_string(),
        password: "password".to_string(),
        database: "database".to_string(),
      })
    );
  }

  #[test]
  fn test_parse_normal_postgres() {
    let url = "postgresql://localhost:5432/yourdb";
    let datasource = Datasource::from(url).unwrap();

    assert_eq!(
      datasource,
      Datasource::Postgres(PostgresDatasource {
        host: "localhost".to_string(),
        port: 5432,
        username: "".to_string(),
        password: "".to_string(),
        database: "yourdb".to_string(),
      })
    );
  }

  #[test]
  fn test_mysql_url_gen() {
    let datasource = Datasource::MySql(MySqlDatasource {
      host: "localhost".to_string(),
      port: 3306,
      username: "username".to_string(),
      password: "password".to_string(),
      database: "database".to_string(),
    });
    assert_eq!(datasource.url(),
      "mysql://username:password@localhost:3306/database"
    );
  }
}