migration_comments 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +27 -0
  4. data/README.rdoc +12 -3
  5. data/Rakefile +24 -0
  6. data/docker-compose.yml +12 -0
  7. data/gemfiles/rails4.gemfile +4 -0
  8. data/gemfiles/rails5.gemfile +4 -0
  9. data/lib/migration_comments.rb +12 -40
  10. data/lib/migration_comments/active_record/connection_adapters/abstract_adapter.rb +1 -10
  11. data/lib/migration_comments/active_record/connection_adapters/abstract_adapter/schema_creation.rb +22 -25
  12. data/lib/migration_comments/active_record/connection_adapters/alter_table.rb +5 -10
  13. data/lib/migration_comments/active_record/connection_adapters/column.rb +1 -5
  14. data/lib/migration_comments/active_record/connection_adapters/comment_definition.rb +1 -9
  15. data/lib/migration_comments/active_record/connection_adapters/mysql2_adapter.rb +97 -3
  16. data/lib/migration_comments/active_record/connection_adapters/postgresql_adapter.rb +19 -22
  17. data/lib/migration_comments/active_record/connection_adapters/sqlite3_adapter.rb +73 -46
  18. data/lib/migration_comments/active_record/connection_adapters/table.rb +3 -3
  19. data/lib/migration_comments/active_record/connection_adapters/table_definition.rb +9 -18
  20. data/lib/migration_comments/active_record/schema_dumper.rb +6 -10
  21. data/lib/migration_comments/annotate_models.rb +6 -8
  22. data/lib/migration_comments/schema_formatter.rb +8 -1
  23. data/lib/migration_comments/version.rb +1 -1
  24. data/migration_comments.gemspec +3 -10
  25. data/test/add_comments_test.rb +43 -2
  26. data/test/annotate_models_test.rb +6 -4
  27. data/test/auto_increment_test.rb +39 -9
  28. data/test/config/database.yml +2 -2
  29. data/test/primary_uuid_test.rb +27 -0
  30. data/test/schema_dumper_test.rb +35 -11
  31. data/test/test_helper.rb +8 -1
  32. metadata +34 -11
  33. data/lib/migration_comments/active_record/connection_adapters/abstract_sqlite_adapter.rb +0 -85
  34. data/lib/migration_comments/active_record/connection_adapters/mysql_adapter.rb +0 -107
  35. data/lib/migration_comments/active_record/connection_adapters/sqlite_adapter.rb +0 -71
@@ -1,12 +1,5 @@
1
1
  module MigrationComments::ActiveRecord::ConnectionAdapters
2
2
  module PostgreSQLAdapter
3
- def self.included(base)
4
- base.class_eval do
5
- alias_method_chain :create_table, :migration_comments
6
- alias_method_chain :add_column, :migration_comments
7
- alias_method_chain :change_column, :migration_comments
8
- end
9
- end
10
3
 
11
4
  def comments_supported?
12
5
  true
@@ -18,48 +11,52 @@ module MigrationComments::ActiveRecord::ConnectionAdapters
18
11
 
19
12
  # Set a comment on a table
20
13
  def set_table_comment(table_name, comment_text)
21
- execute CommentDefinition.new(self, table_name, nil, comment_text).to_sql
14
+ execute comment_sql(CommentDefinition.new(table_name, nil, comment_text))
22
15
  end
23
16
 
24
17
  # Set a comment on a column
25
18
  def set_column_comment(table_name, column_name, comment_text)
26
- execute CommentDefinition.new(self, table_name, column_name, comment_text).to_sql
19
+ execute comment_sql(CommentDefinition.new(table_name, column_name, comment_text))
20
+ end
21
+
22
+ if ::ActiveRecord::VERSION::MAJOR >= 5
23
+ def change_column_comment(table_name, column_name, comment)
24
+ comment_text = comment.respond_to?(:comment_text) ? comment.comment_text : comment
25
+ super(table_name, column_name, comment_text)
26
+ end
27
27
  end
28
28
 
29
29
  def retrieve_table_comment(table_name)
30
- result = select_rows(table_comment_sql(table_name))
31
- result[0].nil? ? nil : result[0][0]
30
+ select_value(table_comment_sql(table_name)).presence
32
31
  end
33
32
 
34
33
  def retrieve_column_comments(table_name, *column_names)
