schema_plus 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -45,7 +45,7 @@ With standard rails migrations, you specify indexes separately from the table de
45
45
  add_index :parts, :name # index repeats table and column names and is defined separately
46
46
  add_index :parts, :product_code, :unique => true
47
47
 
48
- But with SchemaPlus rather than specify your outside your table definition you can specify your indexes when you define each column:
48
+ But with SchemaPlus you can specify your indexes when you define each column:
49
49
 
50
50
  # More DRY way...
51
51
  create_table :parts do |t|
@@ -103,9 +103,9 @@ the same arguments.
103
103
 
104
104
  The foreign key behavior can be configured globally (see Config) or per-table (see create_table).
105
105
 
106
- To examine your foreign key constraints, connection.foreign_keys returns a
106
+ To examine your foreign key constraints, <tt>connection.foreign_keys</tt> returns a
107
107
  list of foreign key constraints defined for a given table, and
108
- connection.reverse_foreign_keys returns a list of foreign key constraints
108
+ <tt>connection.reverse_foreign_keys</tt> returns a list of foreign key constraints
109
109
  that reference a given table. See SchemaPlus::ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.
110
110
 
111
111
  === Views
@@ -120,6 +120,31 @@ ActiveRecord works with views the same as with ordinary tables. That is, for th
120
120
  class UncommentedPosts < ActiveRecord::Base
121
121
  end
122
122
 
123
+ === Schema Dump and Load (schema.rb)
124
+
125
+ When dumping <tt>schema.rb</tt>, SchemaPlus orders the views and tables in
126
+ the schema dump alphabetically, but subject to the requirement that each
127
+ table or view be defined before those that depend on it. This allows all
128
+ foreign key constraints to be defined within the scope of the table
129
+ definition. (Unless there are cyclical dependencies, in which case some
130
+ foreign keys constraints must be defined later.)
131
+
132
+ Also, when dumping <tt>schema.rb</tt>, SchemaPlus dumps explicit foreign key
133
+ definition statements rather than relying on the auto-creation behavior,
134
+ for maximum clarity and for independence from global config. And
135
+ correspondingly, when loading a schema, i.e. with the context of
136
+ <tt>ActiveRecord::Schema.define</tt>, SchemaPlus ensures that auto creation of
137
+ foreign keys is turned off regardless of the global setting. But if for
138
+ some reason you are creating your schema.rb file by hand, and would like to
139
+ take advantage of auto-creation of foreign keys, you can re-enable it:
140
+
141
+ ActiveRecord::Schema.define do
142
+ SchemaPlus.config.foreign_keys.auto_create = true
143
+ SchemaPlus.config.foreign_keys.auto_index = true
144
+
145
+ create_table ...etc...
146
+ end
147
+
123
148
 
124
149
  == History
125
150
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /home/snatcher/projects/schema_plus
3
3
  specs:
4
- schema_plus (0.1.3)
4
+ schema_plus (0.2.0)
5
5
  rails
6
6
  valuable
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /home/snatcher/projects/schema_plus
3
3
  specs:
4
- schema_plus (0.1.3)
4
+ schema_plus (0.2.0)
5
5
  rails
6
6
  valuable
7
7
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /home/snatcher/projects/schema_plus
3
3
  specs:
4
- schema_plus (0.1.3)
4
+ schema_plus (0.2.0)
5
5
  rails
6
6
  valuable
7
7
 
@@ -97,7 +97,7 @@ GEM
97
97
  sprockets (2.0.0)
98
98
  hike (~> 1.2)
99
99
  rack (~> 1.0)
100
- tilt (!= 1.3.0, ~> 1.1)
100
+ tilt (~> 1.1, != 1.3.0)
101
101
  sqlite3 (1.3.4)
102
102
  thor (0.14.6)
103
103
  tilt (1.3.3)
@@ -0,0 +1,5 @@
1
+ namespace :schema_plus do
2
+ task :load do
3
+ SchemaPlus.insert
4
+ end
5
+ end
data/lib/schema_plus.rb CHANGED
@@ -2,6 +2,7 @@ require 'valuable'
2
2
 
3
3
  require 'schema_plus/version'
4
4
  require 'schema_plus/active_record/base'
5
+ require 'schema_plus/active_record/column_options_handler'
5
6
  require 'schema_plus/active_record/foreign_keys'
6
7
  require 'schema_plus/active_record/connection_adapters/table_definition'
7
8
  require 'schema_plus/active_record/connection_adapters/schema_statements'
@@ -0,0 +1,55 @@
1
+ module SchemaPlus::ActiveRecord
2
+ module ColumnOptionsHandler
3
+ def schema_plus_handle_column_options(table_name, column_name, column_options, opts = {}) #:nodoc:
4
+ config = opts[:config] || SchemaPlus.config
5
+ if references = get_references(table_name, column_name, column_options, config)
6
+ if index = column_options.fetch(:index, config.foreign_keys.auto_index?)
7
+ column_index(table_name, column_name, index)
8
+ end
9
+ add_foreign_key(table_name, column_name, references.first, references.last,
10
+ column_options.reverse_merge(:on_update => config.foreign_keys.on_update,
11
+ :on_delete => config.foreign_keys.on_delete))
12
+ elsif column_options[:index]
13
+ column_index(table_name, column_name, column_options[:index])
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ # If auto_create is true:
20
+ # get_references('comments', 'post_id') # => ['posts', 'id']
21
+ #
22
+ # And if <tt>column_name</tt> is parent_id it references to the same table
23
+ # get_references('pages', 'parent_id') # => ['pages', 'id']
24
+ #
25
+ # If :references option is given, it is used (whether or not auto_create is true)
26
+ # get_references('widgets', 'main_page_id', :references => 'pages')) => ['pages', 'id']
27
+ #
28
+ # Also the referenced id column may be specified:
29
+ # get_references('addresses', 'member_id', :references => ['users', 'uuid']) => ['users', 'uuid']
30
+ #
31
+ def get_references(table_name, column_name, column_options = {}, config = {}) #:nodoc:
32
+ if column_options.has_key?(:references)
33
+ references = column_options[:references]
34
+ references = [references, :id] unless references.nil? || references.is_a?(Array)
35
+ references
36
+ elsif config.foreign_keys.auto_create?
37
+ case column_name.to_s
38
+ when 'parent_id'
39
+ [table_name, :id]
40
+ when /^(.*)_id$/
41
+ determined_table_name = ActiveRecord::Base.pluralize_table_names ? $1.to_s.pluralize : $1
42
+ [determined_table_name, :id]
43
+ end
44
+ end
45
+ end
46
+
47
+ def column_index(table_name, column_name, options) #:nodoc:
48
+ options = {} if options == true
49
+ options = { :unique => true } if options == :unique
50
+ column_name = [column_name] + Array.wrap(options.delete(:with)).compact
51
+ add_index(table_name, column_name, options)
52
+ end
53
+
54
+ end
55
+ end
@@ -39,7 +39,10 @@ module SchemaPlus
39
39
  # compatible with the monkey patches; but the definition only
