Skip to content

Commit b4266be

Browse files
committed
Give a more specific error message for unsigned types
We don't yet support these types in MySQL, but the error a user will recieve is not terribly helpful, since the type will contain a space so the `table!` macro invocation will just have bad tokens. This gives a more specific error message for unsigned types, as well as ensuring that we get a reasonable error for other types would result in a bad macro invocation. (I'm not actually aware of any other types which have a space, but I'd rather not dig through the entire manual right now) In theory we could exclude unsigned floats from this, since unsigned floats aren't actually a thing and that "type" in MySQL is basically just a check constraint, but I'd rather hold off and actually represent in Diesel that the type is different when we add support for unsigned integer types. Fixes diesel-rs#754.
1 parent 2562076 commit b4266be

3 files changed

Lines changed: 51 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ All user visible changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org/), as described
55
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)
66

7+
## Unreleased
8+
9+
### Fixed
10+
11+
* `diesel_codegen` will provide a more useful error message when it encounters
12+
an unsupported type that contains a space in MySQL.
13+
714
## [0.11.4] - 2017-02-21
815

916
### Fixed

diesel_infer_schema/src/codegen.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn expand_infer_table_from_schema(database_url: &str, table: &TableData)
2121
let mut tokens = Vec::with_capacity(data.len());
2222

2323
for a in data {
24-
tokens.push(column_def_tokens(&a, &connection)?);
24+
tokens.push(column_def_tokens(table, &a, &connection)?);
2525
}
2626
let default_schema = default_schema(&connection);
2727
if table.schema != default_schema {
@@ -54,11 +54,20 @@ pub fn handle_schema<I>(tables: I, schema_name: Option<&str>) -> quote::Tokens
5454
}
5555

5656
fn column_def_tokens(
57+
table: &TableData,
5758
column: &ColumnInformation,
5859
connection: &InferConnection,
5960
) -> Result<quote::Tokens, Box<Error>> {
6061
let column_name = syn::Ident::new(&*column.column_name);
61-
let column_type = try!(determine_column_type(column, connection));
62+
let column_type = match determine_column_type(column, connection) {
63+
Ok(t) => t,
64+
Err(e) => return Err(format!(
65+
"Error determining type of {}.{}: {}",
66+
table,
67+
column.column_name,
68+
e,
69+
).into()),
70+
};
6271
let tpe = if column_type.path[0] == "diesel" && column_type.path[1] == "types" {
6372
let path_segments = column_type.path
6473
.into_iter()

diesel_infer_schema/src/mysql.rs

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::error::Error;
33
use data_structures::*;
44

55
pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box<Error>> {
6-
let tpe = determine_type_name(&attr.type_name);
6+
let tpe = determine_type_name(&attr.type_name)?;
77

88
Ok(ColumnType {
99
path: vec!["diesel".into(), "types".into(), capitalize(tpe)],
@@ -12,15 +12,23 @@ pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box
1212
})
1313
}
1414

15-
fn determine_type_name(sql_type_name: &str) -> &str {
16-
if sql_type_name == "tinyint(1)" {
15+
fn determine_type_name(sql_type_name: &str) -> Result<&str, Box<Error>> {
16+
let result = if sql_type_name == "tinyint(1)" {
1717
"bool"
1818
} else if sql_type_name.starts_with("int") {
1919
"integer"
2020
} else if let Some(idx) = sql_type_name.find('(') {
2121
&sql_type_name[..idx]
2222
} else {
2323
sql_type_name
24+
};
25+
26+
if result.to_lowercase().contains("unsigned") {
27+
Err("unsigned types are not yet supported".into())
28+
} else if result.contains(' ') {
29+
Err(format!("unrecognized type {:?}", result).into())
30+
} else {
31+
Ok(result)
2432
}
2533
}
2634

@@ -30,26 +38,38 @@ fn capitalize(name: &str) -> String {
3038

3139
#[test]
3240
fn values_which_already_map_to_type_are_returned_unchanged() {
33-
assert_eq!("text", determine_type_name("text"));
34-
assert_eq!("integer", determine_type_name("integer"));
35-
assert_eq!("biginteger", determine_type_name("biginteger"));
41+
assert_eq!("text", determine_type_name("text").unwrap());
42+
assert_eq!("integer", determine_type_name("integer").unwrap());
43+
assert_eq!("biginteger", determine_type_name("biginteger").unwrap());
3644
}
3745

3846
#[test]
3947
fn trailing_parenthesis_are_stripped() {
40-
assert_eq!("varchar", determine_type_name("varchar(255)"));
41-
assert_eq!("decimal", determine_type_name("decimal(10, 2)"));
42-
assert_eq!("float", determine_type_name("float(1)"));
48+
assert_eq!("varchar", determine_type_name("varchar(255)").unwrap());
49+
assert_eq!("decimal", determine_type_name("decimal(10, 2)").unwrap());
50+
assert_eq!("float", determine_type_name("float(1)").unwrap());
4351
}
4452

4553
#[test]
4654
fn tinyint_is_bool_if_limit_1() {
47-
assert_eq!("bool", determine_type_name("tinyint(1)"));
48-
assert_eq!("tinyint", determine_type_name("tinyint(2)"));
55+
assert_eq!("bool", determine_type_name("tinyint(1)").unwrap());
56+
assert_eq!("tinyint", determine_type_name("tinyint(2)").unwrap());
4957
}
5058

5159
#[test]
5260
fn int_is_treated_as_integer() {
53-
assert_eq!("integer", determine_type_name("int"));
54-
assert_eq!("integer", determine_type_name("int(11)"));
61+
assert_eq!("integer", determine_type_name("int").unwrap());
62+
assert_eq!("integer", determine_type_name("int(11)").unwrap());
63+
}
64+
65+
#[test]
66+
fn unsigned_types_are_not_supported() {
67+
assert!(determine_type_name("float unsigned").is_err());
68+
assert!(determine_type_name("UNSIGNED INT").is_err());
69+
assert!(determine_type_name("unsigned bigint").is_err())
70+
}
71+
72+
#[test]
73+
fn types_with_space_are_not_supported() {
74+
assert!(determine_type_name("lol wat").is_err());
5575
}

0 commit comments

Comments
 (0)