Skip to content

Instantly share code, notes, and snippets.

@7even
Created August 27, 2020 00:13
Show Gist options
  • Save 7even/1b673fcd816c566609756fedbbf5be10 to your computer and use it in GitHub Desktop.
Save 7even/1b673fcd816c566609756fedbbf5be10 to your computer and use it in GitHub Desktop.
Schema dumper draft for DbSchema
#!/usr/bin/env ruby
db_name = ARGV.first
raise ArgumentError, 'No database name given' if db_name.nil?
require 'db_schema'
require 'db_schema/reader/postgres'
db = Sequel.connect(adapter: 'postgres', database: db_name) do |db|
db.extension :pg_enum
db.extension :pg_array
end
reader = DbSchema::Reader.reader_for(db)
schema = reader.read_schema
result = []
result << 'DbSchema.describe do |db|'
schema.extensions.each do |extension|
result << " db.extension #{extension.name.inspect}"
end
result << nil if schema.extensions.any?
schema.enums.each do |enum|
result << " db.enum #{enum.name.inspect}, #{enum.values.inspect}"
end
result << nil if schema.enums.any?
schema.tables.sort_by(&:name).each_with_index do |table, idx|
result << " db.table #{table.name.inspect} do |t|"
table.fields.sort_by(&:name).each do |field|
field_str = " t.#{field.type} #{field.name.inspect}"
field_str << ", of: #{field.element_type.type.inspect}" if field.array?
field_str << ', null: false' unless field.null? || %i(smallserial serial bigserial).include?(field.type)
field.attributes.each do |attr_name, attr_value|
field_str << ", #{attr_name}: #{attr_value.inspect}" unless attr_name == :element_type
end
field_str << ", default: #{field.default.inspect}" unless field.default.nil?
result << field_str
end
result << nil if table.indexes.any?
table.indexes.select(&:primary?).each do |pkey|
result << " t.primary_key #{pkey.columns.map(&:name).map(&:inspect).join(', ')}"
end
table.indexes.reject(&:primary?).each do |index|
index_str = " t.index #{index.columns.map(&:name).map(&:inspect).join(', ')}"
index_str << ', unique: true' if index.unique?
unless index.name == :"#{table.name}_#{index.columns.map(&:index_name_segment).join('_')}_index"
index_str << ", name: #{index.name.inspect}"
end
index_str << ", using: #{index.type.inspect}" unless index.type == :btree
index_str << ", where: #{index.condition.inspect}" unless index.condition.nil?
result << index_str
end
result << nil if table.foreign_keys.any?
table.foreign_keys.each do |fkey|
fkey_str = " t.foreign_key #{fkey.fields.map(&:inspect).join(', ')}"
if fkey.references_primary_key?
fkey_str << ", references: #{fkey.table.inspect}"
else
fkey_str << ", references: [#{fkey.table.inspect}, #{fkey.keys.map(&:inspect).join(', ')}]"
end
fkey_str << ", on_update: #{fkey.on_update.inspect}" unless fkey.on_update == :no_action
fkey_str << ", on_delete: #{fkey.on_delete.inspect}" unless fkey.on_delete == :no_action
fkey_str << ', deferrable: true' if fkey.deferrable?
result << fkey_str
end
result << nil if table.checks.any?
table.checks.each do |check|
result << " t.check #{check.name.inspect}, #{check.condition.inspect}"
end
result << " end"
result << nil unless idx == schema.tables.count.pred
end
result << 'end'
puts result.join(?\n)
# TODO:
# * primary keys with custom names
# * index ordering
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment