migration_comments 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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