Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8e9a190
mysql-support start with docker configuration to up container and loa…
0nSystem Jul 22, 2023
adb63dc
mysql-support - first implementation workspace canyon_connection
0nSystem Jul 22, 2023
f99f3b3
mysql - change module bounds pending DateTime<OffSet> look problem an…
0nSystem Jul 23, 2023
e067220
mysql-support canyon macros, pending trait implement FromValue in &st…
0nSystem Jul 30, 2023
e53d7c6
mysql-support count table implemented
0nSystem Aug 7, 2023
bf21ca7
mysql-support - pending implement select test
0nSystem Aug 11, 2023
904e554
mysql-support craete reorder array params to use with mysql params
Aug 12, 2023
f3376fc
mysql-support resolve quotes in queries and innecesary loop in reorde…
Aug 21, 2023
b1da9bb
mysql-support select, update , and query_builder
Aug 21, 2023
b3164c6
mysql-support correction test insert and delete mysql implementation …
0nSystem Aug 31, 2023
39bfa88
develop remove imports not use
0nSystem Aug 31, 2023
9ce698c
mysql-support added integration to returning primary key
0nSystem Sep 2, 2023
9d46976
mysql-support correction cfg features
0nSystem Sep 19, 2023
7245b75
mysql-support remove comment to mysql implementation in canyon_databa…
0nSystem Sep 19, 2023
8b3ecd6
mysql-support canyon_macro.rs added in feature migrations
0nSystem Sep 19, 2023
335fe0d
mysql-support replace error with feature in canyon_macro and separate…
0nSystem Sep 20, 2023
2e9edb2
changes: remove CanyonRowsMysql and implement mysql_async, repair ini…
0nSystem Oct 10, 2023
1715b18
changes: corrections other test
0nSystem Oct 10, 2023
0871b40
changes: insert and multiinsert match_rows
0nSystem Oct 11, 2023
625672a
changes: lib cargo_macros RowMapper
0nSystem Oct 12, 2023
195bd77
changes: select macro remove else if to generate tokenstream with act…
0nSystem Oct 12, 2023
7647373
changes: resolve clippy error format! in expect to create Regex
0nSystem Oct 14, 2023
8631628
changes: resolve clippy error format! in expect to create Regex
0nSystem Oct 14, 2023
144e9df
changes: implement Operator by datasource type
0nSystem Oct 19, 2023
9e4c91d
changes: added default datasources
0nSystem Oct 20, 2023
c51a00e
changes: correction error feature specify in datasources.rs enum Auth
0nSystem Dec 2, 2023
5c09a3f
changes: correction cargo fmt
0nSystem Dec 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ Cargo.lock
canyon_tester/
macro_utils.rs
.vscode/
postgres-data/
postgres-data/
mysql-data/
11 changes: 9 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ members = [
"canyon_entities",
"canyon_migrations",
"canyon_macros",

"tests"
]

Expand All @@ -31,6 +30,9 @@ canyon_macros = { workspace = true, path = "canyon_macros" }
# To be marked as opt deps
tokio-postgres = { workspace = true, optional = true }
tiberius = { workspace = true, optional = true }
mysql_async = { workspace = true, optional = true }
mysql_common = { workspace = true, optional = true }


[workspace.dependencies]
canyon_crud = { version = "0.4.2", path = "canyon_crud" }
Expand All @@ -43,6 +45,8 @@ tokio = { version = "1.27.0", features = ["full"] }
tokio-util = { version = "0.7.4", features = ["compat"] }
tokio-postgres = { version = "0.7.2", features = ["with-chrono-0_4"] }
tiberius = { version = "0.12.1", features = ["tds73", "chrono", "integrated-auth-gssapi"] }
mysql_async = { version = "0.32.2" }
mysql_common = { version = "0.30.6", features = [ "chrono" ]}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure that we need the two dependencies? Why do we need mysql_common? I guess that you've said because the format of the rows returned by the library, but we need to review if there's an approach that only need to rely on having the async crate


chrono = { version = "0.4", features = ["serde"] } # Just from TP better?
serde = { version = "1.0.138", features = ["derive"] }
Expand All @@ -54,12 +58,14 @@ lazy_static = "1.4.0"
toml = "0.7.3"
async-trait = "0.1.68"
walkdir = "2.3.3"
regex = "1.5"
regex = "1.9.3"
partialdebug = "0.2.0"