35
34
  result = select_rows(column_comment_sql(table_name, *column_names))
36
- return {} if result.nil?
37
- return result.inject({}){|m, row| m[row[0].to_sym] = row[1]; m}
35
+ Hash[result.map{|row| [row[0].to_sym, row[1].presence]}]
38
36
  end
39
37
 
40
- def create_table_with_migration_comments(table_name, options = {})
38
+ def create_table(table_name, options = {})
41
39
  local_table_definition = nil
42
- create_table_without_migration_comments(table_name, options) do |td|
40
+ super(table_name, options) do |td|
43
41
  local_table_definition = td
44
- local_table_definition.base = self
45
- local_table_definition.comment options[:comment] if options.has_key?(:comment)
42
+ local_table_definition.comment = options[:comment] if options.has_key?(:comment)
46
43
  yield td if block_given?
47
44
  end
48
45
  comments = local_table_definition.collect_comments(table_name)
49
46
  comments.each do |comment_definition|
50
- execute comment_definition.to_sql
47
+ execute comment_sql(comment_definition)
51
48
  end
52
49
  end
53
50
 
54
- def add_column_with_migration_comments(table_name, column_name, type, options = {})
55
- add_column_without_migration_comments(table_name, column_name, type, options)
51
+ def add_column(table_name, column_name, type, options = {})
52
+ super(table_name, column_name, type, options)
56
53
  if options[:comment]
57
54
  set_column_comment(table_name, column_name, options[:comment])
58
55
  end
59
56
  end
60
57
 
61
- def change_column_with_migration_comments(table_name, column_name, type, options = {})
62
- change_column_without_migration_comments(table_name, column_name, type, options)
58
+ def change_column(table_name, column_name, type, options = {})
59
+ super(table_name, column_name, type, options)
63
60
  if options.keys.include?(:comment)
64
61
  set_column_comment(table_name, column_name, options[:comment])
65
62
  end
@@ -1,40 +1,50 @@
1
1
  module MigrationComments::ActiveRecord::ConnectionAdapters
2
2
  module SQLite3Adapter
3
- include AbstractSQLiteAdapter
4
3
 
5
- def self.included(base)
6
- base.class_eval do
7
- alias_method_chain :columns, :migration_comments
8
- alias_method_chain :copy_table, :migration_comments
9
- alias_method_chain :change_column, :migration_comments
10
- end
4
+ def comments_supported?
5
+ true
11
6
  end
12
7
 
13
- def create_table(table_name, options = {})
14
- td = create_table_definition table_name, options[:temporary], options[:options]
15
- td.base = self
8
+ def inline_comments?
9
+ true
10
+ end
16
11
 
17
- unless options[:id] == false
18
- pk = options.fetch(:primary_key) {
19
- ActiveRecord::Base.get_primary_key table_name.to_s.singularize
20
- }
12
+ def set_table_comment(table_name, comment_text)
13
+ alter_table(table_name, :comment => comment_text)
14
+ end
21
15
 
22
- td.primary_key pk, options.fetch(:id, :primary_key), options
23
- end
24
- td.comment options[:comment] if options.has_key?(:comment)
16
+ def set_column_comment(table_name, column_name, comment_text)
17
+ sql_type = primary_key(table_name) == column_name.to_s ?
18
+ :primary_key :
19
+ column_for(table_name, column_name).sql_type
20
+ change_column table_name, column_name, sql_type, :comment => comment_text
21
+ end
25
22
 
26
- yield td if block_given?
23
+ def retrieve_table_comment(table_name)
24
+ result = select_value(lookup_comment_sql(table_name))
25
+ $1 if result =~ /CREATE (?:TEMPORARY )?TABLE #{quote_table_name table_name} [^\(]*\/\*(.*)\*\/ \(/
26
+ end
27
27
 
28
- if options[:force] && table_exists?(table_name)
29
- drop_table(table_name, options)
28
+ def retrieve_column_comments(table_name, *column_names)
29
+ if column_names.empty?
30
+ return columns(table_name).inject({}) { |m, v| m[v.name.to_sym] = v.comment if v.comment.present?; m }
30
31
  end
