Skip to content

Commit 20c313f

Browse files
committed
feat: address review comments, more work on migration generation
1 parent 4db9303 commit 20c313f

File tree

2 files changed

+118
-19
lines changed

2 files changed

+118
-19
lines changed

flareon-cli/tests/migration_generator.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,21 @@ fn create_model_state_test() {
2727
assert_eq!(field.column_name, "id");
2828
assert!(field.primary_key);
2929
assert!(field.auto_value.unwrap());
30-
assert!(!field.foreign_key.unwrap());
30+
assert!(field.foreign_key.clone().unwrap().is_none());
3131

3232
let field = &fields[1];
3333
assert_eq!(field.column_name, "field_1");
3434
assert!(!field.primary_key);
3535
assert!(!field.auto_value.unwrap());
36-
assert!(!field.foreign_key.unwrap());
36+
assert!(field.foreign_key.clone().unwrap().is_none());
3737

3838
let field = &fields[2];
3939
assert_eq!(field.column_name, "field_2");
4040
assert!(!field.primary_key);
4141
assert!(!field.auto_value.unwrap());
42-
assert!(!field.foreign_key.unwrap());
42+
assert!(field.foreign_key.clone().unwrap().is_none());
43+
} else {
44+
panic!("Expected a create model operation");
4345
}
4446
}
4547

flareon-codegen/src/model.rs

