use indexmap::IndexMap;
use std::collections::HashMap;
use crate::common::model::GeneratorType;
use crate::common::model::index::Index;
use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::spanned::Spanned;
fn is_sized(ident: &Ident) -> bool {
!matches!(ident.to_string().as_str(), "String")
}
#[derive(Debug, Clone)]
pub struct Columns {
pub is_sized: bool,
pub columns_map: HashMap<Ident, TokenStream>,
pub field_positions: HashMap<Ident, usize>,
pub indexes: IndexMap<Ident, Index>,
pub primary_keys: Vec<Ident>,
pub generator_type: GeneratorType,
}
#[derive(Debug)]
pub struct Row {
pub name: Ident,
pub type_: Ident,
pub is_primary_key: bool,
pub gen_type: GeneratorType,
pub optional: bool,
}
impl Columns {
pub fn try_from_rows(rows: Vec<Row>, input: &TokenStream) -> syn::Result<Self> {
let mut columns_map = HashMap::new();
let mut field_positions = HashMap::new();
let mut sized = true;
let mut pk = vec![];
let mut gen_type = None;
for (pos, row) in rows.into_iter().enumerate() {
let type_ = &row.type_;
if sized {
sized = is_sized(type_)
}
let type_ = if row.optional {
quote! { core::option::Option<#type_> }
} else {
quote! { #type_ }
};
columns_map.insert(row.name.clone(), type_);
field_positions.insert(row.name.clone(), pos);
if row.is_primary_key {
if let Some(t) = gen_type {
if t != row.gen_type {
return Err(syn::Error::new(input.span(), "Generator type must be same"));
}
} else {
gen_type = Some(row.gen_type)
}
pk.push(row.name);
}
}
if pk.is_empty() {
return Err(syn::Error::new(input.span(), "Primary key must be set"));
}
Ok(Self {
is_sized: sized,
columns_map,
indexes: Default::default(),
primary_keys: pk,
generator_type: gen_type.expect("set"),
field_positions,
})
}
}