Skip to content

Commit 75b587b

Browse files
authored
Merge pull request #23 from qaspen-python/feature/add_performance_changes
Added some performance changes
2 parents 2d1e665 + 6cf2320 commit 75b587b

File tree

10 files changed

+166
-183
lines changed

10 files changed

+166
-183
lines changed

Cargo.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ Or you can build it by yourself. To do it, install stable rust and [maturin](htt
3333
## Usage
3434

3535
Usage is as easy as possible.
36-
Create new instance of PSQLPool, startup it and start querying.
36+
Create new instance of PSQLPool and start querying.
37+
You don't need to startup connection pool, the connection pool will create connections as needed.
3738

3839
```python
3940
from typing import Any
@@ -51,8 +52,34 @@ db_pool = PSQLPool(
5152
)
5253

5354
async def main() -> None:
54-
await db_pool.startup()
55+
res: QueryResult = await db_pool.execute(
56+
"SELECT * FROM users",
57+
)
5558

59+
print(res.result())
60+
# You don't need to close Database Pool by yourself,
61+
# rust does it instead.
62+
63+
```
64+
65+
Or you can create connection pool with this function:
66+
67+
```python
68+
from typing import Any
69+
70+
from psqlpy import PSQLPool, QueryResult, create_connection_pool
71+
72+
73+
db_pool: PSQLPool = create_connection_pool(
74+
username="postgres",
75+
password="pg_password",
76+
host="localhost",
77+
port=5432,
78+
db_name="postgres",
79+
max_db_pool_size=2,
80+
)
81+
82+
async def main() -> None:
5683
res: QueryResult = await db_pool.execute(
5784
"SELECT * FROM users",
5885
)

python/psqlpy/_internal/__init__.pyi

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,3 +856,27 @@ class PSQLPool:
856856
857857
It acquires new connection from the database pool.
858858
"""
859+
860+
def create_connection_pool(
861+
dsn: Optional[str] = None,
862+
username: Optional[str] = None,
863+
password: Optional[str] = None,
864+
host: Optional[str] = None,
865+
port: Optional[int] = None,
866+
db_name: Optional[str] = None,
867+
max_db_pool_size: Optional[str] = None,
868+
conn_recycling_method: Optional[ConnRecyclingMethod] = None,
869+
) -> PSQLPool:
870+
"""Create new connection pool.
871+
872+
### Parameters:
873+
- `dsn`: full dsn connection string.
874+
`postgres://postgres:postgres@localhost:5432/postgres?target_session_attrs=read-write`
875+
- `username`: username of the user in postgres
876+
- `password`: password of the user in postgres
877+
- `host`: host of postgres
878+
- `port`: port of postgres
879+
- `db_name`: name of the database in postgres
880+
- `max_db_pool_size`: maximum size of the connection pool
881+
- `conn_recycling_method`: how a connection is recycled.
882+
"""

python/tests/conftest.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,13 @@ async def psql_pool(
8181
postgres_port: int,
8282
postgres_dbname: str,
8383
) -> PSQLPool:
84-
pg_pool = PSQLPool(
84+
return PSQLPool(
8585
username=postgres_user,
8686
password=postgres_password,
8787
host=postgres_host,
8888
port=postgres_port,
8989
db_name=postgres_dbname,
9090
)
91-
await pg_pool.startup()
92-
return pg_pool
9391

9492

9593
@pytest.fixture(autouse=True)

python/tests/test_connection_pool.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ async def test_pool_dsn_startup() -> None:
1111
pg_pool = PSQLPool(
1212
dsn="postgres://postgres:postgres@localhost:5432/psqlpy_test",
1313
)
14-
await pg_pool.startup()
1514

1615
await pg_pool.execute("SELECT 1")
1716

@@ -57,8 +56,6 @@ async def test_pool_conn_recycling_method(
5756
conn_recycling_method=conn_recycling_method,
5857
)
5958

60-
await pg_pool.startup()
61-
6259
await pg_pool.execute("SELECT 1")
6360

6461

@@ -68,8 +65,6 @@ async def test_close_connection_pool() -> None:
6865
dsn="postgres://postgres:postgres@localhost:5432/psqlpy_test",
6966
)
7067

71-
await pg_pool.startup()
72-
7368
await pg_pool.execute("SELECT 1")
7469

7570
await pg_pool.close()

src/common.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub fn add_module(
3535
/// # Errors
3636
///
3737
/// May return Err Result if future acts incorrect.
38-
pub fn rustengine_future<F, T>(py: Python<'_>, future: F) -> RustPSQLDriverPyResult<&PyAny>
38+
pub fn rustdriver_future<F, T>(py: Python<'_>, future: F) -> RustPSQLDriverPyResult<&PyAny>
3939
where
4040
F: Future<Output = RustPSQLDriverPyResult<T>> + Send + 'static,
4141
T: IntoPy<PyObject>,

src/driver/connection.rs

Lines changed: 38 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{collections::HashSet, sync::Arc, vec};
44
use tokio_postgres::types::ToSql;
55

66
use crate::{
7-
common::rustengine_future,
7+
common::rustdriver_future,
88
exceptions::rust_errors::RustPSQLDriverPyResult,
99
query_result::PSQLDriverPyQueryResult,
1010
value_converter::{convert_parameters, PythonDTO},
@@ -15,85 +15,14 @@ use super::{
1515
transaction_options::{IsolationLevel, ReadVariant},
1616
};
1717

18-
#[allow(clippy::module_name_repetitions)]
19-
pub struct RustConnection {
20-
pub db_client: Arc<Object>,
21-
}
22-
23-
impl RustConnection {
24-
#[must_use]
25-
pub fn new(db_client: Arc<Object>) -> Self {
26-
RustConnection { db_client }
27-
}
28-
/// Execute statement with or witout parameters.
29-
///
30-
/// # Errors
31-
///
32-
/// May return Err Result if
33-
/// 1) Cannot convert incoming parameters
34-
/// 2) Cannot prepare statement
35-
/// 3) Cannot execute query
36-
pub async fn inner_execute(
37-
&self,
38-
querystring: String,
39-
params: Vec<PythonDTO>,
40-
prepared: bool,
41-
) -> RustPSQLDriverPyResult<PSQLDriverPyQueryResult> {
42-
let db_client = &self.db_client;
43-
let mut vec_parameters: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(params.len());
44-
for param in &params {
45-
vec_parameters.push(param);
46-
}
47-
48-
let result = if prepared {
49-
db_client
50-
.query(
51-
&db_client.prepare_cached(&querystring).await?,
52-
&vec_parameters.into_boxed_slice(),
53-
)
54-
.await?
55-
} else {
56-
db_client
57-
.query(&querystring, &vec_parameters.into_boxed_slice())
58-
.await?
59-
};
60-
61-
Ok(PSQLDriverPyQueryResult::new(result))
62-
}
63-
64-
/// Return new instance of transaction.
65-
#[must_use]
66-
pub fn inner_transaction(
67-
&self,
68-
isolation_level: Option<IsolationLevel>,
69-
read_variant: Option<ReadVariant>,
70-
deferrable: Option<bool>,
71-
) -> Transaction {
72-
let inner_transaction = RustTransaction::new(
73-
self.db_client.clone(),
74-
false,
75-
false,
76-
Arc::new(tokio::sync::RwLock::new(HashSet::new())),
77-
isolation_level,
78-
read_variant,
79-
deferrable,
80-
);
81-
82-
Transaction::new(
83-
Arc::new(tokio::sync::RwLock::new(inner_transaction)),
84-
Default::default(),
85-
)
86-
}
87-
}
88-
8918
#[pyclass()]
9019
pub struct Connection {
91-
pub inner_connection: Arc<RustConnection>,
20+
pub inner_connection: Arc<Object>,
9221
}
9322

9423
impl Connection {
9524
#[must_use]
96-
pub fn new(inner_connection: Arc<RustConnection>) -> Self {
25+
pub fn new(inner_connection: Arc<Object>) -> Self {
9726
Connection { inner_connection }
9827
}
9928
}
@@ -121,10 +50,27 @@ impl Connection {
12150
if let Some(parameters) = parameters {
12251
params = convert_parameters(parameters)?;
12352
}
124-
rustengine_future(py, async move {
125-
connection_arc
126-
.inner_execute(querystring, params, prepared.unwrap_or(true))
127-
.await
53+
let is_prepared = prepared.unwrap_or(true);
54+
rustdriver_future(py, async move {
55+
let mut vec_parameters: Vec<&(dyn ToSql + Sync)> = Vec::with_capacity(params.len());
56+
for param in &params {
57+
vec_parameters.push(param);
58+
}
59+
60+
let result = if is_prepared {
61+
connection_arc
62+
.query(
63+
&connection_arc.prepare_cached(&querystring).await?,
64+
&vec_parameters.into_boxed_slice(),
65+
)
66+
.await?
67+
} else {
68+
connection_arc
69+
.query(&querystring, &vec_parameters.into_boxed_slice())
70+
.await?
71+
};
72+
73+
Ok(PSQLDriverPyQueryResult::new(result))
12874
})
12975
}
13076

@@ -136,7 +82,19 @@ impl Connection {
13682
read_variant: Option<ReadVariant>,
13783
deferrable: Option<bool>,
13884
) -> Transaction {
139-
self.inner_connection
140-
.inner_transaction(isolation_level, read_variant, deferrable)
85+
let inner_transaction = RustTransaction::new(
86+
self.inner_connection.clone(),
87+
false,
88+
false,
89+
Arc::new(tokio::sync::RwLock::new(HashSet::new())),
90+
isolation_level,
91+
read_variant,
92+
deferrable,
93+
);
94+
95+
Transaction::new(
96+
Arc::new(tokio::sync::RwLock::new(inner_transaction)),
97+
Default::default(),
98+
)
14199
}
142100
}

0 commit comments

Comments
 (0)