From ad4609cc8aa66b13e7a48fec64e80a14d664555d Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Thu, 28 Mar 2024 20:54:05 +0100 Subject: [PATCH] Added support for MacAddr8 type --- python/psqlpy/_internal/extra_types.pyi | 10 +++ python/psqlpy/extra_types.py | 11 ++- src/additional_types.rs | 54 ++++++++++---- src/extra_types.rs | 94 +++++++++++++++++++------ src/value_converter.rs | 33 +++++++-- 5 files changed, 161 insertions(+), 41 deletions(-) diff --git a/python/psqlpy/_internal/extra_types.pyi b/python/psqlpy/_internal/extra_types.pyi index e1d2b81e..1069b058 100644 --- a/python/psqlpy/_internal/extra_types.pyi +++ b/python/psqlpy/_internal/extra_types.pyi @@ -72,3 +72,13 @@ class PyMacAddr6: ### Parameters: - `value`: value for MACADDR field. """ + +class PyMacAddr8: + """Represents MACADDR8 in PostgreSQL.""" + + def __init__(self, value: str) -> None: + """Construct new MacAddr8. + + ### Parameters: + - `value`: value for MACADDR8 field. + """ diff --git a/python/psqlpy/extra_types.py b/python/psqlpy/extra_types.py index d9954760..fcb9e518 100644 --- a/python/psqlpy/extra_types.py +++ b/python/psqlpy/extra_types.py @@ -1,4 +1,12 @@ -from ._internal.extra_types import BigInt, Integer, PyJSON, PyMacAddr6, PyUUID, SmallInt +from ._internal.extra_types import ( + BigInt, + Integer, + PyJSON, + PyMacAddr6, + PyMacAddr8, + PyUUID, + SmallInt, +) __all__ = [ "SmallInt", @@ -7,4 +15,5 @@ "PyUUID", "PyJSON", "PyMacAddr6", + "PyMacAddr8", ] diff --git a/src/additional_types.rs b/src/additional_types.rs index 9e9b2ef4..135b99b6 100644 --- a/src/additional_types.rs +++ b/src/additional_types.rs @@ -1,23 +1,30 @@ -use macaddr::MacAddr6; +use macaddr::{MacAddr6, MacAddr8}; use tokio_postgres::types::{FromSql, Type}; -#[derive(Debug)] -pub struct RustMacAddr6 { - inner: MacAddr6, -} +macro_rules! build_additional_rust_type { + ($st_name:ident, $rust_type:ty) => { + #[derive(Debug)] + pub struct $st_name { + inner: $rust_type, + } -impl RustMacAddr6 { - #[must_use] - pub fn new(inner: MacAddr6) -> Self { - RustMacAddr6 { inner } - } + impl $st_name { + #[must_use] + pub fn new(inner: $rust_type) -> Self { + $st_name { inner } + } - #[must_use] - pub fn inner(&self) -> &MacAddr6 { - &self.inner - } + #[must_use] + pub fn inner(&self) -> &$rust_type { + &self.inner + } + } + }; } +build_additional_rust_type!(RustMacAddr6, MacAddr6); +build_additional_rust_type!(RustMacAddr8, MacAddr8); + impl<'a> FromSql<'a> for RustMacAddr6 { fn from_sql( _ty: &Type, @@ -34,3 +41,22 @@ impl<'a> FromSql<'a> for RustMacAddr6 { true } } + +impl<'a> FromSql<'a> for RustMacAddr8 { + fn from_sql( + _ty: &Type, + raw: &'a [u8], + ) -> Result> { + if raw.len() == 8 { + let new_mac_address = MacAddr8::new( + raw[0], raw[1], raw[2], raw[3], raw[4], raw[5], raw[6], raw[7], + ); + return Ok(RustMacAddr8::new(new_mac_address)); + } + Err("Cannot convert PostgreSQL MACADDR8 into rust MacAddr8".into()) + } + + fn accepts(_ty: &Type) -> bool { + true + } +} diff --git a/src/extra_types.rs b/src/extra_types.rs index 603acf5e..b221ad40 100644 --- a/src/extra_types.rs +++ b/src/extra_types.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use macaddr::MacAddr6; +use macaddr::{MacAddr6, MacAddr8}; use pyo3::{pyclass, pymethods, types::PyModule, PyAny, PyResult, Python}; use serde_json::Value; use uuid::Uuid; @@ -95,30 +95,81 @@ impl PyJSON { } } -#[pyclass] -#[derive(Clone)] -pub struct PyMacAddr6 { - inner: MacAddr6, -} +macro_rules! build_macaddr_type { + ($st_name:ident, $rust_type:ty) => { + #[pyclass] + #[derive(Clone)] + pub struct $st_name { + inner: $rust_type, + } -impl PyMacAddr6 { - #[must_use] - pub fn inner(self) -> MacAddr6 { - self.inner - } -} + impl $st_name { + #[must_use] + pub fn inner(self) -> $rust_type { + self.inner + } + } -#[pymethods] -impl PyMacAddr6 { - #[new] - #[allow(clippy::missing_errors_doc)] - pub fn new_macaddr6(value: &str) -> RustPSQLDriverPyResult { - Ok(Self { - inner: MacAddr6::from_str(value)?, - }) - } + #[pymethods] + impl $st_name { + #[new] + #[allow(clippy::missing_errors_doc)] + pub fn new_class(value: &str) -> RustPSQLDriverPyResult { + Ok(Self { + inner: <$rust_type>::from_str(value)?, + }) + } + } + }; } +build_macaddr_type!(PyMacAddr6, MacAddr6); +build_macaddr_type!(PyMacAddr8, MacAddr8); + +// #[pyclass] +// #[derive(Clone)] +// pub struct PyMacAddr6 { +// inner: MacAddr6, +// } + +// impl PyMacAddr6 { +// #[must_use] +// pub fn inner(self) -> MacAddr6 { +// self.inner +// } +// } + +// #[pymethods] +// impl PyMacAddr6 { +// #[new] +// #[allow(clippy::missing_errors_doc)] +// pub fn new_macaddr6(value: &str) -> RustPSQLDriverPyResult { +// Ok(Self { +// inner: MacAddr6::from_str(value)?, +// }) +// } +// } + +// #[pyclass] +// #[derive(Clone)] +// pub struct PyMacAddr8 { +// inner: MacAddr8, +// } + +// impl PyMacAddr8 { +// #[must_use] +// pub fn inner(self) -> MacAddr8 { +// self.inner +// } +// } + +// #[pymethods] +// impl PyMacAddr8 { +// #[new] +// #[allow(clippy::missing_errors_doc)] +// pub fn new_macaddr8(value: &str) -> RustPSQLDriverPyResult {} +// } + #[allow(clippy::module_name_repetitions)] #[allow(clippy::missing_errors_doc)] pub fn extra_types_module(_py: Python<'_>, pymod: &PyModule) -> PyResult<()> { @@ -128,5 +179,6 @@ pub fn extra_types_module(_py: Python<'_>, pymod: &PyModule) -> PyResult<()> { pymod.add_class::()?; pymod.add_class::()?; pymod.add_class::()?; + pymod.add_class::()?; Ok(()) } diff --git a/src/value_converter.rs b/src/value_converter.rs index 949b7fde..6a30fcff 100644 --- a/src/value_converter.rs +++ b/src/value_converter.rs @@ -1,5 +1,5 @@ use chrono::{self, DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime}; -use macaddr::MacAddr6; +use macaddr::{MacAddr6, MacAddr8}; use serde_json::{json, Map, Value}; use std::{fmt::Debug, net::IpAddr}; use uuid::Uuid; @@ -19,9 +19,9 @@ use tokio_postgres::{ }; use crate::{ - additional_types::RustMacAddr6, + additional_types::{RustMacAddr6, RustMacAddr8}, exceptions::rust_errors::{RustPSQLDriverError, RustPSQLDriverPyResult}, - extra_types::{BigInt, Integer, PyJSON, PyMacAddr6, PyUUID, SmallInt}, + extra_types::{BigInt, Integer, PyJSON, PyMacAddr6, PyMacAddr8, PyUUID, SmallInt}, }; pub type QueryParameter = (dyn ToSql + Sync); @@ -54,6 +54,7 @@ pub enum PythonDTO { PyTuple(Vec), PyJson(Value), PyMacAddr6(MacAddr6), + PyMacAddr8(MacAddr8), } impl PythonDTO { @@ -188,6 +189,9 @@ impl ToSql for PythonDTO { PythonDTO::PyMacAddr6(pymacaddr) => { <&[u8] as ToSql>::to_sql(&pymacaddr.as_bytes(), ty, out)?; } + PythonDTO::PyMacAddr8(pymacaddr) => { + <&[u8] as ToSql>::to_sql(&pymacaddr.as_bytes(), ty, out)?; + } PythonDTO::PyList(py_iterable) | PythonDTO::PyTuple(py_iterable) => { let mut items = Vec::new(); for inner in py_iterable { @@ -245,6 +249,7 @@ pub fn convert_parameters(parameters: &PyAny) -> RustPSQLDriverPyResult RustPSQLDriverPyResult { if parameter.is_none() { return Ok(PythonDTO::PyNone); @@ -362,6 +367,12 @@ pub fn py_to_rust(parameter: &PyAny) -> RustPSQLDriverPyResult { )); } + if parameter.is_instance_of::() { + return Ok(PythonDTO::PyMacAddr8( + parameter.extract::()?.inner(), + )); + } + if let Ok(id_address) = parameter.extract::() { return Ok(PythonDTO::PyIpAddress(id_address)); } @@ -494,8 +505,20 @@ pub fn postgres_to_py( } // Convert MACADDR into inner type for macaddr6, then into str Type::MACADDR => { - let macaddr_ = row.try_get::<_, RustMacAddr6>(column_i)?; - Ok(macaddr_.inner().to_string().to_object(py)) + let macaddr_ = row.try_get::<_, Option>(column_i)?; + if let Some(macaddr_) = macaddr_ { + Ok(macaddr_.inner().to_string().to_object(py)) + } else { + Ok(py.None().to_object(py)) + } + } + Type::MACADDR8 => { + let macaddr_ = row.try_get::<_, Option>(column_i)?; + if let Some(macaddr_) = macaddr_ { + Ok(macaddr_.inner().to_string().to_object(py)) + } else { + Ok(py.None().to_object(py)) + } } _ => Err(RustPSQLDriverError::RustToPyValueConversionError( column.type_().to_string(),