40
40
  # appears once the adapter is loaded. so wait til now to check
41
41
  # if that constant exists, then include the patches
42
- ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
42
+ if mysql2index = ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition rescue nil # rescues NameError
43
+ monkeypatch = SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition
44
+ mysql2index.send(:include, monkeypatch) unless mysql2index.include? monkeypatch
45
+ end
43
46
  end
44
47
  extend(SchemaPlus::ActiveRecord::ForeignKeys)
45
48
  end
@@ -61,19 +61,15 @@ module SchemaPlus
61
61
  end
62
62
 
63
63
  # Dumps a definition of foreign key.
64
- # Must be invoked inside create_table block.
65
- #
66
- # It was introduced to satisfy sqlite which requires foreign key definitions
67
- # to be declared when creating a table. That approach is fine for MySQL and
68
- # PostgreSQL too.
69
- def to_dump
70
- dump = " t.foreign_key"
64
+ def to_dump(opts={})
65
+ dump = (opts[:inline] ? " t.foreign_key" : "add_foreign_key #{table_name.inspect},")
71
66
  dump << " [#{Array(column_names).collect{ |name| name.inspect }.join(', ')}]"
72
67
  dump << ", #{references_table_name.inspect}, [#{Array(references_column_names).collect{ |name| name.inspect }.join(', ')}]"
73
68
  dump << ", :on_update => :#{on_update}" if on_update
74
69
  dump << ", :on_delete => :#{on_delete}" if on_delete
75
70
  dump << ", :deferrable => #{deferrable}" if deferrable
76
71
  dump << ", :name => #{name.inspect}" if name
72
+ dump << "\n"
77
73
  dump
78
74
  end
79
75
 
@@ -52,6 +52,10 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
52
52
  # <tt>_id</tt>. So the above examples are redundant, unless automatic
53
53
  # creation was disabled at initialization in the global Config.
54
54
  #
55
+ # SchemaPlus likewise by default automatically creates foreign key constraints for
56
+ # columns defined via <tt>t.references</tt>, unless the
57
+ # <tt>:polymorphic</tt> option is true
58
+ #
55
59
  # Finally, the configuration for foreign keys can be overriden on a per-table
56
60
  # basis by passing Config options to Migration::ClassMethods#create_table, such as
57
61
  #
@@ -60,6 +64,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
60
64
  # end
61
65
  #
62
66
  module TableDefinition
67
+ include SchemaPlus::ActiveRecord::ColumnOptionsHandler
63
68
 
64
69
  attr_accessor :schema_plus_config #:nodoc:
65
70
 
@@ -69,6 +74,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
69
74
  attr_accessor :indexes
70
75
  alias_method_chain :initialize, :schema_plus
71
76
  alias_method_chain :column, :schema_plus
77
+ alias_method_chain :references, :schema_plus
72
78
  alias_method_chain :primary_key, :schema_plus
73
79
  alias_method_chain :to_sql, :schema_plus
74
80
  end
@@ -84,18 +90,16 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
84
90
  column(name, :primary_key, options)
85
91
  end
86
92
 
93
+ def references_with_schema_plus(*args)
94
+ options = args.extract_options!
95
+ options[:references] = nil if options[:polymorphic]
96
+ args << options
97
+ references_without_schema_plus(*args)
98
+ end
99
+
87
100
  def column_with_schema_plus(name, type, options = {}) #:nodoc:
88
101
  column_without_schema_plus(name, type, options)
89
- if references = ActiveRecord::Migration.connection.get_references(self.name, name, options, schema_plus_config)
90
- if index = options.fetch(:index, fk_use_auto_index?)
91
- self.column_index(name, index)
92
- end
93
- foreign_key(name, references.first, references.last,
94
- options.reverse_merge(:on_update => schema_plus_config.foreign_keys.on_update,
95
- :on_delete => schema_plus_config.foreign_keys.on_delete))
96
- elsif options[:index]
97
- self.column_index(name, options[:index])
98
- end
102
+ schema_plus_handle_column_options(self.name, name, options, :config => schema_plus_config)
99
103
  self
100
104
  end
101
105
 
@@ -116,15 +120,16 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
116
120
  end
117
121
 
118
122
  protected
119
- def column_index(name, options) #:nodoc:
120
- options = {} if options == true
121
- options = {:unique => true} if options == :unique
122
- name = [name] + Array.wrap(options.delete(:with)).compact
123
- self.index(name, options)
123
+ # The only purpose of that method is to provide a consistent intefrace
124
+ # for ColumnOptionsHandler. First argument (table name) is ignored.
125
+ def add_index(_, *args) #:nodoc:
126
+ index(*args)
124
127
  end
125
128
 
