feat: String parameters accept any Into<String> (#1439)

This commit is contained in:
Billy Chan 2023-04-11 12:51:51 +08:00 committed by GitHub
parent 8f785c120a
commit 6833529441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 87 deletions

View File

@ -138,7 +138,7 @@ impl ConnectionTrait for DatabaseConnection {
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => { DatabaseConnection::MockDatabaseConnection(conn) => {
let db_backend = conn.get_database_backend(); let db_backend = conn.get_database_backend();
let stmt = Statement::from_string(db_backend, sql.into()); let stmt = Statement::from_string(db_backend, sql);
conn.execute(stmt) conn.execute(stmt)
} }
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")), DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),

View File

@ -281,31 +281,27 @@ where
} }
} }
impl IntoMockRow for BTreeMap<String, Value> { impl<T> IntoMockRow for BTreeMap<T, Value>
where
T: Into<String>,
{
fn into_mock_row(self) -> MockRow { fn into_mock_row(self) -> MockRow {
MockRow { MockRow {
values: self.into_iter().map(|(k, v)| (k, v)).collect(), values: self.into_iter().map(|(k, v)| (k.into(), v)).collect(),
}
}
}
impl IntoMockRow for BTreeMap<&str, Value> {
fn into_mock_row(self) -> MockRow {
MockRow {
values: self.into_iter().map(|(k, v)| (k.to_owned(), v)).collect(),
} }
} }
} }
impl Transaction { impl Transaction {
/// Get the [Value]s from s raw SQL statement depending on the [DatabaseBackend](crate::DatabaseBackend) /// Get the [Value]s from s raw SQL statement depending on the [DatabaseBackend](crate::DatabaseBackend)
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
where where
I: IntoIterator<Item = Value>, I: IntoIterator<Item = Value>,
T: Into<String>,
{ {
Self::one(Statement::from_string_values_tuple( Self::one(Statement::from_string_values_tuple(
db_backend, db_backend,
(sql.to_string(), Values(values.into_iter().collect())), (sql, Values(values.into_iter().collect())),
)) ))
} }
@ -336,10 +332,7 @@ impl Transaction {
impl OpenTransaction { impl OpenTransaction {
fn init() -> Self { fn init() -> Self {
Self { Self {
stmts: vec![Statement::from_string( stmts: vec![Statement::from_string(DbBackend::Postgres, "BEGIN")],
DbBackend::Postgres,
"BEGIN".to_owned(),
)],
transaction_depth: 0, transaction_depth: 0,
} }
} }
@ -354,7 +347,7 @@ impl OpenTransaction {
fn commit(&mut self, db_backend: DbBackend) -> bool { fn commit(&mut self, db_backend: DbBackend) -> bool {
if self.transaction_depth == 0 { if self.transaction_depth == 0 {
self.push(Statement::from_string(db_backend, "COMMIT".to_owned())); self.push(Statement::from_string(db_backend, "COMMIT"));
true true
} else { } else {
self.push(Statement::from_string( self.push(Statement::from_string(
@ -368,7 +361,7 @@ impl OpenTransaction {
fn rollback(&mut self, db_backend: DbBackend) -> bool { fn rollback(&mut self, db_backend: DbBackend) -> bool {
if self.transaction_depth == 0 { if self.transaction_depth == 0 {
self.push(Statement::from_string(db_backend, "ROLLBACK".to_owned())); self.push(Statement::from_string(db_backend, "ROLLBACK"));
true true
} else { } else {
self.push(Statement::from_string( self.push(Statement::from_string(
@ -433,7 +426,7 @@ mod tests {
db.into_transaction_log(), db.into_transaction_log(),
[ [
Transaction::many([ Transaction::many([
Statement::from_string(DbBackend::Postgres, "BEGIN".to_owned()), Statement::from_string(DbBackend::Postgres, "BEGIN"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
@ -444,7 +437,7 @@ mod tests {
r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#, r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
[] []
), ),
Statement::from_string(DbBackend::Postgres, "COMMIT".to_owned()), Statement::from_string(DbBackend::Postgres, "COMMIT"),
]), ]),
Transaction::from_sql_and_values( Transaction::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
@ -478,13 +471,13 @@ mod tests {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
[Transaction::many([ [Transaction::many([
Statement::from_string(DbBackend::Postgres, "BEGIN".to_owned()), Statement::from_string(DbBackend::Postgres, "BEGIN"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
[1u64.into()] [1u64.into()]
), ),
Statement::from_string(DbBackend::Postgres, "ROLLBACK".to_owned()), Statement::from_string(DbBackend::Postgres, "ROLLBACK"),
])] ])]
); );
} }
@ -516,23 +509,20 @@ mod tests {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
[Transaction::many([ [Transaction::many([
Statement::from_string(DbBackend::Postgres, "BEGIN".to_owned()), Statement::from_string(DbBackend::Postgres, "BEGIN"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
[1u64.into()] [1u64.into()]
), ),
Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1".to_owned()), Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#, r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
[] []
), ),
Statement::from_string( Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_1"),
DbBackend::Postgres, Statement::from_string(DbBackend::Postgres, "COMMIT"),
"RELEASE SAVEPOINT savepoint_1".to_owned()
),
Statement::from_string(DbBackend::Postgres, "COMMIT".to_owned()),
]),] ]),]
); );
} }
@ -574,33 +564,27 @@ mod tests {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
[Transaction::many([ [Transaction::many([
Statement::from_string(DbBackend::Postgres, "BEGIN".to_owned()), Statement::from_string(DbBackend::Postgres, "BEGIN"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#,
[1u64.into()] [1u64.into()]
), ),
Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1".to_owned()), Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_1"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#, r#"SELECT "fruit"."id", "fruit"."name", "fruit"."cake_id" FROM "fruit""#,
[] []
), ),
Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_2".to_owned()), Statement::from_string(DbBackend::Postgres, "SAVEPOINT savepoint_2"),
Statement::from_sql_and_values( Statement::from_sql_and_values(
DbBackend::Postgres, DbBackend::Postgres,
r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
[] []
), ),
Statement::from_string( Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_2"),
DbBackend::Postgres, Statement::from_string(DbBackend::Postgres, "RELEASE SAVEPOINT savepoint_1"),
"RELEASE SAVEPOINT savepoint_2".to_owned() Statement::from_string(DbBackend::Postgres, "COMMIT"),
),
Statement::from_string(
DbBackend::Postgres,
"RELEASE SAVEPOINT savepoint_1".to_owned()
),
Statement::from_string(DbBackend::Postgres, "COMMIT".to_owned()),
]),] ]),]
); );
} }

View File

@ -86,29 +86,23 @@ impl Database {
} }
} }
impl From<&str> for ConnectOptions { impl<T> From<T> for ConnectOptions
fn from(string: &str) -> ConnectOptions { where
ConnectOptions::from_str(string) T: Into<String>,
} {
} fn from(s: T) -> ConnectOptions {
ConnectOptions::new(s.into())
impl From<&String> for ConnectOptions {
fn from(string: &String) -> ConnectOptions {
ConnectOptions::from_str(string.as_str())
}
}
impl From<String> for ConnectOptions {
fn from(string: String) -> ConnectOptions {
ConnectOptions::new(string)
} }
} }
impl ConnectOptions { impl ConnectOptions {
/// Create new [ConnectOptions] for a [Database] by passing in a URI string /// Create new [ConnectOptions] for a [Database] by passing in a URI string
pub fn new(url: String) -> Self { pub fn new<T>(url: T) -> Self
where
T: Into<String>,
{
Self { Self {
url, url: url.into(),
max_connections: None, max_connections: None,
min_connections: None, min_connections: None,
connect_timeout: None, connect_timeout: None,
@ -122,10 +116,6 @@ impl ConnectOptions {
} }
} }
fn from_str(url: &str) -> Self {
Self::new(url.to_owned())
}
#[cfg(feature = "sqlx-dep")] #[cfg(feature = "sqlx-dep")]
/// Convert [ConnectOptions] into [sqlx::pool::PoolOptions] /// Convert [ConnectOptions] into [sqlx::pool::PoolOptions]
pub fn pool_options<DB>(self) -> sqlx::pool::PoolOptions<DB> pub fn pool_options<DB>(self) -> sqlx::pool::PoolOptions<DB>
@ -258,8 +248,11 @@ impl ConnectOptions {
} }
/// Set schema search path (PostgreSQL only) /// Set schema search path (PostgreSQL only)
pub fn set_schema_search_path(&mut self, schema_search_path: String) -> &mut Self { pub fn set_schema_search_path<T>(&mut self, schema_search_path: T) -> &mut Self
self.schema_search_path = Some(schema_search_path); where
T: Into<String>,
{
self.schema_search_path = Some(schema_search_path.into());
self self
} }
} }

View File

@ -23,9 +23,12 @@ pub trait StatementBuilder {
impl Statement { impl Statement {
/// Create a [Statement] from a [crate::DatabaseBackend] and a raw SQL statement /// Create a [Statement] from a [crate::DatabaseBackend] and a raw SQL statement
pub fn from_string(db_backend: DbBackend, stmt: String) -> Statement { pub fn from_string<T>(db_backend: DbBackend, stmt: T) -> Statement
where
T: Into<String>,
{
Statement { Statement {
sql: stmt, sql: stmt.into(),
values: None, values: None,
db_backend, db_backend,
} }
@ -33,22 +36,20 @@ impl Statement {
/// Create a SQL statement from a [crate::DatabaseBackend], a /// Create a SQL statement from a [crate::DatabaseBackend], a
/// raw SQL statement and param values /// raw SQL statement and param values
pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self pub fn from_sql_and_values<I, T>(db_backend: DbBackend, sql: T, values: I) -> Self
where where
I: IntoIterator<Item = Value>, I: IntoIterator<Item = Value>,
T: Into<String>,
{ {
Self::from_string_values_tuple( Self::from_string_values_tuple(db_backend, (sql, Values(values.into_iter().collect())))
db_backend,
(sql.to_owned(), Values(values.into_iter().collect())),
)
} }
pub(crate) fn from_string_values_tuple( pub(crate) fn from_string_values_tuple<T>(db_backend: DbBackend, stmt: (T, Values)) -> Statement
db_backend: DbBackend, where
stmt: (String, Values), T: Into<String>,
) -> Statement { {
Statement { Statement {
sql: stmt.0, sql: stmt.0.into(),
values: Some(stmt.1), values: Some(stmt.1),
db_backend, db_backend,
} }

View File

@ -364,7 +364,7 @@ impl ConnectionTrait for DatabaseTransaction {
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
InnerConnection::Mock(conn) => { InnerConnection::Mock(conn) => {
let db_backend = conn.get_database_backend(); let db_backend = conn.get_database_backend();
let stmt = Statement::from_string(db_backend, sql.into()); let stmt = Statement::from_string(db_backend, sql);
conn.execute(stmt) conn.execute(stmt)
} }
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]

View File

@ -149,7 +149,10 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'"
/// ); /// );
/// ``` /// ```
fn like(&self, s: &str) -> SimpleExpr { fn like<T>(&self, s: T) -> SimpleExpr
where
T: Into<String>,
{
Expr::col((self.entity_name(), *self)).like(s) Expr::col((self.entity_name(), *self)).like(s)
} }
@ -164,7 +167,10 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'"
/// ); /// );
/// ``` /// ```
fn not_like(&self, s: &str) -> SimpleExpr { fn not_like<T>(&self, s: T) -> SimpleExpr
where
T: Into<String>,
{
Expr::col((self.entity_name(), *self)).not_like(s) Expr::col((self.entity_name(), *self)).not_like(s)
} }
@ -179,8 +185,11 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'"
/// ); /// );
/// ``` /// ```
fn starts_with(&self, s: &str) -> SimpleExpr { fn starts_with<T>(&self, s: T) -> SimpleExpr
let pattern = format!("{s}%"); where
T: Into<String>,
{
let pattern = format!("{}%", s.into());
Expr::col((self.entity_name(), *self)).like(pattern) Expr::col((self.entity_name(), *self)).like(pattern)
} }
@ -195,8 +204,11 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'"
/// ); /// );
/// ``` /// ```
fn ends_with(&self, s: &str) -> SimpleExpr { fn ends_with<T>(&self, s: T) -> SimpleExpr
let pattern = format!("%{s}"); where
T: Into<String>,
{
let pattern = format!("%{}", s.into());
Expr::col((self.entity_name(), *self)).like(pattern) Expr::col((self.entity_name(), *self)).like(pattern)
} }
@ -211,8 +223,11 @@ pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
/// ); /// );
/// ``` /// ```
fn contains(&self, s: &str) -> SimpleExpr { fn contains<T>(&self, s: T) -> SimpleExpr
let pattern = format!("%{s}%"); where
T: Into<String>,
{
let pattern = format!("%{}%", s.into());
Expr::col((self.entity_name(), *self)).like(pattern) Expr::col((self.entity_name(), *self)).like(pattern)
} }

View File

@ -342,7 +342,7 @@ pub async fn create_json_struct_table(db: &DbConn) -> Result<ExecResult, DbErr>
pub async fn create_collection_table(db: &DbConn) -> Result<ExecResult, DbErr> { pub async fn create_collection_table(db: &DbConn) -> Result<ExecResult, DbErr> {
db.execute(sea_orm::Statement::from_string( db.execute(sea_orm::Statement::from_string(
db.get_database_backend(), db.get_database_backend(),
"CREATE EXTENSION IF NOT EXISTS citext".into(), "CREATE EXTENSION IF NOT EXISTS citext",
)) ))
.await?; .await?;