quote = "1.0.9"
proc-macro2 = "1.0.27"



[workspace.package]
version = "0.4.2"
edition = "2021"
Expand All @@ -73,4 +79,5 @@ description = "A Rust ORM and QueryBuilder"
[features]
postgres = ["tokio-postgres", "canyon_connection/postgres", "canyon_crud/postgres", "canyon_migrations/postgres", "canyon_macros/postgres"]
mssql = ["tiberius", "canyon_connection/mssql", "canyon_crud/mssql", "canyon_migrations/mssql", "canyon_macros/mssql"]
mysql = ["mysql_async", "mysql_common", "canyon_connection/mysql", "canyon_crud/mysql", "canyon_migrations/mysql", "canyon_macros/mysql"]
migrations = ["canyon_migrations", "canyon_macros/migrations"]
Empty file modified bash_aliases.sh
100644 → 100755
Empty file.
6 changes: 6 additions & 0 deletions canyon_connection/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ tokio-util = { workspace = true }

tokio-postgres = { workspace = true, optional = true }
tiberius = { workspace = true, optional = true }
mysql_async = { workspace = true, optional = true }
mysql_common = { workspace = true, optional = true }


futures = { workspace = true }
indexmap = { workspace = true }
Expand All @@ -28,3 +31,6 @@ walkdir = { workspace = true }
[features]
postgres = ["tokio-postgres"]
mssql = ["tiberius", "async-std"]
mysql = ["mysql_async","mysql_common"]


107 changes: 102 additions & 5 deletions canyon_connection/src/canyon_database_connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ use serde::Deserialize;

#[cfg(feature = "mssql")]
use async_std::net::TcpStream;
#[cfg(feature = "mysql")]
use mysql_async::Pool;
#[cfg(feature = "mssql")]
use tiberius::{AuthMethod, Config};
#[cfg(feature = "postgres")]
use tokio_postgres::{Client, NoTls};

use crate::datasources::DatasourceConfig;
use crate::datasources::{Auth, DatasourceConfig};

/// Represents the current supported databases by Canyon
#[derive(Deserialize, Debug, Eq, PartialEq, Clone, Copy)]
Expand All @@ -18,6 +20,19 @@ pub enum DatabaseType {
#[serde(alias = "sqlserver", alias = "mssql")]
#[cfg(feature = "mssql")]
SqlServer,
#[serde(alias = "mysql")]
#[cfg(feature = "mysql")]
MySQL,
}

impl From<&Auth> for DatabaseType {
fn from(value: &Auth) -> Self {
match value {
crate::datasources::Auth::Postgres(_) => DatabaseType::PostgreSql,
crate::datasources::Auth::SqlServer(_) => DatabaseType::SqlServer,
crate::datasources::Auth::MySQL(_) => DatabaseType::MySQL,
}
}
}

/// A connection with a `PostgreSQL` database
Expand All @@ -33,6 +48,12 @@ pub struct SqlServerConnection {
pub client: &'static mut tiberius::Client<TcpStream>,
}

/// A connection with a `Mysql` database
#[cfg(feature = "mysql")]
pub struct MysqlConnection {
pub client: Pool,
}

/// The Canyon database connection handler. When the client's program
/// starts, Canyon gets the information about the desired datasources,
/// process them and generates a pool of 1 to 1 database connection for
Expand All @@ -42,6 +63,8 @@ pub enum DatabaseConnection {
Postgres(PostgreSqlConnection),
#[cfg(feature = "mssql")]
SqlServer(SqlServerConnection),
#[cfg(feature = "mysql")]
MySQL(MysqlConnection),
}

