Skip to content

Commit dcf3713

Browse files
committed
Continue implementing new realization. Implementing Cursor. pre-commit disabled.
Signed-off-by: chandr-andr (Kiselev Aleksandr) <chandr@chandr.net>
1 parent 17c89ec commit dcf3713

File tree

2 files changed

+203
-5
lines changed

2 files changed

+203
-5
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,4 @@ docs/_build/
7373

7474
# Develop
7575
_test*
76+
_load_test

src/driver/cursor.rs

Lines changed: 202 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,18 +515,215 @@
515515

516516
use std::sync::Arc;
517517

518-
use crate::value_converter::PythonDTO;
518+
use deadpool_postgres::Object;
519+
use pyo3::{pyclass, pymethods, Py, PyAny, PyErr, Python};
520+
521+
use crate::{
522+
common::BaseDataBaseQuery,
523+
exceptions::rust_errors::{RustPSQLDriverError, RustPSQLDriverPyResult},
524+
query_result::PSQLDriverPyQueryResult,
525+
};
526+
527+
trait CursorObjectTrait {
528+
async fn cursor_start(
529+
&self,
530+
cursor_name: &String,
531+
scroll: &Option<bool>,
532+
querystring: &String,
533+
prepared: &Option<bool>,
534+
parameters: &Option<Py<PyAny>>,
535+
) -> RustPSQLDriverPyResult<()>;
536+
537+
async fn cursor_close(&self, closed: &bool, cursor_name: &String)
538+
-> RustPSQLDriverPyResult<()>;
539+
}
519540

520-
use super::transaction::Transaction;
541+
impl CursorObjectTrait for Object {
542+
async fn cursor_start(
543+
&self,
544+
cursor_name: &String,
545+
scroll: &Option<bool>,
546+
querystring: &String,
547+
prepared: &Option<bool>,
548+
parameters: &Option<Py<PyAny>>,
549+
) -> RustPSQLDriverPyResult<()> {
550+
let mut cursor_init_query = format!("DECLARE {}", cursor_name);
551+
if let Some(scroll) = scroll {
552+
if *scroll {
553+
cursor_init_query.push_str(" SCROLL");
554+
} else {
555+
cursor_init_query.push_str(" NO SCROLL");
556+
}
557+
}
558+
559+
cursor_init_query.push_str(format!(" CURSOR FOR {}", querystring).as_str());
560+
561+
self.psqlpy_query(cursor_init_query, parameters.clone(), *prepared)
562+
.await?;
563+
564+
Ok(())
565+
}
566+
567+
async fn cursor_close(
568+
&self,
569+
closed: &bool,
570+
cursor_name: &String,
571+
) -> RustPSQLDriverPyResult<()> {
572+
if *closed {
573+
return Err(RustPSQLDriverError::DataBaseCursorError(
574+
"Cursor is already closed".into(),
575+
));
576+
}
577+
578+
self.psqlpy_query(
579+
format!("CLOSE {}", cursor_name),
580+
Default::default(),
581+
Some(false),
582+
)
583+
.await?;
584+
585+
Ok(())
586+
}
587+
}
521588

