Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add derive macros for Encode, Decode and HasSqlType for Transparent types, weak/strong enums and structs #97

Closed
wants to merge 12 commits into from
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,9 @@ required-features = [ "mysql", "chrono", "macros" ]
name = "derives"
required-features = [ "macros" ]

[[test]]
name = "postgres-struct"
required-features = [ "postgres" ]

[profile.release]
lto = true
2 changes: 2 additions & 0 deletions sqlx-core/src/mysql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub use error::MySqlError;

pub use types::MySqlTypeInfo;

pub use protocol::TypeId;

pub use row::MySqlRow;

/// An alias for [`Pool`], specialized for **MySQL**.
Expand Down
3 changes: 3 additions & 0 deletions sqlx-core/src/mysql/protocol/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ impl TypeId {
pub const VAR_CHAR: TypeId = TypeId(253); // or VAR_BINARY
pub const TEXT: TypeId = TypeId(252); // or BLOB

// Enum
pub const ENUM: TypeId = TypeId(247);

// More Bytes
pub const TINY_BLOB: TypeId = TypeId(249);
pub const MEDIUM_BLOB: TypeId = TypeId(250);
Expand Down
9 changes: 8 additions & 1 deletion sqlx-core/src/mysql/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ impl MySqlTypeInfo {
char_set: def.char_set,
}
}

#[doc(hidden)]
pub fn r#enum() -> Self {
Self::new(TypeId::ENUM)
}
}

impl Display for MySqlTypeInfo {
Expand All @@ -67,14 +72,16 @@ impl TypeInfo for MySqlTypeInfo {
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM
if (self.is_binary == other.is_binary)
&& match other.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB => true,
| TypeId::LONG_BLOB
| TypeId::ENUM => true,

_ => false,
} =>
Expand Down
2 changes: 2 additions & 0 deletions sqlx-core/src/postgres/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub use connection::PgConnection;
pub use database::Postgres;
pub use error::PgError;
pub use row::PgRow;
#[doc(hidden)]
pub use types::r#struct::{decode_struct_field, encode_struct_field};
pub use types::PgTypeInfo;

mod arguments;
Expand Down
5 changes: 5 additions & 0 deletions sqlx-core/src/postgres/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod bytes;
mod float;
mod int;
mod str;
pub mod r#struct;

#[cfg(feature = "chrono")]
mod chrono;
Expand Down Expand Up @@ -32,6 +33,10 @@ impl PgTypeInfo {
pub fn with_oid(oid: u32) -> Self {
Self { id: TypeId(oid) }
}

pub fn oid(&self) -> u32 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd probably rather not expose this in the public API if possible (with custom types we may not always have an OID so this will need to be changed to Option<u32>). Either pub(crate) or #[doc(hidden)].

self.id.0
}
}

impl Display for PgTypeInfo {
Expand Down
57 changes: 57 additions & 0 deletions sqlx-core/src/postgres/types/struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::decode::{Decode, DecodeError};
use crate::encode::Encode;
use crate::types::HasSqlType;
use crate::Postgres;
use std::convert::TryInto;

/// read a struct field and advance the buffer
pub fn decode_struct_field<T: Decode<Postgres>>(buf: &mut &[u8]) -> Result<T, DecodeError>
where
Postgres: HasSqlType<T>,
{
if buf.len() < 8 {
return Err(DecodeError::Message(std::boxed::Box::new(
"Not enough data sent",
)));
}

let oid = u32::from_be_bytes(std::convert::TryInto::try_into(&buf[0..4]).unwrap());
if oid != <Postgres as HasSqlType<T>>::type_info().oid() {
return Err(DecodeError::Message(std::boxed::Box::new("Invalid oid")));
}

let len = u32::from_be_bytes(buf[4..8].try_into().unwrap()) as usize;

if buf.len() < 8 + len {
return Err(DecodeError::Message(std::boxed::Box::new(
"Not enough data sent",
)));
}

let raw = &buf[8..8 + len];
let value = T::decode(raw)?;

*buf = &buf[8 + len..];

Ok(value)
}

pub fn encode_struct_field<T: Encode<Postgres>>(buf: &mut Vec<u8>, value: &T)
where
Postgres: HasSqlType<T>,
{
// write oid
let info = <Postgres as HasSqlType<T>>::type_info();
buf.extend(&info.oid().to_be_bytes());

// write zeros for length
buf.extend(&[0; 4]);

let start = buf.len();
value.encode(buf);
let end = buf.len();
let size = end - start;

// replaces zeros with actual length
buf[start - 4..start].copy_from_slice(&(size as u32).to_be_bytes());
}
88 changes: 0 additions & 88 deletions sqlx-macros/src/derives.rs

This file was deleted.

Loading