Skip to content

remove switch between postgres and tokio-postgres #6

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

Merged
merged 1 commit into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ categories = ["database", "parsing", "data-structures"]
[workspace.dependencies]
postgres-from-row-derive = { path = "postgres-from-row-derive", version = "=0.4.0" }

[features]
default = ["postgres"]
postgres = ["dep:postgres"]
tokio-postgres = ["dep:tokio-postgres"]

[dependencies]
tokio-postgres = { version = "0.7.7", default_features = false, optional = true }
postgres = { version = "0.19.4", default_features = false, optional = true }
tokio-postgres = { version = "0.7.7", default_features = false }
postgres-from-row-derive.workspace = true

54 changes: 21 additions & 33 deletions postgres-from-row-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,22 @@ use darling::{ast::Data, Error, FromDeriveInput, FromField, ToTokens};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Ident, Result};

#[proc_macro_derive(FromRowTokioPostgres, attributes(from_row))]
pub fn derive_from_row_tokio_postgres(input: TokenStream) -> TokenStream {
derive_from_row(input, quote::format_ident!("tokio_postgres"))
}

#[proc_macro_derive(FromRowPostgres, attributes(from_row))]
pub fn derive_from_row_postgres(input: TokenStream) -> TokenStream {
derive_from_row(input, quote::format_ident!("postgres"))
}
use syn::{parse_macro_input, DeriveInput, Result};

