Skip to content

Commit b6d8a8c

Browse files
authored
feat: make orm row decoding fallible (#361)
1 parent a679485 commit b6d8a8c

5 files changed

Lines changed: 236 additions & 72 deletions

File tree

kite_sql_serde_macros/src/orm.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
6666
));
6767
};
6868

69-
let mut assignments = Vec::new();
69+
let mut field_initializers = Vec::new();
70+
let mut field_index_declarations = Vec::new();
71+
let mut field_index_resolvers = Vec::new();
7072
let mut params = Vec::new();
7173
let mut orm_fields = Vec::new();
7274
let mut orm_columns = Vec::new();
@@ -132,6 +134,13 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
132134
"decimal field cannot be skipped",
133135
));
134136
}
137+
generics
138+
.make_where_clause()
139+
.predicates
140+
.push(parse_quote!(#field_ty : ::core::default::Default));
141+
field_initializers.push(quote! {
142+
#field_name: ::core::default::Default::default()
143+
});
135144
continue;
136145
}
137146

@@ -163,6 +172,7 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
163172
let is_unique = field.unique;
164173
let is_index = field.index;
165174
let column_index = orm_columns.len();
175+
let field_index_ident = format_ident!("__kite_orm_{field_name}_index");
166176

167177
persisted_columns.push((field_name_string, column_name.clone()));
168178
column_names.push(column_name.clone());
@@ -223,11 +233,22 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
223233
quote! { None::<::kite_sql::types::value::DataValue> }
224234
};
225235

