Skip to content

Commit d29bd6b

Browse files
committed
Started implementing new traits and realizations for convertions from Python to Rust types
1 parent d49eba4 commit d29bd6b

File tree

12 files changed

+488
-261
lines changed

12 files changed

+488
-261
lines changed

src/driver/inner_connection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use crate::{
1010
query_result::{PSQLDriverPyQueryResult, PSQLDriverSinglePyQueryResult},
1111
value_converter::{
1212
consts::QueryParameter,
13+
dto::enums::PythonDTO,
1314
funcs::{from_python::convert_parameters_and_qs, to_python::postgres_to_py},
14-
models::dto::PythonDTO,
1515
},
1616
};
1717

src/extra_types.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@ use crate::{
1313
exceptions::rust_errors::{RustPSQLDriverError, RustPSQLDriverPyResult},
1414
value_converter::{
1515
additional_types::{Circle as RustCircle, Line as RustLine},
16+
dto::enums::PythonDTO,
1617
funcs::from_python::{
1718
build_flat_geo_coords, build_geo_coords, py_sequence_into_postgres_array,
1819
},
19-
models::{dto::PythonDTO, serde_value::build_serde_value},
20+
models::serde_value::build_serde_value,
2021
},
2122
};
2223

24+
pub struct PythonArray;
25+
pub struct PythonDecimal;
26+
pub struct PythonUUID;
27+
pub struct PythonEnum;
28+
2329
#[pyclass]
2430
#[derive(Clone)]
2531
pub struct PgVector(Vec<f32>);
@@ -34,7 +40,7 @@ impl PgVector {
3440

3541
impl PgVector {
3642
#[must_use]
37-
pub fn inner_value(self) -> Vec<f32> {
43+
pub fn inner(self) -> Vec<f32> {
3844
self.0
3945
}
4046
}
@@ -49,7 +55,7 @@ macro_rules! build_python_type {
4955

5056
impl $st_name {
5157
#[must_use]
52-
pub fn retrieve_value(&self) -> $rust_type {
58+
pub fn inner(&self) -> $rust_type {
5359
self.inner_value
5460
}
5561
}
@@ -135,7 +141,12 @@ macro_rules! build_json_py_type {
135141

136142
impl $st_name {
137143
#[must_use]
138-
pub fn inner(&self) -> &$rust_type {
144+
pub fn inner(&self) -> $rust_type {
145+
self.inner.clone()
146+
}
147+
148+
#[must_use]
149+
pub fn inner_ref(&self) -> &$rust_type {
139150
&self.inner
140151
}
141152
}
@@ -144,7 +155,7 @@ macro_rules! build_json_py_type {
144155
impl $st_name {
145156
#[new]
146157
#[allow(clippy::missing_errors_doc)]
147-
pub fn new_class(value: Py<PyAny>) -> RustPSQLDriverPyResult<Self> {
158+
pub fn new_class(value: &Bound<'_, PyAny>) -> RustPSQLDriverPyResult<Self> {
148159
Ok(Self {
149160
inner: build_serde_value(value)?,
150161
})
@@ -223,7 +234,7 @@ macro_rules! build_geo_type {
223234

224235
impl $st_name {
225236
#[must_use]
226-
pub fn retrieve_value(&self) -> $rust_type {
237+
pub fn inner(&self) -> $rust_type {
227238
self.inner.clone()
228239
}
229240
}

src/value_converter/additional_types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use pyo3::{
1313
use serde::{Deserialize, Serialize};
1414
use tokio_postgres::types::{FromSql, Type};
1515

16+
pub struct NonePyType;
17+
1618
macro_rules! build_additional_rust_type {
1719
($st_name:ident, $rust_type:ty) => {
1820
#[derive(Debug)]
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
use std::net::IpAddr;
2+
3+
use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
4+
use pg_interval::Interval;
5+
use pyo3::{
6+
types::{PyAnyMethods, PyDateTime, PyDelta, PyDict},
7+
Bound, PyAny,
8+
};
9+
use rust_decimal::Decimal;
10+
use uuid::Uuid;
11+
12+
use crate::{
13+
exceptions::rust_errors::{RustPSQLDriverError, RustPSQLDriverPyResult},
14+
extra_types::{self, PythonDecimal, PythonUUID},
15+
value_converter::{
16+
additional_types::NonePyType,
17+
funcs::from_python::{
18+
extract_datetime_from_python_object_attrs, py_sequence_into_postgres_array,
19+
},
20+
models::serde_value::build_serde_value,
21+
traits::PythonToDTO,
22+
},
23+
};
24+
25+
use super::enums::PythonDTO;
26+
27+
impl PythonToDTO for NonePyType {
28+
fn to_python_dto(_python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
29+
Ok(PythonDTO::PyNone)
30+
}
31+
}
32+
33+
macro_rules! construct_simple_type_matcher {
34+
($match_type:ty, $kind:path) => {
35+
impl PythonToDTO for $match_type {
36+
fn to_python_dto(python_param: &Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
37+
Ok($kind(python_param.extract::<$match_type>()?))
38+
}
39+
}
40+
};
41+
}
42+
43+
construct_simple_type_matcher!(bool, PythonDTO::PyBool);
44+
construct_simple_type_matcher!(Vec<u8>, PythonDTO::PyBytes);
45+
construct_simple_type_matcher!(String, PythonDTO::PyString);
46+
construct_simple_type_matcher!(f32, PythonDTO::PyFloat32);
47+
construct_simple_type_matcher!(f64, PythonDTO::PyFloat64);
48+
construct_simple_type_matcher!(i16, PythonDTO::PyIntI16);
49+
construct_simple_type_matcher!(i32, PythonDTO::PyIntI32);
50+
construct_simple_type_matcher!(i64, PythonDTO::PyIntI64);
51+
construct_simple_type_matcher!(NaiveDate, PythonDTO::PyDate);
52+
construct_simple_type_matcher!(NaiveTime, PythonDTO::PyTime);
53+
54+
impl PythonToDTO for PyDateTime {
55+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
56+
let timestamp_tz = python_param.extract::<DateTime<FixedOffset>>();
57+
if let Ok(pydatetime_tz) = timestamp_tz {
58+
return Ok(PythonDTO::PyDateTimeTz(pydatetime_tz));
59+
}
60+
61+
let timestamp_no_tz = python_param.extract::<NaiveDateTime>();
62+
if let Ok(pydatetime_no_tz) = timestamp_no_tz {
63+
return Ok(PythonDTO::PyDateTime(pydatetime_no_tz));
64+
}
65+
66+
let timestamp_tz = extract_datetime_from_python_object_attrs(python_param);
67+
if let Ok(pydatetime_tz) = timestamp_tz {
68+
return Ok(PythonDTO::PyDateTimeTz(pydatetime_tz));
69+
}
70+
71+
return Err(RustPSQLDriverError::PyToRustValueConversionError(
72+
"Can not convert you datetime to rust type".into(),
73+
));
74+
}
75+
}
76+
77+
impl PythonToDTO for PyDelta {
78+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
79+
let duration = python_param.extract::<chrono::Duration>()?;
80+
if let Some(interval) = Interval::from_duration(duration) {
81+
return Ok(PythonDTO::PyInterval(interval));
82+
}
83+
return Err(RustPSQLDriverError::PyToRustValueConversionError(
84+
"Cannot convert timedelta from Python to inner Rust type.".to_string(),
85+
));
86+
}
87+
}
88+
89+
impl PythonToDTO for PyDict {
90+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
91+
let serde_value = build_serde_value(python_param)?;
92+
93+
return Ok(PythonDTO::PyJsonb(serde_value));
94+
}
95+
}
96+
97+
macro_rules! construct_extra_type_matcher {
98+
($match_type:ty, $kind:path) => {
99+
impl PythonToDTO for $match_type {
100+
fn to_python_dto(python_param: &Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
101+
Ok($kind(python_param.extract::<$match_type>()?.inner()))
102+
}
103+
}
104+
};
105+
}
106+
107+
construct_extra_type_matcher!(extra_types::JSONB, PythonDTO::PyJsonb);
108+
construct_extra_type_matcher!(extra_types::JSON, PythonDTO::PyJson);
109+
construct_extra_type_matcher!(extra_types::MacAddr6, PythonDTO::PyMacAddr6);
110+
construct_extra_type_matcher!(extra_types::MacAddr8, PythonDTO::PyMacAddr8);
111+
construct_extra_type_matcher!(extra_types::Point, PythonDTO::PyPoint);
112+
construct_extra_type_matcher!(extra_types::Box, PythonDTO::PyBox);
113+
construct_extra_type_matcher!(extra_types::Path, PythonDTO::PyPath);
114+
construct_extra_type_matcher!(extra_types::Line, PythonDTO::PyLine);
115+
construct_extra_type_matcher!(extra_types::LineSegment, PythonDTO::PyLineSegment);
116+
construct_extra_type_matcher!(extra_types::Circle, PythonDTO::PyCircle);
117+
118+
impl PythonToDTO for PythonDecimal {
119+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
120+
Ok(PythonDTO::PyDecimal(Decimal::from_str_exact(
121+
python_param.str()?.extract::<&str>()?,
122+
)?))
123+
}
124+
}
125+
126+
impl PythonToDTO for PythonUUID {
127+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
128+
Ok(PythonDTO::PyUUID(Uuid::parse_str(
129+
python_param.str()?.extract::<&str>()?,
130+
)?))
131+
}
132+
}
133+
134+
impl PythonToDTO for extra_types::PythonArray {
135+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
136+
Ok(PythonDTO::PyArray(py_sequence_into_postgres_array(
137+
python_param,
138+
)?))
139+
}
140+
}
141+
142+
impl PythonToDTO for IpAddr {
143+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
144+
if let Ok(id_address) = python_param.extract::<IpAddr>() {
145+
return Ok(PythonDTO::PyIpAddress(id_address));
146+
}
147+
148+
Err(RustPSQLDriverError::PyToRustValueConversionError(
149+
"Parameter passed to IpAddr is incorrect.".to_string(),
150+
))
151+
}
152+
}
153+
154+
impl PythonToDTO for extra_types::PythonEnum {
155+
fn to_python_dto(python_param: &pyo3::Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
156+
let string = python_param.extract::<String>()?;
157+
return Ok(PythonDTO::PyString(string));
158+
}
159+
}
160+
161+
macro_rules! construct_array_type_matcher {
162+
($match_type:ty) => {
163+
impl PythonToDTO for $match_type {
164+
fn to_python_dto(python_param: &Bound<'_, PyAny>) -> RustPSQLDriverPyResult<PythonDTO> {
165+
python_param
166+
.extract::<$match_type>()?
167+
._convert_to_python_dto()
168+
}
169+
}
170+
};
171+
}
172+
173+
construct_array_type_matcher!(extra_types::BoolArray);
174+
construct_array_type_matcher!(extra_types::UUIDArray);
175+
construct_array_type_matcher!(extra_types::VarCharArray);
176+
construct_array_type_matcher!(extra_types::TextArray);
177+
construct_array_type_matcher!(extra_types::Int16Array);
178+
construct_array_type_matcher!(extra_types::Int32Array);
179+
construct_array_type_matcher!(extra_types::Int64Array);
180+
construct_array_type_matcher!(extra_types::Float32Array);
181+
construct_array_type_matcher!(extra_types::Float64Array);
182+
construct_array_type_matcher!(extra_types::MoneyArray);
183+
construct_array_type_matcher!(extra_types::IpAddressArray);
184+
construct_array_type_matcher!(extra_types::JSONBArray);
185+
construct_array_type_matcher!(extra_types::JSONArray);
186+
construct_array_type_matcher!(extra_types::DateArray);
187+
construct_array_type_matcher!(extra_types::TimeArray);
188+
construct_array_type_matcher!(extra_types::DateTimeArray);
189+
construct_array_type_matcher!(extra_types::DateTimeTZArray);
190+
construct_array_type_matcher!(extra_types::MacAddr6Array);
191+
construct_array_type_matcher!(extra_types::MacAddr8Array);
192+
construct_array_type_matcher!(extra_types::NumericArray);
193+
construct_array_type_matcher!(extra_types::PointArray);
194+
construct_array_type_matcher!(extra_types::BoxArray);
195+
construct_array_type_matcher!(extra_types::PathArray);
196+
construct_array_type_matcher!(extra_types::LineArray);
197+
construct_array_type_matcher!(extra_types::LsegArray);
198+
construct_array_type_matcher!(extra_types::CircleArray);
199+
construct_array_type_matcher!(extra_types::IntervalArray);

src/value_converter/dto/enums.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use chrono::{self, DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
2+
use geo_types::{Line as LineSegment, LineString, Point, Rect};
3+
use macaddr::{MacAddr6, MacAddr8};
4+
use pg_interval::Interval;
5+
use rust_decimal::Decimal;
6+
use serde_json::Value;
7+
use std::{fmt::Debug, net::IpAddr};
8+
use uuid::Uuid;
9+
10+
use crate::value_converter::additional_types::{Circle, Line};
11+
use postgres_array::array::Array;
12+
13+
#[derive(Debug, Clone, PartialEq)]
14+
pub enum PythonDTO {
15+
// Primitive
16+
PyNone,
17+
PyBytes(Vec<u8>),
18+
PyBool(bool),
19+
PyUUID(Uuid),
20+
PyVarChar(String),
21+
PyText(String),
22+
PyString(String),
23+
PyIntI16(i16),
24+
PyIntI32(i32),
25+
PyIntI64(i64),
26+
PyIntU32(u32),
27+
PyIntU64(u64),
28+
PyFloat32(f32),
29+
PyFloat64(f64),
30+
PyMoney(i64),
31+
PyDate(NaiveDate),
32+
PyTime(NaiveTime),
33+
PyDateTime(NaiveDateTime),
34+
PyDateTimeTz(DateTime<FixedOffset>),
35+
PyInterval(Interval),
36+
PyIpAddress(IpAddr),
37+
PyList(Vec<PythonDTO>),
38+
PyArray(Array<PythonDTO>),
39+
PyTuple(Vec<PythonDTO>),
40+
PyJsonb(Value),
41+
PyJson(Value),
42+
PyMacAddr6(MacAddr6),
43+
PyMacAddr8(MacAddr8),
44+
PyDecimal(Decimal),
45+
PyCustomType(Vec<u8>),
46+
PyPoint(Point),
47+
PyBox(Rect),
48+
PyPath(LineString),
49+
PyLine(Line),
50+
PyLineSegment(LineSegment),
51+
PyCircle(Circle),
52+
// Arrays
53+
PyBoolArray(Array<PythonDTO>),
54+
PyUuidArray(Array<PythonDTO>),
55+
PyVarCharArray(Array<PythonDTO>),
56+
PyTextArray(Array<PythonDTO>),
57+
PyInt16Array(Array<PythonDTO>),
58+
PyInt32Array(Array<PythonDTO>),
59+
PyInt64Array(Array<PythonDTO>),
60+
PyFloat32Array(Array<PythonDTO>),
61+
PyFloat64Array(Array<PythonDTO>),
62+
PyMoneyArray(Array<PythonDTO>),
63+
PyIpAddressArray(Array<PythonDTO>),
64+
PyJSONBArray(Array<PythonDTO>),
65+
PyJSONArray(Array<PythonDTO>),
66+
PyDateArray(Array<PythonDTO>),
67+
PyTimeArray(Array<PythonDTO>),
68+
PyDateTimeArray(Array<PythonDTO>),
69+
PyDateTimeTZArray(Array<PythonDTO>),
70+
PyMacAddr6Array(Array<PythonDTO>),
71+
PyMacAddr8Array(Array<PythonDTO>),
72+
PyNumericArray(Array<PythonDTO>),
73+
PyPointArray(Array<PythonDTO>),
74+
PyBoxArray(Array<PythonDTO>),
75+
PyPathArray(Array<PythonDTO>),
76+
PyLineArray(Array<PythonDTO>),
77+
PyLsegArray(Array<PythonDTO>),
78+
PyCircleArray(Array<PythonDTO>),
79+
PyIntervalArray(Array<PythonDTO>),
80+
// PgVector
81+
PyPgVector(Vec<f32>),
82+
}

0 commit comments

Comments
 (0)