unsafe impl Send for DatabaseConnection {}
Expand All @@ -64,6 +87,10 @@ impl DatabaseConnection {
crate::datasources::Auth::SqlServer(_) => {
panic!("Found SqlServer auth configuration for a PostgreSQL datasource")
}
#[cfg(feature = "mysql")]
crate::datasources::Auth::MySQL(_) => {
panic!("Found MySql auth configuration for a PostgreSQL datasource")
}
};
let (new_client, new_connection) = tokio_postgres::connect(
&format!(
Expand Down Expand Up @@ -109,6 +136,10 @@ impl DatabaseConnection {
}
crate::datasources::SqlServerAuth::Integrated => AuthMethod::Integrated,
},
#[cfg(feature = "mysql")]
crate::datasources::Auth::MySQL(_) => {
panic!("Found PostgreSQL auth configuration for a SqlServer database")
}
});

// on production, it is not a good idea to do this. We should upgrade
Expand Down Expand Up @@ -136,14 +167,49 @@ impl DatabaseConnection {
)),
}))
}
#[cfg(feature = "mysql")]
DatabaseType::MySQL => {
let (user, password) = match &datasource.auth {
#[cfg(feature = "mssql")]
crate::datasources::Auth::SqlServer(_) => {
panic!("Found SqlServer auth configuration for a PostgreSQL datasource")
}
#[cfg(feature = "postgres")]
crate::datasources::Auth::Postgres(_) => {
panic!("Found MySql auth configuration for a PostgreSQL datasource")
}
#[cfg(feature = "mysql")]
crate::datasources::Auth::MySQL(mysql_auth) => match mysql_auth {
crate::datasources::MySQLAuth::Basic { username, password } => {
(username, password)
}
},
};

//TODO add options to optionals params in url
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options to optionals?


let url = format!(
"mysql://{}:{}@{}:{}/{}",
user,
password,
datasource.properties.host,
datasource.properties.port.unwrap_or_default(),
datasource.properties.db_name
);
let mysql_connection = Pool::from_url(url)?;

Ok(DatabaseConnection::MySQL(MysqlConnection {
client: { mysql_connection },
}))
}
}
}