226-
assignments.push(quote! {
227-
if let Some(value) = ::kite_sql::orm::try_get::<#field_ty>(&mut tuple, schema, #column_name_lit) {
228-
struct_instance.#field_name = value;
236+
field_index_declarations.push(quote! {
237+
let mut #field_index_ident = None;
238+
});
239+
field_index_resolvers.push(quote! {
240+
if #field_index_ident.is_none() && __kite_orm_column_name == #column_name_lit {
241+
#field_index_ident = Some(__kite_orm_index);
242+
__kite_orm_found_fields += 1;
229243
}
230244
});
245+
field_initializers.push(quote! {
246+
#field_name: ::kite_sql::orm::take_value_at::<#field_ty>(
247+
&mut tuple,
248+
#field_index_ident,
249+
#column_name_lit,
250+
)?
251+
});
231252
params.push(quote! {
232253
(#placeholder_lit, ::kite_sql::orm::ToDataValue::to_data_value(&self.#field_name))
233254
});
@@ -379,23 +400,31 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
379400
let primary_key_value = primary_key_value.expect("primary key checked above");
380401
let _primary_key_column = primary_key_column.expect("primary key checked above");
381402
let _primary_key_placeholder = primary_key_placeholder.expect("primary key checked above");
382-
let mut from_generics = generics.clone();
383-
from_generics.params.insert(0, parse_quote!('__kite_arena));
384-
from_generics.params.insert(0, parse_quote!('__kite_schema));
385-
let (from_impl_generics, _, from_where_clause) = from_generics.split_for_impl();
403+
let field_count = field_index_declarations.len();
386404
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
387405

388406
Ok(quote! {
389-
impl #from_impl_generics ::core::convert::From<(&::kite_sql::types::tuple::SchemaView<'__kite_schema, '__kite_arena>, ::kite_sql::types::tuple::Tuple)>
407+
impl #impl_generics ::kite_sql::orm::FromQueryRow
390408
for #struct_name #ty_generics
391-
#from_where_clause
409+
#where_clause
392410
{
393-
fn from((schema, mut tuple): (&::kite_sql::types::tuple::SchemaView<'__kite_schema, '__kite_arena>, ::kite_sql::types::tuple::Tuple)) -> Self {
394-
let mut struct_instance = <Self as ::core::default::Default>::default();
395-
396-
#(#assignments)*
411+
fn from_query_row(
412+
schema: &::kite_sql::types::tuple::SchemaView<'_, '_>,
413+
mut tuple: ::kite_sql::types::tuple::Tuple,
414+
) -> ::std::result::Result<Self, ::kite_sql::errors::DatabaseError> {
415+
let mut __kite_orm_found_fields = 0usize;
416+
#(#field_index_declarations)*
417+
for (__kite_orm_index, __kite_orm_column) in schema.iter().enumerate() {
418+
let __kite_orm_column_name = __kite_orm_column.name();
419+
#(#field_index_resolvers)*
420+
if __kite_orm_found_fields == #field_count {
421+
break;
422+
}
423+
}
397424

398-
struct_instance
425+
Ok(Self {
426+
#(#field_initializers),*
427+
})
399428
}
400429
}
401430

kite_sql_serde_macros/src/projection.rs

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use darling::ast::Data;
22
use darling::{FromDeriveInput, FromField};
33
use proc_macro2::{Span, TokenStream};
4-
use quote::quote;
4+
use quote::{format_ident, quote};
55
use syn::{parse_quote, DeriveInput, Error, Generics, Ident, LitStr, Type};
66

77
#[derive(Debug, FromDeriveInput)]
@@ -34,7 +34,9 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
3434
};
3535

3636
let mut projection_exprs = Vec::new();
37-
let mut assignments = Vec::new();
37+
let mut field_initializers = Vec::new();
38+
let mut field_index_declarations = Vec::new();
39+
let mut field_index_resolvers = Vec::new();
3840

3941
for field in data_struct.fields {
4042
let ProjectionFieldOpts {
@@ -50,6 +52,7 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
5052
let source_name = rename.clone().unwrap_or_else(|| field_name_string.clone());
5153
let source_name_lit = LitStr::new(&source_name, Span::call_site());
5254
let field_name_lit = LitStr::new(&field_name_string, Span::call_site());
55+
let field_index_ident = format_ident!("__kite_projection_{field_name}_index");
5356
let relation_expr = if let Some(source_relation) = from {
5457
let relation_lit = LitStr::new(&source_relation, Span::call_site());
5558
quote!(#relation_lit)
@@ -74,17 +77,25 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
7477
scope.column_ref(#relation_expr, #source_name_lit)?
7578
}
7679
});
77-
assignments.push(quote! {
78-
if let Some(value) = ::kite_sql::orm::try_get::<#field_ty>(&mut tuple, schema, #field_name_lit) {
79-
struct_instance.#field_name = value;
80+
field_index_declarations.push(quote! {
81+
let mut #field_index_ident = None;
82+
});
83+
field_index_resolvers.push(quote! {
84+
if #field_index_ident.is_none() && __kite_orm_column_name == #field_name_lit {
85+
#field_index_ident = Some(__kite_orm_index);
86+
__kite_orm_found_fields += 1;
8087
}
8188
});
89+
field_initializers.push(quote! {
90+
#field_name: ::kite_sql::orm::take_value_at::<#field_ty>(
91+
&mut tuple,
92+
#field_index_ident,
93+
#field_name_lit,
94+
)?
95+
});
8296
}
8397

84-
let mut from_generics = generics.clone();
85-
from_generics.params.insert(0, parse_quote!('__kite_arena));
86-
from_generics.params.insert(0, parse_quote!('__kite_schema));
87-
let (from_impl_generics, _, from_where_clause) = from_generics.split_for_impl();
98+
let field_count = field_index_declarations.len();
8899
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
89100

90101
Ok(quote! {
@@ -105,13 +116,26 @@ pub(crate) fn handle(ast: DeriveInput) -> Result<TokenStream, Error> {
105116
}
106117
}
107118

108-
impl #from_impl_generics From<(&::kite_sql::types::tuple::SchemaView<'__kite_schema, '__kite_arena>, ::kite_sql::types::tuple::Tuple)> for #struct_name #ty_generics
109-
#from_where_clause
119+
impl #impl_generics ::kite_sql::orm::FromQueryRow for #struct_name #ty_generics
120+
#where_clause
110121
{
111-
fn from((schema, mut tuple): (&::kite_sql::types::tuple::SchemaView<'__kite_schema, '__kite_arena>, ::kite_sql::types::tuple::Tuple)) -> Self {
112-
let mut struct_instance = <Self as ::std::default::Default>::default();
113-
#(#assignments)*
114-
struct_instance
122+
fn from_query_row(
123+
schema: &::kite_sql::types::tuple::SchemaView<'_, '_>,
124+
mut tuple: ::kite_sql::types::tuple::Tuple,
125+
) -> ::std::result::Result<Self, ::kite_sql::errors::DatabaseError> {
126+
let mut __kite_orm_found_fields = 0usize;
127+
#(#field_index_declarations)*
128+
for (__kite_orm_index, __kite_orm_column) in schema.iter().enumerate() {
129+
let __kite_orm_column_name = __kite_orm_column.name();
130+
#(#field_index_resolvers)*
131+
if __kite_orm_found_fields == #field_count {
132+
break;
133+
}
134+
}
135+
136+
Ok(Self {
137+
#(#field_initializers),*
138+
})
115139
}
116140
}
117141
})

src/db.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ use crate::optimizer::heuristic::batch::HepBatchStrategy;
3737
use crate::optimizer::heuristic::optimizer::HepOptimizerPipeline;
3838
use crate::optimizer::rule::implementation::ImplementationRuleImpl;
3939
use crate::optimizer::rule::normalization::NormalizationRuleImpl;
40+
#[cfg(feature = "orm")]
41+
use crate::orm::FromQueryRow;
4042
use crate::planner::operator::Operator;
4143
use crate::planner::{LogicalPlan, PlanArena, TableArenaCell};
4244
#[cfg(all(not(target_arch = "wasm32"), feature = "lmdb"))]
@@ -945,12 +947,12 @@ pub trait ResultIter: BorrowResultIter + Iterator<Item = Result<Tuple, DatabaseE
945947
/// Converts this iterator into a typed ORM iterator.
946948
///
947949
/// This is available when the `orm` feature is enabled and the target type
948-
/// implements `From<(&SchemaView, Tuple)>`, which is typically generated by
949-
/// `#[derive(Model)]`.
950+
/// implements `FromQueryRow`, which is typically generated by
951+
/// `#[derive(Model)]` or `#[derive(Projection)]`.
950952
fn orm<T>(self) -> OrmIter<Self, T>
951953
where
952954
Self: Sized,
953-
T: for<'view, 'schema, 'arena> From<(&'view SchemaView<'schema, 'arena>, Tuple)>,
955+
T: FromQueryRow,
954956
{
955957
OrmIter::new(self)
956958
}
@@ -969,7 +971,7 @@ pub struct OrmIter<I, T> {
969971
impl<I, T> OrmIter<I, T>
970972
where
971973
I: ResultIter,
972-
T: for<'view, 'schema, 'arena> From<(&'view SchemaView<'schema, 'arena>, Tuple)>,
974+
T: FromQueryRow,
973975
{
974976
fn new(inner: I) -> Self {
975977
Self {
@@ -993,7 +995,7 @@ where
993995
impl<I, T> Iterator for OrmIter<I, T>
994996
where
995997
I: ResultIter,
996-
T: for<'view, 'schema, 'arena> From<(&'view SchemaView<'schema, 'arena>, Tuple)>,
998+
T: FromQueryRow,
997999
{
9981000
type Item = Result<T, DatabaseError>;
9991001

@@ -1002,7 +1004,7 @@ where
10021004
Ok(tuple) => tuple,
10031005
Err(err) => return Some(Err(err)),
10041006
};
1005-
Some(Ok(self.inner.schema(|schema| T::from((schema, tuple)))))
1007+
Some(self.inner.schema(|schema| T::from_query_row(schema, tuple)))
10061008
}
10071009
}
10081010

0 commit comments

Comments
 (0)