Skip to content
Draft
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
37 changes: 26 additions & 11 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,39 @@ fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> Result<T
Ok(match &data.fields {
Fields::Named(fields) => {
let rename_rule = container.rename_all_rules().deserialize;
let column_names_iter = fields

let chain_iters = fields
.named
.iter()
.enumerate()
.map(|(index, field)| Field::from_ast(cx, index, field, None, &SerdeDefault::None))
.filter(|field| !field.skip_serializing() && !field.skip_deserializing())
.map(|field| {
rename_rule
.apply_to_field(field.name().serialize_name())
.to_string()
.map(|(index, field)| {
(
Field::from_ast(cx, index, field, None, &SerdeDefault::None),
&field.ty,
)
})
.filter(|(field, _)| !(field.skip_serializing() || field.skip_deserializing()))
.map(|(field_meta, ty)| {
if field_meta.flatten() {
quote! {
<#ty as clickhouse::Row>::column_names().into_iter()
}
} else {
let column_name = rename_rule
.apply_to_field(field_meta.name().serialize_name())
.to_string();
quote! {
std::iter::once(#column_name)
}
}
});

quote! {
&[#( #column_names_iter,)*]
std::iter::empty() #(.chain(#chain_iters))*
}
}
Fields::Unnamed(_) => {
quote! { &[] }
quote! { [] }
}
Fields::Unit => unreachable!("checked by the caller"),
})
Expand Down Expand Up @@ -94,8 +109,8 @@ fn row_impl(input: DeriveInput) -> Result<TokenStream> {
#[automatically_derived]
impl #impl_generics clickhouse::Row for #name #ty_generics #where_clause {
const NAME: &'static str = stringify!(#name);
const COLUMN_NAMES: &'static [&'static str] = #column_names;
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> { #column_names }
fn column_count() -> usize { <Self as clickhouse::Row>::column_names().into_iter().count() }
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;

type Value<'__v> = #value;
Expand Down
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_borrowed_row-2.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample<'a, A, B> {
#[automatically_derived]
impl<'a, A, B> clickhouse::Row for Sample<'a, A, B> {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Sample<'__v, A, B>;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_borrowed_row-3.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ where
T: Clone,
{
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Sample<'__v, T>;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_borrowed_row.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample<'a, T> {
#[automatically_derived]
impl<'a, T> clickhouse::Row for Sample<'a, T> {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Sample<'__v, T>;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_owned_row-2.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample<A, B> {
#[automatically_derived]
impl<A, B> clickhouse::Row for Sample<A, B> {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_owned_row-3.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ where
T: Clone,
{
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/generic_owned_row.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample<T> {
#[automatically_derived]
impl<T> clickhouse::Row for Sample<T> {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
11 changes: 9 additions & 2 deletions derive/src/tests/snapshots/serde_rename.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@ struct Sample {
#[automatically_derived]
impl clickhouse::Row for Sample {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "items.a", "items.b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty()
.chain(std::iter::once("a"))
.chain(std::iter::once("items.a"))
.chain(std::iter::once("items.b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/serde_skip_deserializing.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ struct Sample {
#[automatically_derived]
impl clickhouse::Row for Sample {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/serde_skip_serializing.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ struct Sample {
#[automatically_derived]
impl clickhouse::Row for Sample {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/simple_borrowed_row.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample<'a> {
#[automatically_derived]
impl<'a> clickhouse::Row for Sample<'a> {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Sample<'__v>;
}
8 changes: 6 additions & 2 deletions derive/src/tests/snapshots/simple_owned_row.snap
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ struct Sample {
#[automatically_derived]
impl clickhouse::Row for Sample {
const NAME: &'static str = stringify!(Sample);
const COLUMN_NAMES: &'static [&'static str] = &["a", "b"];
const COLUMN_COUNT: usize = <Self as clickhouse::Row>::COLUMN_NAMES.len();
fn column_names() -> impl IntoIterator<Item = &'static str> {
std::iter::empty().chain(std::iter::once("a")).chain(std::iter::once("b"))
}
fn column_count() -> usize {
<Self as clickhouse::Row>::column_names().into_iter().count()
}
const KIND: clickhouse::_priv::RowKind = clickhouse::_priv::RowKind::Struct;
type Value<'__v> = Self;
}
69 changes: 50 additions & 19 deletions src/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ pub trait Row {
const NAME: &'static str;
// TODO: different list for SELECT/INSERT (de/ser)
#[doc(hidden)]
const COLUMN_NAMES: &'static [&'static str];
fn column_names() -> impl IntoIterator<Item = &'static str>;
#[doc(hidden)]
const COLUMN_COUNT: usize;
fn column_count() -> usize;
#[doc(hidden)]
const KIND: RowKind;
#[doc(hidden)]
Expand Down Expand Up @@ -220,8 +220,8 @@ macro_rules! impl_row_for_tuple {
($i:ident $($other:ident)+) => {
impl<$i: Row, $($other: Primitive),+> Row for ($i, $($other),+) {
const NAME: &'static str = $i::NAME;
const COLUMN_NAMES: &'static [&'static str] = $i::COLUMN_NAMES;
const COLUMN_COUNT: usize = $i::COLUMN_COUNT + count_tokens!($($other)*);
fn column_names() -> impl IntoIterator<Item = &'static str> { $i::column_names() }
fn column_count() -> usize { $i::column_count() + count_tokens!($($other)*) }
const KIND: RowKind = RowKind::Tuple;

type Value<'a> = Self;
Expand All @@ -237,8 +237,12 @@ impl Primitive for () {}

impl<P: Primitive> Row for P {
const NAME: &'static str = stringify!(P);
const COLUMN_NAMES: &'static [&'static str] = &[];
const COLUMN_COUNT: usize = 1;
fn column_names() -> impl IntoIterator<Item = &'static str> {
[]
}
fn column_count() -> usize {
1
}
const KIND: RowKind = RowKind::Primitive;

type Value<'a> = Self;
Expand All @@ -248,29 +252,34 @@ impl_row_for_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8);

impl<T> Row for Vec<T> {
const NAME: &'static str = "Vec";
const COLUMN_NAMES: &'static [&'static str] = &[];
const COLUMN_COUNT: usize = 1;
fn column_names() -> impl IntoIterator<Item = &'static str> {
[]
}
fn column_count() -> usize {
1
}
const KIND: RowKind = RowKind::Vec;

type Value<'a> = Self;
}

/// Collects all field names in depth and joins them with comma.
pub(crate) fn join_column_names<R: Row>() -> Option<String> {
if R::COLUMN_NAMES.is_empty() {
if R::column_names().into_iter().next().is_none() {
return None;
}

let out = R::COLUMN_NAMES
.iter()
.enumerate()
.fold(String::new(), |mut res, (idx, name)| {
if idx > 0 {
res.push(',');
}
sql::escape::identifier(name, &mut res).expect("impossible");
res
});
let out =
R::column_names()
.into_iter()
.enumerate()
.fold(String::new(), |mut res, (idx, name)| {
if idx > 0 {
res.push(',');
}
sql::escape::identifier(name, &mut res).expect("impossible");
res
});

Some(out)
}
Expand Down Expand Up @@ -381,4 +390,26 @@ mod tests {

assert_eq!(join_column_names::<MyRow>().unwrap(), "`type`,`if`");
}

#[test]
fn it_flattens() {
use serde::Serialize;

#[derive(Row, Serialize)]
#[allow(dead_code)]
struct Inner {
a: u32,
b: u32,
}

#[derive(Row, Serialize)]
#[allow(dead_code)]
struct Outer {
#[serde(flatten)]
inner: Inner,
c: u32,
}

assert_eq!(join_column_names::<Outer>().unwrap(), "`a`,`b`,`c`");
}
}
Loading