#[cfg(feature = "postgres")]
pub fn postgres_connection(&self) -> &PostgreSqlConnection {
match self {
DatabaseConnection::Postgres(conn) => conn,
#[cfg(all(feature = "postgres", feature = "mssql"))]
#[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))]
_ => panic!(),
}
}
Expand All @@ -152,7 +218,16 @@ impl DatabaseConnection {
pub fn sqlserver_connection(&mut self) -> &mut SqlServerConnection {
match self {
DatabaseConnection::SqlServer(conn) => conn,
#[cfg(all(feature = "postgres", feature = "mssql"))]
#[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))]
_ => panic!(),
}
}

#[cfg(feature = "mysql")]
pub fn mysql_connection(&self) -> &MysqlConnection {
match self {
DatabaseConnection::MySQL(conn) => conn,
#[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))]
_ => panic!(),
}
}
Expand All @@ -166,13 +241,14 @@ mod database_connection_handler {
/// Tests the behaviour of the `DatabaseType::from_datasource(...)`
#[test]
fn check_from_datasource() {
#[cfg(all(feature = "postgres", feature = "mssql"))]
#[cfg(all(feature = "postgres", feature = "mssql", feature = "mysql"))]
{
const CONFIG_FILE_MOCK_ALT_ALL: &str = r#"
[canyon_sql]
datasources = [
{name = 'PostgresDS', auth = { postgresql = { basic = { username = "postgres", password = "postgres" } } }, properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled' },
{name = 'SqlServerDS', auth = { sqlserver = { basic = { username = "sa", password = "SqlServer-10" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }
{name = 'SqlServerDS', auth = { sqlserver = { basic = { username = "sa", password = "SqlServer-10" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' },
{name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }
]
"#;
let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_ALL)
Expand All @@ -185,6 +261,10 @@ mod database_connection_handler {
config.canyon_sql.datasources[1].get_db_type(),
DatabaseType::SqlServer
);
assert_eq!(
config.canyon_sql.datasources[2].get_db_type(),
DatabaseType::MySQL
);
}

#[cfg(feature = "postgres")]
Expand Down Expand Up @@ -218,5 +298,22 @@ mod database_connection_handler {
DatabaseType::SqlServer
);
}

#[cfg(feature = "mysql")]
{
const CONFIG_FILE_MOCK_ALT_MYSQL: &str = r#"
[canyon_sql]
datasources = [
{name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }
]
"#;

let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_MYSQL)
.expect("A failure happened retrieving the [canyon_sql] section");
assert_eq!(
config.canyon_sql.datasources[0].get_db_type(),
DatabaseType::MySQL
);
}
}
}
43 changes: 41 additions & 2 deletions canyon_connection/src/datasources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn load_ds_config_from_array() {
[canyon_sql]
datasources = [
{name = 'PostgresDS', auth = { postgresql = { basic = { username = "postgres", password = "postgres" } } }, properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled' },
]
]
"#;
let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_PG)
.expect("A failure happened retrieving the [canyon_sql] section");
Expand Down Expand Up @@ -64,6 +64,33 @@ fn load_ds_config_from_array() {

assert_eq!(ds_2.auth, Auth::SqlServer(SqlServerAuth::Integrated));
}
#[cfg(feature = "mysql")]
{
const CONFIG_FILE_MOCK_ALT_MYSQL: &str = r#"
[canyon_sql]
datasources = [
{name = 'MysqlDS', auth = { mysql = { basic = { username = "root", password = "root" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }
]
"#;
let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT_MYSQL)
.expect("A failure happened retrieving the [canyon_sql] section");

let ds_1 = &config.canyon_sql.datasources[0];

assert_eq!(ds_1.name, "MysqlDS");
assert_eq!(ds_1.get_db_type(), DatabaseType::MySQL);
assert_eq!(
ds_1.auth,
Auth::MySQL(MySQLAuth::Basic {
username: "root".to_string(),
password: "root".to_string()
})
);
assert_eq!(ds_1.properties.host, "192.168.0.250.1");
assert_eq!(ds_1.properties.port, Some(3340));
assert_eq!(ds_1.properties.db_name, "triforce2");
assert_eq!(ds_1.properties.migrations, Some(Migrations::Disabled));
}
}
///
#[derive(Deserialize, Debug, Clone)]
Expand All @@ -90,18 +117,23 @@ impl DatasourceConfig {
Auth::Postgres(_) => DatabaseType::PostgreSql,
#[cfg(feature = "mssql")]
Auth::SqlServer(_) => DatabaseType::SqlServer,
#[cfg(feature = "mysql")]
Auth::MySQL(_) => DatabaseType::MySQL,
}
}
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
pub enum Auth {
#[serde(alias = "PostgreSQL", alias = "postgresql", alias = "postgres")]
#[serde(alias = "PostgresSQL", alias = "postgresql", alias = "postgres")]
#[cfg(feature = "postgres")]
Postgres(PostgresAuth),
#[serde(alias = "SqlServer", alias = "sqlserver", alias = "mssql")]
#[cfg(feature = "mssql")]
SqlServer(SqlServerAuth),
#[serde(alias = "MYSQL", alias = "mysql", alias = "MySQL")]
#[cfg(feature = "mysql")]
MySQL(MySQLAuth),
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
Expand All @@ -120,6 +152,13 @@ pub enum SqlServerAuth {
Integrated,
}

#[derive(Deserialize, Debug, Clone, PartialEq)]
#[cfg(feature = "mysql")]
pub enum MySQLAuth {
#[serde(alias = "Basic", alias = "basic")]
Basic { username: String, password: String },
}

#[derive(Deserialize, Debug, Clone)]
pub struct DatasourceProperties {
pub host: String,
Expand Down
18 changes: 18 additions & 0 deletions canyon_connection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pub extern crate async_std;
pub extern crate futures;
pub extern crate lazy_static;
#[cfg(feature = "mysql")]
pub extern crate mysql_async;
#[cfg(feature = "mssql")]
pub extern crate tiberius;
pub extern crate tokio;
Expand Down Expand Up @@ -104,3 +106,19 @@ pub fn get_database_connection<'a>(
)
}
}

pub fn get_database_config<'a>(
datasource_name: &str,
datasources_config: &'a [DatasourceConfig],
) -> &'a DatasourceConfig {
if datasource_name.is_empty() {
datasources_config
.get(0)
.unwrap_or_else(|| panic!("Not exist datasource"))
} else {
datasources_config
.iter()
.find(|dc| dc.name == datasource_name)
.unwrap_or_else(|| panic!("Not found datasource expected {datasource_name}"))
}
}
Loading