Lines changed: 113 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ pub struct FieldOpts {
133133

134134
impl FieldOpts {
135135
#[must_use]
136-
fn find_type(&self, type_to_check: &str, symbol_resolver: &SymbolResolver) -> bool {
136+
fn has_type(&self, type_to_check: &str, symbol_resolver: &SymbolResolver) -> bool {
137137
let mut ty = self.ty.clone();
138138
symbol_resolver.resolve(&mut ty);
139139
Self::inner_type_names(&ty)
@@ -171,6 +171,54 @@ impl FieldOpts {
171171
}
172172
}
173173

174+
fn find_type(&self, type_to_find: &str, symbol_resolver: &SymbolResolver) -> Option<syn::Type> {
175+
let mut ty = self.ty.clone();
176+
symbol_resolver.resolve(&mut ty);
177+
Self::find_type_resolved(&ty, type_to_find)
178+
}
179+
180+
fn find_type_resolved(ty: &syn::Type, type_to_find: &str) -> Option<syn::Type> {
181+
if let syn::Type::Path(type_path) = ty {
182+
let name = type_path
183+
.path
184+
.segments
185+
.iter()
186+
.map(|s| s.ident.to_string())
187+
.collect::<Vec<_>>()
188+
.join("::");
189+
190+
if name == type_to_find {
191+
return Some(ty.clone());
192+
}
193+
194+
for arg in &type_path.path.segments {
195+
if let syn::PathArguments::AngleBracketed(arg) = &arg.arguments {
196+
if let Some(ty) = Self::find_type_in_generics(arg, type_to_find) {
197+
return Some(ty);
198+
}
199+
}
200+
}
201+
}
202+
203+
None
204+
}
205+
206+
fn find_type_in_generics(
207+
arg: &syn::AngleBracketedGenericArguments,
208+
type_to_find: &str,
209+
) -> Option<syn::Type> {
210+
arg.args
211+
.iter()
212+
.filter_map(|arg| {
213+
if let syn::GenericArgument::Type(ty) = arg {
214+
Self::find_type_resolved(ty, type_to_find)
215+
} else {
216+
None
217+
}
218+
})
219+
.next()
220+
}
221+
174222
/// Convert the field options into a field.
175223
///
176224
/// # Panics
@@ -183,10 +231,13 @@ impl FieldOpts {
183231
let column_name = name.to_string();
184232
let (auto_value, foreign_key) = match symbol_resolver {
185233
Some(resolver) => (
186-
Some(self.find_type("flareon::db::Auto", resolver)),
187-
Some(self.find_type("flareon::db::ForeignKey", resolver)),
234+
MaybeUnknown::Determined(self.find_type("flareon::db::Auto", resolver).is_some()),
235+
MaybeUnknown::Determined(
236+
self.find_type("flareon::db::ForeignKey", resolver)
237+
.map(ForeignKeySpec::from),
238+
),
188239
),
189-
None => (None, None),
240+
None => (MaybeUnknown::Unknown, MaybeUnknown::Unknown),
190241
};
191242
let is_primary_key = column_name == "id" || self.primary_key.is_present();
192243

@@ -224,19 +275,65 @@ pub struct Field {
224275
pub field_name: syn::Ident,
225276
pub column_name: String,
226277
pub ty: syn::Type,
227-
/// Whether the field is an auto field (e.g. `id`); `None` if it could not
228-
/// be determined.
229-
pub auto_value: Option<bool>,
278+
/// Whether the field is an auto field (e.g. `id`);
279+
/// [`MaybeUnknown::Unknown`] if this `Field` instance was not resolved with
280+
/// a [`SymbolResolver`].
281+
pub auto_value: MaybeUnknown<bool>,
230282
pub primary_key: bool,
231-
/// Whether the field is a foreign key; `None` if it could not be
232-
/// determined.
233-
pub foreign_key: Option<bool>,
283+
/// [`Some`] wrapped in [`MaybeUnknown::Determined`] if this field is a
284+
/// foreign key; [`None`] wrapped in [`MaybeUnknown::Determined`] if this
285+
/// field is determined not to be a foreign key; [`MaybeUnknown::Unknown`]
286+
/// if this `Field` instance was not resolved with a [`SymbolResolver`].
287+
pub foreign_key: MaybeUnknown<Option<ForeignKeySpec>>,
234288
pub unique: bool,
235289
}
236290

291+
/// Wraps a type whose value may or may not be possible to be determined using
292+
/// the information available.
293+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
294+
pub enum MaybeUnknown<T> {
295+
/// Indicates that this instance is determined to be a certain value
296+
/// (possibly [`None`] if wrapping an [`Option`]).
297+
Determined(T),
298+
/// Indicates that the value is unknown.
299+
Unknown,
300+
}
301+
302+
impl<T> MaybeUnknown<T> {
303+
pub fn unwrap(self) -> T {
304+
match self {
305+
MaybeUnknown::Determined(value) => value,
306+
MaybeUnknown::Unknown => {
307+
panic!("called `MaybeUnknown::unwrap()` on an `Unknown` value")
308+
}
309+
}
310+
}
311+
312+
pub fn expect(self, msg: &str) -> T {
313+
match self {
314+
MaybeUnknown::Determined(value) => value,
315+
MaybeUnknown::Unknown => {
316+
panic!("{}", msg)
317+
}
318+
}
319+
}
320+
}
321+
322+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
323+
pub struct ForeignKeySpec {
324+
pub ty: syn::Type,
325+
}
326+
327+
impl From<syn::Type> for ForeignKeySpec {
328+
fn from(value: syn::Type) -> Self {
329+
todo!()
330+
}
331+
}
332+
237333
#[cfg(test)]
238334
mod tests {
239335
use syn::parse_quote;
336+
use syn::TraitBoundModifier::Maybe;
240337

241338
use super::*;
242339
#[cfg(feature = "symbol-resolver")]
@@ -371,8 +468,8 @@ mod tests {
371468
assert_eq!(field.column_name, "name");
372469
assert_eq!(field.ty, parse_quote!(String));
373470
assert!(field.unique);
374-
assert_eq!(field.auto_value, None);
375-
assert_eq!(field.foreign_key, None);
471+
assert_eq!(field.auto_value, MaybeUnknown::Unknown);
472+
assert_eq!(field.foreign_key, MaybeUnknown::Unknown);
376473
}
377474

378475
#[test]
@@ -403,9 +500,9 @@ mod tests {
403500
unique: Default::default(),
404501
};
405502

406-
assert!(opts.find_type("my_crate::MyContainer", &resolver));
407-
assert!(opts.find_type("std::string::String", &resolver));
408-
assert!(!opts.find_type("MyContainer", &resolver));
409-
assert!(!opts.find_type("String", &resolver));
503+
assert!(opts.has_type("my_crate::MyContainer", &resolver));
504+
assert!(opts.has_type("std::string::String", &resolver));
505+
assert!(!opts.has_type("MyContainer", &resolver));
506+
assert!(!opts.has_type("String", &resolver));
410507
}
411508
}

0 commit comments

Comments
 (0)