forked from diesel-rs/diesel
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcodegen.rs
More file actions
110 lines (100 loc) · 3.27 KB
/
Copy pathcodegen.rs
File metadata and controls
110 lines (100 loc) · 3.27 KB
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
102
103
104
105
106
107
108
109
110
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(table, &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(
table: &TableData,
column: &ColumnInformation,
connection: &InferConnection,
) -> Result<quote::Tokens, Box<Error>> {
let column_name = syn::Ident::new(&*column.column_name);
let column_type = match determine_column_type(column, connection) {
Ok(t) => t,
Err(e) => return Err(format!(
"Error determining type of {}.{}: {}",
table,
column.column_name,
e,
).into()),
};
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(),
}
}