schema_plus 0.1.3 → 0.2.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/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
-