Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions derive/src/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod row;
pub use row::Row;
43 changes: 43 additions & 0 deletions derive/src/attributes/row.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use quote::ToTokens;

pub const ATTRIBUTE_NAME: &str = "row";
pub const ATTRIBUTE_SYNTAX: &str = "#[row(crate = ...)]";

pub const CRATE_PATH: &str = "crate";
pub const DEFAULT_CRATE_PATH: &str = "::clickhouse";

pub struct Row {
pub crate_path: syn::Path,
}

impl Default for Row {
fn default() -> Self {
let default_crate_path = syn::parse_str::<syn::Path>(DEFAULT_CRATE_PATH).unwrap();
Self {
crate_path: default_crate_path,
}
}
}

impl<'a> TryFrom<&'a syn::Attribute> for Row {
type Error = &'a syn::Attribute;

fn try_from(attr: &'a syn::Attribute) -> Result<Self, Self::Error> {
if attr.path().is_ident(ATTRIBUTE_NAME) {
let row = attr.parse_args::<syn::Expr>().unwrap();
let syn::Expr::Assign(syn::ExprAssign { left, right, .. }) = row else {
panic!("expected `{}`", ATTRIBUTE_SYNTAX);
};
if left.to_token_stream().to_string() != CRATE_PATH {
panic!("expected `{}`", ATTRIBUTE_SYNTAX);
}
let syn::Expr::Path(syn::ExprPath { path, .. }) = *right else {
panic!("expected `{}`", ATTRIBUTE_SYNTAX);
};
Ok(Self { crate_path: path })
} else {
return Err(attr);
}
}
}

28 changes: 25 additions & 3 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod attributes;

use proc_macro2::TokenStream;
use quote::quote;
use serde_derive_internals::{
Expand All @@ -6,6 +8,24 @@ use serde_derive_internals::{
};
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields};

struct Attributes {
row: attributes::Row,
}

impl From<&[syn::Attribute]> for Attributes {
fn from(attrs: &[syn::Attribute]) -> Self {
let mut row = None;
for attr in attrs {
if let Ok(r) = attributes::Row::try_from(attr) {
row = Some(r);
}
}
Self {
row: row.unwrap_or_default(),
}
}
}

fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> TokenStream {
match &data.fields {
Fields::Named(fields) => {
Expand Down Expand Up @@ -36,11 +56,14 @@ fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> TokenStr
// TODO: support wrappers `Wrapper(Inner)` and `Wrapper<T>(T)`.
// TODO: support the `nested` attribute.
// TODO: support the `crate` attribute.
#[proc_macro_derive(Row)]
#[proc_macro_derive(Row, attributes(row))]
pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);

let cx = Ctxt::new();
let Attributes {
row: attributes::Row { crate_path },
} = Attributes::from(input.attrs.as_slice());
let container = Container::from_ast(&cx, &input);
let name = input.ident;

Expand All @@ -54,10 +77,9 @@ pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream {

let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

// TODO: replace `clickhouse` with `::clickhouse` here.
let expanded = quote! {
#[automatically_derived]
impl #impl_generics clickhouse::Row for #name #ty_generics #where_clause {
impl #impl_generics #crate_path::Row for #name #ty_generics #where_clause {
const COLUMN_NAMES: &'static [&'static str] = #column_names;
}
};
Expand Down
12 changes: 9 additions & 3 deletions src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ pub(crate) fn join_column_names<R: Row>() -> Option<String> {

#[cfg(test)]
mod tests {
// XXX: need for `derive(Row)`. Provide `row(crate = ..)` instead.
use crate as clickhouse;
use clickhouse::Row;
use crate::Row;

use super::*;

#[test]
fn it_grabs_simple_struct() {
#[derive(Row)]
#[row(crate = crate)]
#[allow(dead_code)]
struct Simple1 {
one: u32,
}

#[derive(Row)]
#[row(crate = crate)]
#[allow(dead_code)]
struct Simple2 {
one: u32,
Expand All @@ -103,6 +103,7 @@ mod tests {
#[test]
fn it_grabs_mix() {
#[derive(Row)]
#[row(crate = crate)]
struct SomeRow {
_a: u32,
}
Expand All @@ -115,6 +116,7 @@ mod tests {
use serde::Serialize;

#[derive(Row, Serialize)]
#[row(crate = crate)]
#[allow(dead_code)]
struct TopLevel {
#[serde(rename = "two")]
Expand All @@ -129,6 +131,7 @@ mod tests {
use serde::Serialize;

#[derive(Row, Serialize)]
#[row(crate = crate)]
#[allow(dead_code)]
struct TopLevel {
one: u32,
Expand All @@ -144,6 +147,7 @@ mod tests {
use serde::Deserialize;

#[derive(Row, Deserialize)]
#[row(crate = crate)]
#[allow(dead_code)]
struct TopLevel {
one: u32,
Expand All @@ -158,6 +162,7 @@ mod tests {
fn it_rejects_other() {
#[allow(dead_code)]
#[derive(Row)]
#[row(crate = crate)]
struct NamedTuple(u32, u32);

assert_eq!(join_column_names::<u32>(), None);
Expand All @@ -170,6 +175,7 @@ mod tests {
use serde::Serialize;

#[derive(Row, Serialize)]
#[row(crate = crate)]
#[allow(dead_code)]
struct MyRow {
r#type: u32,
Expand Down
4 changes: 2 additions & 2 deletions src/sql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,19 +149,19 @@ impl SqlBuilder {
mod tests {
use super::*;

// XXX: need for `derive(Row)`. Provide `row(crate = ..)` instead.
use crate as clickhouse;
use clickhouse_derive::Row;

#[allow(unused)]
#[derive(Row)]
#[row(crate = crate)]
struct Row {
a: u32,
b: u32,
}

#[allow(unused)]
#[derive(Row)]
#[row(crate = crate)]
struct Unnamed(u32, u32);

#[test]
Expand Down