126
- def fk_use_auto_index? #:nodoc:
127
- schema_plus_config.foreign_keys.auto_index? && !ActiveRecord::Schema.defining?
129
+ # The only purpose of that method is to provide a consistent intefrace
130
+ # for ColumnOptionsHandler. First argument (table name) is ignored.
131
+ def add_foreign_key(_, *args) #:nodoc:
132
+ foreign_key(*args)
128
133
  end
129
134
 
130
135
  end
@@ -1,5 +1,7 @@
1
1
  module SchemaPlus::ActiveRecord
2
2
  module ForeignKeys
3
+ include SchemaPlus::ActiveRecord::ColumnOptionsHandler
4
+
3
5
  # Enhances ActiveRecord::ConnectionAdapters::AbstractAdapter#add_column to support indexes and foreign keys, with automatic creation
4
6
  #
5
7
  # == Indexes
@@ -104,69 +106,17 @@ module SchemaPlus::ActiveRecord
104
106
  #
105
107
  def add_column(table_name, column_name, type, options = {})
106
108
  super
107
- handle_column_options(table_name, column_name, options)
109
+ schema_plus_handle_column_options(table_name, column_name, options)
108
110
  end
109
111
 
110
112
  # Enhances ActiveRecord::Migration#change_column to support indexes and foreign keys same as add_column.
111
113
  def change_column(table_name, column_name, type, options = {})
112
114
  super
113
115
  remove_foreign_key_if_exists(table_name, column_name)
114
- handle_column_options(table_name, column_name, options)
115
- end
116
-
117
- # Determines referenced table and column.
118
- # Used in migrations.
119
- #
120
- # If auto_create is true:
121
- # get_references('comments', 'post_id') # => ['posts', 'id']
122
- #
123
- # And if <tt>column_name</tt> is parent_id it references to the same table
124
- # get_references('pages', 'parent_id') # => ['pages', 'id']
125
- #
126
- # If :references option is given, it is used (whether or not auto_create is true)
127
- # get_references('widgets', 'main_page_id', :references => 'pages'))
128
- # # => ['pages', 'id']
129
- #
130
- # Also the referenced id column may be specified:
131
- # get_references('addresses', 'member_id', :references => ['users', 'uuid'])
132
- # # => ['users', 'uuid']
133
- def get_references(table_name, column_name, options = {}, config=nil) #:nodoc:
134
- column_name = column_name.to_s
135
- if options.has_key?(:references)
136
- references = options[:references]
137
- references = [references, :id] unless references.nil? || references.is_a?(Array)
138
- references
139
- elsif (config || SchemaPlus.config).foreign_keys.auto_create? && !ActiveRecord::Schema.defining?
140
- if column_name == 'parent_id'
141
- [table_name, :id]
142
- elsif column_name =~ /^(.*)_id$/
143
- determined_table_name = ActiveRecord::Base.pluralize_table_names ? $1.to_s.pluralize : $1
144
- [determined_table_name, :id]
145
- end
146
- end
116
+ schema_plus_handle_column_options(table_name, column_name, options)
147
117
  end
148
118
 
149
119
  protected
150
- def handle_column_options(table_name, column_name, options) #:nodoc:
151
- if references = get_references(table_name, column_name, options)
152
- if index = options.fetch(:index, SchemaPlus.config.foreign_keys.auto_index? && !ActiveRecord::Schema.defining?)
153
- column_index(table_name, column_name, index)
154
- end
155
- add_foreign_key(table_name, column_name, references.first, references.last,
156
- options.reverse_merge(:on_update => SchemaPlus.config.foreign_keys.on_update,
157
- :on_delete => SchemaPlus.config.foreign_keys.on_delete))
158
- elsif options[:index]
159
- column_index(table_name, column_name, options[:index])
160
- end
161
- end
162
-
163
- def column_index(table_name, column_name, options) #:nodoc:
164
- options = {} if options == true
165
- options = { :unique => true } if options == :unique
166
- column_name = [column_name] + Array.wrap(options.delete(:with)).compact
167
- add_index(table_name, column_name, options)
168
- end
169
-
170
120
  def remove_foreign_key_if_exists(table_name, column_name) #:nodoc:
171
121
  foreign_keys = ActiveRecord::Base.connection.foreign_keys(table_name.to_s)
172
122
  fk = foreign_keys.detect { |fk| fk.table_name == table_name.to_s && fk.column_names == Array(column_name).collect(&:to_s) }
@@ -8,18 +8,19 @@ module SchemaPlus
8
8
  module ClassMethods
9
9
  def self.extended(base)
10
10
  class << base
11
- attr_accessor :defining
12
- alias :defining? :defining
13
-
14
11
  alias_method_chain :define, :schema_plus
15
12
  end
16
13
  end
17
14
 
18
15
  def define_with_schema_plus(info={}, &block)
19
- self.defining = true
20
- define_without_schema_plus(info, &block)
21
- ensure
22
- self.defining = false
16
+ fk_override = { :auto_create => false, :auto_index => false }
17
+ save = Hash[fk_override.keys.collect{|key| [key, SchemaPlus.config.foreign_keys.send(key)]}]
18
+ begin
19
+ SchemaPlus.config.foreign_keys.update_attributes(fk_override)
20
+ define_without_schema_plus(info, &block)
21
+ ensure
22
+ SchemaPlus.config.foreign_keys.update_attributes(save)
23
+ end
23
24
  end
24
25
  end
25
26
  end
@@ -31,24 +31,60 @@ module SchemaPlus
31
31
 
32
32
  private
33
33
 
34
+ def break_fk_cycles #:nodoc:
35
+ strongly_connected_components.select{|component| component.size > 1}.each do |tables|
36
+ table = tables.sort.first
37
+ backref_fks = @inline_fks[table].select{|fk| tables.include?(fk.references_table_name)}
38
+ @inline_fks[table] -= backref_fks
39
+ @dump_dependencies[table] -= backref_fks.collect(&:references_table_name)
40
+ backref_fks.each do |fk|
41
+ @backref_fks[fk.references_table_name] << fk
42
+ end
43
+ end
44
+ end
45
+
34
46
  def tables_with_schema_plus(stream) #:nodoc:
