Cleanup panic and unwrap (#1231)
* Add clippy linter checks * Mock * InnerConnection * panic -> Err * panic -> Err * More panic -> Err * Replace unwrap * Fix clippy * add clippy linters * Refactor * Dump DbErr::Mock * Revert if...else rewrite * Remove except * DbErr helper functions * Fix clippy * Negative SQLite last_insert_rowid throw unreachable * Update panics docs * Fixup * Fixup * Fixup * Fixup * Revert adding `ExecResultHolder::Disconnected` * More fixup * Fix * Revert adding `QueryResultRow::Disconnected` * Fix * Refactoring * Fix * Refactoring * More refactoring * More refactoring * Fix * Revert `InnerConnection::Disconnected` * Revert breaking changes * Fix * Fix * Fix * Refactor `.take().expect()` * Revert changing `if ... else` to `match` block * Revert changing return type of `MockDatabaseConnection` transaction method * Borrow sqlcipher_key * Fetching unsupported type from query result will thrown `DbErr::Type(...)` error * Revert adding `DatabaseConnection::try_into_transaction_log()` method * Refactoring * Refactoring
This commit is contained in:
parent
48a9ffec2a
commit
91c4930391
@ -36,6 +36,12 @@ pub enum DatabaseConnection {
|
|||||||
/// The same as a [DatabaseConnection]
|
/// The same as a [DatabaseConnection]
|
||||||
pub type DbConn = DatabaseConnection;
|
pub type DbConn = DatabaseConnection;
|
||||||
|
|
||||||
|
impl Default for DatabaseConnection {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The type of database backend for real world databases.
|
/// The type of database backend for real world databases.
|
||||||
/// This is enabled by feature flags as specified in the crate documentation
|
/// This is enabled by feature flags as specified in the crate documentation
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
@ -50,6 +56,7 @@ pub enum DatabaseBackend {
|
|||||||
|
|
||||||
/// The same as [DatabaseBackend] just shorter :)
|
/// The same as [DatabaseBackend] just shorter :)
|
||||||
pub type DbBackend = DatabaseBackend;
|
pub type DbBackend = DatabaseBackend;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum InnerConnection {
|
pub(crate) enum InnerConnection {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
@ -62,12 +69,6 @@ pub(crate) enum InnerConnection {
|
|||||||
Mock(std::sync::Arc<crate::MockDatabaseConnection>),
|
Mock(std::sync::Arc<crate::MockDatabaseConnection>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for DatabaseConnection {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Disconnected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for DatabaseConnection {
|
impl std::fmt::Debug for DatabaseConnection {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@ -116,9 +117,7 @@ impl ConnectionTrait for DatabaseConnection {
|
|||||||
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.execute(stmt).await,
|
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.execute(stmt).await,
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
DatabaseConnection::MockDatabaseConnection(conn) => conn.execute(stmt),
|
DatabaseConnection::MockDatabaseConnection(conn) => conn.execute(stmt),
|
||||||
DatabaseConnection::Disconnected => {
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,9 +141,7 @@ impl ConnectionTrait for DatabaseConnection {
|
|||||||
let stmt = Statement::from_string(db_backend, sql.into());
|
let stmt = Statement::from_string(db_backend, sql.into());
|
||||||
conn.execute(stmt)
|
conn.execute(stmt)
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => {
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,9 +157,7 @@ impl ConnectionTrait for DatabaseConnection {
|
|||||||
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_one(stmt).await,
|
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_one(stmt).await,
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_one(stmt),
|
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_one(stmt),
|
||||||
DatabaseConnection::Disconnected => {
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,9 +173,7 @@ impl ConnectionTrait for DatabaseConnection {
|
|||||||
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_all(stmt).await,
|
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.query_all(stmt).await,
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_all(stmt),
|
DatabaseConnection::MockDatabaseConnection(conn) => conn.query_all(stmt),
|
||||||
DatabaseConnection::Disconnected => {
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,25 +188,25 @@ impl StreamTrait for DatabaseConnection {
|
|||||||
type Stream<'a> = crate::QueryStream;
|
type Stream<'a> = crate::QueryStream;
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
#[allow(unused_variables, unreachable_code)]
|
#[allow(unused_variables)]
|
||||||
fn stream<'a>(
|
fn stream<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
stmt: Statement,
|
stmt: Statement,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<Self::Stream<'a>, DbErr>> + 'a + Send>> {
|
) -> Pin<Box<dyn Future<Output = Result<Self::Stream<'a>, DbErr>> + 'a + Send>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
Ok(match self {
|
match self {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
DatabaseConnection::SqlxMySqlPoolConnection(conn) => conn.stream(stmt).await?,
|
DatabaseConnection::SqlxMySqlPoolConnection(conn) => conn.stream(stmt).await,
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
DatabaseConnection::SqlxPostgresPoolConnection(conn) => conn.stream(stmt).await?,
|
DatabaseConnection::SqlxPostgresPoolConnection(conn) => conn.stream(stmt).await,
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.stream(stmt).await?,
|
DatabaseConnection::SqlxSqlitePoolConnection(conn) => conn.stream(stmt).await,
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
DatabaseConnection::MockDatabaseConnection(conn) => {
|
DatabaseConnection::MockDatabaseConnection(conn) => {
|
||||||
crate::QueryStream::from((Arc::clone(conn), stmt, None))
|
Ok(crate::QueryStream::from((Arc::clone(conn), stmt, None)))
|
||||||
|
}
|
||||||
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,7 +226,7 @@ impl TransactionTrait for DatabaseConnection {
|
|||||||
DatabaseConnection::MockDatabaseConnection(conn) => {
|
DatabaseConnection::MockDatabaseConnection(conn) => {
|
||||||
DatabaseTransaction::new_mock(Arc::clone(conn), None).await
|
DatabaseTransaction::new_mock(Arc::clone(conn), None).await
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +253,7 @@ impl TransactionTrait for DatabaseConnection {
|
|||||||
DatabaseConnection::MockDatabaseConnection(conn) => {
|
DatabaseConnection::MockDatabaseConnection(conn) => {
|
||||||
DatabaseTransaction::new_mock(Arc::clone(conn), None).await
|
DatabaseTransaction::new_mock(Arc::clone(conn), None).await
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +289,7 @@ impl TransactionTrait for DatabaseConnection {
|
|||||||
.map_err(TransactionError::Connection)?;
|
.map_err(TransactionError::Connection)?;
|
||||||
transaction.run(_callback).await
|
transaction.run(_callback).await
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected").into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +333,7 @@ impl TransactionTrait for DatabaseConnection {
|
|||||||
.map_err(TransactionError::Connection)?;
|
.map_err(TransactionError::Connection)?;
|
||||||
transaction.run(_callback).await
|
transaction.run(_callback).await
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => panic!("Disconnected"),
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected").into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -348,16 +341,28 @@ impl TransactionTrait for DatabaseConnection {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
impl DatabaseConnection {
|
impl DatabaseConnection {
|
||||||
/// Generate a database connection for testing the Mock database
|
/// Generate a database connection for testing the Mock database
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if [DbConn] is not a mock connection.
|
||||||
pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection {
|
pub fn as_mock_connection(&self) -> &crate::MockDatabaseConnection {
|
||||||
match self {
|
match self {
|
||||||
DatabaseConnection::MockDatabaseConnection(mock_conn) => mock_conn,
|
DatabaseConnection::MockDatabaseConnection(mock_conn) => mock_conn,
|
||||||
_ => panic!("not mock connection"),
|
_ => panic!("Not mock connection"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the transaction log as a collection Vec<[crate::Transaction]>
|
/// Get the transaction log as a collection Vec<[crate::Transaction]>
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the mocker mutex is being held by another thread.
|
||||||
pub fn into_transaction_log(self) -> Vec<crate::Transaction> {
|
pub fn into_transaction_log(self) -> Vec<crate::Transaction> {
|
||||||
let mut mocker = self.as_mock_connection().get_mocker_mutex().lock().unwrap();
|
let mut mocker = self
|
||||||
|
.as_mock_connection()
|
||||||
|
.get_mocker_mutex()
|
||||||
|
.lock()
|
||||||
|
.expect("Fail to acquire mocker");
|
||||||
mocker.drain_transaction_log()
|
mocker.drain_transaction_log()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -399,9 +404,7 @@ impl DatabaseConnection {
|
|||||||
// Nothing to cleanup, we just consume the `DatabaseConnection`
|
// Nothing to cleanup, we just consume the `DatabaseConnection`
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
DatabaseConnection::Disconnected => {
|
DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal("Disconnected".to_owned())))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -409,6 +412,10 @@ impl DatabaseConnection {
|
|||||||
#[cfg(feature = "sea-orm-internal")]
|
#[cfg(feature = "sea-orm-internal")]
|
||||||
impl DatabaseConnection {
|
impl DatabaseConnection {
|
||||||
/// Get [sqlx::MySqlPool]
|
/// Get [sqlx::MySqlPool]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if [DbConn] is not a MySQL connection.
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
pub fn get_mysql_connection_pool(&self) -> &sqlx::MySqlPool {
|
pub fn get_mysql_connection_pool(&self) -> &sqlx::MySqlPool {
|
||||||
match self {
|
match self {
|
||||||
@ -418,6 +425,10 @@ impl DatabaseConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get [sqlx::PgPool]
|
/// Get [sqlx::PgPool]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if [DbConn] is not a Postgres connection.
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
pub fn get_postgres_connection_pool(&self) -> &sqlx::PgPool {
|
pub fn get_postgres_connection_pool(&self) -> &sqlx::PgPool {
|
||||||
match self {
|
match self {
|
||||||
@ -427,6 +438,10 @@ impl DatabaseConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get [sqlx::SqlitePool]
|
/// Get [sqlx::SqlitePool]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if [DbConn] is not a SQLite connection.
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
pub fn get_sqlite_connection_pool(&self) -> &sqlx::SqlitePool {
|
pub fn get_sqlite_connection_pool(&self) -> &sqlx::SqlitePool {
|
||||||
match self {
|
match self {
|
||||||
@ -440,7 +455,7 @@ impl DbBackend {
|
|||||||
/// Check if the URI is the same as the specified database backend.
|
/// Check if the URI is the same as the specified database backend.
|
||||||
/// Returns true if they match.
|
/// Returns true if they match.
|
||||||
pub fn is_prefix_of(self, base_url: &str) -> bool {
|
pub fn is_prefix_of(self, base_url: &str) -> bool {
|
||||||
let base_url_parsed = Url::parse(base_url).unwrap();
|
let base_url_parsed = Url::parse(base_url).expect("Fail to parse database URL");
|
||||||
match self {
|
match self {
|
||||||
Self::Postgres => {
|
Self::Postgres => {
|
||||||
base_url_parsed.scheme() == "postgres" || base_url_parsed.scheme() == "postgresql"
|
base_url_parsed.scheme() == "postgres" || base_url_parsed.scheme() == "postgresql"
|
||||||
|
@ -123,9 +123,7 @@ impl MockDatabaseTrait for MockDatabase {
|
|||||||
if counter < self.exec_results.len() {
|
if counter < self.exec_results.len() {
|
||||||
match std::mem::replace(
|
match std::mem::replace(
|
||||||
&mut self.exec_results[counter],
|
&mut self.exec_results[counter],
|
||||||
Err(DbErr::Exec(RuntimeErr::Internal(
|
Err(exec_err("this value has been consumed already")),
|
||||||
"this value has been consumed already".to_owned(),
|
|
||||||
))),
|
|
||||||
) {
|
) {
|
||||||
Ok(result) => Ok(ExecResult {
|
Ok(result) => Ok(ExecResult {
|
||||||
result: ExecResultHolder::Mock(result),
|
result: ExecResultHolder::Mock(result),
|
||||||
@ -133,9 +131,7 @@ impl MockDatabaseTrait for MockDatabase {
|
|||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(DbErr::Exec(RuntimeErr::Internal(
|
Err(exec_err("`exec_results` buffer is empty"))
|
||||||
"`exec_results` buffer is empty".to_owned(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,9 +145,7 @@ impl MockDatabaseTrait for MockDatabase {
|
|||||||
if counter < self.query_results.len() {
|
if counter < self.query_results.len() {
|
||||||
match std::mem::replace(
|
match std::mem::replace(
|
||||||
&mut self.query_results[counter],
|
&mut self.query_results[counter],
|
||||||
Err(DbErr::Query(RuntimeErr::Internal(
|
Err(query_err("this value has been consumed already")),
|
||||||
"this value has been consumed already".to_owned(),
|
|
||||||
))),
|
|
||||||
) {
|
) {
|
||||||
Ok(result) => Ok(result
|
Ok(result) => Ok(result
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -162,45 +156,43 @@ impl MockDatabaseTrait for MockDatabase {
|
|||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(DbErr::Query(RuntimeErr::Internal(
|
Err(query_err("`query_results` buffer is empty."))
|
||||||
"`query_results` buffer is empty.".to_owned(),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn begin(&mut self) {
|
fn begin(&mut self) {
|
||||||
if self.transaction.is_some() {
|
match self.transaction.as_mut() {
|
||||||
self.transaction
|
Some(transaction) => transaction.begin_nested(self.db_backend),
|
||||||
.as_mut()
|
None => self.transaction = Some(OpenTransaction::init()),
|
||||||
.unwrap()
|
|
||||||
.begin_nested(self.db_backend);
|
|
||||||
} else {
|
|
||||||
self.transaction = Some(OpenTransaction::init());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn commit(&mut self) {
|
fn commit(&mut self) {
|
||||||
if self.transaction.is_some() {
|
match self.transaction.as_mut() {
|
||||||
if self.transaction.as_mut().unwrap().commit(self.db_backend) {
|
Some(transaction) => {
|
||||||
let transaction = self.transaction.take().unwrap();
|
if transaction.commit(self.db_backend) {
|
||||||
|
if let Some(transaction) = self.transaction.take() {
|
||||||
self.transaction_log.push(transaction.into_transaction());
|
self.transaction_log.push(transaction.into_transaction());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
panic!("There is no open transaction to commit");
|
}
|
||||||
|
None => panic!("There is no open transaction to commit"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn rollback(&mut self) {
|
fn rollback(&mut self) {
|
||||||
if self.transaction.is_some() {
|
match self.transaction.as_mut() {
|
||||||
if self.transaction.as_mut().unwrap().rollback(self.db_backend) {
|
Some(transaction) => {
|
||||||
let transaction = self.transaction.take().unwrap();
|
if transaction.rollback(self.db_backend) {
|
||||||
|
if let Some(transaction) = self.transaction.take() {
|
||||||
self.transaction_log.push(transaction.into_transaction());
|
self.transaction_log.push(transaction.into_transaction());
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
panic!("There is no open transaction to rollback");
|
}
|
||||||
|
None => panic!("There is no open transaction to rollback"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,17 +215,17 @@ impl MockRow {
|
|||||||
T::try_from(
|
T::try_from(
|
||||||
self.values
|
self.values
|
||||||
.get(index)
|
.get(index)
|
||||||
.unwrap_or_else(|| panic!("No column for ColIdx {index:?}"))
|
.ok_or_else(|| query_err(format!("No column for ColIdx {index:?}")))?
|
||||||
.clone(),
|
.clone(),
|
||||||
)
|
)
|
||||||
.map_err(|e| DbErr::Type(e.to_string()))
|
.map_err(type_err)
|
||||||
} else if let Some(index) = index.as_usize() {
|
} else if let Some(index) = index.as_usize() {
|
||||||
let (_, value) = self.values.iter().nth(*index).ok_or_else(|| {
|
let (_, value) = self
|
||||||
DbErr::Query(RuntimeErr::Internal(format!(
|
.values
|
||||||
"Column at index {index} not found"
|
.iter()
|
||||||
)))
|
.nth(*index)
|
||||||
})?;
|
.ok_or_else(|| query_err(format!("Column at index {index} not found")))?;
|
||||||
T::try_from(value.clone()).map_err(|e| DbErr::Type(e.to_string()))
|
T::try_from(value.clone()).map_err(type_err)
|
||||||
} else {
|
} else {
|
||||||
unreachable!("Missing ColIdx implementation for MockRow");
|
unreachable!("Missing ColIdx implementation for MockRow");
|
||||||
}
|
}
|
||||||
@ -393,10 +385,10 @@ impl OpenTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn into_transaction(self) -> Transaction {
|
fn into_transaction(self) -> Transaction {
|
||||||
if self.transaction_depth != 0 {
|
match self.transaction_depth {
|
||||||
panic!("There is uncommitted nested transaction.");
|
0 => Transaction { stmts: self.stmts },
|
||||||
|
_ => panic!("There is uncommitted nested transaction"),
|
||||||
}
|
}
|
||||||
Transaction { stmts: self.stmts }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,8 +396,8 @@ impl OpenTransaction {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::*, tests_cfg::*, DbBackend, DbErr, IntoMockRow, MockDatabase, RuntimeErr,
|
entity::*, error::*, tests_cfg::*, DbBackend, DbErr, IntoMockRow, MockDatabase, Statement,
|
||||||
Statement, Transaction, TransactionError, TransactionTrait,
|
Transaction, TransactionError, TransactionTrait,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@ -480,7 +472,7 @@ mod tests {
|
|||||||
Err(TransactionError::Transaction(err)) => {
|
Err(TransactionError::Transaction(err)) => {
|
||||||
assert_eq!(err, MyErr("test".to_owned()))
|
assert_eq!(err, MyErr("test".to_owned()))
|
||||||
}
|
}
|
||||||
_ => panic!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -846,34 +838,26 @@ mod tests {
|
|||||||
#[smol_potat::test]
|
#[smol_potat::test]
|
||||||
async fn test_query_err() {
|
async fn test_query_err() {
|
||||||
let db = MockDatabase::new(DbBackend::MySql)
|
let db = MockDatabase::new(DbBackend::MySql)
|
||||||
.append_query_errors([DbErr::Query(RuntimeErr::Internal(
|
.append_query_errors([query_err("this is a mock query error")])
|
||||||
"this is a mock query error".to_owned(),
|
|
||||||
))])
|
|
||||||
.into_connection();
|
.into_connection();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake::Entity::find().all(&db).await,
|
cake::Entity::find().all(&db).await,
|
||||||
Err(DbErr::Query(RuntimeErr::Internal(
|
Err(query_err("this is a mock query error"))
|
||||||
"this is a mock query error".to_owned()
|
|
||||||
)))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[smol_potat::test]
|
#[smol_potat::test]
|
||||||
async fn test_exec_err() {
|
async fn test_exec_err() {
|
||||||
let db = MockDatabase::new(DbBackend::MySql)
|
let db = MockDatabase::new(DbBackend::MySql)
|
||||||
.append_exec_errors([DbErr::Exec(RuntimeErr::Internal(
|
.append_exec_errors([exec_err("this is a mock exec error")])
|
||||||
"this is a mock exec error".to_owned(),
|
|
||||||
))])
|
|
||||||
.into_connection();
|
.into_connection();
|
||||||
|
|
||||||
let model = cake::ActiveModel::new();
|
let model = cake::ActiveModel::new();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
model.save(&db).await,
|
model.save(&db).await,
|
||||||
Err(DbErr::Exec(RuntimeErr::Internal(
|
Err(exec_err("this is a mock exec error"))
|
||||||
"this is a mock exec error".to_owned()
|
|
||||||
)))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ pub use stream::*;
|
|||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
pub use transaction::*;
|
pub use transaction::*;
|
||||||
|
|
||||||
use crate::{DbErr, RuntimeErr};
|
use crate::error::*;
|
||||||
|
|
||||||
/// Defines a database
|
/// Defines a database
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
@ -77,10 +77,10 @@ impl Database {
|
|||||||
if crate::MockDatabaseConnector::accepts(&opt.url) {
|
if crate::MockDatabaseConnector::accepts(&opt.url) {
|
||||||
return crate::MockDatabaseConnector::connect(&opt.url).await;
|
return crate::MockDatabaseConnector::connect(&opt.url).await;
|
||||||
}
|
}
|
||||||
Err(DbErr::Conn(RuntimeErr::Internal(format!(
|
Err(conn_err(format!(
|
||||||
"The connection string '{}' has no supporting driver.",
|
"The connection string '{}' has no supporting driver.",
|
||||||
opt.url
|
opt.url
|
||||||
))))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#![allow(missing_docs, unreachable_code, unused_variables)]
|
#![allow(missing_docs, unreachable_code, unused_variables)]
|
||||||
|
|
||||||
use std::{pin::Pin, task::Poll};
|
use tracing::instrument;
|
||||||
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::{pin::Pin, task::Poll};
|
||||||
|
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
@ -12,11 +13,10 @@ use futures::TryStreamExt;
|
|||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
use sqlx::{pool::PoolConnection, Executor};
|
use sqlx::{pool::PoolConnection, Executor};
|
||||||
|
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
|
||||||
|
|
||||||
use super::metric::MetricStream;
|
use super::metric::MetricStream;
|
||||||
|
#[cfg(feature = "sqlx-dep")]
|
||||||
|
use crate::driver::*;
|
||||||
|
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
||||||
|
|
||||||
/// Creates a stream from a [QueryResult]
|
/// Creates a stream from a [QueryResult]
|
||||||
#[ouroboros::self_referencing]
|
#[ouroboros::self_referencing]
|
||||||
@ -130,7 +130,7 @@ impl QueryStream {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
@ -141,7 +141,7 @@ impl QueryStream {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ impl QueryStream {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use std::{ops::DerefMut, pin::Pin, task::Poll};
|
use std::{ops::DerefMut, pin::Pin, task::Poll};
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
use futures::Stream;
|
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
use futures::{lock::MutexGuard, Stream};
|
||||||
|
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
use sqlx::Executor;
|
use sqlx::Executor;
|
||||||
|
|
||||||
use futures::lock::MutexGuard;
|
|
||||||
|
|
||||||
use tracing::instrument;
|
|
||||||
|
|
||||||
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
|
||||||
|
|
||||||
use super::metric::MetricStream;
|
use super::metric::MetricStream;
|
||||||
|
#[cfg(feature = "sqlx-dep")]
|
||||||
|
use crate::driver::*;
|
||||||
|
use crate::{DbErr, InnerConnection, QueryResult, Statement};
|
||||||
|
|
||||||
/// `TransactionStream` cannot be used in a `transaction` closure as it does not impl `Send`.
|
/// `TransactionStream` cannot be used in a `transaction` closure as it does not impl `Send`.
|
||||||
/// It seems to be a Rust limitation right now, and solution to work around this deemed to be extremely hard.
|
/// It seems to be a Rust limitation right now, and solution to work around this deemed to be extremely hard.
|
||||||
@ -55,7 +53,7 @@ impl<'a> TransactionStream<'a> {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
@ -66,7 +64,7 @@ impl<'a> TransactionStream<'a> {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
@ -77,7 +75,7 @@ impl<'a> TransactionStream<'a> {
|
|||||||
let stream = c
|
let stream = c
|
||||||
.fetch(query)
|
.fetch(query)
|
||||||
.map_ok(Into::into)
|
.map_ok(Into::into)
|
||||||
.map_err(crate::sqlx_error_to_query_err);
|
.map_err(sqlx_error_to_query_err);
|
||||||
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
let elapsed = _start.map(|s| s.elapsed().unwrap_or_default());
|
||||||
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
MetricStream::new(_metric_callback, stmt, elapsed, stream)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
debug_print, AccessMode, ConnectionTrait, DbBackend, DbErr, ExecResult, InnerConnection,
|
debug_print, error::*, AccessMode, ConnectionTrait, DbBackend, DbErr, ExecResult,
|
||||||
IsolationLevel, QueryResult, Statement, StreamTrait, TransactionStream, TransactionTrait,
|
InnerConnection, IsolationLevel, QueryResult, Statement, StreamTrait, TransactionStream,
|
||||||
|
TransactionTrait,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
use crate::{sqlx_error_to_exec_err, sqlx_error_to_query_err};
|
use crate::{sqlx_error_to_exec_err, sqlx_error_to_query_err};
|
||||||
@ -95,7 +96,6 @@ impl DatabaseTransaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace", skip(metric_callback))]
|
#[instrument(level = "trace", skip(metric_callback))]
|
||||||
#[allow(unreachable_code)]
|
|
||||||
async fn begin(
|
async fn begin(
|
||||||
conn: Arc<Mutex<InnerConnection>>,
|
conn: Arc<Mutex<InnerConnection>>,
|
||||||
backend: DbBackend,
|
backend: DbBackend,
|
||||||
@ -117,7 +117,7 @@ impl DatabaseTransaction {
|
|||||||
.await?;
|
.await?;
|
||||||
<sqlx::MySql as sqlx::Database>::TransactionManager::begin(c)
|
<sqlx::MySql as sqlx::Database>::TransactionManager::begin(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?;
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
InnerConnection::Postgres(ref mut c) => {
|
InnerConnection::Postgres(ref mut c) => {
|
||||||
@ -130,7 +130,7 @@ impl DatabaseTransaction {
|
|||||||
isolation_level,
|
isolation_level,
|
||||||
access_mode,
|
access_mode,
|
||||||
)
|
)
|
||||||
.await?;
|
.await
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
InnerConnection::Sqlite(ref mut c) => {
|
InnerConnection::Sqlite(ref mut c) => {
|
||||||
@ -139,13 +139,16 @@ impl DatabaseTransaction {
|
|||||||
.await?;
|
.await?;
|
||||||
<sqlx::Sqlite as sqlx::Database>::TransactionManager::begin(c)
|
<sqlx::Sqlite as sqlx::Database>::TransactionManager::begin(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?;
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(ref mut c) => {
|
InnerConnection::Mock(ref mut c) => {
|
||||||
c.begin();
|
c.begin();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(conn_err("Disconnected")),
|
||||||
|
}?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,25 +184,28 @@ impl DatabaseTransaction {
|
|||||||
InnerConnection::MySql(ref mut c) => {
|
InnerConnection::MySql(ref mut c) => {
|
||||||
<sqlx::MySql as sqlx::Database>::TransactionManager::commit(c)
|
<sqlx::MySql as sqlx::Database>::TransactionManager::commit(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
InnerConnection::Postgres(ref mut c) => {
|
InnerConnection::Postgres(ref mut c) => {
|
||||||
<sqlx::Postgres as sqlx::Database>::TransactionManager::commit(c)
|
<sqlx::Postgres as sqlx::Database>::TransactionManager::commit(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
InnerConnection::Sqlite(ref mut c) => {
|
InnerConnection::Sqlite(ref mut c) => {
|
||||||
<sqlx::Sqlite as sqlx::Database>::TransactionManager::commit(c)
|
<sqlx::Sqlite as sqlx::Database>::TransactionManager::commit(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(ref mut c) => {
|
InnerConnection::Mock(ref mut c) => {
|
||||||
c.commit();
|
c.commit();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(conn_err("Disconnected")),
|
||||||
|
}?;
|
||||||
self.open = false;
|
self.open = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -213,32 +219,35 @@ impl DatabaseTransaction {
|
|||||||
InnerConnection::MySql(ref mut c) => {
|
InnerConnection::MySql(ref mut c) => {
|
||||||
<sqlx::MySql as sqlx::Database>::TransactionManager::rollback(c)
|
<sqlx::MySql as sqlx::Database>::TransactionManager::rollback(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
InnerConnection::Postgres(ref mut c) => {
|
InnerConnection::Postgres(ref mut c) => {
|
||||||
<sqlx::Postgres as sqlx::Database>::TransactionManager::rollback(c)
|
<sqlx::Postgres as sqlx::Database>::TransactionManager::rollback(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
InnerConnection::Sqlite(ref mut c) => {
|
InnerConnection::Sqlite(ref mut c) => {
|
||||||
<sqlx::Sqlite as sqlx::Database>::TransactionManager::rollback(c)
|
<sqlx::Sqlite as sqlx::Database>::TransactionManager::rollback(c)
|
||||||
.await
|
.await
|
||||||
.map_err(sqlx_error_to_query_err)?
|
.map_err(sqlx_error_to_query_err)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(ref mut c) => {
|
InnerConnection::Mock(ref mut c) => {
|
||||||
c.rollback();
|
c.rollback();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
#[allow(unreachable_patterns)]
|
||||||
|
_ => Err(conn_err("Disconnected")),
|
||||||
|
}?;
|
||||||
self.open = false;
|
self.open = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// the rollback is queued and will be performed on next async operation, like returning the connection to the pool
|
// the rollback is queued and will be performed on next async operation, like returning the connection to the pool
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
fn start_rollback(&mut self) {
|
fn start_rollback(&mut self) -> Result<(), DbErr> {
|
||||||
if self.open {
|
if self.open {
|
||||||
if let Some(mut conn) = self.conn.try_lock() {
|
if let Some(mut conn) = self.conn.try_lock() {
|
||||||
match &mut *conn {
|
match &mut *conn {
|
||||||
@ -259,13 +268,14 @@ impl DatabaseTransaction {
|
|||||||
c.rollback();
|
c.rollback();
|
||||||
}
|
}
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => return Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//this should never happen
|
//this should never happen
|
||||||
panic!("Dropping a locked Transaction");
|
return Err(conn_err("Dropping a locked Transaction"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sqlx-dep")]
|
#[cfg(feature = "sqlx-dep")]
|
||||||
@ -282,7 +292,7 @@ impl DatabaseTransaction {
|
|||||||
|
|
||||||
impl Drop for DatabaseTransaction {
|
impl Drop for DatabaseTransaction {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.start_rollback();
|
self.start_rollback().expect("Fail to rollback transaction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +336,7 @@ impl ConnectionTrait for DatabaseTransaction {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.execute(stmt),
|
InnerConnection::Mock(conn) => return conn.execute(stmt),
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +368,7 @@ impl ConnectionTrait for DatabaseTransaction {
|
|||||||
conn.execute(stmt)
|
conn.execute(stmt)
|
||||||
}
|
}
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +408,7 @@ impl ConnectionTrait for DatabaseTransaction {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.query_one(stmt),
|
InnerConnection::Mock(conn) => return conn.query_one(stmt),
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +454,7 @@ impl ConnectionTrait for DatabaseTransaction {
|
|||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
InnerConnection::Mock(conn) => return conn.query_all(stmt),
|
InnerConnection::Mock(conn) => return conn.query_all(stmt),
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => Err(conn_err("Disconnected")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -564,3 +574,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E> std::error::Error for TransactionError<E> where E: std::error::Error {}
|
impl<E> std::error::Error for TransactionError<E> where E: std::error::Error {}
|
||||||
|
|
||||||
|
impl<E> From<DbErr> for TransactionError<E>
|
||||||
|
where
|
||||||
|
E: std::error::Error,
|
||||||
|
{
|
||||||
|
fn from(e: DbErr) -> Self {
|
||||||
|
Self::Connection(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -115,7 +115,10 @@ impl MockDatabaseConnection {
|
|||||||
|
|
||||||
/// Get the [DatabaseBackend](crate::DatabaseBackend) being used by the [MockDatabase]
|
/// Get the [DatabaseBackend](crate::DatabaseBackend) being used by the [MockDatabase]
|
||||||
pub fn get_database_backend(&self) -> DbBackend {
|
pub fn get_database_backend(&self) -> DbBackend {
|
||||||
self.mocker.lock().unwrap().get_database_backend()
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.expect("Fail to acquire mocker")
|
||||||
|
.get_database_backend()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the SQL statement in the [MockDatabase]
|
/// Execute the SQL statement in the [MockDatabase]
|
||||||
@ -123,7 +126,10 @@ impl MockDatabaseConnection {
|
|||||||
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
pub fn execute(&self, statement: Statement) -> Result<ExecResult, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.execute_counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.execute_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().execute(counter, statement)
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.map_err(exec_err)?
|
||||||
|
.execute(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return one [QueryResult] if the query was successful
|
/// Return one [QueryResult] if the query was successful
|
||||||
@ -131,7 +137,11 @@ impl MockDatabaseConnection {
|
|||||||
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
pub fn query_one(&self, statement: Statement) -> Result<Option<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
let result = self.mocker.lock().unwrap().query(counter, statement)?;
|
let result = self
|
||||||
|
.mocker
|
||||||
|
.lock()
|
||||||
|
.map_err(query_err)?
|
||||||
|
.query(counter, statement)?;
|
||||||
Ok(result.into_iter().next())
|
Ok(result.into_iter().next())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +150,10 @@ impl MockDatabaseConnection {
|
|||||||
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
pub fn query_all(&self, statement: Statement) -> Result<Vec<QueryResult>, DbErr> {
|
||||||
debug_print!("{}", statement);
|
debug_print!("{}", statement);
|
||||||
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
let counter = self.query_counter.fetch_add(1, Ordering::SeqCst);
|
||||||
self.mocker.lock().unwrap().query(counter, statement)
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.map_err(query_err)?
|
||||||
|
.query(counter, statement)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return [QueryResult]s from a multi-query operation
|
/// Return [QueryResult]s from a multi-query operation
|
||||||
@ -158,18 +171,27 @@ impl MockDatabaseConnection {
|
|||||||
/// Create a statement block of SQL statements that execute together.
|
/// Create a statement block of SQL statements that execute together.
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
pub fn begin(&self) {
|
pub fn begin(&self) {
|
||||||
self.mocker.lock().unwrap().begin()
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.expect("Failed to acquire mocker")
|
||||||
|
.begin()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Commit a transaction atomically to the database
|
/// Commit a transaction atomically to the database
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
pub fn commit(&self) {
|
pub fn commit(&self) {
|
||||||
self.mocker.lock().unwrap().commit()
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.expect("Failed to acquire mocker")
|
||||||
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Roll back a faulty transaction
|
/// Roll back a faulty transaction
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
pub fn rollback(&self) {
|
pub fn rollback(&self) {
|
||||||
self.mocker.lock().unwrap().rollback()
|
self.mocker
|
||||||
|
.lock()
|
||||||
|
.expect("Failed to acquire mocker")
|
||||||
|
.rollback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ impl SqlxMySqlPoolConnection {
|
|||||||
.map_err(|e| TransactionError::Connection(e))?;
|
.map_err(|e| TransactionError::Connection(e))?;
|
||||||
transaction.run(callback).await
|
transaction.run(callback).await
|
||||||
} else {
|
} else {
|
||||||
Err(TransactionError::Connection(DbErr::ConnectionAcquire))
|
Err(DbErr::ConnectionAcquire.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ impl SqlxPostgresPoolConnection {
|
|||||||
.map_err(|e| TransactionError::Connection(e))?;
|
.map_err(|e| TransactionError::Connection(e))?;
|
||||||
transaction.run(callback).await
|
transaction.run(callback).await
|
||||||
} else {
|
} else {
|
||||||
Err(TransactionError::Connection(DbErr::ConnectionAcquire))
|
Err(DbErr::ConnectionAcquire.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +48,8 @@ impl SqlxSqliteConnector {
|
|||||||
.url
|
.url
|
||||||
.parse::<SqliteConnectOptions>()
|
.parse::<SqliteConnectOptions>()
|
||||||
.map_err(sqlx_error_to_conn_err)?;
|
.map_err(sqlx_error_to_conn_err)?;
|
||||||
if options.sqlcipher_key.is_some() {
|
if let Some(sqlcipher_key) = &options.sqlcipher_key {
|
||||||
opt = opt.pragma("key", options.sqlcipher_key.clone().unwrap());
|
opt = opt.pragma("key", sqlcipher_key.clone());
|
||||||
}
|
}
|
||||||
use sqlx::ConnectOptions;
|
use sqlx::ConnectOptions;
|
||||||
if !options.sqlx_logging {
|
if !options.sqlx_logging {
|
||||||
@ -218,7 +218,7 @@ impl SqlxSqlitePoolConnection {
|
|||||||
.map_err(|e| TransactionError::Connection(e))?;
|
.map_err(|e| TransactionError::Connection(e))?;
|
||||||
transaction.run(callback).await
|
transaction.run(callback).await
|
||||||
} else {
|
} else {
|
||||||
Err(TransactionError::Connection(DbErr::ConnectionAcquire))
|
Err(DbErr::ConnectionAcquire.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ where
|
|||||||
fn try_get_by<I: crate::ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: crate::ColIdx>(res: &QueryResult, index: I) -> Result<Self, TryGetError> {
|
||||||
<T::ValueVec as TryGetable>::try_get_by(res, index)?
|
<T::ValueVec as TryGetable>::try_get_by(res, index)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|value| T::try_from_value(&value).map_err(TryGetError::DbErr))
|
.map(|value| T::try_from_value(&value).map_err(Into::into))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate as sea_orm;
|
use crate as sea_orm;
|
||||||
use crate::{entity::prelude::*, sea_query::SeaRc, *};
|
use crate::{error::*, sea_query::SeaRc, *};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -210,9 +210,7 @@ mod tests {
|
|||||||
match v.as_ref() {
|
match v.as_ref() {
|
||||||
"B" => Ok(Self::Big),
|
"B" => Ok(Self::Big),
|
||||||
"S" => Ok(Self::Small),
|
"S" => Ok(Self::Small),
|
||||||
_ => Err(DbErr::Type(format!(
|
_ => Err(type_err(format!("unexpected value for Category enum: {v}"))),
|
||||||
"unexpected value for Category enum: {v}"
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,9 +239,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Category::try_from_value(&"A".to_owned()).err(),
|
Category::try_from_value(&"A".to_owned()).err(),
|
||||||
Some(DbErr::Type(
|
Some(type_err("unexpected value for Category enum: A"))
|
||||||
"unexpected value for Category enum: A".to_owned()
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Category::try_from_value(&"B".to_owned()).ok(),
|
Category::try_from_value(&"B".to_owned()).ok(),
|
||||||
@ -255,9 +251,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeriveCategory::try_from_value(&"A".to_owned()).err(),
|
DeriveCategory::try_from_value(&"A".to_owned()).err(),
|
||||||
Some(DbErr::Type(
|
Some(type_err("unexpected value for DeriveCategory enum: A"))
|
||||||
"unexpected value for DeriveCategory enum: A".to_owned()
|
|
||||||
))
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeriveCategory::try_from_value(&"B".to_owned()).ok(),
|
DeriveCategory::try_from_value(&"B".to_owned()).ok(),
|
||||||
@ -326,7 +320,7 @@ mod tests {
|
|||||||
assert_eq!($ident::try_from_value(&-10).ok(), Some($ident::Negative));
|
assert_eq!($ident::try_from_value(&-10).ok(), Some($ident::Negative));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
$ident::try_from_value(&2).err(),
|
$ident::try_from_value(&2).err(),
|
||||||
Some(DbErr::Type(format!(
|
Some(type_err(format!(
|
||||||
"unexpected value for {} enum: 2",
|
"unexpected value for {} enum: 2",
|
||||||
stringify!($ident)
|
stringify!($ident)
|
||||||
)))
|
)))
|
||||||
@ -391,7 +385,7 @@ mod tests {
|
|||||||
assert_eq!($ident::try_from_value(&0).ok(), Some($ident::Small));
|
assert_eq!($ident::try_from_value(&0).ok(), Some($ident::Small));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
$ident::try_from_value(&2).err(),
|
$ident::try_from_value(&2).err(),
|
||||||
Some(DbErr::Type(format!(
|
Some(type_err(format!(
|
||||||
"unexpected value for {} enum: 2",
|
"unexpected value for {} enum: 2",
|
||||||
stringify!($ident)
|
stringify!($ident)
|
||||||
)))
|
)))
|
||||||
|
@ -119,6 +119,10 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the primary key of the ActiveModel
|
/// Get the primary key of the ActiveModel
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if arity of primary key exceed maximum arity of [ValueTuple]
|
||||||
#[allow(clippy::question_mark)]
|
#[allow(clippy::question_mark)]
|
||||||
fn get_primary_key_value(&self) -> Option<ValueTuple> {
|
fn get_primary_key_value(&self) -> Option<ValueTuple> {
|
||||||
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
|
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
|
||||||
@ -547,17 +551,20 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
|
|
||||||
// Convert JSON object into ActiveModel via Model
|
// Convert JSON object into ActiveModel via Model
|
||||||
let model: <Self::Entity as EntityTrait>::Model =
|
let model: <Self::Entity as EntityTrait>::Model =
|
||||||
serde_json::from_value(json).map_err(|e| DbErr::Json(e.to_string()))?;
|
serde_json::from_value(json).map_err(json_err)?;
|
||||||
let mut am = model.into_active_model();
|
let mut am = model.into_active_model();
|
||||||
|
|
||||||
// Transform attribute that exists in JSON object into ActiveValue::Set, otherwise ActiveValue::NotSet
|
// Transform attribute that exists in JSON object into ActiveValue::Set, otherwise ActiveValue::NotSet
|
||||||
for (col, json_key_exists) in json_keys {
|
for (col, json_key_exists) in json_keys {
|
||||||
if json_key_exists && !am.is_not_set(col) {
|
match (json_key_exists, am.get(col)) {
|
||||||
am.set(col, am.get(col).unwrap());
|
(true, ActiveValue::Set(value) | ActiveValue::Unchanged(value)) => {
|
||||||
} else {
|
am.set(col, value);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
am.not_set(col);
|
am.not_set(col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(am)
|
Ok(am)
|
||||||
}
|
}
|
||||||
@ -823,6 +830,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an owned value of the [ActiveValue]
|
/// Get an owned value of the [ActiveValue]
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if it is [ActiveValue::NotSet]
|
||||||
pub fn unwrap(self) -> V {
|
pub fn unwrap(self) -> V {
|
||||||
match self {
|
match self {
|
||||||
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
|
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
|
||||||
@ -861,6 +872,9 @@ impl<V> std::convert::AsRef<V> for ActiveValue<V>
|
|||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
{
|
{
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if it is [ActiveValue::NotSet]
|
||||||
fn as_ref(&self) -> &V {
|
fn as_ref(&self) -> &V {
|
||||||
match self {
|
match self {
|
||||||
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
|
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => value,
|
||||||
|
@ -256,6 +256,10 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if arity of input values don't match arity of primary key
|
||||||
fn find_by_id<T>(values: T) -> Select<Self>
|
fn find_by_id<T>(values: T) -> Select<Self>
|
||||||
where
|
where
|
||||||
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
|
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
|
||||||
@ -818,6 +822,10 @@ pub trait EntityTrait: EntityName {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if arity of input values don't match arity of primary key
|
||||||
fn delete_by_id<T>(values: T) -> DeleteMany<Self>
|
fn delete_by_id<T>(values: T) -> DeleteMany<Self>
|
||||||
where
|
where
|
||||||
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
|
T: Into<<Self::PrimaryKey as PrimaryKeyTrait>::ValueType>,
|
||||||
|
@ -88,9 +88,10 @@
|
|||||||
/// // Create a Relation for the Entity
|
/// // Create a Relation for the Entity
|
||||||
/// impl RelationTrait for Relation {
|
/// impl RelationTrait for Relation {
|
||||||
/// fn def(&self) -> RelationDef {
|
/// fn def(&self) -> RelationDef {
|
||||||
/// panic!()
|
/// unimplemented!()
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
/// // Implement user defined operations for CREATE, UPDATE and DELETE operations
|
/// // Implement user defined operations for CREATE, UPDATE and DELETE operations
|
||||||
/// // to create an ActiveModel using the [ActiveModelBehavior]
|
/// // to create an ActiveModel using the [ActiveModelBehavior]
|
||||||
/// impl ActiveModelBehavior for ActiveModel {}
|
/// impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
@ -303,8 +303,8 @@ where
|
|||||||
rel_type: b.rel_type,
|
rel_type: b.rel_type,
|
||||||
from_tbl: b.from_tbl,
|
from_tbl: b.from_tbl,
|
||||||
to_tbl: b.to_tbl,
|
to_tbl: b.to_tbl,
|
||||||
from_col: b.from_col.unwrap(),
|
from_col: b.from_col.expect("Reference column is not set"),
|
||||||
to_col: b.to_col.unwrap(),
|
to_col: b.to_col.expect("Owner column is not set"),
|
||||||
is_owner: b.is_owner,
|
is_owner: b.is_owner,
|
||||||
on_delete: b.on_delete,
|
on_delete: b.on_delete,
|
||||||
on_update: b.on_update,
|
on_update: b.on_update,
|
||||||
|
40
src/error.rs
40
src/error.rs
@ -99,3 +99,43 @@ impl Eq for DbErr {}
|
|||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
#[error("Failed to match \"{0}\" as Column")]
|
#[error("Failed to match \"{0}\" as Column")]
|
||||||
pub struct ColumnFromStrErr(pub String);
|
pub struct ColumnFromStrErr(pub String);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn conn_err<T>(s: T) -> DbErr
|
||||||
|
where
|
||||||
|
T: ToString,
|
||||||
|
{
|
||||||
|
DbErr::Conn(RuntimeErr::Internal(s.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn exec_err<T>(s: T) -> DbErr
|
||||||
|
where
|
||||||
|
T: ToString,
|
||||||
|
{
|
||||||
|
DbErr::Exec(RuntimeErr::Internal(s.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn query_err<T>(s: T) -> DbErr
|
||||||
|
where
|
||||||
|
T: ToString,
|
||||||
|
{
|
||||||
|
DbErr::Query(RuntimeErr::Internal(s.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn type_err<T>(s: T) -> DbErr
|
||||||
|
where
|
||||||
|
T: ToString,
|
||||||
|
{
|
||||||
|
DbErr::Type(s.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn json_err<T>(s: T) -> DbErr
|
||||||
|
where
|
||||||
|
T: ToString,
|
||||||
|
{
|
||||||
|
DbErr::Json(s.to_string())
|
||||||
|
}
|
||||||
|
@ -28,6 +28,10 @@ pub(crate) enum ExecResultHolder {
|
|||||||
|
|
||||||
impl ExecResult {
|
impl ExecResult {
|
||||||
/// Get the last id after `AUTOINCREMENT` is done on the primary key
|
/// Get the last id after `AUTOINCREMENT` is done on the primary key
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Postgres does not support retrieving last insert id this way except through `RETURNING` clause
|
||||||
pub fn last_insert_id(&self) -> u64 {
|
pub fn last_insert_id(&self) -> u64 {
|
||||||
match &self.result {
|
match &self.result {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
@ -40,7 +44,7 @@ impl ExecResult {
|
|||||||
ExecResultHolder::SqlxSqlite(result) => {
|
ExecResultHolder::SqlxSqlite(result) => {
|
||||||
let last_insert_rowid = result.last_insert_rowid();
|
let last_insert_rowid = result.last_insert_rowid();
|
||||||
if last_insert_rowid < 0 {
|
if last_insert_rowid < 0 {
|
||||||
panic!("negative last_insert_rowid")
|
unreachable!("negative last_insert_rowid")
|
||||||
} else {
|
} else {
|
||||||
last_insert_rowid as u64
|
last_insert_rowid as u64
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables, unreachable_code)]
|
|
||||||
async fn exec_insert<A, C>(
|
async fn exec_insert<A, C>(
|
||||||
primary_key: Option<ValueTuple>,
|
primary_key: Option<ValueTuple>,
|
||||||
statement: Statement,
|
statement: Statement,
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
use crate::{error::*, SelectGetableValue, SelectorRaw, Statement};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
use crate::debug_print;
|
use crate::debug_print;
|
||||||
use crate::{DbErr, SelectGetableValue, SelectorRaw, Statement};
|
|
||||||
use std::fmt;
|
#[cfg(feature = "sqlx-dep")]
|
||||||
|
use crate::driver::*;
|
||||||
|
#[cfg(feature = "sqlx-dep")]
|
||||||
|
use sqlx::Row;
|
||||||
|
|
||||||
/// Defines the result of a query operation on a Model
|
/// Defines the result of a query operation on a Model
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -52,12 +58,18 @@ impl From<TryGetError> for DbErr {
|
|||||||
match e {
|
match e {
|
||||||
TryGetError::DbErr(e) => e,
|
TryGetError::DbErr(e) => e,
|
||||||
TryGetError::Null(s) => {
|
TryGetError::Null(s) => {
|
||||||
DbErr::Type(format!("A null value was encountered while decoding {s}"))
|
type_err(format!("A null value was encountered while decoding {s}"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<DbErr> for TryGetError {
|
||||||
|
fn from(e: DbErr) -> TryGetError {
|
||||||
|
Self::DbErr(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// QueryResult //
|
// QueryResult //
|
||||||
|
|
||||||
impl QueryResult {
|
impl QueryResult {
|
||||||
@ -236,26 +248,20 @@ macro_rules! try_getable_all {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
@ -276,23 +282,21 @@ macro_rules! try_getable_unsigned {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(_) => {
|
QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-postgres", stringify!($type))
|
"{} unsupported by sqlx-postgres",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_sqlite_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
@ -313,20 +317,22 @@ macro_rules! try_getable_mysql {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(_) => {
|
QueryResultRow::SqlxPostgres(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-postgres", stringify!($type))
|
"{} unsupported by sqlx-postgres",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(_) => {
|
QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
"{} unsupported by sqlx-sqlite",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
@ -350,25 +356,21 @@ macro_rules! try_getable_date_time {
|
|||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => {
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use sqlx::Row;
|
|
||||||
row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_mysql_index())
|
row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_mysql_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<$type>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => {
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use sqlx::Row;
|
|
||||||
row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
|
row.try_get::<Option<DateTime<Utc>>, _>(idx.as_sqlx_sqlite_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
||||||
.map(|v| v.into())
|
.map(|v| v.into())
|
||||||
}
|
}
|
||||||
@ -440,32 +442,28 @@ impl TryGetable for Decimal {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<Decimal>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<Decimal>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => {
|
||||||
use sqlx::Row;
|
|
||||||
let val: Option<f64> = row
|
let val: Option<f64> = row
|
||||||
.try_get(idx.as_sqlx_sqlite_index())
|
.try_get(idx.as_sqlx_sqlite_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?;
|
.map_err(sqlx_error_to_query_err)?;
|
||||||
match val {
|
match val {
|
||||||
Some(v) => Decimal::try_from(v).map_err(|e| {
|
Some(v) => Decimal::try_from(v).map_err(|e| {
|
||||||
TryGetError::DbErr(DbErr::TryIntoErr {
|
DbErr::TryIntoErr {
|
||||||
from: "f64",
|
from: "f64",
|
||||||
into: "Decimal",
|
into: "Decimal",
|
||||||
source: Box::new(e),
|
source: Box::new(e),
|
||||||
})
|
}
|
||||||
|
.into()
|
||||||
}),
|
}),
|
||||||
None => Err(err_null_idx_col(idx)),
|
None => Err(err_null_idx_col(idx)),
|
||||||
}
|
}
|
||||||
@ -491,32 +489,28 @@ impl TryGetable for BigDecimal {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<BigDecimal>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<BigDecimal>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => {
|
||||||
use sqlx::Row;
|
|
||||||
let val: Option<f64> = row
|
let val: Option<f64> = row
|
||||||
.try_get(idx.as_sqlx_sqlite_index())
|
.try_get(idx.as_sqlx_sqlite_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))?;
|
.map_err(sqlx_error_to_query_err)?;
|
||||||
match val {
|
match val {
|
||||||
Some(v) => BigDecimal::try_from(v).map_err(|e| {
|
Some(v) => BigDecimal::try_from(v).map_err(|e| {
|
||||||
TryGetError::DbErr(DbErr::TryIntoErr {
|
DbErr::TryIntoErr {
|
||||||
from: "f64",
|
from: "f64",
|
||||||
into: "BigDecimal",
|
into: "BigDecimal",
|
||||||
source: Box::new(e),
|
source: Box::new(e),
|
||||||
})
|
}
|
||||||
|
.into()
|
||||||
}),
|
}),
|
||||||
None => Err(err_null_idx_col(idx)),
|
None => Err(err_null_idx_col(idx)),
|
||||||
}
|
}
|
||||||
@ -541,26 +535,20 @@ macro_rules! try_getable_uuid {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
let res: Result<uuid::Uuid, TryGetError> = match &res.row {
|
let res: Result<uuid::Uuid, TryGetError> = match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_sqlite_index())
|
||||||
row.try_get::<Option<uuid::Uuid>, _>(idx.as_sqlx_sqlite_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get::<uuid::Uuid, _>(idx).map_err(|e| {
|
||||||
@ -596,30 +584,25 @@ impl TryGetable for u32 {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<u32>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => {
|
||||||
use sqlx::postgres::types::Oid;
|
use sqlx::postgres::types::Oid;
|
||||||
// Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
|
// Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
|
||||||
// Instead, `u32` was wrapped by a `sqlx::Oid`.
|
// Instead, `u32` was wrapped by a `sqlx::Oid`.
|
||||||
use sqlx::Row;
|
|
||||||
row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index())
|
row.try_get::<Option<Oid>, _>(idx.as_sqlx_postgres_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
||||||
.map(|oid| oid.0)
|
.map(|oid| oid.0)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
|
||||||
row.try_get::<Option<u32>, _>(idx.as_sqlx_sqlite_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
@ -649,20 +632,22 @@ mod postgres_array {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(_) => {
|
QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-mysql", stringify!($type))
|
"{} unsupported by sqlx-mysql",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<Vec<$type>>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(_) => {
|
QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
"{} unsupported by sqlx-sqlite",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
@ -733,20 +718,22 @@ mod postgres_array {
|
|||||||
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_by<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
|
let res: Result<Vec<uuid::Uuid>, TryGetError> = match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-mysql", stringify!($type))
|
"{} unsupported by sqlx-mysql",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<Vec<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<Vec<uuid::Uuid>>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx))),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(_) => {
|
QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
"{} unsupported by sqlx-sqlite",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
QueryResultRow::Mock(row) => {
|
QueryResultRow::Mock(row) => {
|
||||||
row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
|
row.try_get::<Vec<uuid::Uuid>, _>(idx).map_err(|e| {
|
||||||
@ -784,23 +771,24 @@ mod postgres_array {
|
|||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(_) => {
|
QueryResultRow::SqlxMySql(_) => {
|
||||||
panic!("{} unsupported by sqlx-mysql", stringify!($type))
|
Err(type_err(format!("{} unsupported by sqlx-mysql", stringify!($type))).into())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => {
|
||||||
use sqlx::postgres::types::Oid;
|
use sqlx::postgres::types::Oid;
|
||||||
// Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
|
// Since 0.6.0, SQLx has dropped direct mapping from PostgreSQL's OID to Rust's `u32`;
|
||||||
// Instead, `u32` was wrapped by a `sqlx::Oid`.
|
// Instead, `u32` was wrapped by a `sqlx::Oid`.
|
||||||
use sqlx::Row;
|
|
||||||
row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
|
row.try_get::<Option<Vec<Oid>>, _>(idx.as_sqlx_postgres_index())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)))
|
||||||
.map(|oids| oids.into_iter().map(|oid| oid.0).collect())
|
.map(|oids| oids.into_iter().map(|oid| oid.0).collect())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(_) => {
|
QueryResultRow::SqlxSqlite(_) => Err(type_err(format!(
|
||||||
panic!("{} unsupported by sqlx-sqlite", stringify!($type))
|
"{} unsupported by sqlx-sqlite",
|
||||||
}
|
stringify!($type)
|
||||||
|
))
|
||||||
|
.into()),
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
QueryResultRow::Mock(row) => row.try_get(idx).map_err(|e| {
|
||||||
@ -1050,11 +1038,12 @@ where
|
|||||||
|
|
||||||
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
|
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
|
||||||
if cols.len() < len {
|
if cols.len() < len {
|
||||||
Err(TryGetError::DbErr(DbErr::Type(format!(
|
Err(type_err(format!(
|
||||||
"Expect {} column names supplied but got slice of length {}",
|
"Expect {} column names supplied but got slice of length {}",
|
||||||
len,
|
len,
|
||||||
cols.len()
|
cols.len()
|
||||||
))))
|
))
|
||||||
|
.into())
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -1073,26 +1062,20 @@ where
|
|||||||
fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
fn try_get_from_json<I: ColIdx>(res: &QueryResult, idx: I) -> Result<Self, TryGetError> {
|
||||||
match &res.row {
|
match &res.row {
|
||||||
#[cfg(feature = "sqlx-mysql")]
|
#[cfg(feature = "sqlx-mysql")]
|
||||||
QueryResultRow::SqlxMySql(row) => {
|
QueryResultRow::SqlxMySql(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
|
||||||
row.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_mysql_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-postgres")]
|
#[cfg(feature = "sqlx-postgres")]
|
||||||
QueryResultRow::SqlxPostgres(row) => {
|
QueryResultRow::SqlxPostgres(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
|
||||||
row.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_postgres_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "sqlx-sqlite")]
|
#[cfg(feature = "sqlx-sqlite")]
|
||||||
QueryResultRow::SqlxSqlite(row) => {
|
QueryResultRow::SqlxSqlite(row) => row
|
||||||
use sqlx::Row;
|
.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
|
||||||
row.try_get::<Option<sqlx::types::Json<Self>>, _>(idx.as_sqlx_sqlite_index())
|
.map_err(|e| sqlx_error_to_query_err(e).into())
|
||||||
.map_err(|e| TryGetError::DbErr(crate::sqlx_error_to_query_err(e)))
|
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0)),
|
||||||
.and_then(|opt| opt.ok_or_else(|| err_null_idx_col(idx)).map(|json| json.0))
|
|
||||||
}
|
|
||||||
#[cfg(feature = "mock")]
|
#[cfg(feature = "mock")]
|
||||||
QueryResultRow::Mock(row) => row
|
QueryResultRow::Mock(row) => row
|
||||||
.try_get::<serde_json::Value, I>(idx)
|
.try_get::<serde_json::Value, I>(idx)
|
||||||
@ -1100,10 +1083,7 @@ where
|
|||||||
debug_print!("{:#?}", e.to_string());
|
debug_print!("{:#?}", e.to_string());
|
||||||
err_null_idx_col(idx)
|
err_null_idx_col(idx)
|
||||||
})
|
})
|
||||||
.and_then(|json| {
|
.and_then(|json| serde_json::from_value(json).map_err(|e| json_err(e).into())),
|
||||||
serde_json::from_value(json)
|
|
||||||
.map_err(|e| TryGetError::DbErr(DbErr::Json(e.to_string())))
|
|
||||||
}),
|
|
||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -906,11 +906,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if r.is_some() {
|
let rows = match r {
|
||||||
acc.push((l, vec![r.unwrap()]));
|
Some(r) => vec![r],
|
||||||
} else {
|
None => vec![],
|
||||||
acc.push((l, vec![]));
|
};
|
||||||
}
|
acc.push((l, rows));
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(
|
#![deny(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
|
clippy::missing_panics_doc,
|
||||||
|
clippy::unwrap_used,
|
||||||
clippy::print_stderr,
|
clippy::print_stderr,
|
||||||
clippy::print_stdout
|
clippy::print_stdout
|
||||||
)]
|
)]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyToColumn,
|
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, IntoActiveModel, Iterable,
|
||||||
QueryFilter, QueryTrait,
|
PrimaryKeyToColumn, QueryFilter, QueryTrait,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::DeleteStatement;
|
use sea_query::DeleteStatement;
|
||||||
@ -109,10 +109,11 @@ where
|
|||||||
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
|
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
|
||||||
let col = key.into_column();
|
let col = key.into_column();
|
||||||
let av = self.model.get(col);
|
let av = self.model.get(col);
|
||||||
if av.is_set() || av.is_unchanged() {
|
match av {
|
||||||
self = self.filter(col.eq(av.unwrap()));
|
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
|
||||||
} else {
|
self = self.filter(col.eq(value));
|
||||||
panic!("PrimaryKey is not set");
|
}
|
||||||
|
ActiveValue::NotSet => panic!("PrimaryKey is not set"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveModelTrait, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable,
|
ActiveModelTrait, ActiveValue, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable,
|
||||||
PrimaryKeyTrait, QueryTrait,
|
PrimaryKeyTrait, QueryTrait,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
@ -109,6 +109,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a Model to Self
|
/// Add a Model to Self
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if the column value has discrepancy across rows
|
||||||
#[allow(clippy::should_implement_trait)]
|
#[allow(clippy::should_implement_trait)]
|
||||||
pub fn add<M>(mut self, m: M) -> Self
|
pub fn add<M>(mut self, m: M) -> Self
|
||||||
where
|
where
|
||||||
@ -132,9 +136,12 @@ where
|
|||||||
} else if self.columns[idx] != av_has_val {
|
} else if self.columns[idx] != av_has_val {
|
||||||
panic!("columns mismatch");
|
panic!("columns mismatch");
|
||||||
}
|
}
|
||||||
if av_has_val {
|
match av {
|
||||||
|
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
|
||||||
columns.push(col);
|
columns.push(col);
|
||||||
values.push(col.save_as(Expr::val(av.into_value().unwrap())));
|
values.push(col.save_as(Expr::val(value)));
|
||||||
|
}
|
||||||
|
ActiveValue::NotSet => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.query.columns(columns);
|
self.query.columns(columns);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{DbErr, FromQueryResult, QueryResult};
|
use crate::{error::*, FromQueryResult, QueryResult};
|
||||||
use serde_json::Map;
|
use serde_json::Map;
|
||||||
pub use serde_json::Value as JsonValue;
|
pub use serde_json::Value as JsonValue;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ColumnTrait, Condition, ConnectionTrait, DbErr, EntityTrait, Identity, ModelTrait, QueryFilter,
|
error::*, ColumnTrait, Condition, ConnectionTrait, DbErr, EntityTrait, Identity, ModelTrait,
|
||||||
Related, RelationType, Select,
|
QueryFilter, Related, RelationType, Select,
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use sea_query::{Expr, IntoColumnRef, SimpleExpr, ValueTuple};
|
use sea_query::{Expr, IntoColumnRef, SimpleExpr, ValueTuple};
|
||||||
@ -76,9 +76,7 @@ where
|
|||||||
// we verify that is has_one relation
|
// we verify that is has_one relation
|
||||||
match (rel_def).rel_type {
|
match (rel_def).rel_type {
|
||||||
RelationType::HasOne => (),
|
RelationType::HasOne => (),
|
||||||
RelationType::HasMany => {
|
RelationType::HasMany => return Err(type_err("Relation is HasMany instead of HasOne")),
|
||||||
return Err(DbErr::Type("Relation is HasMany instead of HasOne".into()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let keys: Vec<ValueTuple> = self
|
let keys: Vec<ValueTuple> = self
|
||||||
@ -126,9 +124,7 @@ where
|
|||||||
// we verify that is has_many relation
|
// we verify that is has_many relation
|
||||||
match (rel_def).rel_type {
|
match (rel_def).rel_type {
|
||||||
RelationType::HasMany => (),
|
RelationType::HasMany => (),
|
||||||
RelationType::HasOne => {
|
RelationType::HasOne => return Err(type_err("Relation is HasOne instead of HasMany")),
|
||||||
return Err(DbErr::Type("Relation is HasOne instead of HasMany".into()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let keys: Vec<ValueTuple> = self
|
let keys: Vec<ValueTuple> = self
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ActiveModelTrait, ColumnTrait, EntityTrait, Iterable, PrimaryKeyToColumn, QueryFilter,
|
ActiveModelTrait, ActiveValue, ColumnTrait, EntityTrait, Iterable, PrimaryKeyToColumn,
|
||||||
QueryTrait,
|
QueryFilter, QueryTrait,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement};
|
use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement};
|
||||||
@ -92,11 +92,11 @@ where
|
|||||||
fn prepare_filters(mut self) -> Self {
|
fn prepare_filters(mut self) -> Self {
|
||||||
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
|
for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
|
||||||
let col = key.into_column();
|
let col = key.into_column();
|
||||||
let av = self.model.get(col);
|
match self.model.get(col) {
|
||||||
if av.is_set() || av.is_unchanged() {
|
ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
|
||||||
self = self.filter(col.eq(av.unwrap()));
|
self = self.filter(col.eq(value));
|
||||||
} else {
|
}
|
||||||
panic!("PrimaryKey is not set");
|
ActiveValue::NotSet => panic!("PrimaryKey is not set"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
@ -107,11 +107,13 @@ where
|
|||||||
if <A::Entity as EntityTrait>::PrimaryKey::from_column(col).is_some() {
|
if <A::Entity as EntityTrait>::PrimaryKey::from_column(col).is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let av = self.model.get(col);
|
match self.model.get(col) {
|
||||||
if av.is_set() {
|
ActiveValue::Set(value) => {
|
||||||
let expr = col.save_as(Expr::val(av.into_value().unwrap()));
|
let expr = col.save_as(Expr::val(value));
|
||||||
self.query.value(col, expr);
|
self.query.value(col, expr);
|
||||||
}
|
}
|
||||||
|
ActiveValue::Unchanged(_) | ActiveValue::NotSet => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -187,11 +189,13 @@ where
|
|||||||
A: ActiveModelTrait<Entity = E>,
|
A: ActiveModelTrait<Entity = E>,
|
||||||
{
|
{
|
||||||
for col in E::Column::iter() {
|
for col in E::Column::iter() {
|
||||||
let av = model.get(col);
|
match model.get(col) {
|
||||||
if av.is_set() {
|
ActiveValue::Set(value) => {
|
||||||
let expr = col.save_as(Expr::val(av.into_value().unwrap()));
|
let expr = col.save_as(Expr::val(value));
|
||||||
self.query.value(col, expr);
|
self.query.value(col, expr);
|
||||||
}
|
}
|
||||||
|
ActiveValue::Unchanged(_) | ActiveValue::NotSet => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ impl Schema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a column definition for example to update a table.
|
/// Creates a column definition for example to update a table.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use crate::sea_orm::IdenStatic;
|
/// use crate::sea_orm::IdenStatic;
|
||||||
/// use sea_orm::{
|
/// use sea_orm::{
|
||||||
@ -61,6 +62,7 @@ impl Schema {
|
|||||||
///
|
///
|
||||||
/// #[derive(Copy, Clone, Debug, EnumIter)]
|
/// #[derive(Copy, Clone, Debug, EnumIter)]
|
||||||
/// pub enum Relation {}
|
/// pub enum Relation {}
|
||||||
|
///
|
||||||
/// impl RelationTrait for Relation {
|
/// impl RelationTrait for Relation {
|
||||||
/// fn def(&self) -> RelationDef {
|
/// fn def(&self) -> RelationDef {
|
||||||
/// panic!("No RelationDef")
|
/// panic!("No RelationDef")
|
||||||
|
@ -44,7 +44,7 @@ impl PrimaryKeyTrait for PrimaryKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
impl ColumnTrait for Column {
|
impl ColumnTrait for Column {
|
||||||
@ -60,10 +60,4 @@ impl ColumnTrait for Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RelationTrait for Relation {
|
|
||||||
fn def(&self) -> RelationDef {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
@ -62,15 +62,9 @@ pub struct Model {
|
|||||||
pub r#yield: i32,
|
pub r#yield: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
impl RelationTrait for Relation {
|
|
||||||
fn def(&self) -> RelationDef {
|
|
||||||
panic!("No RelationDef")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -9,15 +9,9 @@ pub struct Model {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {}
|
pub enum Relation {}
|
||||||
|
|
||||||
impl RelationTrait for Relation {
|
|
||||||
fn def(&self) -> RelationDef {
|
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::filling::Entity> for Entity {
|
impl Related<super::filling::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
super::filling::Relation::Vendor.def()
|
super::filling::Relation::Vendor.def()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user