/// Calls the fallible entry point and writes any errors to the tokenstream.
fn derive_from_row(input: TokenStream, module: Ident) -> TokenStream {
#[proc_macro_derive(FromRow, attributes(from_row))]
pub fn derive_from_row(input: TokenStream) -> TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
match try_derive_from_row(&derive_input, module) {
match try_derive_from_row(&derive_input) {
Ok(result) => result,
Err(err) => err.write_errors().into(),
}
}

/// Fallible entry point for generating a `FromRow` implementation
fn try_derive_from_row(
input: &DeriveInput,
module: Ident,
) -> std::result::Result<TokenStream, Error> {
fn try_derive_from_row(input: &DeriveInput) -> std::result::Result<TokenStream, Error> {
let from_row_derive = DeriveFromRow::from_derive_input(input)?;
Ok(from_row_derive.generate(module)?)
Ok(from_row_derive.generate()?)
}

/// Main struct for deriving `FromRow` for a struct.
Expand All @@ -56,11 +44,11 @@ impl DeriveFromRow {
}

/// Generates any additional where clause predicates needed for the fields in this struct.
fn predicates(&self, module: &Ident) -> Result<Vec<TokenStream2>> {
fn predicates(&self) -> Result<Vec<TokenStream2>> {
let mut predicates = Vec::new();

for field in self.fields() {
field.add_predicates(&module, &mut predicates)?;
field.add_predicates(&mut predicates)?;
}

Ok(predicates)
Expand All @@ -75,37 +63,37 @@ impl DeriveFromRow {
}

/// Generate the `FromRow` implementation.
fn generate(self, module: Ident) -> Result<TokenStream> {
fn generate(self) -> Result<TokenStream> {
self.validate()?;

let ident = &self.ident;

let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
let original_predicates = where_clause.clone().map(|w| &w.predicates).into_iter();
let predicates = self.predicates(&module)?;
let predicates = self.predicates()?;

let from_row_fields = self
.fields()
.iter()
.map(|f| f.generate_from_row(&module))
.map(|f| f.generate_from_row())
.collect::<syn::Result<Vec<_>>>()?;

let try_from_row_fields = self
.fields()
.iter()
.map(|f| f.generate_try_from_row(&module))
.map(|f| f.generate_try_from_row())
.collect::<syn::Result<Vec<_>>>()?;

Ok(quote! {
impl #impl_generics postgres_from_row::FromRow for #ident #ty_generics where #(#original_predicates),* #(#predicates),* {

fn from_row(row: &#module::Row) -> Self {
fn from_row(row: &postgres_from_row::tokio_postgres::Row) -> Self {
Self {
#(#from_row_fields),*
}
}

fn try_from_row(row: &#module::Row) -> std::result::Result<Self, #module::Error> {
fn try_from_row(row: &postgres_from_row::tokio_postgres::Row) -> std::result::Result<Self, postgres_from_row::tokio_postgres::Error> {
Ok(Self {
#(#try_from_row_fields),*
})
Expand Down Expand Up @@ -187,14 +175,14 @@ impl FromRowField {
/// and when using either `from` or `try_from` attributes it additionally pushes this bound:
/// `T: std::convert::From<R>`, where `T` is the type specified in the struct and `R` is the
/// type specified in the `[try]_from` attribute.
fn add_predicates(&self, module: &Ident, predicates: &mut Vec<TokenStream2>) -> Result<()> {
fn add_predicates(&self, predicates: &mut Vec<TokenStream2>) -> Result<()> {
let target_ty = &self.target_ty()?;
let ty = &self.ty;

predicates.push(if self.flatten {
quote! (#target_ty: postgres_from_row::FromRow)
} else {
quote! (#target_ty: for<'a> #module::types::FromSql<'a>)
quote! (#target_ty: for<'a> postgres_from_row::tokio_postgres::types::FromSql<'a>)
});

if self.from.is_some() {
Expand All @@ -203,15 +191,15 @@ impl FromRowField {
let try_from = quote!(std::convert::TryFrom<#target_ty>);

predicates.push(quote!(#ty: #try_from));
predicates.push(quote!(#module::Error: std::convert::From<<#ty as #try_from>::Error>));
predicates.push(quote!(postgres_from_row::tokio_postgres::Error: std::convert::From<<#ty as #try_from>::Error>));
predicates.push(quote!(<#ty as #try_from>::Error: std::fmt::Debug));
}

Ok(())
}

/// Generate the line needed to retrievee this field from a row when calling `from_row`.
fn generate_from_row(&self, module: &Ident) -> Result<TokenStream2> {
fn generate_from_row(&self) -> Result<TokenStream2> {
let ident = self.ident.as_ref().unwrap();
let column_name = self.column_name();
let field_ty = &self.ty;
Expand All @@ -220,7 +208,7 @@ impl FromRowField {
let mut base = if self.flatten {
quote!(<#target_ty as postgres_from_row::FromRow>::from_row(row))
} else {
quote!(#module::Row::get::<&str, #target_ty>(row, #column_name))
quote!(postgres_from_row::tokio_postgres::Row::get::<&str, #target_ty>(row, #column_name))
};

if self.from.is_some() {
Expand All @@ -233,7 +221,7 @@ impl FromRowField {
}

/// Generate the line needed to retrieve this field from a row when calling `try_from_row`.
fn generate_try_from_row(&self, module: &Ident) -> Result<TokenStream2> {
fn generate_try_from_row(&self) -> Result<TokenStream2> {
let ident = self.ident.as_ref().unwrap();
let column_name = self.column_name();
let field_ty = &self.ty;
Expand All @@ -242,7 +230,7 @@ impl FromRowField {
let mut base = if self.flatten {
quote!(<#target_ty as postgres_from_row::FromRow>::try_from_row(row)?)
} else {
quote!(#module::Row::try_get::<&str, #target_ty>(row, #column_name)?)
quote!(postgres_from_row::tokio_postgres::Row::try_get::<&str, #target_ty>(row, #column_name)?)
};

if self.from.is_some() {
Expand Down
28 changes: 4 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,20 @@
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]

#[cfg(feature = "postgres")]
mod active_postgres {
pub use postgres::{Error, Row};
pub use postgres_from_row_derive::FromRowPostgres as FromRow;
}

#[cfg(feature = "tokio-postgres")]
mod active_postgres {
pub use postgres_from_row_derive::FromRowTokioPostgres as FromRow;
pub use tokio_postgres::{Error, Row};
}
pub use postgres_from_row_derive::FromRow;
pub use tokio_postgres;

/// A trait that allows mapping rows from either [postgres](<https://docs.rs/postgres>) or [tokio-postgres](<https://docs.rs/tokio-postgres>), to other types.
#[cfg(any(feature = "postgres", feature = "tokio-postgres"))]
pub trait FromRow: Sized {
/// Performce the conversion
///
/// # Panics
///
/// panics if the row does not contain the expected column names.
fn from_row(row: &active_postgres::Row) -> Self;
fn from_row(row: &tokio_postgres::Row) -> Self;

/// Try's to perform the conversion.
///
/// Will return an error if the row does not contain the expected column names.
fn try_from_row(row: &active_postgres::Row) -> Result<Self, active_postgres::Error>;
fn try_from_row(row: &tokio_postgres::Row) -> Result<Self, tokio_postgres::Error>;
}

#[doc(hidden)]
pub use active_postgres::FromRow;

//
// #[cfg(all(feature = "postgres", feature = "tokio-postgres"))]
// compile_error!("Can't combine feature `postgres` and `tokio-postgres`");
//
// #[cfg(not(any(feature = "postgres", feature = "tokio-postgres")))]
// compile_error!("Must have at least one enabled feature: `postgres` or `tokio-postgres`.");