Hello!
I’ve modified ActiveRecord a bit to support enum columns. This is tested
only with MySQL, and maybe needs some changes for other adapters (if
they use another syntax or quoting style).
I believe this patch should be tested well, so I haven’t (yet) tried to
post it to the official Trac. It is also not solid-as-a-rock when it
comes to quoting ENUM values.
After applying this thing, rake db_schema_dump properly handles enum
columns, and also it’s possible to write migrations like this:
add_column :users, :level, :enum, :limit => [‘viewer’, ‘author’,
‘admin’]
Observe that I’m (over)using the limit field to specify ENUM values.
Here’s the patch.
Index:
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
(revision 3486)
+++
activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
(working copy)
@@ -235,7 +235,15 @@
def type_to_sql(type, limit = nil) #:nodoc:
native = native_database_types[type]
-
limit ||= native[:limit]
-
# this is a special case, because data type differs -
case type -
when :enum -
fail ":enum column limit must be specified" if limit.nil? -
fail ":enum column limit must be an array" unless
limit.is_a? Array
-
limit = limit.collect {|n| "'#{n}'"}.join "," -
else -
limit ||= native[:limit] -
end column_type_sql = native[:name] column_type_sql << "(#{limit})" if limit column_type_sql
Index:
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
(revision 3486)
+++
activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
(working copy)
@@ -18,7 +18,7 @@
@sql_type = sql_type
# have to do this one separately because type_cast depends on
#type
@default = type_cast(default)
-
@limit = extract_limit(sql_type) unless sql_type.nil?
-
@limit = extract_limit_or_enum_values(sql_type) unless
sql_type.nil?
@primary = nil
@text = [:string, :text].include? @type
@number = [:float, :integer].include? @type
@@ -44,6 +44,7 @@
when :text, :string then String
when :binary then String
when :boolean then Object
-
when :enum then Symbol end end
@@ -61,6 +62,7 @@
when :date then self.class.string_to_date(value)
when :binary then self.class.binary_to_string(value)
when :boolean then self.class.value_to_boolean(value)
-
when :enum then value.intern else value end end
@@ -77,6 +79,7 @@
when :date then
“#{self.class.name}.string_to_date(#{var_name})”
when :binary then
“#{self.class.name}.binary_to_string(#{var_name})”
when :boolean then
“#{self.class.name}.value_to_boolean(#{var_name})”
-
when :enum then "#{var_name}.to_s.intern" else nil end end
@@ -135,6 +138,26 @@
$1.to_i if sql_type =~ /((.*))/
end
-
def extract_enum_values(sql_type) -
paren_string = $1 if sql_type =~ /\((.*)\)/ -
return [] if paren_string.nil? -
values = [] -
paren_string.split(",").each do |item| -
item.strip! -
item = item[1..-2] if item[0] == ?' && item[-1] == ?' #
remove quoting
-
values << item -
end -
values -
end -
def extract_limit_or_enum_values(sql_type) -
if type == :enum -
extract_enum_values(sql_type) -
else -
extract_limit(sql_type) -
end -
end -
def simplified_type(field_type) case field_type when /int/i
@@ -157,6 +180,8 @@
:string
when /boolean/i
:boolean
-
when /enum/i -
end:enum end end
Index:
activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
===================================================================
— activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
(revision 3486)
+++ activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
(working copy)
@@ -107,7 +107,8 @@
:time => { :name => “time” },
:date => { :name => “date” },
:binary => { :name => “blob” },
-
:boolean => { :name => "tinyint", :limit => 1 }
-
:boolean => { :name => "tinyint", :limit => 1 }, -
:enum => { :name => "enum", :limit => [] } } end