migration_comments 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in migration_comments.gemspec
4
+ gemspec
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ = MigrationComments
2
+
3
+ Comments for your migrations
4
+
5
+ Tested on Ruby 1.8.6 using Rails 2.3.x.
6
+
7
+ == Why?
8
+
9
+ Migrations are wonderful. They handle all your schema changes, and in a pinch they can bring
10
+ any database up to speed. However, database schemas can change rapidly while a project is
11
+ maturing, and it can be difficult to know (or remember) the purpose for each table and field.
12
+ As such, they deserve to be commented. These comments should be available for display wherever
13
+ those fields are found.
14
+
15
+ == Solution!
16
+
17
+ Using MigrationComments, you can simply add comments during your migrations. Or if you already
18
+ have existing data structures, just add the comments afterwards in a separate migration. And of
19
+ course you can always modify and delete these comments in later migrations.
20
+
21
+ So where are these comments used? Firstly, they will be included in your schema.rb dump which
22
+ is where your IDE (e.g. RubyMine) should be learning about your model structure. This means that
23
+ they'll be available at any point in your project. Additionally, if you are using the 'annotate'
24
+ gem, these comments will be added to the annotations that are generated within your model.rb
25
+ file.
26
+
27
+ == Examples
28
+
29
+ Want to add a comment to an existing structure...
30
+
31
+ self.up
32
+ add_table_comment :table_name, "A table comment"
33
+ comment_table :table_name, "A table comment" # does the same thing
34
+
35
+ add_column_comment :table_name, :column_name, "A column comment"
36
+ comment_column :table_name, :column_name, "A column comment" # does the same thing
37
+ end
38
+
39
+ Or you can use the change_table macro...
40
+
41
+ self.up
42
+ change_table :table_name do |t|
43
+ t.comment "A table comment"
44
+ t.change_comment :column_name, "A column comment"
45
+ end
46
+ end
47
+
48
+ Creating a new table?
49
+
50
+ self.up
51
+ create_table :table_name, :comment => "A table comment" do |t|
52
+ t.string :column_name, :comment => "A column comment"
53
+ end
54
+ end
55
+
56
+ You can also remove comments...
57
+
58
+ self.up
59
+ remove_table_comment :table_name
60
+ remove_column_comment :table_name, :column_name
61
+ end
62
+
63
+ Or you can combine these commands while modifying a table...
64
+
65
+ self.up
66
+ change_table :existing_table do |t|
67
+ t.comment nil # remove an existing table comment
68
+ t.string :new_column, :comment => "a new column" # add a new column with a comment
69
+ t.change_comment :existing_column, nil # remove a comment on an existing column
70
+ t.integer :another_existing_column, :comment => nil # remove a comment on an existing column while modifying the column type
71
+ t.boolean :column_with_comment # modify an existing column without altering the comment
72
+ end
73
+ end
74
+
75
+
76
+ == Requirements
77
+
78
+ You must be using a DBMS that supports COMMENTing (currently only PostgreSQL and MySQL).
79
+
80
+ If this isn't an option for you, check out the 'schema_comments' gem:
81
+ https://github.com/akm/schema_comments
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,41 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module AbstractAdapter
3
+ def add_table_comment(table_name, comment_text)
4
+ # SQL standard doesn't support schema commenting
5
+ raise "Table comments are not supported"
6
+ end
7
+ alias comment_table :add_table_comment
8
+
9
+ def add_column_comment(table_name, column_name, comment_text)
10
+ # SQL standard doesn't support schema commenting
11
+ raise "Column comments are not supported"
12
+ end
13
+ alias comment_column :add_column_comment
14
+
15
+ def comments_supported?
16
+ false
17
+ end
18
+
19
+ # Remove a comment on a table (if set)
20
+ def remove_table_comment(table_name)
21
+ add_table_comment(table_name, nil)
22
+ end
23
+
24
+ # Remove a comment on a column (if set)
25
+ def remove_column_comment(table_name, column_name)
26
+ add_column_comment(table_name, column_name, nil)
27
+ end
28
+
29
+ def retrieve_table_comment(table_name)
30
+ nil
31
+ end
32
+
33
+ def retrieve_column_comments(table_name, *column_names)
34
+ {}
35
+ end
36
+
37
+ def retrieve_column_comment(table_name, column_name)
38
+ retrieve_column_comments(table_name, column_name)[column_name]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,5 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module ColumnDefinition
3
+ attr_accessor :comment
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ class CommentDefinition < Struct.new(:adapter, :table, :column_name, :comment_text)
3
+ def to_dump
4
+ table_comment? ?
5
+ "add_table_comment :#{table_name}, %{#{comment_text}}" :
6
+ "add_column_comment :#{table_name}, :#{column_name}, %{#{comment_text}}"
7
+ end
8
+
9
+ def to_sql
10
+ adapter.comment_sql(self)
11
+ end
12
+ alias to_s :to_sql
13
+
14
+ def table_comment?
15
+ column_name.blank?
16
+ end
17
+
18
+ def table_name
19
+ table.respond_to?(:name) ? table.name : table
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module Mysql2Adapter
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include MigrationComments::ActiveRecord::ConnectionAdapters::MysqlAdapter
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,97 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module MysqlAdapter
3
+ def self.included(base)
4
+ base.class_eval do
5
+ attr_accessor :database_name
6
+ alias_method_chain :create_table, :migration_comments
7
+ alias_method_chain :change_column, :migration_comments
8
+ end
9
+ end
10
+
11
+ def add_table_comment(table_name, comment)
12
+ execute "ALTER TABLE #{table_name} COMMENT #{escaped_comment(comment)}"
13
+ end
14
+
15
+ def add_column_comment(table_name, column_name, comment)
16
+ column = column_for(table_name, column_name)
17
+ change_column table_name, column_name, column.sql_type, :comment => comment
18
+ end
19
+
20
+ def retrieve_table_comment(table_name)
21
+ result = select_rows(table_comment_sql(table_name))
22
+ result[0].nil? || result[0][0].blank? ? nil : result[0][0]
23
+ end
24
+
25
+ def retrieve_column_comments(table_name, *column_names)
26
+ result = select_rows(column_comment_sql(table_name, *column_names))
27
+ return {} if result.nil?
28
+ return result.inject({}){|m, row| m[row[0].to_sym] = (row[1].blank? ? nil : row[1]); m}
29
+ end
30
+
31
+ def create_table_with_migration_comments(table_name, options={}, &block)
32
+ local_table_definition = nil
33
+ create_table_without_migration_comments(table_name, options) do |td|
34
+ local_table_definition = td
35
+ local_table_definition.comment options[:comment] if options.has_key?(:comment)
36
+ block.call(td)
37
+ end
38
+ comments = local_table_definition.collect_comments(table_name)
39
+ comments.each do |comment_definition|
40
+ execute_comment comment_definition
41
+ end
42
+ end
43
+
44
+ def change_column_with_migration_comments(table_name, column_name, type, options={})
45
+ unless options.keys.include?(:comment)
46
+ options.merge!(:comment => retrieve_column_comment(table_name, column_name))
47
+ end
48
+ change_column_without_migration_comments(table_name, column_name, type, options)
49
+ end
50
+
51
+ def add_column_options!(sql, options)
52
+ super(sql, options)
53
+ if options.keys.include?(:comment)
54
+ sql << " COMMENT #{escaped_comment(options[:comment])}"
55
+ end
56
+ end
57
+
58
+ def execute_comment(comment_definition)
59
+ if comment_definition.table_comment?
60
+ add_table_comment comment_definition.table_name, comment_definition.comment_text
61
+ else
62
+ add_column_comment comment_definition.table_name, comment_definition.column_name, comment_definition.comment_text
63
+ end
64
+ end
65
+
66
+ private
67
+ def escaped_comment(comment)
68
+ comment.nil? ? "''" : "'#{comment.gsub("'", "''").gsub("\\", "\\\\\\\\")}'"
69
+ end
70
+
71
+ def table_comment_sql(table_name)
72
+ ensure_database_name
73
+ <<SQL
74
+ SELECT table_comment FROM INFORMATION_SCHEMA.TABLES
75
+ WHERE table_schema = '#{database_name}'
76
+ AND table_name = '#{table_name}'
77
+ SQL
78
+ end
79
+
80
+ def column_comment_sql(table_name, *column_names)
81
+ ensure_database_name
82
+ col_matcher_sql = column_names.empty? ? "" : " AND column_name IN (#{column_names.map{|c_name| "'#{c_name}'"}.join(',')})"
83
+ <<SQL
84
+ SELECT column_name, column_comment FROM INFORMATION_SCHEMA.COLUMNS
85
+ WHERE table_schema = '#{database_name}'
86
+ AND table_name = '#{table_name}' #{col_matcher_sql}
87
+ SQL
88
+ end
89
+
90
+ def ensure_database_name
91
+ return if database_name
92
+ info = YAML::load(IO.read('config/database.yml'))
93
+ @database_name = info[ENV['DB'] || RAILS_ENV]["database"]
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,111 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
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
+
11
+ def comments_supported?
12
+ true
13
+ end
14
+
15
+ # Set a comment on a table
16
+ def add_table_comment(table_name, comment_text)
17
+ execute CommentDefinition.new(self, table_name, nil, comment_text).to_sql
18
+ end
19
+
20
+ # Set a comment on a column
21
+ def add_column_comment(table_name, column_name, comment_text)
22
+ execute CommentDefinition.new(self, table_name, column_name, comment_text).to_sql
23
+ end
24
+
25
+ def retrieve_table_comment(table_name)
26
+ result = execute(table_comment_sql(table_name)).result
27
+ result[0].nil? ? nil : result[0][0]
28
+ end
29
+
30
+ def retrieve_column_comments(table_name, *column_names)
31
+ result = execute(column_comment_sql(table_name, *column_names)).result
32
+ return {} if result.nil?
33
+ return result.inject({}){|m, row| m[row[0].to_sym] = row[1]; m}
34
+ end
35
+
36
+ def create_table_with_migration_comments(table_name, options = {}, &block)
37
+ local_table_definition = nil
38
+ create_table_without_migration_comments(table_name, options) do |td|
39
+ local_table_definition = td
40
+ local_table_definition.comment options[:comment] if options.has_key?(:comment)
41
+ block.call(td)
42
+ end
43
+ comments = local_table_definition.collect_comments(table_name)
44
+ comments.each do |comment_definition|
45
+ execute comment_definition.to_sql
46
+ end
47
+ end
48
+
49
+ def add_column_with_migration_comments(table_name, column_name, type, options = {})
50
+ add_column_without_migration_comments(table_name, column_name, type, options)
51
+ if options[:comment]
52
+ add_column_comment(table_name, column_name, options[:comment])
53
+ end
54
+ end
55
+
56
+ def change_column_with_migration_comments(table_name, column_name, type, options = {})
57
+ change_column_without_migration_comments(table_name, column_name, type, options)
58
+ if options.keys.include?(:comment)
59
+ add_column_comment(table_name, column_name, options[:comment])
60
+ end
61
+ end
62
+
63
+ def comment_sql(comment_definition)
64
+ "COMMENT ON #{comment_target(comment_definition)} IS #{escaped_comment(comment_definition.comment_text)}"
65
+ end
66
+
67
+ private
68
+
69
+ private
70
+ def comment_target(comment_definition)
71
+ comment_definition.table_comment? ?
72
+ "TABLE #{quote_table_name(comment_definition.table_name)}" :
73
+ "COLUMN #{quote_table_name(comment_definition.table_name)}.#{quote_column_name(comment_definition.column_name)}"
74
+ end
75
+
76
+ def escaped_comment(comment)
77
+ comment.nil? ? 'NULL' : "'#{comment.gsub("'", "''")}'"
78
+ end
79
+
80
+ def table_comment_sql(table_name)
81
+ <<SQL
82
+ SELECT d.description FROM (
83
+ #{table_oids(table_name)}) tt
84
+ JOIN pg_catalog.pg_description d
85
+ ON tt.oid = d.objoid AND tt.tableoid = d.classoid AND d.objsubid = 0;
86
+ SQL
87
+ end
88
+
89
+ def column_comment_sql(table_name, *column_names)
90
+ col_matcher_sql = column_names.empty? ? "" : " a.attname IN (#{column_names.map{|c_name| "'#{c_name}'"}.join(',')}) AND "
91
+ <<SQL
92
+ SELECT a.attname, pg_catalog.col_description(a.attrelid, a.attnum)
93
+ FROM pg_catalog.pg_attribute a
94
+ JOIN (
95
+ #{table_oids(table_name)}) tt
96
+ ON tt.oid = a.attrelid
97
+ WHERE #{col_matcher_sql} a.attnum > 0 AND NOT a.attisdropped;
98
+ SQL
99
+ end
100
+
101
+ def table_oids(table_name)
102
+ <<SQL
103
+ SELECT c.oid, c.tableoid
104
+ FROM pg_catalog.pg_class c
105
+ WHERE c.relname = '#{table_name}'
106
+ AND c.relkind = 'r'
107
+ AND pg_catalog.pg_table_is_visible(c.oid)
108
+ SQL
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,12 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module Table
3
+ def change_comment(column_name, comment_text)
4
+ @base.add_column_comment(@table_name, column_name, comment_text)
5
+ end
6
+
7
+ def change_table_comment(comment_text)
8
+ @base.add_table_comment(@table_name, comment_text)
9
+ end
10
+ alias comment :change_table_comment
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module MigrationComments::ActiveRecord::ConnectionAdapters
2
+ module TableDefinition
3
+
4
+ attr_accessor :table_comment
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method_chain :column, :migration_comments
8
+ end
9
+ end
10
+
11
+ def comment(text)
12
+ @table_comment = CommentDefinition.new(@base, nil, nil, text)
13
+ self
14
+ end
15
+
16
+ def column_with_migration_comments(name, type, options = {})
17
+ column_without_migration_comments(name, type, options)
18
+ col = self[name]
19
+ col.comment = CommentDefinition.new(@base, nil, name, options[:comment])
20
+ self
21
+ end
22
+
23
+ def collect_comments(table_name)
24
+ comments = []
25
+ comments << @table_comment << @columns.map(&:comment)
26
+ comments.flatten!.compact!
27
+ comments.each{|comment| comment.table = table_name}
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ module MigrationComments::ActiveRecord
2
+ module SchemaDumper
3
+ def self.included(base)
4
+ base.class_eval do
5
+ alias_method_chain :table, :migration_comments
6
+ end
7
+ end
8
+
9
+ def table_with_migration_comments(table, stream)
10
+ tbl_stream = StringIO.new
11
+ table_without_migration_comments(table, tbl_stream)
12
+ tbl_stream.rewind
13
+ commented_stream = append_comments(table, tbl_stream)
14
+ tbl_stream.close
15
+ stream.print commented_stream.read
16
+ end
17
+
18
+ def append_comments(table, stream)
19
+ table_name = table.inspect.gsub('"', '')
20
+ table_comment = @connection.retrieve_table_comment(table_name)
21
+ column_comments = @connection.retrieve_column_comments(table_name)
22
+ comment_stream = StringIO.new
23
+ lines = []
24
+ table_line = 0
25
+ col_names = {}
26
+ while (line = stream.gets)
27
+ content = line.chomp
28
+ if content =~ /create_table\s/
29
+ table_line = lines.size
30
+ elsif content =~ /t\.\w+\s+"(\w+)"/
31
+ col_names[lines.size] = $1.to_sym
32
+ end
33
+ lines << content
34
+ end
35
+ len = col_names.keys.map{|index| lines[index]}.map(&:length).max + 2
36
+ lines.each_with_index do |line, index|
37
+ if table_line == index && table_comment.present?
38
+ block_init = " do |t|"
39
+ line.chomp!(block_init) << ", " << render_comment(table_comment) << block_init
40
+ elsif col_names[index]
41
+ comment = column_comments[col_names[index]]
42
+ line << ',' << ' ' * (len - line.length) << render_comment(comment) unless comment.blank?
43
+ end
44
+ comment_stream.puts line
45
+ end
46
+ comment_stream.rewind
47
+ comment_stream
48
+ end
49
+
50
+ def render_comment(comment)
51
+ ":comment => \"#{comment}\""
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,40 @@
1
+ module MigrationComments
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
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def get_schema_info_with_migration_comments(*args)
14
+ info = get_schema_info_without_migration_comments(*args)
15
+ klass = args[0]
16
+ commented_info(klass, info)
17
+ end
18
+
19
+ def commented_info(klass, info)
20
+ table_name = klass.table_name
21
+ adapter = klass.connection
22
+ table_comment = adapter.retrieve_table_comment(table_name)
23
+ column_comments = adapter.retrieve_column_comments(table_name)
24
+ lines = []
25
+ info.each_line{|l| lines << l.chomp}
26
+ column_regex = /^#\s+(\w+)\s+:\w+/
27
+ len = lines.select{|l| l =~ column_regex}.map{|l| l.length}.max
28
+ lines.each do |line|
29
+ if line =~ /# Table name: |# table \+\w+\+ /
30
+ line << " # #{table_comment}" if table_comment
31
+ elsif line =~ column_regex
32
+ comment = column_comments[$1.to_sym]
33
+ line << " " * (len - line.length) << " # #{comment}" if comment
34
+ end
35
+ end
36
+ lines.join($/) + $/
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module MigrationComments
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,58 @@
1
+ require "migration_comments/version"
2
+
3
+ require 'migration_comments/active_record/schema_dumper'
4
+ require 'migration_comments/active_record/connection_adapters/comment_definition'
5
+ require 'migration_comments/active_record/connection_adapters/column_definition'
6
+ require 'migration_comments/active_record/connection_adapters/table'
7
+ require 'migration_comments/active_record/connection_adapters/table_definition'
8
+ require 'migration_comments/active_record/connection_adapters/abstract_adapter'
9
+ require 'migration_comments/active_record/connection_adapters/mysql_adapter'
10
+ require 'migration_comments/active_record/connection_adapters/mysql2_adapter'
11
+ require 'migration_comments/active_record/connection_adapters/postgresql_adapter'
12
+
13
+ module MigrationComments
14
+ def self.setup
15
+ base_names = %w(SchemaDumper) +
16
+ %w(ColumnDefinition Table TableDefinition AbstractAdapter).map{|name| "ConnectionAdapters::#{name}"}
17
+
18
+ base_names.each do |base_name|
19
+ ar_class = "ActiveRecord::#{base_name}".constantize
20
+ mc_class = "MigrationComments::ActiveRecord::#{base_name}".constantize
21
+ unless ar_class.ancestors.include?(mc_class)
22
+ ar_class.__send__(:include, mc_class)
23
+ end
24
+ end
25
+
26
+ %w(PostgreSQL Mysql Mysql2).each do |adapter|
27
+ begin
28
+ require("active_record/connection_adapters/#{adapter.downcase}_adapter")
29
+ adapter_class = ('ActiveRecord::ConnectionAdapters::' << "#{adapter}Adapter").constantize
30
+ mc_class = ('MigrationComments::ActiveRecord::ConnectionAdapters::' << "#{adapter}Adapter").constantize
31
+ adapter_class.module_eval do
32
+ adapter_class.__send__(:include, mc_class)
33
+ end
34
+ rescue Exception => ex
35
+ end
36
+ end
37
+
38
+ # annotations are not required for this gem, but if they exist they should be updated
39
+ begin
40
+ begin # first try to load from the 'annotate' gem
41
+ require 'annotate/annotate_models'
42
+ rescue Exception => ex
43
+ # continue as it may be already accessible through a plugin
44
+ end
45
+ gem_class = AnnotateModels
46
+ # don't require this until after the original AnnotateModels loads to avoid namespace confusion
47
+ require 'migration_comments/annotate_models'
48
+ mc_class = MigrationComments::AnnotateModels
49
+ unless gem_class.ancestors.include?(mc_class)
50
+ gem_class.__send__(:include, mc_class)
51
+ end
52
+ rescue Exception => ex
53
+ # if we got here, don't bother installing comments into annotations
54
+ end
55
+ end
56
+ end
57
+
58
+ MigrationComments.setup
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "migration_comments/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "migration_comments"
7
+ s.version = MigrationComments::VERSION
8
+ s.authors = ["Pinny"]
9
+ s.email = ["pinny@medwiztech.com"]
10
+ s.homepage = "https://github.com/pinnymz/migration_comments"
11
+ s.summary = %q{Comments for your migrations}
12
+ s.description = %q{Add schema comments in your migrations, see them in model annotations and db/schema.rb dump}
13
+
14
+ s.rubyforge_project = "migration_comments"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'rails', '~> 2.3', '>= 2.3.2'
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'
28
+
29
+ s.add_development_dependency 'postgres-pr' # replace with other adapter as needed
30
+ # s.add_development_dependency 'mysql'
31
+ # s.add_development_dependency 'mysql2'
32
+ end
@@ -0,0 +1,135 @@
1
+ require 'test_helper'
2
+
3
+ class AddCommentsTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def test_adding_a_table_comment
7
+ comment_text = "a comment on the sample table"
8
+ result = nil
9
+ ActiveRecord::Schema.define do
10
+ add_table_comment :sample, comment_text
11
+ result = retrieve_table_comment :sample
12
+ end
13
+ assert_equal comment_text, result
14
+ end
15
+
16
+ def test_adding_a_column_comment
17
+ comment_text = "a comment on the sample table in the column field"
18
+ result_field1 = nil
19
+ result_field2 = nil
20
+ ActiveRecord::Schema.define do
21
+ add_column_comment :sample, :field1, comment_text
22
+ result_field1 = retrieve_column_comment :sample, :field1
23
+ result_field2 = retrieve_column_comment :sample, :field2
24
+ end
25
+ assert_equal comment_text, result_field1
26
+ assert_nil result_field2
27
+ end
28
+
29
+ def test_creating_a_table_with_table_and_column_comments
30
+ table_comment = "a table comment"
31
+ column_comment = "a column comment"
32
+ result_table_comment = nil
33
+ result_column_comments = nil
34
+ ActiveRecord::Schema.define do
35
+ begin
36
+ create_table :sample2, :comment => table_comment do |t|
37
+ t.integer :field1, :comment => column_comment
38
+ t.string :field2
39
+ end
40
+ result_table_comment = retrieve_table_comment :sample2
41
+ result_column_comments = retrieve_column_comments :sample2
42
+ ensure
43
+ drop_table :sample2
44
+ end
45
+ end
46
+ assert_equal table_comment, result_table_comment
47
+ assert_equal column_comment, result_column_comments[:field1]
48
+ assert_nil result_column_comments[:field2]
49
+ end
50
+
51
+ def test_changing_a_table_with_new_comments
52
+ table_comment = "a table comment"
53
+ column_comment1 = "a column comment"
54
+ column_comment2 = "another column comment"
55
+ result_table_comment = nil
56
+ result_column_comments = nil
57
+ ActiveRecord::Schema.define do
58
+ change_table :sample do |t|
59
+ t.comment table_comment
60
+ t.change :field1, :string, :comment => column_comment1
61
+ t.change :field2, :integer
62
+ t.boolean :field3, :comment => column_comment2
63
+ end
64
+ result_table_comment = retrieve_table_comment :sample
65
+ result_column_comments = retrieve_column_comments :sample
66
+ end
67
+ assert_equal table_comment, result_table_comment
68
+ assert_equal column_comment1, result_column_comments[:field1]
69
+ assert_equal column_comment2, result_column_comments[:field3]
70
+ assert_nil result_column_comments[:field2]
71
+ end
72
+
73
+ def test_partially_modifying_comments_from_a_table
74
+ table_comment = "a table comment"
75
+ column_comment1 = "a column comment"
76
+ column_comment2 = "another column comment"
77
+ column_comment3 = "yet a third column comment"
78
+ modified_comment = "modified comment"
79
+ result_table_comment = nil
80
+ result_column_comments = nil
81
+ ActiveRecord::Schema.define do
82
+ change_table :sample do |t|
83
+ t.comment table_comment
84
+ t.change :field1, :string, :comment => column_comment1
85
+ t.change :field2, :integer, :comment => column_comment2
86
+ t.boolean :field3, :comment => column_comment3
87
+ end
88
+ change_table :sample do |t|
89
+ t.comment nil
90
+ t.change :field1, :string
91
+ t.change :field2, :integer, :comment => modified_comment
92
+ t.change :field3, :boolean, :comment => nil
93
+ end
94
+ result_table_comment = retrieve_table_comment :sample
95
+ result_column_comments = retrieve_column_comments :sample
96
+ end
97
+ assert_nil result_table_comment
98
+ assert_equal column_comment1, result_column_comments[:field1]
99
+ assert_equal modified_comment, result_column_comments[:field2]
100
+ assert_nil result_column_comments[:field3]
101
+ end
102
+
103
+ def test_removing_comments_from_a_table
104
+ comment_text = "a comment on the sample table"
105
+ result = nil
106
+ ActiveRecord::Schema.define do
107
+ add_table_comment :sample, comment_text
108
+ remove_table_comment :sample
109
+ result = retrieve_table_comment :sample
110
+ end
111
+ assert_nil result
112
+ end
113
+
114
+ def test_removing_comments_from_a_column
115
+ comment_text = "a comment on field1 of sample table"
116
+ result = nil
117
+ ActiveRecord::Schema.define do
118
+ add_column_comment :sample, :field1, comment_text
119
+ remove_column_comment :sample, :field1
120
+ result = retrieve_column_comment :sample, :field1
121
+ end
122
+ assert_nil result
123
+ end
124
+
125
+ def test_comment_text_is_escaped_properly
126
+ comment_text = "a \"comment\" \\ that ' needs; escaping''"
127
+ result = nil
128
+ ActiveRecord::Schema.define do
129
+ add_table_comment :sample, comment_text
130
+ result = retrieve_table_comment :sample
131
+ end
132
+ assert_equal comment_text, result
133
+ end
134
+
135
+ end
@@ -0,0 +1,53 @@
1
+ require 'test_helper'
2
+ gem 'annotate'
3
+ require 'annotate/annotate_models'
4
+
5
+ class Sample < ActiveRecord::Base
6
+ self.table_name = 'sample'
7
+ end
8
+
9
+ class AnnotateModelsTest < Test::Unit::TestCase
10
+ include TestHelper
11
+
12
+ TEST_PREFIX = "== Schema Information"
13
+
14
+ def test_annotate_includes_comments
15
+ db_type = :default
16
+ ActiveRecord::Schema.define do
17
+ db_type = :postgres if connection.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) rescue false
18
+
19
+ add_table_comment :sample, "a table comment"
20
+ add_column_comment :sample, :field1, "a \"comment\" \\ that ' needs; escaping''"
21
+ add_column :sample, :field3, :string, :null => false, :comment => "third column comment"
22
+ end
23
+
24
+ result = AnnotateModels.get_schema_info(Sample, TEST_PREFIX)
25
+ postgres_expected = <<EOS
26
+ # #{TEST_PREFIX}
27
+ #
28
+ # Table name: sample # a table comment
29
+ #
30
+ # id :integer not null, primary key
31
+ # field1 :string(255) # a "comment" \\ that ' needs; escaping''
32
+ # field2 :integer
33
+ # field3 :string(255) not null # third column comment
34
+ #
35
+
36
+ EOS
37
+ default_expected = <<EOS
38
+ # #{TEST_PREFIX}
39
+ #
40
+ # Table name: sample # a table comment
41
+ #
42
+ # id :integer(4) not null, primary key
43
+ # field1 :string(255) # a "comment" \\ that ' needs; escaping''
44
+ # field2 :integer(4)
45
+ # field3 :string(255) not null # third column comment
46
+ #
47
+
48
+ EOS
49
+ expected = instance_eval "#{db_type}_expected"
50
+ assert_equal expected, result
51
+ end
52
+ end
53
+
@@ -0,0 +1,12 @@
1
+ postgres:
2
+ adapter: postgresql
3
+ database: migration_comments_test
4
+ host: 127.0.0.1
5
+ username: postgres
6
+ password: postgres
7
+
8
+ mysql:
9
+ adapter: mysql # mysql2
10
+ database: migration_comments_test
11
+ user: root
12
+ password: password
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+
3
+ class SchemaDumperTest < Test::Unit::TestCase
4
+ include TestHelper
5
+
6
+ def test_dump
7
+ ActiveRecord::Schema.define do
8
+ add_table_comment :sample, "a table comment"
9
+ add_column_comment :sample, :field1, "a \"comment\" \\ that ' needs; escaping''"
10
+ add_column :sample, :field3, :string, :null => false, :comment => "third column comment"
11
+ end
12
+ dest = StringIO.new
13
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, dest)
14
+ dest.rewind
15
+ result = dest.read
16
+ expected = <<EOS
17
+ # This file is auto-generated from the current state of the database. Instead of editing this file,
18
+ # please use the migrations feature of Active Record to incrementally modify your database, and
19
+ # then regenerate this schema definition.
20
+ #
21
+ # Note that this schema.rb definition is the authoritative source for your database schema. If you need
22
+ # to create the application database on another system, you should be using db:schema:load, not running
23
+ # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
24
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
25
+ #
26
+ # It's strongly recommended to check this file into your version control system.
27
+
28
+ ActiveRecord::Schema.define(:version => 1) do
29
+
30
+ create_table "sample", :force => true, :comment => "a table comment" do |t|
31
+ t.string "field1", :comment => "a \"comment\" \\ that ' needs; escaping''"
32
+ t.integer "field2"
33
+ t.string "field3", :null => false, :comment => "third column comment"
34
+ end
35
+
36
+ end
37
+ EOS
38
+ assert_equal expected, result
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ gem 'rails', '>= 2.3.2'
5
+ require 'active_record'
6
+ require 'yaml'
7
+
8
+ CONFIGURATIONS = YAML::load(IO.read('config/database.yml'))
9
+
10
+ ActiveRecord::Base.establish_connection(CONFIGURATIONS[ENV['DB'] || 'postgres'])
11
+
12
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
13
+ require 'migration_comments'
14
+
15
+ module TestHelper
16
+ def setup
17
+ ActiveRecord::Schema.define(:version => 1) do
18
+ create_table :sample do |t|
19
+ t.string :field1
20
+ t.integer :field2
21
+ end
22
+ end
23
+ end
24
+
25
+ def teardown
26
+ ActiveRecord::Schema.define do
27
+ drop_table :sample
28
+ end
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: migration_comments
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Pinny
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-10 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 2
32
+ - 3
33
+ version: "2.3"
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ hash: 7
37
+ segments:
38
+ - 2
39
+ - 3
40
+ - 2
41
+ version: 2.3.2
42
+ type: :runtime
43
+ version_requirements: *id001
44
+ - !ruby/object:Gem::Dependency
45
+ name: annotate
46
+ prerelease: false
47
+ requirement: &id002 !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ hash: 3
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ type: :development
57
+ version_requirements: *id002
58
+ - !ruby/object:Gem::Dependency
59
+ name: postgres-pr
60
+ prerelease: false
61
+ requirement: &id003 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id003
72
+ description: Add schema comments in your migrations, see them in model annotations and db/schema.rb dump
73
+ email:
74
+ - pinny@medwiztech.com
75
+ executables: []
76
+
77
+ extensions: []
78
+
79
+ extra_rdoc_files: []
80
+
81
+ files:
82
+ - .gitignore
83
+ - Gemfile
84
+ - README.rdoc
85
+ - Rakefile
86
+ - lib/migration_comments.rb
87
+ - lib/migration_comments/active_record/connection_adapters/abstract_adapter.rb
88
+ - lib/migration_comments/active_record/connection_adapters/column_definition.rb
89
+ - lib/migration_comments/active_record/connection_adapters/comment_definition.rb
90
+ - lib/migration_comments/active_record/connection_adapters/mysql2_adapter.rb
91
+ - lib/migration_comments/active_record/connection_adapters/mysql_adapter.rb
92
+ - lib/migration_comments/active_record/connection_adapters/postgresql_adapter.rb
93
+ - lib/migration_comments/active_record/connection_adapters/table.rb
94
+ - lib/migration_comments/active_record/connection_adapters/table_definition.rb
95
+ - lib/migration_comments/active_record/schema_dumper.rb
96
+ - lib/migration_comments/annotate_models.rb
97
+ - lib/migration_comments/version.rb
98
+ - migration_comments.gemspec
99
+ - test/add_comments_test.rb
100
+ - test/annotate_models_test.rb
101
+ - test/config/database.yml
102
+ - test/schema_dumper_test.rb
103
+ - test/test_helper.rb
104
+ has_rdoc: true
105
+ homepage: https://github.com/pinnymz/migration_comments
106
+ licenses: []
107
+
108
+ post_install_message:
109
+ rdoc_options: []
110
+
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ hash: 3
128
+ segments:
129
+ - 0
130
+ version: "0"
131
+ requirements: []
132
+
133
+ rubyforge_project: migration_comments
134
+ rubygems_version: 1.4.2
135
+ signing_key:
136
+ specification_version: 3
137
+ summary: Comments for your migrations
138
+ test_files: []
139
+