589+
#[pyclass]
522590
pub struct Cursor {
523-
db_transaction: Arc<Transaction>,
591+
db_transaction: Arc<Object>,
524592
querystring: String,
525-
parameters: Vec<PythonDTO>,
593+
parameters: Option<pyo3::Py<pyo3::PyAny>>,
526594
cursor_name: String,
527595
fetch_number: usize,
528596
scroll: Option<bool>,
529-
prepared: bool,
597+
prepared: Option<bool>,
530598
is_started: bool,
531599
closed: bool,
532600
}
601+
602+
#[pymethods]
603+
impl Cursor {
604+
#[must_use]
605+
pub fn __aiter__(slf: Py<Self>) -> Py<Self> {
606+
slf
607+
}
608+
609+
fn __await__(slf: Py<Self>) -> Py<Self> {
610+
slf
611+
}
612+
613+
async fn __aenter__<'a>(slf: Py<Self>) -> RustPSQLDriverPyResult<Py<Self>> {
614+
let (db_transaction, cursor_name, scroll, querystring, prepared, parameters) =
615+
Python::with_gil(|gil| {
616+
let self_ = slf.borrow(gil);
617+
return (
618+
self_.db_transaction.clone(),
619+
self_.cursor_name.clone(),
620+
self_.scroll,
621+
self_.querystring.clone(),
622+
self_.prepared,
623+
self_.parameters.clone(),
624+
);
625+
});
626+
db_transaction
627+
.cursor_start(&cursor_name, &scroll, &querystring, &prepared, &parameters)
628+
.await?;
629+
Python::with_gil(|gil| {
630+
let mut self_ = slf.borrow_mut(gil);
631+
self_.is_started = true;
632+
});
633+
Ok(slf)
634+
}
635+
636+
#[allow(clippy::needless_pass_by_value)]
637+
async fn __aexit__<'a>(
638+
slf: Py<Self>,
639+
_exception_type: Py<PyAny>,
640+
exception: Py<PyAny>,
641+
_traceback: Py<PyAny>,
642+
) -> RustPSQLDriverPyResult<()> {
643+
let (db_transaction, closed, cursor_name, is_exception_none, py_err) =
644+
pyo3::Python::with_gil(|gil| {
645+
let self_ = slf.borrow(gil);
646+
(
647+
self_.db_transaction.clone(),
648+
self_.closed,
649+
self_.cursor_name.clone(),
650+
exception.is_none(gil),
651+
PyErr::from_value_bound(exception.into_bound(gil)),
652+
)
653+
});
654+
655+
db_transaction.cursor_close(&closed, &cursor_name).await?;
656+
if !is_exception_none {
657+
return Err(RustPSQLDriverError::PyError(py_err));
658+
}
659+
Ok(())
660+
}
661+
662+
pub async fn start(&mut self) -> RustPSQLDriverPyResult<()> {
663+
let db_transaction_arc = self.db_transaction.clone();
664+
665+
db_transaction_arc
666+
.cursor_start(
667+
&self.cursor_name,
668+
&self.scroll,
669+
&self.querystring,
670+
&self.prepared,
671+
&self.parameters,
672+
)
673+
.await?;
674+
675+
self.is_started = true;
676+
Ok(())
677+
}
678+
679+
/// Close the cursor.
680+
///
681+
/// It executes CLOSE command to close cursor in the transaction.
682+
///
683+
/// # Errors
684+
/// May return Err Result if cannot execute query.
685+
pub async fn close(&mut self) -> RustPSQLDriverPyResult<()> {
686+
let db_transaction_arc = self.db_transaction.clone();
687+
688+
db_transaction_arc
689+
.cursor_close(&self.closed, &self.cursor_name)
690+
.await?;
691+
692+
self.closed = true;
693+
Ok(())
694+
}
695+
696+
/// Fetch data from cursor.
697+
///
698+
/// It's possible to specify fetch number.
699+
///
700+
/// # Errors
701+
/// May return Err Result if cannot execute query.
702+
pub async fn fetch<'a>(
703+
slf: Py<Self>,
704+
fetch_number: Option<usize>,
705+
) -> RustPSQLDriverPyResult<PSQLDriverPyQueryResult> {
706+
let (db_transaction, inner_fetch_number, cursor_name) = Python::with_gil(|gil| {
707+
let self_ = slf.borrow(gil);
708+
return (
709+
self_.db_transaction.clone(),
710+
self_.fetch_number,
711+
self_.cursor_name.clone(),
712+
);
713+
});
714+
715+
let fetch_number = match fetch_number {
716+
Some(usize) => usize,
717+
None => inner_fetch_number,
718+
};
719+
720+
let result = db_transaction
721+
.psqlpy_query(
722+
format!("FETCH {fetch_number} FROM {}", cursor_name),
723+
None,
724+
Some(false),
725+
)
726+
.await?;
727+
Ok(result)
728+
}
729+
}

0 commit comments

Comments
 (0)