diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index eb8f6197..ed9dae54 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -30,7 +30,7 @@ jobs: - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - args: -p psqlpy --all-features -- -W clippy::all -W clippy::pedantic + args: -p psqlpy --all-features -- -W clippy::all -W clippy::pedantic -D warnings pytest: name: ${{matrix.job.os}}-${{matrix.py_version}}-${{ matrix.postgres_version }} strategy: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a30d0b38..0a7ef668 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -58,8 +58,8 @@ repos: - clippy::all - -W - clippy::pedantic - # - -D - # - warnings + - -D + - warnings - id: check types: diff --git a/src/connection/impls.rs b/src/connection/impls.rs index 795554c2..62d9a830 100644 --- a/src/connection/impls.rs +++ b/src/connection/impls.rs @@ -110,6 +110,7 @@ impl Connection for SingleConnection { } impl StartTransaction for SingleConnection { + #[allow(clippy::used_underscore_items)] async fn start_transaction( &mut self, isolation_level: Option, @@ -125,6 +126,7 @@ impl StartTransaction for SingleConnection { } impl CloseTransaction for SingleConnection { + #[allow(clippy::used_underscore_items)] async fn commit(&mut self) -> PSQLPyResult<()> { self._commit().await?; self.in_transaction = false; @@ -132,6 +134,7 @@ impl CloseTransaction for SingleConnection { Ok(()) } + #[allow(clippy::used_underscore_items)] async fn rollback(&mut self) -> PSQLPyResult<()> { self._rollback().await?; self.in_transaction = false; @@ -193,6 +196,7 @@ impl Connection for PoolConnection { } impl StartTransaction for PoolConnection { + #[allow(clippy::used_underscore_items)] async fn start_transaction( &mut self, isolation_level: Option, @@ -206,6 +210,7 @@ impl StartTransaction for PoolConnection { } impl CloseTransaction for PoolConnection { + #[allow(clippy::used_underscore_items)] async fn commit(&mut self) -> PSQLPyResult<()> { self._commit().await?; self.in_transaction = false; @@ -213,6 +218,7 @@ impl CloseTransaction for PoolConnection { Ok(()) } + #[allow(clippy::used_underscore_items)] async fn rollback(&mut self) -> PSQLPyResult<()> { self._rollback().await?; self.in_transaction = false; @@ -324,6 +330,7 @@ impl CloseTransaction for PSQLPyConnection { } impl PSQLPyConnection { + #[must_use] pub fn in_transaction(&self) -> bool { match self { PSQLPyConnection::PoolConn(conn) => conn.in_transaction, @@ -331,6 +338,10 @@ impl PSQLPyConnection { } } + /// Prepare internal `PSQLPy` statement + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn prepare_statement( &self, querystring: String, @@ -341,6 +352,10 @@ impl PSQLPyConnection { .await } + /// Execute prepared `PSQLPy` statement. + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn execute_statement( &self, statement: &PsqlpyStatement, @@ -352,6 +367,10 @@ impl PSQLPyConnection { Ok(PSQLDriverPyQueryResult::new(result)) } + /// Execute raw query with parameters. + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn execute( &self, querystring: String, @@ -363,15 +382,12 @@ impl PSQLPyConnection { .await?; let prepared = prepared.unwrap_or(true); - let result = match prepared { - true => { - self.query(statement.statement_query()?, &statement.params()) - .await - } - false => { - self.query_typed(statement.raw_query(), &statement.params_typed()) - .await - } + let result = if prepared { + self.query(statement.statement_query()?, &statement.params()) + .await + } else { + self.query_typed(statement.raw_query(), &statement.params_typed()) + .await }; let return_result = result.map_err(|err| { @@ -383,6 +399,10 @@ impl PSQLPyConnection { Ok(PSQLDriverPyQueryResult::new(return_result)) } + /// Execute many queries without return. + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn execute_many( &self, querystring: String, @@ -431,6 +451,11 @@ impl PSQLPyConnection { Ok(()) } + /// Execute raw query with parameters. Return one raw row + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn fetch_row_raw( &self, querystring: String, @@ -466,6 +491,11 @@ impl PSQLPyConnection { Ok(result) } + /// Execute raw query with parameters. Return one row + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn fetch_row( &self, querystring: String, @@ -479,6 +509,11 @@ impl PSQLPyConnection { Ok(PSQLDriverSinglePyQueryResult::new(result)) } + /// Execute raw query with parameters. Return single python object + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn fetch_val( &self, querystring: String, @@ -495,6 +530,11 @@ impl PSQLPyConnection { }) } + /// Create new sink for COPY operation. + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn copy_in(&self, statement: &T) -> PSQLPyResult> where T: ?Sized + ToStatement, @@ -510,6 +550,14 @@ impl PSQLPyConnection { } } + /// Create and open new transaction. + /// + /// Unsafe here isn't a problem cuz it is stored within + /// the struct with the connection created this transaction. + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn transaction(&mut self) -> PSQLPyResult { match self { PSQLPyConnection::PoolConn(conn) => { @@ -531,33 +579,33 @@ impl PSQLPyConnection { } } + /// Create new Portal (server-side byte cursor). + /// + /// # Errors + /// May return error if there is some problem with DB communication. + /// Or if cannot build statement. pub async fn portal( &mut self, querystring: Option<&String>, parameters: &Option>, statement: Option<&PsqlpyStatement>, ) -> PSQLPyResult<(PSQLPyTransaction, tp_Portal)> { - let statement = { - match statement { - Some(stmt) => stmt, - None => { - let Some(querystring) = querystring else { - return Err(RustPSQLDriverError::ConnectionExecuteError( - "Can't create cursor without querystring".into(), - )); - }; - - &StatementBuilder::new(querystring, parameters, self, Some(false)) - .build() - .await? - } - } + let stmt = if let Some(stmt) = statement { + stmt + } else { + let Some(querystring) = querystring else { + return Err(RustPSQLDriverError::ConnectionExecuteError( + "Can't create cursor without querystring".into(), + )); + }; + + &StatementBuilder::new(querystring, parameters, self, Some(false)) + .build() + .await? }; let transaction = self.transaction().await?; - let inner_portal = transaction - .portal(statement.raw_query(), &statement.params()) - .await?; + let inner_portal = transaction.portal(stmt.raw_query(), &stmt.params()).await?; Ok((transaction, inner_portal)) } diff --git a/src/connection/structs.rs b/src/connection/structs.rs index a50d3d69..9cbd9d05 100644 --- a/src/connection/structs.rs +++ b/src/connection/structs.rs @@ -12,6 +12,7 @@ pub struct PoolConnection { } impl PoolConnection { + #[must_use] pub fn new(connection: Object, pg_config: Arc) -> Self { Self { connection, @@ -31,6 +32,7 @@ pub struct SingleConnection { } impl SingleConnection { + #[must_use] pub fn new(connection: Client, pg_config: Arc) -> Self { Self { connection, diff --git a/src/connection/traits.rs b/src/connection/traits.rs index 1e9d0960..697256e6 100644 --- a/src/connection/traits.rs +++ b/src/connection/traits.rs @@ -57,7 +57,7 @@ pub trait Transaction { if let Some(level) = isolation_level { let level = &level.to_str_level(); querystring.push_str(format!(" ISOLATION LEVEL {level}").as_str()); - }; + } querystring.push_str(match read_variant { Some(ReadVariant::ReadOnly) => " READ ONLY", diff --git a/src/driver/common.rs b/src/driver/common.rs index dc92a28f..3c22517a 100644 --- a/src/driver/common.rs +++ b/src/driver/common.rs @@ -133,20 +133,21 @@ macro_rules! impl_cursor_method { #[pymethods] impl $name { #[pyo3(signature = (querystring=None, parameters=None, array_size=None))] + #[must_use] pub fn cursor( &self, querystring: Option, parameters: Option>, array_size: Option, - ) -> PSQLPyResult { - Ok(Cursor::new( + ) -> Cursor { + Cursor::new( self.conn.clone(), querystring, parameters, array_size, self.pg_config.clone(), None, - )) + ) } } }; @@ -159,6 +160,10 @@ macro_rules! impl_prepare_method { ($name:ident) => { #[pymethods] impl $name { + /// Create new prepared statement. + /// + /// # Errors + /// May return error if there is some problem with DB communication. #[pyo3(signature = (querystring, parameters=None))] pub async fn prepare( &self, @@ -191,6 +196,10 @@ macro_rules! impl_transaction_methods { ($name:ident, $val:expr $(,)?) => { #[pymethods] impl $name { + /// Commit existing transaction. + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn commit(&mut self) -> PSQLPyResult<()> { let conn = self.conn.clone(); let Some(conn) = conn else { @@ -206,6 +215,10 @@ macro_rules! impl_transaction_methods { Ok(()) } + /// Rollback existing transaction. + /// + /// # Errors + /// May return error if there is some problem with DB communication. pub async fn rollback(&mut self) -> PSQLPyResult<()> { let conn = self.conn.clone(); let Some(conn) = conn else { @@ -230,6 +243,10 @@ macro_rules! impl_binary_copy_method { ($name:ident) => { #[pymethods] impl $name { + /// Perform binary copy to table. + /// + /// # Errors + /// May return error if there is some problem with DB communication. #[pyo3(signature = (source, table_name, columns=None, schema_name=None))] pub async fn binary_copy_to_table( self_: pyo3::Py, diff --git a/src/driver/connection.rs b/src/driver/connection.rs index 0d562b00..a89f3edd 100644 --- a/src/driver/connection.rs +++ b/src/driver/connection.rs @@ -158,7 +158,7 @@ impl Connection { read_conn_g.in_transaction() } - async fn __aenter__<'a>(self_: Py) -> PSQLPyResult> { + async fn __aenter__(self_: Py) -> PSQLPyResult> { let (db_client, db_pool, pg_config) = pyo3::Python::with_gil(|gil| { let self_ = self_.borrow(gil); ( @@ -191,7 +191,7 @@ impl Connection { } #[allow(clippy::unused_async)] - async fn __aexit__<'a>( + async fn __aexit__( self_: Py, _exception_type: Py, exception: Py, @@ -278,7 +278,7 @@ impl Connection { /// 1) Cannot convert python parameters /// 2) Cannot execute querystring. #[pyo3(signature = (querystring, parameters=None, prepared=None))] - pub async fn execute_many<'a>( + pub async fn execute_many( self_: pyo3::Py, querystring: String, parameters: Option>>, @@ -369,7 +369,7 @@ impl Connection { /// 2) Cannot execute querystring. /// 3) Query returns more than one row #[pyo3(signature = (querystring, parameters=None, prepared=None))] - pub async fn fetch_val<'a>( + pub async fn fetch_val( self_: pyo3::Py, querystring: String, parameters: Option>, diff --git a/src/driver/connection_pool.rs b/src/driver/connection_pool.rs index 7d7d96e8..d75094ab 100644 --- a/src/driver/connection_pool.rs +++ b/src/driver/connection_pool.rs @@ -244,6 +244,10 @@ impl ConnectionPool { } } + /// Retrieve new connection from the pool. + /// + /// # Errors + /// May return error if cannot get new connection. pub async fn retrieve_connection(&mut self) -> PSQLPyResult { let connection = self.pool.get().await?; @@ -406,7 +410,7 @@ impl ConnectionPool { (b_gil.pg_config.clone(), b_gil.pool_conf.clone()) }); - Listener::new(pg_config, pool_conf.ca_file, pool_conf.ssl_mode) + Listener::new(&pg_config, pool_conf.ca_file, pool_conf.ssl_mode) } /// Return new single connection. diff --git a/src/driver/connection_pool_builder.rs b/src/driver/connection_pool_builder.rs index dcecd761..29012a78 100644 --- a/src/driver/connection_pool_builder.rs +++ b/src/driver/connection_pool_builder.rs @@ -52,7 +52,7 @@ impl ConnectionPoolBuilder { mgr_config = ManagerConfig { recycling_method: RecyclingMethod::Fast, }; - }; + } let mgr: Manager = build_manager( mgr_config, diff --git a/src/driver/cursor.rs b/src/driver/cursor.rs index 1dde4723..b0eed718 100644 --- a/src/driver/cursor.rs +++ b/src/driver/cursor.rs @@ -32,6 +32,7 @@ pub struct Cursor { } impl Cursor { + #[must_use] pub fn new( conn: Option>>, querystring: Option, @@ -90,7 +91,8 @@ impl Cursor { slf } - async fn __aenter__<'a>(slf: Py) -> PSQLPyResult> { + #[allow(clippy::single_match_else)] + async fn __aenter__(slf: Py) -> PSQLPyResult> { let (conn, querystring, parameters, statement) = Python::with_gil(|gil| { let self_ = slf.borrow(gil); ( @@ -132,8 +134,8 @@ impl Cursor { Ok(slf) } - #[allow(clippy::needless_pass_by_value)] - async fn __aexit__<'a>( + #[allow(clippy::needless_pass_by_value, clippy::unused_async)] + async fn __aexit__( &mut self, _exception_type: Py, exception: Py, @@ -174,7 +176,7 @@ impl Cursor { "Iteration is over, no more results in portal", ) .into()); - }; + } Ok(result) }) @@ -183,6 +185,7 @@ impl Cursor { Ok(Some(py_future?)) } + #[allow(clippy::single_match_else)] async fn start(&mut self) -> PSQLPyResult<()> { let Some(conn) = &self.conn else { return Err(RustPSQLDriverError::ConnectionClosedError); diff --git a/src/driver/listener/core.rs b/src/driver/listener/core.rs index 8ae57d22..7d37679f 100644 --- a/src/driver/listener/core.rs +++ b/src/driver/listener/core.rs @@ -45,7 +45,11 @@ pub struct Listener { impl Listener { #[must_use] - pub fn new(pg_config: Arc, ca_file: Option, ssl_mode: Option) -> Self { + pub fn new( + pg_config: &Arc, + ca_file: Option, + ssl_mode: Option, + ) -> Self { Listener { pg_config: pg_config.clone(), ca_file, @@ -92,12 +96,12 @@ impl Listener { } #[allow(clippy::unused_async)] - async fn __aenter__<'a>(slf: Py) -> PSQLPyResult> { + async fn __aenter__(slf: Py) -> PSQLPyResult> { Ok(slf) } #[allow(clippy::unused_async)] - async fn __aexit__<'a>( + async fn __aexit__( slf: Py, _exception_type: Py, exception: Py, @@ -234,6 +238,8 @@ impl Listener { Ok(()) } + /// TODO: remove clippy ignore after removing async + #[allow(clippy::unused_async)] async fn shutdown(&mut self) { self.abort_listen(); std::mem::take(&mut self.connection); diff --git a/src/driver/listener/structs.rs b/src/driver/listener/structs.rs index 6236547e..f557403b 100644 --- a/src/driver/listener/structs.rs +++ b/src/driver/listener/structs.rs @@ -22,7 +22,7 @@ impl ChannelCallbacks { Entry::Occupied(mut e) => { e.get_mut().push(callback); } - }; + } } #[must_use] diff --git a/src/driver/prepared_statement.rs b/src/driver/prepared_statement.rs index 03b6c27d..43a69979 100644 --- a/src/driver/prepared_statement.rs +++ b/src/driver/prepared_statement.rs @@ -22,6 +22,7 @@ pub struct PreparedStatement { } impl PreparedStatement { + #[must_use] pub fn new( conn: Option>>, pg_config: Arc, @@ -46,15 +47,15 @@ impl PreparedStatement { read_conn_g.execute_statement(&self.statement).await } - fn cursor(&self) -> PSQLPyResult { - Ok(Cursor::new( + fn cursor(&self) -> Cursor { + Cursor::new( self.conn.clone(), None, None, None, self.pg_config.clone(), Some(self.statement.clone()), - )) + ) } fn columns(&self) -> Vec { diff --git a/src/driver/transaction.rs b/src/driver/transaction.rs index 781d95d3..75e3dfec 100644 --- a/src/driver/transaction.rs +++ b/src/driver/transaction.rs @@ -31,6 +31,7 @@ pub struct Transaction { } impl Transaction { + #[must_use] pub fn new( conn: Option>>, pg_config: Arc, @@ -59,7 +60,7 @@ impl Transaction { self_ } - async fn __aenter__<'a>(self_: Py) -> PSQLPyResult> { + async fn __aenter__(self_: Py) -> PSQLPyResult> { let (isolation_level, read_variant, deferrable, conn) = pyo3::Python::with_gil(|gil| { let self_ = self_.borrow(gil); ( @@ -82,7 +83,7 @@ impl Transaction { } #[allow(clippy::needless_pass_by_value)] - async fn __aexit__<'a>( + async fn __aexit__( self_: Py, _exception_type: Py, exception: Py, @@ -118,6 +119,10 @@ impl Transaction { } } + /// Begin the transaction. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. pub async fn begin(&mut self) -> PSQLPyResult<()> { let conn = &self.conn; let Some(conn) = conn else { @@ -131,6 +136,10 @@ impl Transaction { Ok(()) } + /// Execute querystring with parameters. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn execute( &self, @@ -146,6 +155,10 @@ impl Transaction { read_conn_g.execute(querystring, parameters, prepared).await } + /// Execute querystring with parameters. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn fetch( &self, @@ -161,6 +174,11 @@ impl Transaction { read_conn_g.execute(querystring, parameters, prepared).await } + /// Execute querystring with parameters and return single value. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. + /// Or if query returns more than one value. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn fetch_val( &self, @@ -178,6 +196,14 @@ impl Transaction { .await } + /// Executes a sequence of SQL statements using the simple query protocol. + /// + /// Statements should be separated by semicolons. + /// If an error occurs, execution of the sequence will stop at that point. + /// This is intended for use when, for example, initializing a database schema. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. pub async fn execute_batch(&self, querystring: String) -> PSQLPyResult<()> { let Some(conn) = &self.conn else { return Err(RustPSQLDriverError::TransactionClosedError); @@ -187,6 +213,10 @@ impl Transaction { read_conn_g.batch_execute(&querystring).await } + /// Executes one query with different parameters. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn execute_many( &self, @@ -204,6 +234,10 @@ impl Transaction { .await } + /// Executes query and return one row. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. #[pyo3(signature = (querystring, parameters=None, prepared=None))] pub async fn fetch_row( &self, @@ -221,6 +255,10 @@ impl Transaction { .await } + /// Create new savepoint in a transaction. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. pub async fn create_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { let Some(conn) = &self.conn else { return Err(RustPSQLDriverError::TransactionClosedError); @@ -234,6 +272,10 @@ impl Transaction { Ok(()) } + /// Release a savepoint in a transaction. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. pub async fn release_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { let Some(conn) = &self.conn else { return Err(RustPSQLDriverError::TransactionClosedError); @@ -247,6 +289,10 @@ impl Transaction { Ok(()) } + /// Rollback to a savepoint in a transaction. + /// + /// # Errors + /// Can return error if there is a problem with DB communication. pub async fn rollback_savepoint(&mut self, savepoint_name: String) -> PSQLPyResult<()> { let Some(conn) = &self.conn else { return Err(RustPSQLDriverError::TransactionClosedError); @@ -260,8 +306,16 @@ impl Transaction { Ok(()) } + /// Execute many queries in a transaction. + /// + /// More information in a documentation: + /// https://psqlpy-python.github.io/components/transaction.html#pipeline + /// + /// # Errors + /// Can return error if there is a problem with DB communication. + #[allow(for_loops_over_fallibles)] #[pyo3(signature = (queries=None, prepared=None))] - pub async fn pipeline<'py>( + pub async fn pipeline( self_: Py, queries: Option>, prepared: Option, diff --git a/src/extra_types.rs b/src/extra_types.rs index b3411eae..88c350bd 100644 --- a/src/extra_types.rs +++ b/src/extra_types.rs @@ -347,6 +347,7 @@ macro_rules! build_array_type { self.inner.clone() } + #[must_use] pub fn element_type() -> Type { $elem_kind } diff --git a/src/statement/cache.rs b/src/statement/cache.rs index a0f071d8..90ba70ee 100644 --- a/src/statement/cache.rs +++ b/src/statement/cache.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use once_cell::sync::Lazy; use postgres_types::Type; use tokio::sync::RwLock; use tokio_postgres::Statement; @@ -54,5 +53,5 @@ impl StatementCacheInfo { } } -pub(crate) static STMTS_CACHE: Lazy> = - Lazy::new(|| RwLock::new(Default::default())); +pub(crate) static STMTS_CACHE: std::sync::LazyLock> = + std::sync::LazyLock::new(|| RwLock::new(StatementsCache::default())); diff --git a/src/statement/mod.rs b/src/statement/mod.rs index c894b9a8..c5a82349 100644 --- a/src/statement/mod.rs +++ b/src/statement/mod.rs @@ -1,6 +1,7 @@ pub mod cache; pub mod parameters; pub mod query; +#[allow(clippy::module_inception)] pub mod statement; pub mod statement_builder; pub mod utils; diff --git a/src/statement/parameters.rs b/src/statement/parameters.rs index 6b74b902..ac3f433f 100644 --- a/src/statement/parameters.rs +++ b/src/statement/parameters.rs @@ -26,6 +26,7 @@ pub struct Column { } impl Column { + #[must_use] pub fn new(name: String, table_oid: Option) -> Self { Self { name, table_oid } } @@ -52,12 +53,12 @@ pub(crate) struct ParametersBuilder { impl ParametersBuilder { pub fn new( - parameters: &Option, + parameters: Option<&PyObject>, types: Option>, columns: Vec, ) -> Self { Self { - parameters: parameters.clone(), + parameters: parameters.cloned(), types, columns, } @@ -98,7 +99,7 @@ impl ParametersBuilder { prepared_parameters = Some( MappingParametersBuilder::new(mapping, self.types, self.columns) .prepare(gil, parameters_names)?, - ) + ); } } _ => {} @@ -217,8 +218,7 @@ impl MappingParametersBuilder { Ok(param_value) => params_as_pyobject.push(param_value.unbind()), Err(_) => { return Err(RustPSQLDriverError::PyToRustValueConversionError(format!( - "Cannot find parameter with name <{}>", - param_name + "Cannot find parameter with name <{param_name}>", ))) } } @@ -286,6 +286,7 @@ pub struct PreparedParameters { } impl PreparedParameters { + #[must_use] pub fn new(parameters: Vec, types: Vec, columns: Vec) -> Self { Self { parameters, @@ -294,6 +295,7 @@ impl PreparedParameters { } } + #[must_use] pub fn params(&self) -> Box<[&(dyn ToSql + Sync)]> { let params_ref = &self.parameters; params_ref @@ -303,6 +305,7 @@ impl PreparedParameters { .into_boxed_slice() } + #[must_use] pub fn params_typed(&self) -> Box<[(&(dyn ToSql + Sync), Type)]> { let params_ref = &self.parameters; let types = self.types.clone(); @@ -313,6 +316,7 @@ impl PreparedParameters { .into_boxed_slice() } + #[must_use] pub fn columns(&self) -> &Vec { &self.columns } diff --git a/src/statement/query.rs b/src/statement/query.rs index 54d78266..312cdad0 100644 --- a/src/statement/query.rs +++ b/src/statement/query.rs @@ -21,9 +21,10 @@ impl Display for QueryString { } impl QueryString { - pub fn new(initial_qs: &String) -> Self { + #[must_use] + pub fn new(initial_qs: &str) -> Self { Self { - initial_qs: initial_qs.clone(), + initial_qs: initial_qs.to_owned(), converted_qs: None, } } diff --git a/src/statement/statement.rs b/src/statement/statement.rs index b1f85f53..e13900c3 100644 --- a/src/statement/statement.rs +++ b/src/statement/statement.rs @@ -28,10 +28,15 @@ impl PsqlpyStatement { } } + #[must_use] pub fn raw_query(&self) -> &str { self.query.query() } + /// Return tokio-postgres prepared statement. + /// + /// # Errors + /// May return error if there is no prepared stmt from tokio-postgres. pub fn statement_query(&self) -> PSQLPyResult<&Statement> { match &self.prepared_statement { Some(prepared_stmt) => Ok(prepared_stmt), @@ -41,14 +46,17 @@ impl PsqlpyStatement { } } + #[must_use] pub fn params(&self) -> Box<[&(dyn ToSql + Sync)]> { self.prepared_parameters.params() } + #[must_use] pub fn params_typed(&self) -> Box<[(&(dyn ToSql + Sync), Type)]> { self.prepared_parameters.params_typed() } + #[must_use] pub fn columns(&self) -> &Vec { self.prepared_parameters.columns() } diff --git a/src/statement/statement_builder.rs b/src/statement/statement_builder.rs index 9c9b27bd..1ad81704 100644 --- a/src/statement/statement_builder.rs +++ b/src/statement/statement_builder.rs @@ -22,6 +22,7 @@ pub struct StatementBuilder<'a> { } impl<'a> StatementBuilder<'a> { + #[must_use] pub fn new( querystring: &'a String, parameters: &'a Option, @@ -36,6 +37,10 @@ impl<'a> StatementBuilder<'a> { } } + /// Build new internal statement. + /// + /// # Errors + /// May return error if cannot prepare statement. pub async fn build(self) -> PSQLPyResult { if !self.prepared { { @@ -51,8 +56,11 @@ impl<'a> StatementBuilder<'a> { } fn build_with_cached(self, cached: StatementCacheInfo) -> PSQLPyResult { - let raw_parameters = - ParametersBuilder::new(self.parameters, Some(cached.types()), cached.columns()); + let raw_parameters = ParametersBuilder::new( + self.parameters.as_ref(), + Some(cached.types()), + cached.columns(), + ); let parameters_names = cached .query @@ -84,7 +92,7 @@ impl<'a> StatementBuilder<'a> { .map(|column| Column::new(column.name().to_string(), column.table_oid())) .collect::>(); let parameters_builder = ParametersBuilder::new( - self.parameters, + self.parameters.as_ref(), Some(prepared_stmt.params().to_vec()), columns, ); @@ -96,22 +104,19 @@ impl<'a> StatementBuilder<'a> { let prepared_parameters = parameters_builder.prepare(parameters_names)?; - match self.prepared { - true => Ok(PsqlpyStatement::new( + if self.prepared { + Ok(PsqlpyStatement::new( querystring, prepared_parameters, Some(prepared_stmt), - )), - false => { - self.write_to_cache(cache_guard, &querystring, &prepared_stmt) - .await; - Ok(PsqlpyStatement::new(querystring, prepared_parameters, None)) - } + )) + } else { + Self::write_to_cache(cache_guard, &querystring, &prepared_stmt); + Ok(PsqlpyStatement::new(querystring, prepared_parameters, None)) } } - async fn write_to_cache( - &self, + fn write_to_cache( mut cache_guard: RwLockWriteGuard<'_, StatementsCache>, query: &QueryString, inner_stmt: &Statement, diff --git a/src/transaction/impls.rs b/src/transaction/impls.rs index a2a7c147..95b02d63 100644 --- a/src/transaction/impls.rs +++ b/src/transaction/impls.rs @@ -4,6 +4,10 @@ use super::structs::PSQLPyTransaction; use tokio_postgres::{Portal as tp_Portal, ToStatement}; impl PSQLPyTransaction { + /// Query the portal (server-side cursor) to retrieve next elements. + /// + /// # Errors + /// May return error if there is a problem with DB communication. pub async fn query_portal( &self, portal: &tp_Portal, @@ -17,6 +21,10 @@ impl PSQLPyTransaction { Ok(PSQLDriverPyQueryResult::new(portal_res)) } + /// Create new portal (server-side cursor). + /// + /// # Errors + /// May return error if there is a problem with DB communication. pub async fn portal( &self, querystring: &T, diff --git a/src/value_converter/consts.rs b/src/value_converter/consts.rs index 82a34f0f..fe4b7b34 100644 --- a/src/value_converter/consts.rs +++ b/src/value_converter/consts.rs @@ -1,6 +1,3 @@ -use once_cell::sync::Lazy; -use std::{collections::HashMap, sync::RwLock}; - use pyo3::{ sync::GILOnceCell, types::{PyAnyMethods, PyType}, @@ -11,9 +8,8 @@ pub static KWARGS_PARAMS_REGEXP: &str = r"\$\(([^)]+)\)p"; pub static DECIMAL_CLS: GILOnceCell> = GILOnceCell::new(); pub static TIMEDELTA_CLS: GILOnceCell> = GILOnceCell::new(); -pub static KWARGS_QUERYSTRINGS: Lazy)>>> = - Lazy::new(|| RwLock::new(Default::default())); +#[allow(clippy::missing_errors_doc)] pub fn get_decimal_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> { DECIMAL_CLS .get_or_try_init(py, || { @@ -23,6 +19,7 @@ pub fn get_decimal_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> { .map(|ty| ty.bind(py)) } +#[allow(clippy::missing_errors_doc)] pub fn get_timedelta_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> { TIMEDELTA_CLS .get_or_try_init(py, || { diff --git a/src/value_converter/dto/funcs.rs b/src/value_converter/dto/funcs.rs index 116db7d0..eec045e0 100644 --- a/src/value_converter/dto/funcs.rs +++ b/src/value_converter/dto/funcs.rs @@ -1,5 +1,6 @@ use postgres_types::Type; +#[must_use] pub fn array_type_to_single_type(array_type: &Type) -> Type { match *array_type { Type::BOOL_ARRAY => Type::BOOL, diff --git a/src/value_converter/from_python.rs b/src/value_converter/from_python.rs index 6c1c0022..c2d069c7 100644 --- a/src/value_converter/from_python.rs +++ b/src/value_converter/from_python.rs @@ -581,7 +581,6 @@ pub fn py_sequence_into_flat_vec( final_vec.append(&mut next_vec); } else { final_vec.push(from_python_typed(&ok_seq_elem, type_)?); - continue; } } @@ -627,7 +626,7 @@ fn convert_py_to_rust_coord_values(parameters: Vec>) -> PSQLPyResult, RustPSQLDriverError>(coord_values_vec) @@ -693,7 +692,7 @@ pub fn build_geo_coords( return Err(RustPSQLDriverError::PyToRustValueConversionError( "Inner coordinates must be passed as pairs of int/float in list/tuple/set or as flat structure with int/float values".into(), )); - }; + } Ok::, RustPSQLDriverError>(result_vec) })?; @@ -735,7 +734,7 @@ pub fn build_flat_geo_coords( return Err(RustPSQLDriverError::PyToRustValueConversionError(format!( "Invalid number of values for this geo type, allowed {allowed_length}, got: {parameters_length}" ))); - }; + } let result_vec = convert_py_to_rust_coord_values(parameters)?; @@ -744,7 +743,7 @@ pub fn build_flat_geo_coords( return Err(RustPSQLDriverError::PyToRustValueConversionError(format!( "Invalid number of values for this geo type, allowed {allowed_length}, got: {parameters_length}" ))); - }; + } Ok::, RustPSQLDriverError>(result_vec) }) @@ -783,7 +782,7 @@ fn py_sequence_to_rust(bind_parameters: &Bound) -> PSQLPyResult>, RustPSQLDriverError>(coord_values_sequence_vec) } diff --git a/src/value_converter/models/interval.rs b/src/value_converter/models/interval.rs index e4aa9ae1..02a1ee4a 100644 --- a/src/value_converter/models/interval.rs +++ b/src/value_converter/models/interval.rs @@ -22,10 +22,10 @@ impl<'py> IntoPyObject<'py> for InnerInterval { let months = self.0.months * 30; let _ = pydict.set_item("days", self.0.days + months); let _ = pydict.set_item("microseconds", self.0.microseconds); - let ret = td_cls + let timedelta = td_cls .call((), Some(&pydict)) .expect("failed to call datetime.timedelta(days=<>, microseconds=<>)"); - match ret.into_pyobject(py) { + match timedelta.into_pyobject(py) { Ok(res) => Ok(res), Err(_) => unreachable!(), } diff --git a/src/value_converter/models/serde_value.rs b/src/value_converter/models/serde_value.rs index 8d61d5a8..222ffe56 100644 --- a/src/value_converter/models/serde_value.rs +++ b/src/value_converter/models/serde_value.rs @@ -126,6 +126,9 @@ pub fn build_serde_value(value: &Bound<'_, PyAny>) -> PSQLPyResult { /// Convert Array of `PythonDTO`s to serde `Value`. /// /// It can convert multidimensional arrays. +/// +/// # Errors +/// May return error if cannot create serde value. pub fn pythondto_array_to_serde(array: Option>) -> PSQLPyResult { match array { Some(array) => inner_pythondto_array_to_serde( @@ -167,7 +170,7 @@ fn inner_pythondto_array_to_serde( _ => unreachable!(), } lower_bound += next_dimension.len as usize; - }; + } } return Ok(final_list); diff --git a/src/value_converter/to_python.rs b/src/value_converter/to_python.rs index a7495775..abc734c8 100644 --- a/src/value_converter/to_python.rs +++ b/src/value_converter/to_python.rs @@ -136,7 +136,7 @@ where ); final_list.append(inner_pylist).unwrap(); lower_bound += next_dimension.len as usize; - }; + } } return final_list.unbind(); diff --git a/src/value_converter/traits.rs b/src/value_converter/traits.rs index d9d3512e..58f373ca 100644 --- a/src/value_converter/traits.rs +++ b/src/value_converter/traits.rs @@ -6,10 +6,12 @@ use crate::exceptions::rust_errors::PSQLPyResult; use super::dto::enums::PythonDTO; pub trait ToPythonDTO { + #[allow(clippy::missing_errors_doc)] fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> PSQLPyResult; } pub trait ToPythonDTOArray { + #[allow(clippy::missing_errors_doc)] fn to_python_dto( python_param: &pyo3::Bound<'_, PyAny>, array_type_: Type,