32
+ result = select_value(lookup_comment_sql(table_name))
33
+ result =~ /^CREATE (?:TEMPORARY )?TABLE "\w*" [^\(]*(?:\/\*.*\*\/ )?\((.*)\)[^\)]*$/
34
+ col_defs = $1
35
+ comment_matches = col_defs.scan(/"([^",]+)"[^,]*\/\*(.+?)\*\//)
36
+ Hash[comment_matches.map{|col_name, comment| [col_name.to_sym, comment.presence] }]
37
+ end
31
38
 
32
- execute schema_creation.accept td
33
- td.indexes.each_pair { |c,o| add_index table_name, c, o }
39
+ def create_table(table_name, options = {})
40
+ super(table_name, options) do |td|
41
+ td.comment = options[:comment] if options.has_key?(:comment)
42
+ yield td if block_given?
43
+ end
34
44
  end
35
45
 
36
- def columns_with_migration_comments(table_name)
37
- cols = columns_without_migration_comments(table_name)
46
+ def columns(table_name)
47
+ cols = super(table_name)
38
48
  comments = retrieve_column_comments(table_name, *(cols.map(&:name)))
39
49
  cols.each do |col|
40
50
  col.comment = comments[col.name.to_sym] if comments.has_key?(col.name.to_sym)
@@ -42,34 +52,51 @@ module MigrationComments::ActiveRecord::ConnectionAdapters
42
52
  cols
43
53
  end
44
54
 
45
- def copy_table_with_migration_comments(from, to, options = {}) #:nodoc:
46
- from_primary_key = primary_key(from)
47
- options[:id] = false
55
+ def copy_table(from, to, options = {}) #:nodoc:
48
56
  unless options.has_key?(:comment)
49
57
  table_comment = retrieve_table_comment(from)
50
- options = options.merge(:comment => table_comment) if table_comment
58
+ options.merge!(comment: table_comment) if table_comment
59
+ end
60
+ super(from, to, options) do |definition|
61
+ retrieve_column_comments(from).each do |col_name, comment|
62
+ definition[col_name].comment = CommentDefinition.new(from, col_name, comment)
63
+ end
64
+ yield definition if block_given?
51
65
  end
52
- create_table(to, options) do |definition|
53
- @definition = definition
54
- @definition.primary_key(from_primary_key) if from_primary_key.present?
55
- columns(from).each do |column|
56
- column_name = options[:rename] ?
57
- (options[:rename][column.name] ||
58
- options[:rename][column.name.to_sym] ||
59
- column.name) : column.name
60
- next if column_name == from_primary_key
66
+ end
61
67
 
62
- @definition.column(column_name, column.type,
63
- :limit => column.limit, :default => column.default,
64
- :precision => column.precision, :scale => column.scale,
65
- :null => column.null, :comment => column.comment)
68
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
69
+ super(table_name, column_name, type, options)
70
+ if options.has_key?(:comment)
71
+ alter_table(table_name) do |definition|
72
+ definition[column_name].comment = CommentDefinition.new(table_name, column_name, options[:comment])
66
73
  end
67
- yield @definition if block_given?
68
74
  end
