mysql: tweak type equivalence rules to try and support both rust best practices but still be compatible with the loose types of mysql

This commit is contained in:
Ryan Leckey
2020-03-25 03:56:39 -07:00
parent 50928b06b8
commit ad2cf1676f
7 changed files with 124 additions and 24 deletions

View File

@@ -95,6 +95,16 @@ impl MySqlTypeInfo {
}
}
#[doc(hidden)]
pub const fn r#enum() -> Self {
Self {
id: TypeId::ENUM,
is_unsigned: false,
is_binary: false,
char_set: 0,
}
}
pub(crate) fn from_nullable_column_def(def: &ColumnDefinition) -> Self {
Self {
id: def.type_id,
@@ -157,6 +167,51 @@ impl Display for MySqlTypeInfo {
}
}
impl PartialEq<MySqlTypeInfo> for MySqlTypeInfo {
fn eq(&self, other: &MySqlTypeInfo) -> bool {
match self.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM
if (self.is_binary == other.is_binary)
&& match other.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM => true,
_ => false,
} =>
{
return true;
}
_ => {}
}
if self.id.0 != other.id.0 {
return false;
}
match self.id {
TypeId::TINY_INT | TypeId::SMALL_INT | TypeId::INT | TypeId::BIG_INT => {
return self.is_unsigned == other.is_unsigned;
}
_ => {}
}
true
}
}
impl TypeInfo for MySqlTypeInfo {
fn compatible(&self, other: &Self) -> bool {
// NOTE: MySQL is weakly typed so much of this may be surprising to a Rust developer.
@@ -190,19 +245,45 @@ impl TypeInfo for MySqlTypeInfo {
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM
if (self.is_binary == other.is_binary)
&& match other.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM => true,
if match other.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB => true,
_ => false,
} =>
_ => false,
} =>
{
true
}
// Enums are considered compatible with other text/binary types
TypeId::ENUM
if match other.id {
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM => true,
_ => false,
} =>
{
true
}
TypeId::VAR_CHAR
| TypeId::TEXT
| TypeId::CHAR
| TypeId::TINY_BLOB
| TypeId::MEDIUM_BLOB
| TypeId::LONG_BLOB
| TypeId::ENUM
if other.id == TypeId::ENUM =>
{
true
}
@@ -227,8 +308,7 @@ impl TypeInfo for MySqlTypeInfo {
true
}
// Fallback to equality of only [id] and [is_unsigned]
_ => self.id.0 == other.id.0 && self.is_unsigned == other.is_unsigned,
_ => self.eq(other),
}
}
}

View File

@@ -46,7 +46,7 @@ pub mod ipnetwork {
#[derive(Debug, PartialEq)]
pub struct Json<T>(pub T);
pub trait TypeInfo: Debug + Display + Clone {
pub trait TypeInfo: PartialEq<Self> + Debug + Display + Clone {
/// Compares type information to determine if `other` is compatible at the Rust level
/// with `self`.
fn compatible(&self, other: &Self) -> bool;