35
47
  @table_dumps = {}
36
- @re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(#{(@connection.tables + @connection.views).join('|')})\b}
37
- begin
38
- tables_without_schema_plus(nil)
48
+ @inline_fks = Hash.new{ |h, k| h[k] = [] }
49
+ @backref_fks = Hash.new{ |h, k| h[k] = [] }
50
+ @dump_dependencies = {}
39
51
 
40
- @connection.views.each do |view_name|
41
- definition = @connection.view_definition(view_name)
42
- @table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}\n"
43
- end
52
+ tables_without_schema_plus(nil)
44
53
 
45
- tsort().each do |table|
46
- stream.print @table_dumps[table]
54
+ @connection.views.each do |view_name|
55
+ definition = @connection.view_definition(view_name)
56
+ @table_dumps[view_name] = " create_view #{view_name.inspect}, #{definition.inspect}\n"
57
+ end
58
+
59
+ re_view_referent = %r{(?:(?i)FROM|JOIN) \S*\b(#{(@table_dumps.keys).join('|')})\b}
60
+ @table_dumps.keys.each do |table|
61
+ if @connection.views.include?(table)
62
+ dependencies = @connection.view_definition(table).scan(re_view_referent).flatten
63
+ else
64
+ @inline_fks[table] = @connection.foreign_keys(table)
65
+ dependencies = @inline_fks[table].collect(&:references_table_name)
47
66
  end
67
+ @dump_dependencies[table] = dependencies.sort.uniq - ::ActiveRecord::SchemaDumper.ignore_tables
68
+ end
48
69
 
49
- ensure
50
- @table_dumps = nil
70
+ # Normally we dump foreign key constraints inline in the table
71
+ # definitions, both for visual cleanliness and because sqlite3
72
+ # doesn't allow foreign key constraints to be added afterwards.
73
+ # But in case there's a cycle in the constraint references, some
74
+ # constraints will need to be broken out then added later. (Adding
75
+ # constraints later won't work with sqlite3, but that means sqlite3
76
+ # won't let you create cycles in the first place.)
77
+ break_fk_cycles while strongly_connected_components.any?{|component| component.size > 1}
78
+
79
+ tsort().each do |table|
80
+ table_dump = @table_dumps[table]
81
+ if i = (table_dump =~ /^\s*[e]nd\s*$/)
82
+ table_dump.insert i, dump_indexes(table) + dump_foreign_keys(@inline_fks[table], :inline => true)
83
+ end
84
+ stream.print table_dump
85
+ stream.puts dump_foreign_keys(@backref_fks[table], :inline => false)+"\n" if @backref_fks[table].any?
51
86
  end
87
+
52
88
  end
53
89
 
54
90
  def tsort_each_node(&block) #:nodoc:
@@ -56,30 +92,13 @@ module SchemaPlus
56
92
  end
57
93
 
58
94
  def tsort_each_child(table, &block) #:nodoc:
59
- references = if @connection.views.include?(table)
60
- @connection.view_definition(table).scan(@re_view_referent).flatten
61
- else
62
- @connection.foreign_keys(table).collect(&:references_table_name)
63
- end
64
- references.sort.uniq.each(&block)
95
+ @dump_dependencies[table].each(&block)
65
96
  end
66
97
 
67
98
  def table_with_schema_plus(table, ignore) #:nodoc:
68
-
69
99
  stream = StringIO.new
70
100
  table_without_schema_plus(table, stream)
71
- stream.rewind
72
- table_dump = stream.read
73
-
74
- if i = (table_dump =~ /^\s*[e]nd\s*$/)
75
- stream = StringIO.new
76
- dump_indexes(table, stream)
77
- dump_foreign_keys(table, stream)
78
- stream.rewind
79
- table_dump.insert i, stream.read
80
- end
81
-
82
- @table_dumps[table] = table_dump
101
+ @table_dumps[table] = stream.string
83
102
  end
84
103
 
85
104
  def indexes_with_schema_plus(table, stream) #:nodoc:
@@ -87,36 +106,29 @@ module SchemaPlus
87
106
  # dumping the tables
88
107
  end
89
108
 
90
- def dump_indexes(table, stream) #:nodoc:
91
- indexes = @connection.indexes(table)
92
- indexes.each do |index|
93
- stream.print " t.index"
109
+ def dump_indexes(table) #:nodoc:
110
+ @connection.indexes(table).collect{ |index|
111
+ dump = " t.index"
94
112
  unless index.columns.blank?
95
- stream.print " #{index.columns.inspect}, :name => #{index.name.inspect}"
96
- stream.print ", :unique => true" if index.unique
97
- stream.print ", :kind => \"#{index.kind}\"" unless index.kind.blank?
98
- stream.print ", :case_sensitive => false" unless index.case_sensitive?
99
- stream.print ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
113
+ dump << " #{index.columns.inspect}, :name => #{index.name.inspect}"
114
+ dump << ", :unique => true" if index.unique
115
+ dump << ", :kind => \"#{index.kind}\"" unless index.kind.blank?
116
+ dump << ", :case_sensitive => false" unless index.case_sensitive?
117
+ dump << ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
100
118
  index_lengths = index.lengths.compact if index.lengths.is_a?(Array)
101
- stream.print ", :length => #{Hash[*index.columns.zip(index.lengths).flatten].inspect}" if index_lengths.present?
119
+ dump << ", :length => #{Hash[*index.columns.zip(index.lengths).flatten].inspect}" if index_lengths.present?
102
120
  else
103
- stream.print " :name => #{index.name.inspect}"
104
- stream.print ", :kind => \"#{index.kind}\"" unless index.kind.blank?
105
- stream.print ", :expression => #{index.expression.inspect}"
121
+ dump << " :name => #{index.name.inspect}"
122
+ dump << ", :kind => \"#{index.kind}\"" unless index.kind.blank?
123
+ dump << ", :expression => #{index.expression.inspect}"
106
124
  end
107
-
108
- stream.puts
109
- end
125
+ dump << "\n"
126
+ }.join
110
127
  end
111
128
 
112
- def dump_foreign_keys(table, stream) #:nodoc:
113
- foreign_keys = @connection.foreign_keys(table)
114
- foreign_keys.each do |foreign_key|
115
- stream.print " "
116
- stream.puts foreign_key.to_dump
117
- end
129
+ def dump_foreign_keys(foreign_keys, opts={}) #:nodoc:
130
+ foreign_keys.collect{ |foreign_key| " " + foreign_key.to_dump(:inline => opts[:inline]) }.join
118
131
  end
119
-
120
132
  end
121
133
  end
122
134
  end
@@ -1,4 +1,4 @@
1
- module SchemaPlus
1
+ module SchemaPlus
2
2
  class Railtie < Rails::Railtie #:nodoc:
3
3
 
4
4
  initializer 'schema_plus.insert', :after => "active_record.initialize_database" do
@@ -7,5 +7,12 @@ module SchemaPlus
7
7
  end
8
8
  end
9
9
 
10
+ rake_tasks do
11
+ load 'rails/tasks/database.rake'
12
+ if task = Rake.application.tasks.find { |task| task.name == 'db:schema:dump' }
13
+ task.enhance(["schema_plus:load"])
14
+ end
15
+ end
16
+
10
17
  end
11
18
  end
@@ -1,3 +1,3 @@
1
1
  module SchemaPlus
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
data/runspecs CHANGED
@@ -8,7 +8,7 @@ RAILS_VERSIONS = %W[2.3 3.0 3.1]
8
8
  DB_ADAPTERS = %W[postgresql mysql mysql2 sqlite3]
9
9
 
10
10
  o = OpenStruct.new
11
- o.ruby_versions = ["1.9.2"]
11
+ o.ruby_versions = RUBY_VERSIONS
12
12
  o.rails_versions = RAILS_VERSIONS
13
13
  o.db_adapters = DB_ADAPTERS - ["mysql"]
14
14
 
@@ -71,7 +71,7 @@ o.ruby_versions.each do |ruby|
71
71
  puts "\n\n*** ruby version #{ruby} - rails version #{rails} - db adapters: #{o.db_adapters.join(' ')} [#{n} of #{total}]\n\n"
72
72
  gemfile = File.join(GEMFILES_DIR, "Gemfile.rails-#{rails}")
73
73
  n += 1
74
- command = %Q{BUNDLE_GEMFILE="#{gemfile}" rvm #{ruby} exec #{cmd}}
74
+ command = %Q{BUNDLE_GEMFILE="#{gemfile}" rvm #{ruby} do #{cmd}}
75
75
  puts command
76
76
  next if o.dry_run
77
77
  system(command) or errs << "ruby #{ruby}, rails #{rails}"
data/schema_plus.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = "schema_plus"
7
7
  s.version = SchemaPlus::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.authors = ["Ronen Barzel", "Michał Łomnicki"]
9
+ s.authors = ["Ronen Barzel", "Michal Lomnicki"]
10
10
  s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
11
  s.homepage = "https://github.com/lomba/schema_plus"
12
12
  s.summary = "Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views."
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Connection" do
4
+
5
+ it "should re-open without failure" do
6
+ expect {
7
+ ActiveRecord::Base.establish_connection "schema_plus"
8
+ }.should_not raise_error
9
+ end
10
+ end
@@ -38,6 +38,11 @@ describe ActiveRecord::Migration do
38
38
  @model.should_not reference(:users, :id).on(:user_id)
39
39
  end
40
40
 
41
+ it "should not create foreign key using t.references with :polymorphic => true" do
42
+ create_table(@model, :user => {:METHOD => :references, :polymorphic => true})
43
+ @model.should_not reference(:users, :id).on(:user_id)
44
+ end
45
+
41
46
  it "should create foreign key to the same table on parent_id" do
42
47
  create_table(@model, :parent_id => {})
43
48
  @model.should reference(@model.table_name, :id).on(:parent_id)
@@ -1,48 +1,94 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'stringio'
3
3
 
4
- require 'models/post'
5
-
6
- describe "Schema dump (core)" do
4
+ describe "Schema dump" do
7
5
 
8
6
  before(:all) do
9
- load_core_schema
7
+ SchemaPlus.setup do |config|
8
+ config.foreign_keys.auto_create = false
9
+ end
10
+ ActiveRecord::Migration.suppress_messages do
11
+ ActiveRecord::Schema.define do
12
+ connection.tables.each do |table| drop_table table end
13
+
14
+ create_table :users, :force => true do |t|
15
+ t.string :login
16
+ t.datetime :deleted_at
17
+ t.integer :first_post_id
18
+ end
19
+
20
+ create_table :posts, :force => true do |t|
21
+ t.text :body
22
+ t.integer :user_id
23
+ t.integer :first_comment_id
24
+ end
25
+
26
+ create_table :comments, :force => true do |t|
27
+ t.text :body
28
+ t.integer :post_id
29
+ t.integer :commenter_id
30
+ end
31
+ end
32
+ end
33
+ class ::User < ActiveRecord::Base ; end
34
+ class ::Post < ActiveRecord::Base ; end
35
+ class ::Comment < ActiveRecord::Base ; end
10
36
  end
11
37
 
12
- let(:dump) do
38
+ let(:dump_posts) do
13
39
  stream = StringIO.new
14
40
  ActiveRecord::SchemaDumper.ignore_tables = %w[users comments]
15
41
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
16
42
  stream.string
17
43
  end
18
44
 
45
+ let(:dump_all) do
46
+ stream = StringIO.new
47
+ ActiveRecord::SchemaDumper.ignore_tables = []
48
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
49
+ stream.string
50
+ end
51
+
19
52
  it "should include foreign_key definition" do
20
53
  with_foreign_key Post, :user_id, :users, :id do
21
- dump.should match(to_regexp(%q{t.foreign_key ["user_id"], "users", ["id"]}))
54
+ dump_posts.should match(to_regexp(%q{t.foreign_key ["user_id"], "users", ["id"]}))
55
+ end
56
+ end
57
+
58
+ context "with constraint dependencies" do
59
+ it "should sort in Posts => Comments direction" do
60
+ with_foreign_key Comment, :post_id, :posts, :id do
61
+ dump_all.should match(%r{create_table "posts".*create_table "comments"}m)
62
+ end
63
+ end
64
+ it "should sort in Comments => Posts direction" do
65
+ with_foreign_key Post, :first_comment_id, :comments, :id do
66
+ dump_all.should match(%r{create_table "comments".*create_table "posts"}m)
67
+ end
22
68
  end
23
69
  end
24
70
 
25
71
  it "should include foreign_key options" do
26
72
  with_foreign_key Post, :user_id, :users, :id, :on_update => :cascade, :on_delete => :set_null do
27
- dump.should match(to_regexp(%q{t.foreign_key ["user_id"], "users", ["id"], :on_update => :cascade, :on_delete => :set_null}))
73
+ dump_posts.should match(to_regexp(%q{t.foreign_key ["user_id"], "users", ["id"], :on_update => :cascade, :on_delete => :set_null}))
28
74
  end
29
75
  end
30
76
 
31
77
  it "should include index definition" do
32
78
  with_index Post, :user_id do
33
- dump.should match(to_regexp(%q{t.index ["user_id"]}))
79
+ dump_posts.should match(to_regexp(%q{t.index ["user_id"]}))
34
80
  end
35
81
  end
36
82
 
37
83
  it "should include index name" do
38
84
  with_index Post, :user_id, :name => "posts_user_id_index" do
39
- dump.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index"}))
85
+ dump_posts.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index"}))
40
86
  end
41
87
  end
42
88
 
43
89
  it "should define unique index" do
44
90
  with_index Post, :user_id, :name => "posts_user_id_index", :unique => true do
45
- dump.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index", :unique => true}))
91
+ dump_posts.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index", :unique => true}))
46
92
  end
47
93
  end
48
94
 
@@ -50,30 +96,54 @@ describe "Schema dump (core)" do
50
96
 
51
97
  it "should define case insensitive index" do
52
98
  with_index Post, :name => "posts_user_body_index", :expression => "USING btree (LOWER(body))" do
53
- dump.should match(to_regexp(%q{t.index ["body"], :name => "posts_user_body_index", :case_sensitive => false}))
99
+ dump_posts.should match(to_regexp(%q{t.index ["body"], :name => "posts_user_body_index", :case_sensitive => false}))
54
100
  end
55
101
  end
56
102
 
57
103
  it "should define conditions" do
58
104
  with_index Post, :user_id, :name => "posts_user_id_index", :conditions => "user_id IS NOT NULL" do
59
- dump.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index", :conditions => "(user_id IS NOT NULL)"}))
105
+ dump_posts.should match(to_regexp(%q{t.index ["user_id"], :name => "posts_user_id_index", :conditions => "(user_id IS NOT NULL)"}))
60
106
  end
61
107
  end
62
108
 
63
109
  it "should define expression" do
64
110
  with_index Post, :name => "posts_freaky_index", :expression => "USING hash (least(id, user_id))" do
65
- dump.should match(to_regexp(%q{t.index :name => "posts_freaky_index", :kind => "hash", :expression => "LEAST(id, user_id)"}))
111
+ dump_posts.should match(to_regexp(%q{t.index :name => "posts_freaky_index", :kind => "hash", :expression => "LEAST(id, user_id)"}))
66
112
  end
67
113
  end
68
114
 
69
115
  it "should define kind" do
70
116
  with_index Post, :name => "posts_body_index", :expression => "USING hash (body)" do
71
- dump.should match(to_regexp(%q{t.index ["body"], :name => "posts_body_index", :kind => "hash"}))
117
+ dump_posts.should match(to_regexp(%q{t.index ["body"], :name => "posts_body_index", :kind => "hash"}))
72
118
  end
73
119
  end
74
120
 
75
121
  end
76
122
 
123
+ unless SchemaPlusHelpers.sqlite3?
124
+ context "with cyclic foreign key constraints" do
125
+ before (:all) do
126
+ ActiveRecord::Base.connection.add_foreign_key(Comment.table_name, :commenter_id, User.table_name, :id)
127
+ ActiveRecord::Base.connection.add_foreign_key(Comment.table_name, :post_id, Post.table_name, :id)
128
+ ActiveRecord::Base.connection.add_foreign_key(Post.table_name, :first_comment_id, Comment.table_name, :id)
129
+ ActiveRecord::Base.connection.add_foreign_key(Post.table_name, :user_id, User.table_name, :id)
130
+ ActiveRecord::Base.connection.add_foreign_key(User.table_name, :first_post_id, Post.table_name, :id)
131
+ end
132
+
133
+ it "should not raise an error" do
134
+ expect { dump_all }.should_not raise_error
135
+ end
136
+
137
+ it "should dump constraints after the tables they reference" do
138
+ dump_all.should match(%r{create_table "comments".*foreign_key.*\["first_comment_id"\], "comments", \["id"\]}m)
139
+ dump_all.should match(%r{create_table "posts".*foreign_key.*\["first_post_id"\], "posts", \["id"\]}m)
140
+ dump_all.should match(%r{create_table "posts".*foreign_key.*\["post_id"\], "posts", \["id"\]}m)
141
+ dump_all.should match(%r{create_table "users".*foreign_key.*\["commenter_id"\], "users", \["id"\]}m)
142
+ dump_all.should match(%r{create_table "users".*foreign_key.*\["user_id"\], "users", \["id"\]}m)
143
+ end
144
+ end
145
+ end
146
+
77
147
  protected
78
148
  def to_regexp(string)
79
149
  Regexp.new(Regexp.escape(string))
@@ -130,38 +200,3 @@ describe "Schema dump (core)" do
130
200
  end
131
201
 
132
202
  end
133
-
134
- describe "Schema dump (auto)" do
135
-
136
- before(:all) do
137
- load_auto_schema
138
- end
139
-
140
- let(:dump) do
141
- stream = StringIO.new
142
- ActiveRecord::SchemaDumper.ignore_tables = []
143
- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
144
- stream.string
145
- end
146
-
147
- unless SchemaPlusHelpers.sqlite3?
148
- it "shouldn't include :index option for index" do
149
- add_column(:author_id, :integer, :references => :users, :index => true) do
150
- dump.should_not match(/index => true/)
151
- end
152
- end
153
- end
154
-
155
- protected
156
- def add_column(column_name, *args)
157
- table = Post.table_name
158
- ActiveRecord::Migration.suppress_messages do
159
- ActiveRecord::Migration.add_column(table, column_name, *args)
160
- Post.reset_column_information
161
- yield if block_given?
162
- ActiveRecord::Migration.remove_column(table, column_name)
163
- end
164
- end
165
-
166
- end
167
-
data/spec/views_spec.rb CHANGED
@@ -98,6 +98,8 @@ describe ActiveRecord do
98
98
 
99
99
  def define_schema_and_data
100
100
  migration.suppress_messages do
101
+ connection.views.each do |view| connection.drop_view view end
102
+ connection.tables.each do |table| connection.drop_table table end
101
103
 
102
104
  schema.define do
103
105
 
metadata CHANGED
@@ -1,126 +1,144 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: schema_plus
3
- version: !ruby/object:Gem::Version
4
- version: 0.1.3
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - Ronen Barzel
9
- - Michał Łomnicki
13
+ - Michal Lomnicki
10
14
  autorequire:
11
15
  bindir: bin
12
16
  cert_chain: []
13
- date: 2011-09-28 00:00:00.000000000Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2011-10-22 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
16
22
  name: rails
17
- requirement: &69439930 !ruby/object:Gem::Requirement
18
- none: false
19
- requirements:
20
- - - ! '>='
21
- - !ruby/object:Gem::Version
22
- version: '0'
23
- type: :runtime
24
23
  prerelease: false
25
- version_requirements: *69439930
26
- - !ruby/object:Gem::Dependency
27
- name: valuable
28
- requirement: &69439700 !ruby/object:Gem::Requirement
29
- none: false
30
- requirements:
31
- - - ! '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
34
31
  type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: valuable
35
35
  prerelease: false
36
- version_requirements: *69439700
37
- - !ruby/object:Gem::Dependency
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ version_requirements: *id002
45
+ - !ruby/object:Gem::Dependency
38
46
  name: rake
39
- requirement: &69439390 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
42
50
  - - ~>
43
- - !ruby/object:Gem::Version
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ - 8
55
+ - 7
44
56
  version: 0.8.7
45
57
  type: :development
46
- prerelease: false
47
- version_requirements: *69439390
48
- - !ruby/object:Gem::Dependency
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
49
60
  name: rspec
50
- requirement: &69439120 !ruby/object:Gem::Requirement
51
- none: false
52
- requirements:
53
- - - ! '>='
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- type: :development
57
61
  prerelease: false
58
- version_requirements: *69439120
59
- - !ruby/object:Gem::Dependency
60
- name: pg
61
- requirement: &69438750 !ruby/object:Gem::Requirement
62
- none: false
63
- requirements:
64
- - - ! '>='
65
- - !ruby/object:Gem::Version
66
- version: '0'
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 0
68
+ version: "0"
67
69
  type: :development
70
+ version_requirements: *id004
71
+ - !ruby/object:Gem::Dependency
72
+ name: pg
68
73
  prerelease: false
69
- version_requirements: *69438750
70
- - !ruby/object:Gem::Dependency
71
- name: mysql
72
- requirement: &69438370 !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
74
+ requirement: &id005 !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
78
81
  type: :development
82
+ version_requirements: *id005
83
+ - !ruby/object:Gem::Dependency
84
+ name: mysql
79
85
  prerelease: false
80
- version_requirements: *69438370
81
- - !ruby/object:Gem::Dependency
82
- name: sqlite3
83
- requirement: &69437940 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
86
- - - ! '>='
87
- - !ruby/object:Gem::Version
88
- version: '0'
86
+ requirement: &id006 !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
89
93
  type: :development
94
+ version_requirements: *id006
95
+ - !ruby/object:Gem::Dependency
96
+ name: sqlite3
90
97
  prerelease: false
91
- version_requirements: *69437940
92
- - !ruby/object:Gem::Dependency
93
- name: simplecov
94
- requirement: &69437700 !ruby/object:Gem::Requirement
95
- none: false
96
- requirements:
97
- - - ! '>='
98
- - !ruby/object:Gem::Version
99
- version: '0'
98
+ requirement: &id007 !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ segments:
103
+ - 0
104
+ version: "0"
100
105
  type: :development
106
+ version_requirements: *id007
107
+ - !ruby/object:Gem::Dependency
108
+ name: simplecov
101
109
  prerelease: false
102
- version_requirements: *69437700
103
- - !ruby/object:Gem::Dependency
104
- name: simplecov-gem-adapter
105
- requirement: &69437420 !ruby/object:Gem::Requirement
106
- none: false
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
110
+ requirement: &id008 !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ segments:
115
+ - 0
116
+ version: "0"
111
117
  type: :development
118
+ version_requirements: *id008
119
+ - !ruby/object:Gem::Dependency
120
+ name: simplecov-gem-adapter
112
121
  prerelease: false
113
- version_requirements: *69437420
114
- description: ! 'SchemaPlus is an ActiveRecord extension that provides enhanced capabilities
115
- for schema definition and querying, including: enhanced and more DRY index capabilities,
116
- support and automation for foreign key constraints, and support for views.'
117
- email:
122
+ requirement: &id009 !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ type: :development
130
+ version_requirements: *id009
131
+ description: "SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views."
132
+ email:
118
133
  - ronen@barzel.org
119
134
  - michal.lomnicki@gmail.com
120
135
  executables: []
136
+
121
137
  extensions: []
138
+
122
139
  extra_rdoc_files: []
123
- files:
140
+
141
+ files:
124
142
  - .gitignore
125
143
  - .travis.yml
126
144
  - Gemfile
@@ -134,8 +152,10 @@ files:
134
152
  - gemfiles/Gemfile.rails-3.1
135
153
  - gemfiles/Gemfile.rails-3.1.lock
136
154
  - init.rb
155
+ - lib/rails/tasks/database.rake
137
156
  - lib/schema_plus.rb
138
157
  - lib/schema_plus/active_record/base.rb
158
+ - lib/schema_plus/active_record/column_options_handler.rb
139
159
  - lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb
140
160
  - lib/schema_plus/active_record/connection_adapters/column.rb
141
161
  - lib/schema_plus/active_record/connection_adapters/foreign_key_definition.rb
@@ -153,6 +173,7 @@ files:
153
173
  - runspecs
154
174
  - schema_plus.gemspec
155
175
  - spec/column_spec.rb
176
+ - spec/connection_spec.rb
156
177
  - spec/connections/mysql/connection.rb
157
178
  - spec/connections/mysql2/connection.rb
158
179
  - spec/connections/postgresql/connection.rb
@@ -166,7 +187,6 @@ files:
166
187
  - spec/models/post.rb
167
188
  - spec/models/user.rb
168
189
  - spec/rails3_migration_spec.rb
169
- - spec/references_spec.rb
170
190
  - spec/schema/auto_schema.rb
171
191
  - spec/schema/core_schema.rb
172
192
  - spec/schema_dumper_spec.rb
@@ -178,29 +198,35 @@ files:
178
198
  - spec/support/matchers/reference.rb
179
199
  - spec/support/reference.rb
180
200
  - spec/views_spec.rb
201
+ has_rdoc: true
181
202
  homepage: https://github.com/lomba/schema_plus
182
203
  licenses: []
204
+
183
205
  post_install_message:
184
206
  rdoc_options: []
185
- require_paths:
207
+
208
+ require_paths:
186
209
  - lib
187
- required_ruby_version: !ruby/object:Gem::Requirement
188
- none: false
189
- requirements:
190
- - - ! '>='
191
- - !ruby/object:Gem::Version
192
- version: '0'
193
- required_rubygems_version: !ruby/object:Gem::Requirement
194
- none: false
195
- requirements:
196
- - - ! '>='
197
- - !ruby/object:Gem::Version
198
- version: '0'
210
+ required_ruby_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ segments:
215
+ - 0
216
+ version: "0"
217
+ required_rubygems_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ segments:
222
+ - 0
223
+ version: "0"
199
224
  requirements: []
225
+
200
226
  rubyforge_project: schema_plus
201
- rubygems_version: 1.8.10
227
+ rubygems_version: 1.3.6
202
228
  signing_key:
203
229
  specification_version: 3
204
- summary: Enhances ActiveRecord schema mechanism, including more DRY index creation
205
- and support for foreign key constraints and views.
230
+ summary: Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views.
206
231
  test_files: []
232
+
@@ -1,78 +0,0 @@
1
- # encoding: utf-8
2
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
-
4
- describe 'get_references method' do
5
-
6
- before(:all) do
7
- @target = ActiveRecord::Migration.connection
8
- @table_name = 'comments'
9
- @column_name = 'post_id'
10
- @destination_table = 'posts'
11
- @destinantion_column = :id
12
- end
13
-
14
- around(:each) do |example|
15
- with_auto_create do
16
- example.run
17
- end
18
- end
19
-
20
- it "should accept table name and column name to references" do
21
- lambda { @target.get_references(@table_name, @column_name) }.should_not raise_error
22
- end
23
-
24
- it "should return an array" do
25
- @target.get_references(@table_name, @column_name).should be_an(Array)
26
- end
27
-
28
- it "should return nil if auto_create is disabled" do
29
- SchemaPlus.config.foreign_keys.auto_create = false
30
- @target.get_references(@table_name, @column_name).should be_nil
31
- end
32
-
33
- it "should split column name to table name and primary key" do
34
- result = @target.get_references(@table_name, @column_name)
35
- result[0].should eql @destination_table
36
- result[1].should eql @destinantion_column
37
- end
38
-
39
- it "should not auto create referencs when configured not to" do
40
- with_auto_create(false) do
41
- result = @target.get_references(@table_name, @column_name)
42
- result.should be_nil
43
- end
44
- end
45
-
46
- it "should handle parent_id as belonging to the same table" do
47
- column_name = 'parent_id'
48
- result = @target.get_references(@table_name, column_name)
49
- result[0].should eql @table_name
50
- result[1].should eql :id
51
- end
52
-
53
- it "should accept :references option which overrides default table name" do
54
- result = @target.get_references(@table_name, @column_name, :references => 'users')
55
- result[0].should eql 'users'
56
- result[1].should eql :id
57
- end
58
-
59
- it "should accept :references option which overrides default table name and default column name" do
60
- result = @target.get_references(@table_name, @column_name, :references => ['users', 'uuid'])
61
- result[0].should eql 'users'
62
- result[1].should eql 'uuid'
63
- end
64
-
65
- protected
66
-
67
- def with_auto_create(value = true)
68
- old_value = SchemaPlus.config.foreign_keys.auto_create
69
- SchemaPlus.config.foreign_keys.auto_create = value
70
- begin
71
- yield
72
- ensure
73
- SchemaPlus.config.foreign_keys.auto_create = old_value
74
- end
75
- end
76
-
77
- end
78
-