69
- copy_table_indexes(from, to, options[:rename] || {})
70
- copy_table_contents(from, to,
71
- @definition.columns.map {|column| column.name},
72
- options[:rename] || {})
75
+ end
76
+
77
+ def comment_sql(comment_definition)
78
+ if comment_definition.nil? || comment_definition.comment_text.blank?
79
+ ""
80
+ else
81
+ " /*#{escaped_comment(comment_definition.comment_text)}*/"
82
+ end
83
+
84
+ end
85
+
86
+ def add_column_options!(sql, options)
87
+ super(sql, options)
88
+ if options.keys.include?(:comment)
89
+ sql << comment_sql(CommentDefinition.new(nil, nil, options[:comment]))
90
+ end
91
+ end
92
+
93
+ private
94
+ def escaped_comment(comment)
95
+ comment.gsub(/\*\//, "*-/")
96
+ end
97
+
98
+ def lookup_comment_sql(table_name)
99
+ "select sql from (select * from sqlite_master where type='table' union select * from sqlite_temp_master where type='table') where tbl_name = '#{table_name}'"
73
100
  end
74
101
  end
75
102
  end
@@ -1,12 +1,12 @@
1
1
  module MigrationComments::ActiveRecord::ConnectionAdapters
2
2
  module Table
3
3
  def change_comment(column_name, comment_text)
4
- @base.set_column_comment(@table_name, column_name, comment_text)
4
+ @base.set_column_comment(name, column_name, comment_text)
5
5
  end
6
6
 
7
7
  def change_table_comment(comment_text)
8
- @base.set_table_comment(@table_name, comment_text)
8
+ @base.set_table_comment(name, comment_text)
9
9
  end
10
- alias comment :change_table_comment
10
+ alias_method :comment, :change_table_comment
11
11
  end
12
12
  end
@@ -1,33 +1,24 @@
1
1
  module MigrationComments::ActiveRecord::ConnectionAdapters
2
2
  module TableDefinition
3
+ attr_accessor :comment
3
4
 
4
- attr_accessor :table_comment
5
- def self.included(base)
6
- base.class_eval do
7
- alias_method_chain :column, :migration_comments
8
- attr_accessor :base
9
- end
10
- end
11
-
12
- def comment(text)
13
- @table_comment = CommentDefinition.new(base, nil, nil, text)
14
- self
5
+ def comment=(text)
6
+ @comment = text.respond_to?(:comment_text) ? text : CommentDefinition.new(nil, nil, text)
15
7
  end
16
8
 
17
- def column_with_migration_comments(name, type, options = {})
18
- column_without_migration_comments(name, type, options)
9
+ def column(name, type, options = {})
10
+ super(name, type, options)
19
11
  if options.has_key?(:comment)
20
12
  col = self[name]
21
- col.comment = CommentDefinition.new(base, nil, name, options[:comment])
13
+ col.comment = CommentDefinition.new(nil, name, options[:comment])
22
14
  end
23
15
  self
24
16
  end
25
17
 
26
18
  def collect_comments(table_name)
27
- comments = []
28
- comments << @table_comment << columns.map(&:comment)
29
- comments.flatten!.compact!
30
- comments.each{|comment| comment.table = table_name; comment.adapter = base}
19
+ comments = [comment] + columns.map(&:comment)
20
+ comments.compact!
21
+ comments.each{|comment| comment.table_name = table_name }
31
22
  end
32
23
  end
33
24
  end
@@ -1,15 +1,11 @@
1
1
  module MigrationComments::ActiveRecord
2
2
  module SchemaDumper
3
3
  include MigrationComments::SchemaFormatter
4
- def self.included(base)
5
- base.class_eval do
6
- alias_method_chain :table, :migration_comments
7
- end
8
- end
9
4
 
10
- def table_with_migration_comments(table, stream)
5
+ def table(table, stream)
6
+ return super if ::ActiveRecord::VERSION::MAJOR >= 5 && @connection.class.name !~ /SQLite/
11
7
  tbl_stream = StringIO.new
12
- table_without_migration_comments(table, tbl_stream)
8
+ super(table, tbl_stream)
13
9
  tbl_stream.rewind
14
10
  commented_stream = append_comments(table, tbl_stream)
15
11
  tbl_stream.close
@@ -25,8 +21,8 @@ module MigrationComments::ActiveRecord
25
21
  table_line = 0
26
22
  col_names = {}
27
23
  error = false
28
- while (line = stream.gets)
29
- content = line.chomp
24
+ while (stream_line = stream.gets)
25
+ content = stream_line.chomp
30
26
  if content =~ /^# Could not dump table "#{table_name}"/
31
27
  error = true
32
28
  elsif content =~ /create_table\s/
@@ -43,7 +39,7 @@ module MigrationComments::ActiveRecord
43
39
  elsif table_line == index && table_comment.present?
44
40
  block_init = " do |t|"
45
41
  line.chomp!(block_init) << ", " << render_comment(table_comment) << block_init
46
- elsif col_names[index]
42
+ elsif col_names[index] && ::ActiveRecord::VERSION::MAJOR < 5
47
43
  comment = column_comments[col_names[index]]
48
44
  line << ',' << ' ' * (len - line.length) << render_comment(comment) unless comment.blank?
49
45
  end
@@ -1,18 +1,16 @@
1
1
  module MigrationComments
2
2
  module AnnotateModels
3
- def self.included(base)
4
- base.class_eval do
5
- class << self
6
- include ClassMethods
7
- alias_method_chain :get_schema_info, :migration_comments
8
- end
3
+ def self.prepended(base)
4
+ class << base
5
+ prepend ClassMethods
9
6
  end
10
7
  end
11
8
 
12
9
  module ClassMethods
13
- def get_schema_info_with_migration_comments(*args)
14
- info = get_schema_info_without_migration_comments(*args)
10
+ def get_schema_info(*args)
15
11
  klass = args[0]
12
+ klass.reset_column_information
13
+ info = super(*args)
16
14
  commented_info(klass, info)
17
15
  end
18
16
 
@@ -13,7 +13,14 @@ module MigrationComments
13
13
  end
14
14
 
15
15
  def render_value(value)
16
- value.is_a?(String) ? %Q[#{value}].inspect : value
16
+ case value
17
+ when String
18
+ %Q[#{value}].inspect
19
+ when Symbol
20
+ value.inspect
21
+ else
22
+ value
23
+ end
17
24
  end
18
25
  end
19
26
  end
@@ -1,3 +1,3 @@
1
1
  module MigrationComments
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -18,18 +18,11 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_runtime_dependency 'activerecord', '>= 2.3.2'
21
+ s.add_runtime_dependency 'activerecord', '>= 4.2.0'
22
22
 
23
- # for development, we are testing against the 'annotate' gem
24
- # however, the comments should work with the original 'annotate_models' plugin as well at:
25
- # http://repo.pragprog.com/svn/Public/plugins/annotate_models
26
- # provided the environment is not loaded until _after_ the AnnotateModels module is declared
27
- s.add_development_dependency 'annotate', '~> 2.5.0'
28
-
29
- # add / replace with other adapter(s) as needed
23
+ s.add_development_dependency 'annotate', '~> 2.7.0'
30
24
  s.add_development_dependency 'pg'
31
- # s.add_development_dependency 'postgres-pr'
32
- # s.add_development_dependency 'mysql'
33
25
  s.add_development_dependency 'mysql2'
34
26
  s.add_development_dependency 'sqlite3'
27
+ s.add_development_dependency 'minitest-byebug'
35
28
  end
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
- class AddCommentsTest < Minitest::Unit::TestCase
3
+ class AddCommentsTest < Minitest::Test
4
4
  include TestHelper
5
5
 
6
6
  def test_adding_a_table_comment
@@ -26,10 +26,51 @@ class AddCommentsTest < Minitest::Unit::TestCase
26
26
  assert_nil result_field2
27
27
  end
28
28
 
29
+ def test_adding_a_column_with_a_comment
30
+ comment_text = "a comment in a new column"
31
+ result_field1 = nil
32
+ result_field3 = nil
33
+ ActiveRecord::Schema.define do
34
+ add_column :sample, :field3, :string, :comment => comment_text
35
+ result_field3 = retrieve_column_comment :sample, :field3
36
+ result_field1 = retrieve_column_comment :sample, :field1
37
+ end
38
+ assert_equal comment_text, result_field3
39
+ assert_nil result_field1
40
+ end
41
+
42
+ def test_changing_a_column_while_adding_a_comment
43
+ comment_text = "a comment in a changing column"
44
+ result_field1 = nil
45
+ ActiveRecord::Schema.define do
46
+ change_column :sample, :field1, :string, :limit => 25, :comment => comment_text
47
+ result_field1 = retrieve_column_comment :sample, :field1
48
+ end
49
+ assert_equal comment_text, result_field1
50
+ end
51
+
52
+ def test_creating_a_temp_table_with_table_comments_and_no_block
53
+ ActiveRecord::Schema.define do
54
+ begin
55
+ create_table :sample3, temporary: true, comment: "a table comment"
56
+ ensure
57
+ drop_table :sample3 rescue nil
58
+ end
59
+ end
60
+ end
61
+
29
62
  def test_creating_a_table_with_table_comments_and_no_block
63
+ table_comment = "a table comment"
64
+ result_table_comment = nil
30
65
  ActiveRecord::Schema.define do
31
- create_table :sample3, :temporary => true, :comment => "a table comment"
66
+ begin
67
+ create_table :sample3, comment: table_comment
68
+ result_table_comment = retrieve_table_comment :sample3
69
+ ensure
70
+ drop_table :sample3 rescue nil
71
+ end
32
72
  end
73
+ assert_equal table_comment, result_table_comment
33
74
  end
34
75
 
35
76
  def test_creating_a_table_with_table_and_column_comments