@@ -152,7 +152,8 @@ def configure_connection
152152 tstzrange : { name : 'tstzrange' } ,
153153 tsvector : { name : 'tsvector' } ,
154154 uuid : { name : 'uuid' } ,
155- xml : { name : 'xml' }
155+ xml : { name : 'xml' } ,
156+ enum : { } # special type https://www.postgresql.org/docs/current/datatype-enum.html
156157 }
157158
158159 def set_standard_conforming_strings
@@ -380,6 +381,59 @@ def create_enum(name, values, **options)
380381 internal_exec_query ( query ) . tap { reload_type_map }
381382 end
382383
384+ # Drops an enum type.
385+ #
386+ # If the <tt>if_exists: true</tt> option is provided, the enum is dropped
387+ # only if it exists. Otherwise, if the enum doesn't exist, an error is
388+ # raised.
389+ #
390+ # The +values+ parameter will be ignored if present. It can be helpful
391+ # to provide this in a migration's +change+ method so it can be reverted.
392+ # In that case, +values+ will be used by #create_enum.
393+ def drop_enum ( name , values = nil , **options )
394+ query = <<~SQL
395+ DROP TYPE#{ ' IF EXISTS' if options [ :if_exists ] } #{ quote_table_name ( name ) } ;
396+ SQL
397+ internal_exec_query ( query ) . tap { reload_type_map }
398+ end
399+
400+ # Rename an existing enum type to something else.
401+ def rename_enum ( name , options = { } )
402+ to = options . fetch ( :to ) { raise ArgumentError , ":to is required" }
403+
404+ exec_query ( "ALTER TYPE #{ quote_table_name ( name ) } RENAME TO #{ to } " ) . tap { reload_type_map }
405+ end
406+
407+ # Add enum value to an existing enum type.
408+ def add_enum_value ( type_name , value , options = { } )
409+ before , after = options . values_at ( :before , :after )
410+ sql = +"ALTER TYPE #{ quote_table_name ( type_name ) } ADD VALUE '#{ value } '"
411+
412+ if before && after
413+ raise ArgumentError , "Cannot have both :before and :after at the same time"
414+ elsif before
415+ sql << " BEFORE '#{ before } '"
416+ elsif after
417+ sql << " AFTER '#{ after } '"
418+ end
419+
420+ execute ( sql ) . tap { reload_type_map }
421+ end
422+
423+ # Rename enum value on an existing enum type.
424+ def rename_enum_value ( type_name , options = { } )
425+ unless database_version >= 10_00_00 # >= 10.0
426+ raise ArgumentError , "Renaming enum values is only supported in PostgreSQL 10 or later"
427+ end
428+
429+ from = options . fetch ( :from ) { raise ArgumentError , ":from is required" }
430+ to = options . fetch ( :to ) { raise ArgumentError , ":to is required" }
431+
432+ execute ( "ALTER TYPE #{ quote_table_name ( type_name ) } RENAME VALUE '#{ from } ' TO '#{ to } '" ) . tap {
433+ reload_type_map
434+ }
435+ end
436+
383437 # Returns the configured supported identifier length supported by PostgreSQL
384438 def max_identifier_length
385439 @max_identifier_length ||= query_value ( "SHOW max_identifier_length" , "SCHEMA" ) . to_i
0 commit comments