Commit 5322fd96 by Jason Wadsworth

Adds support for foreign key annotations

parent b38328d9
...@@ -175,6 +175,7 @@ you can do so with a simple environment variable, instead of editing the ...@@ -175,6 +175,7 @@ you can do so with a simple environment variable, instead of editing the
-v, --version Show the current version of this gem -v, --version Show the current version of this gem
-m, --show-migration Include the migration version number in the annotation -m, --show-migration Include the migration version number in the annotation
-i, --show-indexes List the table's database indexes in the annotation -i, --show-indexes List the table's database indexes in the annotation
-k, --show-foreign-keys List the table's foreign key constraints in the annotation
-s, --simple-indexes Concat the column's related indexes in the annotation -s, --simple-indexes Concat the column's related indexes in the annotation
--model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with comas --model-dir dir Annotate model files stored in dir rather than app/models, separate multiple dirs with comas
--ignore-model-subdirects Ignore subdirectories of the models directory --ignore-model-subdirects Ignore subdirectories of the models directory
......
...@@ -109,6 +109,11 @@ OptionParser.new do |opts| ...@@ -109,6 +109,11 @@ OptionParser.new do |opts|
ENV['include_version'] = "yes" ENV['include_version'] = "yes"
end end
opts.on('-k', '--show-foreign-keys',
"List the table's foreign key constraints in the annotation") do
ENV['show_foreign_keys'] = "yes"
end
opts.on('-i', '--show-indexes', opts.on('-i', '--show-indexes',
"List the table's database indexes in the annotation") do "List the table's database indexes in the annotation") do
ENV['show_indexes'] = "yes" ENV['show_indexes'] = "yes"
......
...@@ -26,7 +26,7 @@ module Annotate ...@@ -26,7 +26,7 @@ module Annotate
:show_indexes, :simple_indexes, :include_version, :exclude_tests, :show_indexes, :simple_indexes, :include_version, :exclude_tests,
:exclude_fixtures, :exclude_factories, :ignore_model_sub_dir, :exclude_fixtures, :exclude_factories, :ignore_model_sub_dir,
:format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace, :format_bare, :format_rdoc, :format_markdown, :sort, :force, :trace,
:timestamp, :exclude_serializers, :classified_sort :timestamp, :exclude_serializers, :classified_sort, :show_foreign_keys,
] ]
OTHER_OPTIONS=[ OTHER_OPTIONS=[
:ignore_columns :ignore_columns
......
...@@ -193,6 +193,10 @@ module AnnotateModels ...@@ -193,6 +193,10 @@ module AnnotateModels
info << get_index_info(klass, options) info << get_index_info(klass, options)
end end
if options[:show_foreign_keys] && klass.table_exists?
info << get_foreign_key_info(klass, options)
end
if options[:format_rdoc] if options[:format_rdoc]
info << "#--\n" info << "#--\n"
info << "# #{END_MARK}\n" info << "# #{END_MARK}\n"
...@@ -223,6 +227,28 @@ module AnnotateModels ...@@ -223,6 +227,28 @@ module AnnotateModels
return index_info return index_info
end end
def get_foreign_key_info(klass, options={})
if(options[:format_markdown])
fk_info = "#\n# ### Foreign Keys\n#\n"
else
fk_info = "#\n# Foreign Keys\n#\n"
end
foreign_keys = klass.connection.respond_to?(:foreign_keys) ? klass.connection.foreign_keys(klass.table_name) : []
return "" if foreign_keys.empty?
max_size = foreign_keys.collect{|fk| fk.name.size}.max + 1
foreign_keys.sort_by{|fk| fk.name}.each do |fk|
ref_info = "#{fk.column} => #{fk.to_table}.#{fk.primary_key}"
if(options[:format_markdown])
fk_info << sprintf("# * `%s`:\n# * **`%s`**\n", fk.name, ref_info)
else
fk_info << sprintf("# %-#{max_size}.#{max_size}s %s", fk.name, "(#{ref_info})").rstrip + "\n"
end
end
return fk_info
end
# Add a schema block to a file. If the file already contains # Add a schema block to a file. If the file already contains
# a schema info block (a comment starting with "== Schema Information"), check if it # a schema info block (a comment starting with "== Schema Information"), check if it
# matches the block that is already there. If so, leave it be. If not, remove the old # matches the block that is already there. If so, leave it be. If not, remove the old
...@@ -350,9 +376,9 @@ module AnnotateModels ...@@ -350,9 +376,9 @@ module AnnotateModels
options.merge(:position=>(options[position_in] || options[:position])) options.merge(:position=>(options[position_in] || options[:position]))
end end
# Return a list of the model files to annotate. # Return a list of the model files to annotate.
# If we have command line arguments, they're assumed to the path # If we have command line arguments, they're assumed to the path
# of model files from root dir. Otherwise we take all the model files # of model files from root dir. Otherwise we take all the model files
# in the model_dir directory. # in the model_dir directory.
def get_model_files(options) def get_model_files(options)
models = [] models = []
...@@ -364,7 +390,7 @@ module AnnotateModels ...@@ -364,7 +390,7 @@ module AnnotateModels
begin begin
model_dir.each do |dir| model_dir.each do |dir|
Dir.chdir(dir) do Dir.chdir(dir) do
lst = lst =
if options[:ignore_model_sub_dir] if options[:ignore_model_sub_dir]
Dir["*.rb"].map{ |f| [dir, f] } Dir["*.rb"].map{ |f| [dir, f] }
else else
......
...@@ -11,6 +11,7 @@ if Rails.env.development? ...@@ -11,6 +11,7 @@ if Rails.env.development?
'position_in_test' => "before", 'position_in_test' => "before",
'position_in_fixture' => "before", 'position_in_fixture' => "before",
'position_in_factory' => "before", 'position_in_factory' => "before",
'show_foreign_keys' => "true",
'show_indexes' => "true", 'show_indexes' => "true",
'simple_indexes' => "false", 'simple_indexes' => "false",
'model_dir' => "app/models", 'model_dir' => "app/models",
......
...@@ -4,15 +4,32 @@ require 'annotate/annotate_models' ...@@ -4,15 +4,32 @@ require 'annotate/annotate_models'
require 'annotate/active_record_patch' require 'annotate/active_record_patch'
describe AnnotateModels do describe AnnotateModels do
def mock_class(table_name, primary_key, columns) def mock_foreign_key(name, from_column, to_table, to_column = 'id')
double("ForeignKeyDefinition",
:name => name,
:column => from_column,
:to_table => to_table,
:primary_key => to_column,
)
end
def mock_connection(indexes = [], foreign_keys = [])
double("Conn",
:indexes => indexes,
:foreign_keys => foreign_keys,
)
end
def mock_class(table_name, primary_key, columns, foreign_keys = [])
options = { options = {
:connection => double("Conn", :indexes => []), :connection => mock_connection([], foreign_keys),
:table_name => table_name, :table_exists? => true,
:primary_key => primary_key, :table_name => table_name,
:column_names => columns.map { |col| col.name.to_s }, :primary_key => primary_key,
:columns => columns, :column_names => columns.map { |col| col.name.to_s },
:column_defaults => Hash[columns.map { |col| :columns => columns,
[col.name, col.default] :column_defaults => Hash[columns.map { |col|
[col.name, col.default]
}] }]
} }
...@@ -127,6 +144,33 @@ EOS ...@@ -127,6 +144,33 @@ EOS
EOS EOS
end end
it "should get foreign key info" do
klass = mock_class(:users, :id, [
mock_column(:id, :integer),
mock_column(:foreign_thing_id, :integer),
],
[
mock_foreign_key(
'fk_rails_02e851e3b7',
'foreign_thing_id',
'foreign_things'
)
])
expect(AnnotateModels.get_schema_info(klass, "Schema Info", :show_foreign_keys => true)).to eql(<<-EOS)
# Schema Info
#
# Table name: users
#
# id :integer not null, primary key
# foreign_thing_id :integer not null
#
# Foreign Keys
#
# fk_rails_02e851e3b7 (foreign_thing_id => foreign_things.id)
#
EOS
end
it "should get schema info as RDoc" do it "should get schema info as RDoc" do
klass = mock_class(:users, :id, [ klass = mock_class(:users, :id, [
mock_column(:id, :integer), mock_column(:id, :integer),
......
...@@ -11,6 +11,7 @@ if Rails.env.development? ...@@ -11,6 +11,7 @@ if Rails.env.development?
'position_in_test' => "before", 'position_in_test' => "before",
'position_in_fixture' => "before", 'position_in_fixture' => "before",
'position_in_factory' => "before", 'position_in_factory' => "before",
'show_foreign_keys' => "true",
'show_indexes' => "true", 'show_indexes' => "true",
'simple_indexes' => "false", 'simple_indexes' => "false",
'model_dir' => "app/models", 'model_dir' => "app/models",
......
...@@ -11,6 +11,7 @@ if Rails.env.development? ...@@ -11,6 +11,7 @@ if Rails.env.development?
'position_in_test' => "before", 'position_in_test' => "before",
'position_in_fixture' => "before", 'position_in_fixture' => "before",
'position_in_factory' => "before", 'position_in_factory' => "before",
'show_foreign_keys' => "true",
'show_indexes' => "true", 'show_indexes' => "true",
'simple_indexes' => "false", 'simple_indexes' => "false",
'model_dir' => "app/models", 'model_dir' => "app/models",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment