1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
use std::error::Error; use quote; use syn; use table_data::TableData; use data_structures::ColumnInformation; use inference::{establish_connection, get_table_data, determine_column_type, get_primary_keys, InferConnection}; pub fn expand_infer_table_from_schema(database_url: &str, table: &TableData) -> Result<quote::Tokens, Box<Error>> { let connection = establish_connection(database_url)?; let data = get_table_data(&connection, table)?; let primary_keys = get_primary_keys(&connection, table)? .into_iter() .map(syn::Ident::new); let table_name = syn::Ident::new(&*table.name); let mut tokens = Vec::with_capacity(data.len()); for a in data { tokens.push(column_def_tokens(&a, &connection)?); } let default_schema = default_schema(&connection); if table.schema != default_schema { if let Some(ref schema) = table.schema { let schema_name = syn::Ident::new(&schema[..]); return Ok(quote!(table! { #schema_name.#table_name (#(#primary_keys),*) { #(#tokens),*, } })); } } Ok(quote!(table! { #table_name (#(#primary_keys),*) { #(#tokens),*, } })) } pub fn handle_schema<I>(tables: I, schema_name: Option<&str>) -> quote::Tokens where I: Iterator<Item = quote::Tokens> { match schema_name { Some(name) => { let schema_ident = syn::Ident::new(name); quote! { pub mod #schema_ident { #(#tables)* } } } None => quote!(#(#tables)*), } } fn column_def_tokens( column: &ColumnInformation, connection: &InferConnection, ) -> Result<quote::Tokens, Box<Error>> { let column_name = syn::Ident::new(&*column.column_name); let column_type = try!(determine_column_type(column, connection)); let tpe = if column_type.path[0] == "diesel" && column_type.path[1] == "types" { let path_segments = column_type.path .into_iter() .skip(2) .map(syn::PathSegment::from) .collect(); syn::Path { global: false, segments: path_segments } } else { let path_segments = column_type.path .into_iter() .map(syn::PathSegment::from) .collect(); syn::Path { global: true, segments: path_segments } }; let mut tpe = quote!(#tpe); if column_type.is_array { tpe = quote!(Array<#tpe>); } if column_type.is_nullable { tpe = quote!(Nullable<#tpe>); } Ok(quote!(#column_name -> #tpe)) } fn default_schema(conn: &InferConnection) -> Option<String> { #[cfg(feature="mysql")] use information_schema::UsesInformationSchema; #[cfg(feature="mysql")] use diesel::mysql::Mysql; match *conn { #[cfg(feature="sqlite")] InferConnection::Sqlite(_) => None, #[cfg(feature="postgres")] InferConnection::Pg(_) => Some("public".into()), #[cfg(feature="mysql")] InferConnection::Mysql(ref c) => Mysql::default_schema(c).ok(), } }