Custom Enums and Arrays
Relevant source files
The following files were used as context for generating this wiki page:
SeaSchema provides comprehensive support for database-specific custom types, notably PostgreSQL user-defined Enums and Arrays, as well as MySQL Enum and Set definitions. This system enables the discovery of existing custom types from a live database and the generation of corresponding SQL statements via the writer module.
The architecture separates the concerns into discovery (querying the database), parsing (transforming raw rows into structured definitions), and writing (converting definitions back into sea-query statements). This ensures that complex types like arrays of enums are correctly mapped between the application and the database.
Custom Enums
Custom enums are handled differently depending on the database backend. In PostgreSQL, enums are treated as first-class user-defined types (UDTs) that exist at the schema level, whereas in MySQL, they are often defined inline within the column specification.
Discovery and Parsing Logic
The discovery process for PostgreSQL involves identifying custom types through the EnumQueryResult which captures the typename and the associated enumlabel values. These are stored in an EnumVariantMap during discovery to allow columns to resolve their specific enum types during the parsing phase.
The diagram above shows the dependency of column discovery on the initial enum discovery phase to correctly map User Defined Types.
Sources: [src/postgres/discovery/mod.rs:55-75], [src/postgres/parser/column.rs:72-80]
Implementation Details
PostgreSQL enum discovery is schema-specific, ensuring that types defined in one schema do not conflict with those in another. The parse_enum_attributes function explicitly populates an EnumDef with values retrieved from the variant map based on the udt_name provided by the database.
| Feature | PostgreSQL Implementation | MySQL Implementation |
|---|---|---|
| Storage | Schema-level User Defined Type | Inline column attribute |
| Discovery | Querying pg_type and pg_enum | Parsed from information_schema.columns |
| Writer | Uses Type::create().as_enum() | Writes inline ENUM ('val1', 'val2') |
Sources: [src/postgres/parser/column.rs:175-190], [src/mysql/writer/types.rs:163-176], [tests/live/postgres/src/main.rs:25-35]
Array Types
PostgreSQL supports array columns which can contain standard types or custom enums. SeaSchema represents these using a recursive Type::Array definition.
Array Metadata Parsing
The parse_array_attributes function handles the conversion of PostgreSQL array strings (e.g., _int4 or my_enum[]) into a structured ColumnType. It strips the array markers and identifies if the inner type is an enum by checking against the EnumVariantMap.
The diagram illustrates the recursive resolution of the base type within a PostgreSQL array.
Sources: [src/postgres/parser/column.rs:192-212], [CHANGELOG.md:88-89]
Usage in Table Definitions
Arrays are defined in sea-query using the .array() method on a ColumnDef. For example, a collection table might store an array of integers or custom text types like citext.
Sources: [tests/live/postgres/src/main.rs:309-322]
MySQL Specific Types: Enum and Set
In MySQL, enums and sets are defined with specific attributes such as character sets and collations. The writer handles these by escaping the string values and appending string attributes.
MySQL Type Writing
The write_enum_def and write_set_def functions in the MySQL writer iterate through the members of the definition, escaping each string value for safe SQL generation.
pub fn write_enum_def(s: &mut String, def: &EnumDef) {
write!(s, " (").unwrap();
for (i, val) in def.values.iter().enumerate() {
if i > 0 {
write!(s, ", ").unwrap();
}
write!(s, "\'{}\'", MysqlQueryBuilder.escape_string(val.as_str())).unwrap();
}
write!(s, ")").unwrap();
Self::write_string_attr(s, &def.attr);
}
Sources: [src/mysql/writer/types.rs:163-176], [src/mysql/writer/column.rs:170-178]
Summary of Data Structures
Key structures used across the discovery and writer modules for managing these types:
| Struct/Enum | Description | File Path |
|---|---|---|
EnumDef | Contains the typename and a list of string values for an Enum. | src/postgres/def.rs |
EnumVariantMap | A HashMap mapping enum typenames to their variant labels. | src/postgres/discovery/mod.rs |
ColumnType | An enum representing all possible SQL types, including Enum, Set, and Array. | src/postgres/def.rs |
NumericAttr | Attributes for numeric types (precision, scale, unsigned, zerofill). | src/mysql/def.rs |
Sources: [src/postgres/discovery/mod.rs:25-25], [src/mysql/writer/column.rs:1-5], [src/postgres/parser/column.rs:1-5]
Conclusion
The handling of custom enums and arrays in SeaSchema allows for high-fidelity database schema synchronization. By utilizing a pre-discovery phase for enums in PostgreSQL and detailed attribute writing in MySQL, the library ensures that complex user-defined structures are preserved and correctly represented in Rust type definitions.