mini_record 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -1,9 +1,10 @@
1
+ language: ruby
1
2
  before_install: 'gem update --system'
2
3
  rvm:
3
4
  - 1.8.7
4
5
  - 1.9.2
5
6
  - 1.9.3
6
- - rbx-2.0
7
+ - rbx-18mode
7
8
  - ruby-head
8
9
  - ree
9
10
  notifications:
data/Gemfile CHANGED
@@ -1,7 +1,11 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in mini_record.gemspec
4
- gem "rake"
5
- gem "minitest"
6
- gem "sqlite3"
4
+ gem 'rake'
5
+ gem 'minitest'
6
+ gem 'sqlite3'
7
+ gem 'mysql2'
8
+ gem 'mysql'
9
+ gem 'pg'
10
+
7
11
  gemspec
data/Rakefile CHANGED
@@ -20,8 +20,8 @@ end
20
20
 
21
21
  task :release => :bump
22
22
  Rake::TestTask.new(:test) do |test|
23
- test.libs << 'spec'
24
- test.test_files = Dir['spec/**/*_spec.rb']
23
+ test.libs << 'test'
24
+ test.test_files = Dir['test/**/test_*.rb']
25
25
  test.verbose = true
26
26
  end
27
27
 
@@ -14,10 +14,10 @@ module MiniRecord
14
14
  return superclass.table_definition unless superclass == ActiveRecord::Base
15
15
 
16
16
  @_table_definition ||= begin
17
- tb = ActiveRecord::ConnectionAdapters::TableDefinition.new(connection)
18
- tb.primary_key(primary_key)
19
- tb
20
- end
17
+ tb = ActiveRecord::ConnectionAdapters::TableDefinition.new(connection)
18
+ tb.primary_key(primary_key)
19
+ tb
20
+ end
21
21
  end
22
22
 
23
23
  def indexes
@@ -26,31 +26,66 @@ module MiniRecord
26
26
  @_indexes ||= {}
27
27
  end
28
28
 
29
- def col(*args)
29
+ def indexes_in_db
30
+ connection.indexes(table_name).inject({}) do |hash, index|
31
+ hash[index.name] = index
32
+ hash
33
+ end
34
+ end
35
+
36
+ def fields
37
+ table_definition.columns.inject({}) do |hash, column|
38
+ hash[column.name] = column
39
+ hash
40
+ end
41
+ end
42
+
43
+ def fields_in_db
44
+ connection.columns(table_name).inject({}) do |hash, column|
45
+ hash[column.name] = column
46
+ hash
47
+ end
48
+ end
49
+
50
+ def field(*args)
30
51
  return unless connection?
31
52
 
32
- options = args.extract_options!
33
- type = options.delete(:as) || options.delete(:type) || :string
53
+ options = args.extract_options!
54
+ type = options.delete(:as) || options.delete(:type) || :string
55
+ index = options.delete(:index)
56
+
34
57
  args.each do |column_name|
35
- table_definition.send(type, column_name, options)
58
+
59
+ # Allow custom types like:
60
+ # t.column :type, "ENUM('EMPLOYEE','CLIENT','SUPERUSER','DEVELOPER')"
61
+ if type.is_a?(String)
62
+ # will be converted in: t.column :type, "ENUM('EMPLOYEE','CLIENT')"
63
+ table_definition.column(column_name, type, options.reverse_merge(:limit => 0))
64
+ else
65
+ # wil be converted in: t.string :name
66
+ table_definition.send(type, column_name, options)
67
+ end
68
+
69
+ # Get the correct column_name i.e. in field :category, :as => :references
36
70
  column_name = table_definition.columns[-1].name
37
- case index_name = options.delete(:index)
71
+
72
+ # Parse indexes
73
+ case index
38
74
  when Hash
39
- add_index(options.delete(:column) || column_name, index_name)
75
+ add_index(options.delete(:column) || column_name, index)
40
76
  when TrueClass
41
77
  add_index(column_name)
42
78
  when String, Symbol, Array
43
- add_index(index_name)
79
+ add_index(index)
44
80
  end
45
81
  end
46
82
  end
47
- alias :key :col
48
- alias :property :col
49
- alias :field :col
50
- alias :attribute :col
83
+ alias :key :field
84
+ alias :property :field
85
+ alias :col :field
51
86
 
52
87
  def timestamps
53
- col :created_at, :updated_at, :as => :datetime
88
+ field :created_at, :updated_at, :as => :datetime
54
89
  end
55
90
 
56
91
  def reset_table_definition!
@@ -63,14 +98,10 @@ module MiniRecord
63
98
  yield table_definition
64
99
  table_definition
65
100
  end
66
- alias :keys :schema
67
- alias :properties :schema
68
- alias :fields :schema
69
- alias :attributes :schema
70
101
 
71
102
  def add_index(column_name, options={})
72
103
  index_name = connection.index_name(table_name, :column => column_name)
73
- indexes[index_name] = options.merge(:column => column_name)
104
+ indexes[index_name] = options.merge(:column => column_name) unless indexes.key?(index_name)
74
105
  index_name
75
106
  end
76
107
  alias :index :add_index
@@ -83,7 +114,6 @@ module MiniRecord
83
114
  end
84
115
 
85
116
  def clear_tables!
86
- # Drop unsued tables
87
117
  (connection.tables - schema_tables).each do |name|
88
118
  connection.drop_table(name)
89
119
  schema_tables.delete(name)
@@ -97,7 +127,7 @@ module MiniRecord
97
127
  descendants.each(&:auto_upgrade!)
98
128
  clear_tables!
99
129
  else
100
- # Table doesn't exist, create it
130
+ # If table doesn't exist, create it
101
131
  unless connection.tables.include?(table_name)
102
132
  # TODO: create_table options
103
133
  class << connection; attr_accessor :table_definition; end unless connection.respond_to?(:table_definition=)
@@ -109,25 +139,19 @@ module MiniRecord
109
139
  # Add this to our schema tables
110
140
  schema_tables << table_name unless schema_tables.include?(table_name)
111
141
 
112
- # Grab database columns
113
- fields_in_db = connection.columns(table_name).inject({}) do |hash, column|
114
- hash[column.name] = column
115
- hash
116
- end
117
-
118
142
  # Generate fields from associations
119
143
  if reflect_on_all_associations.any?
120
144
  reflect_on_all_associations.each do |association|
121
- foreign_key = association.options[:foreign_key] || "#{association.name.to_s}_id"
145
+ foreign_key = association.options[:foreign_key] || "#{association.name}_id"
122
146
  type_key = "#{association.name.to_s}_type"
123
147
  case association.macro
124
148
  when :belongs_to
125
- table_definition.column(foreign_key, :integer)
149
+ field foreign_key, :as => :integer unless fields.key?(foreign_key.to_s)
126
150
  if association.options[:polymorphic]
127
- table_definition.column(type_key, :string)
128
- add_index [foreign_key, type_key]
151
+ field type_key, :as => :string unless fields.key?(type_key.to_s)
152
+ index [foreign_key, type_key]
129
153
  else
130
- add_index foreign_key
154
+ index foreign_key
131
155
  end
132
156
  when :has_and_belongs_to_many
133
157
  table = if name = association.options[:join_table]
@@ -135,15 +159,16 @@ module MiniRecord
135
159
  else
136
160
  [table_name, association.name.to_s].sort.join("_")
137
161
  end
138
- index = ""
139
162
  unless connection.tables.include?(table.to_s)
140
- foreign_key = association.options[:foreign_key] || "#{table.singularize}_id"
141
- association_foreign_key = association.options[:association_foreign_key] || "#{association.name.to_s.singularize}_id"
163
+ foreign_key = association.options[:foreign_key] || association.foreign_key
164
+ association_foreign_key = association.options[:association_foreign_key] || association.association_foreign_key
142
165
  connection.create_table(table, :id => false) do |t|
143
166
  t.integer foreign_key
144
167
  t.integer association_foreign_key
145
168
  end
146
- connection.add_index table.to_sym, [foreign_key, association_foreign_key].map(&:to_sym), association.options
169
+ index_name = connection.index_name(table, :column => [foreign_key, association_foreign_key])
170
+ index_name = index_name[0...connection.index_name_length] if index_name.length > connection.index_name_length
171
+ connection.add_index table, [foreign_key, association_foreign_key], :name => index_name, :unique => true
147
172
  end
148
173
  # Add join table to our schema tables
149
174
  schema_tables << table unless schema_tables.include?(table)
@@ -151,54 +176,57 @@ module MiniRecord
151
176
  end
152
177
  end
153
178
 
154
- # Grab new schema
155
- fields_in_schema = table_definition.columns.inject({}) do |hash, column|
156
- hash[column.name.to_s] = column
157
- hash
158
- end
159
-
160
179
  # Add to schema inheritance column if necessary
161
- if descendants.present? && !fields_in_schema.include?(inheritance_column.to_s)
162
- table_definition.column inheritance_column, :string
180
+ if descendants.present?
181
+ field inheritance_column, :as => :string unless fields.key?(inheritance_column.to_s)
182
+ index inheritance_column
163
183
  end
164
184
 
165
185
  # Remove fields from db no longer in schema
166
- (fields_in_db.keys - fields_in_schema.keys & fields_in_db.keys).each do |field|
186
+ (fields_in_db.keys - fields.keys & fields_in_db.keys).each do |field|
167
187
  column = fields_in_db[field]
168
188
  connection.remove_column table_name, column.name
169
189
  end
170
190
 
171
191
  # Add fields to db new to schema
172
- (fields_in_schema.keys - fields_in_db.keys).each do |field|
173
- column = fields_in_schema[field]
192
+ (fields.keys - fields_in_db.keys).each do |field|
193
+ column = fields[field]
174
194
  options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
175
- options[:default] = column.default if !column.default.nil?
176
- options[:null] = column.null if !column.null.nil?
195
+ options[:default] = column.default unless column.default.nil?
196
+ options[:null] = column.null unless column.null.nil?
177
197
  connection.add_column table_name, column.name, column.type.to_sym, options
178
198
  end
179
199
 
180
200
  # Change attributes of existent columns
181
- (fields_in_schema.keys & fields_in_db.keys).each do |field|
201
+ (fields.keys & fields_in_db.keys).each do |field|
182
202
  if field != primary_key #ActiveRecord::Base.get_primary_key(table_name)
183
203
  changed = false # flag
184
- new_type = fields_in_schema[field].type.to_sym
204
+ new_type = fields[field].type.to_sym
185
205
  new_attr = {}
186
206
 
187
207
  # First, check if the field type changed
188
- if fields_in_schema[field].type.to_sym != fields_in_db[field].type.to_sym
208
+ if fields[field].sql_type.to_s.downcase != fields_in_db[field].sql_type.to_s.downcase
209
+ logger.debug "[MiniRecord] Detected schema change for #{table_name}.#{field}#type from " +
210
+ "#{fields[field].sql_type.to_s.downcase.inspect} in #{fields_in_db[field].sql_type.to_s.downcase.inspect}" if logger
189
211
  changed = true
190
212
  end
191
213
 
192
214
  # Special catch for precision/scale, since *both* must be specified together
193
215
  # Always include them in the attr struct, but they'll only get applied if changed = true
194
- new_attr[:precision] = fields_in_schema[field][:precision]
195
- new_attr[:scale] = fields_in_schema[field][:scale]
216
+ new_attr[:precision] = fields[field][:precision]
217
+ new_attr[:scale] = fields[field][:scale]
218
+
219
+ # If we have precision this is also the limit
220
+ fields[field][:limit] ||= fields[field][:precision]
196
221
 
197
222
  # Next, iterate through our extended attributes, looking for any differences
198
223
  # This catches stuff like :null, :precision, etc
199
- fields_in_schema[field].each_pair do |att,value|
224
+ fields[field].each_pair do |att,value|
200
225
  next if att == :type or att == :base or att == :name # special cases
201
- if !value.nil? && value != fields_in_db[field].send(att)
226
+ value = true if att == :null && value.nil?
227
+ if value != fields_in_db[field].send(att)
228
+ logger.debug "[MiniRecord] Detected schema change for #{table_name}.#{field}##{att} "+
229
+ "from #{fields_in_db[field].send(att).inspect} in #{value.inspect}" if logger
202
230
  new_attr[att] = value
203
231
  changed = true
204
232
  end
@@ -210,9 +238,7 @@ module MiniRecord
210
238
  end
211
239
 
212
240
  # Remove old index
213
- # TODO: remove index from habtm t
214
- indexes_in_db = connection.indexes(table_name).map(&:name)
215
- (indexes_in_db - indexes.keys).each do |name|
241
+ (indexes_in_db.keys - indexes.keys).each do |name|
216
242
  connection.remove_index(table_name, :name => name)
217
243
  end
218
244
 
@@ -227,7 +253,6 @@ module MiniRecord
227
253
  # Reload column information
228
254
  reset_column_information
229
255
  end
230
-
231
256
  end
232
257
  end # ClassMethods
233
258
  end # AutoSchema
@@ -1,3 +1,3 @@
1
1
  module MiniRecord
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/mini_record.gemspec CHANGED
@@ -24,5 +24,5 @@ Gem::Specification.new do |s|
24
24
 
25
25
  # specify any dependencies here; for example:
26
26
  # s.add_development_dependency "rspec"
27
- s.add_dependency "activerecord", "~>3.2.0"
27
+ s.add_dependency "activerecord", ">=3.2.0"
28
28
  end
data/test/helper.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems' unless defined?(Gem)
2
+ require 'bundler/setup'
3
+ require 'mini_record'
4
+ require 'minitest/autorun'
5
+
6
+ class ActiveRecord::Base
7
+ class << self
8
+ attr_accessor :logs
9
+
10
+ def db_fields
11
+ connection.columns(table_name).inject({}) do |hash, column|
12
+ hash[column.name.to_sym] = column
13
+ hash
14
+ end
15
+ end
16
+
17
+ def db_columns
18
+ connection.columns(table_name).map(&:name).sort
19
+ end
20
+
21
+ def db_indexes
22
+ connection.indexes(table_name).map(&:name).sort
23
+ end
24
+
25
+ def schema_columns
26
+ table_definition.columns.map { |c| c.name.to_s }.sort
27
+ end
28
+
29
+ def schema_fields
30
+ table_definition.columns.inject({}) do |hash, column|
31
+ hash[column.name.to_sym] = column
32
+ hash
33
+ end
34
+ end
35
+
36
+ def queries(pragma=false)
37
+ ActiveRecord::Base.logs.string.gsub(/\e\[[\d;]+m/, '').lines.reject { |l| !pragma && l =~ /pragma/i }.join("\n")
38
+ end
39
+
40
+ def auto_upgrade!
41
+ ActiveRecord::Base.logs = StringIO.new
42
+ ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new(ActiveRecord::Base.logs)
43
+ silence_stream(STDERR) { super }
44
+ end
45
+ end
46
+ end # ActiveRecord::Base
47
+
48
+ # Setup Adatper
49
+ case ENV['DB']
50
+ when 'mysql'
51
+ ActiveRecord::Base.establish_connection(:adapter => 'mysql', :database => 'test', :user => 'root')
52
+ when 'pg', 'postgresql'
53
+ ActiveRecord::Base.establish_connection(:adapter => 'postgresql', :database => 'test', :user => 'postgres', :host => 'localhost')
54
+ else
55
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
56
+ end
57
+
58
+
59
+ # Some helpers to minitest
60
+ class MiniTest::Spec
61
+ def connection
62
+ ActiveRecord::Base.connection
63
+ end
64
+ alias :conn :connection
65
+ end
@@ -1,6 +1,3 @@
1
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
2
- # ActiveRecord::Base.logger = ActiveSupport::BufferedLogger.new($stdout)
3
-
4
1
  class Person < ActiveRecord::Base
5
2
  schema do |s|
6
3
  s.string :name
@@ -65,3 +62,13 @@ end
65
62
  class Activity < ActiveRecord::Base
66
63
  belongs_to :author, :class_name => 'Account', :foreign_key => 'custom_id'
67
64
  end
65
+
66
+ class Page < ActiveRecord::Base
67
+ key :title
68
+ has_and_belongs_to_many :photogalleries
69
+ end
70
+
71
+ class Photogallery < ActiveRecord::Base
72
+ key :title
73
+ has_and_belongs_to_many :pages
74
+ end
@@ -0,0 +1,503 @@
1
+ require File.expand_path('../helper.rb', __FILE__)
2
+
3
+ describe MiniRecord do
4
+
5
+ before do
6
+ conn.tables.each { |table| silence_stream(STDERR) { conn.execute "DROP TABLE IF EXISTS #{table}" } }
7
+ ActiveRecord::Base.descendants.each { |klass| Object.send(:remove_const, klass.to_s) }
8
+ ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base).clear
9
+ load File.expand_path('../models.rb', __FILE__)
10
+ ActiveRecord::Base.auto_upgrade!
11
+ end
12
+
13
+ it 'has #schema inside model' do
14
+ assert_equal 'people', Person.table_name
15
+ assert_equal %w[created_at id name updated_at], Person.db_columns.sort
16
+ assert_equal Person.db_columns, Person.column_names.sort
17
+ assert_equal Person.schema_columns, Person.column_names.sort
18
+
19
+ # Check surname attribute
20
+ person = Person.create(:name => 'foo')
21
+ assert_equal 'foo', person.name
22
+ assert_raises(NoMethodError){ person.surname }
23
+
24
+ # Test the timestamp columns exist
25
+ assert_respond_to person, :created_at
26
+ assert_respond_to person, :updated_at
27
+
28
+ # Add a column without lost data
29
+ Person.class_eval do
30
+ schema do |p|
31
+ p.string :name
32
+ p.string :surname
33
+ end
34
+ timestamps
35
+ end
36
+ Person.auto_upgrade!
37
+ assert_equal 1, Person.count
38
+
39
+ person = Person.last
40
+ assert_equal 'foo', person.name
41
+ assert_nil person.surname
42
+
43
+ person.update_attribute(:surname, 'bar')
44
+ assert_equal %w[created_at id name surname updated_at], Person.db_columns.sort
45
+
46
+ # Remove a column without lost data
47
+ Person.class_eval do
48
+ schema do |p|
49
+ p.string :name
50
+ end
51
+ timestamps
52
+ end
53
+ Person.auto_upgrade!
54
+ person = Person.last
55
+ assert_equal 'foo', person.name
56
+ assert_raises(NoMethodError) { person.surname }
57
+ assert_equal %w[created_at id name updated_at], Person.db_columns
58
+ assert_equal Person.column_names.sort, Person.db_columns
59
+ assert_equal Person.column_names.sort, Person.schema_columns
60
+
61
+ # Change column without lost data
62
+ Person.class_eval do
63
+ schema do |p|
64
+ p.text :name
65
+ end
66
+ end
67
+ person = Person.last
68
+ assert_equal 'foo', person.name
69
+ end
70
+
71
+ it 'has #key,col,property,attribute inside model' do
72
+ assert_equal Post.column_names.sort, Post.db_columns
73
+ assert_equal Category.column_names.sort, Category.schema_columns
74
+
75
+ # Check default properties
76
+ category = Category.create(:title => 'category')
77
+ post = Post.create(:title => 'foo', :body => 'bar', :category_id => category.id)
78
+ post = Post.first
79
+ assert_equal 'foo', post.title
80
+ assert_equal 'bar', post.body
81
+ assert_equal category, post.category
82
+
83
+
84
+ # Remove a column
85
+ Post.reset_table_definition!
86
+ Post.class_eval do
87
+ col :name
88
+ col :category, :as => :references
89
+ end
90
+ Post.auto_upgrade!
91
+ refute_includes %w[title body], Post.db_columns
92
+
93
+ post = Post.first
94
+ assert_nil post.name
95
+ assert_equal category, post.category
96
+ assert_raises(NoMethodError, ActiveModel::MissingAttributeError) { post.title }
97
+ end
98
+
99
+ it 'has indexes inside model' do
100
+ # Check indexes
101
+ assert Animal.db_indexes.size > 0
102
+ assert_equal Animal.db_indexes, Animal.indexes.keys.sort
103
+
104
+
105
+ # Remove an index
106
+ indexes_was = Animal.db_indexes
107
+ Animal.indexes.delete(indexes_was.pop)
108
+ Animal.auto_upgrade!
109
+ assert_equal indexes_was, Animal.indexes.keys
110
+ assert_equal indexes_was, Animal.db_indexes
111
+
112
+ # Add a new index
113
+ Animal.class_eval do
114
+ col :category, :as => :references, :index => true
115
+ end
116
+ Animal.auto_upgrade!
117
+ new_indexes = indexes_was + %w[index_animals_on_category_id]
118
+ assert_includes Animal.db_columns, 'category_id'
119
+ assert_equal new_indexes.sort, Animal.db_indexes
120
+ end
121
+
122
+ it 'not add already defined indexes' do
123
+ class Foo < ActiveRecord::Base
124
+ index :customer_id, :unique => true, :name => 'by_customer'
125
+ belongs_to :customer
126
+ end
127
+ Foo.auto_upgrade!
128
+ assert_equal 1, Foo.db_indexes.size
129
+ assert_includes Foo.db_indexes, 'by_customer'
130
+ end
131
+
132
+ it 'works with STI' do
133
+ class Dog < Pet; end
134
+ class Cat < Pet; end
135
+ class Kitten < Cat; end
136
+ ActiveRecord::Base.auto_upgrade!
137
+
138
+ # Check inheritance column
139
+ assert_includes Pet.db_columns, "type"
140
+
141
+ # Now, let's we know if STI is working
142
+ Pet.create(:name => "foo")
143
+ Dog.create(:name => "bar")
144
+ Kitten.create(:name => 'foxy')
145
+ assert_equal 1, Dog.count
146
+ assert_equal 'bar', Dog.first.name
147
+ assert_equal 3, Pet.count
148
+ assert_equal %w[foo bar foxy], Pet.all.map(&:name)
149
+ assert_equal 'bar', Dog.first.name
150
+
151
+ # What's happen if we change schema?
152
+ assert_equal Dog.table_definition, Pet.table_definition
153
+ assert_equal Dog.indexes, Pet.indexes
154
+
155
+ Dog.class_eval do
156
+ col :bau
157
+ end
158
+ ActiveRecord::Base.auto_upgrade!
159
+ assert_includes Dog.schema_columns, 'bau'
160
+ assert_includes Pet.db_columns, 'bau'
161
+ end
162
+
163
+ it 'works with custom inheritance column' do
164
+ class User < ActiveRecord::Base
165
+ col :name
166
+ col :surname
167
+ col :role
168
+ def self.inheritance_column; 'role'; end
169
+ end
170
+
171
+ class Administrator < User; end
172
+ class Customer < User; end
173
+
174
+ User.auto_upgrade!
175
+ assert_equal 'role', User.inheritance_column
176
+
177
+ Administrator.create(:name => "Davide", :surname => 'DAddYE')
178
+ Customer.create(:name => "Foo", :surname => "Bar")
179
+ assert_equal 1, Administrator.count
180
+ assert_equal 'Davide', Administrator.first.name
181
+ assert_equal 1, Customer.count
182
+ assert_equal 'Foo', Customer.first.name
183
+ assert_equal 2, User.count
184
+ assert_equal 'Administrator', User.first.role
185
+ assert_equal 'Customer', User.last.role
186
+ assert_includes User.db_indexes, 'index_users_on_role'
187
+ end
188
+
189
+ it 'allow multiple columns definitions' do
190
+ class Fake < ActiveRecord::Base
191
+ col :name, :surname
192
+ col :category, :group, :as => :references
193
+ end
194
+ Fake.auto_upgrade!
195
+ Fake.create(:name => 'foo', :surname => 'bar', :category_id => 1, :group_id => 2)
196
+ fake = Fake.first
197
+ assert_equal 'foo', fake.name
198
+ assert_equal 'bar', fake.surname
199
+ assert_equal 1, fake.category_id
200
+ assert_equal 2, fake.group_id
201
+ end
202
+
203
+ it 'allow custom query' do
204
+ skip unless conn.adapter_name =~ /mysql/i
205
+
206
+ class Foo < ActiveRecord::Base
207
+ col :name, :as => "ENUM('foo','bar')"
208
+ end
209
+ Foo.auto_upgrade!
210
+ assert_match /ENUM/, Foo.queries
211
+
212
+ Foo.auto_upgrade!
213
+ assert_empty Foo.queries
214
+ assert_equal %w[id name], Foo.db_columns
215
+ assert_equal %w[id name], Foo.schema_columns
216
+
217
+ foo = Foo.create(:name => 'test')
218
+ assert_empty Foo.first.name
219
+
220
+ foo.update_attribute(:name, 'foo')
221
+
222
+ assert_equal 'foo', Foo.first.name
223
+ end
224
+
225
+ describe 'relation #belongs_to' do
226
+ it 'creates a column and index based on relation' do
227
+ Article.create(:title => 'Hello', :publisher_id => 1)
228
+ Article.first.tap do |a|
229
+ assert_equal 'Hello', a.title
230
+ assert_equal 1, a.publisher_id
231
+ end
232
+ assert_includes Article.db_indexes, 'index_articles_on_publisher_id'
233
+
234
+ # Ensure that associated field/index is not deleted on upgrade
235
+ Article.auto_upgrade!
236
+ assert_equal 1, Article.first.publisher_id
237
+ assert_includes Article.db_indexes, 'index_articles_on_publisher_id'
238
+ end
239
+
240
+ it 'removes a column and index when relation is removed' do
241
+ class Foo < ActiveRecord::Base
242
+ key :name
243
+ belongs_to :image, :polymorphic => true
244
+ end
245
+ Foo.auto_upgrade!
246
+ assert_includes Foo.db_columns, 'name'
247
+ assert_includes Foo.db_columns, 'image_type'
248
+ assert_includes Foo.db_columns, 'image_id'
249
+ assert_includes Foo.db_indexes, 'index_foos_on_image_id_and_image_type'
250
+
251
+ Foo.class_eval do
252
+ reset_table_definition!
253
+ reflections.clear
254
+ indexes.clear
255
+ key :name
256
+ end
257
+ Foo.auto_upgrade!
258
+ assert_includes Foo.db_columns, 'name'
259
+ refute_includes Foo.db_columns, 'image_type'
260
+ refute_includes Foo.db_columns, 'image_id'
261
+ assert_empty Foo.db_indexes
262
+ end
263
+
264
+ it 'creates columns and index based on polymorphic relation' do
265
+ Attachment.create(:name => 'Avatar', :attachable_id => 1, :attachable_type => 'Post')
266
+ Attachment.first.tap do |attachment|
267
+ assert_equal 'Avatar', attachment.name
268
+ assert_equal 1, attachment.attachable_id
269
+ assert_equal 'Post', attachment.attachable_type
270
+ end
271
+ index = 'index_attachments_on_attachable_id_and_attachable_type'
272
+ assert_includes Attachment.db_indexes, index
273
+
274
+ # Ensure that associated fields/indexes are not deleted on subsequent upgrade
275
+ Attachment.auto_upgrade!
276
+ assert_equal 1, Attachment.first.attachable_id
277
+ assert_equal 'Post', Attachment.first.attachable_type
278
+ assert_includes Attachment.db_indexes, index
279
+ end
280
+
281
+ it 'should support :class_name' do
282
+ assert_includes Task.schema_columns, 'author_id'
283
+ assert_includes Task.db_columns, 'author_id'
284
+ end
285
+
286
+ it 'should support :foreign_key' do
287
+ assert_includes Activity.schema_columns, 'custom_id'
288
+ assert_includes Activity.db_columns, 'custom_id'
289
+ end
290
+
291
+ it 'should memonize in schema relationships' do
292
+ silence_stream(STDERR) { conn.create_table('foos') }
293
+ conn.add_column :foos, :name, :string
294
+ conn.add_column :foos, :bar_id, :integer
295
+ conn.add_index :foos, :bar_id
296
+ class Foo < ActiveRecord::Base
297
+ col :name
298
+ belongs_to :bar
299
+ end
300
+ assert_includes Foo.db_columns, 'name'
301
+ assert_includes Foo.db_columns, 'bar_id'
302
+ assert_includes Foo.db_indexes, 'index_foos_on_bar_id'
303
+
304
+ Foo.auto_upgrade!
305
+ assert_includes Foo.schema_columns, 'name'
306
+ assert_includes Foo.schema_columns, 'bar_id'
307
+ assert_includes Foo.indexes, 'index_foos_on_bar_id'
308
+ end
309
+
310
+ it 'should add new columns without lost belongs_to schema' do
311
+ publisher = Publisher.create(:name => 'foo')
312
+ article = Article.create(:title => 'bar', :publisher => publisher)
313
+ assert article.valid?
314
+ assert_includes Article.indexes, 'index_articles_on_publisher_id'
315
+
316
+ # Here we perform a schema change
317
+ Article.key :body
318
+ Article.auto_upgrade!
319
+ article.reload
320
+ assert_nil article.body
321
+
322
+ article.update_attribute(:body, 'null')
323
+ assert_equal 'null', article.body
324
+
325
+ # Finally check the index existance
326
+ assert_includes Article.db_indexes, 'index_articles_on_publisher_id'
327
+ end
328
+
329
+ it 'should not override previous defined column relation' do
330
+ class Foo < ActiveRecord::Base
331
+ key :user, :as => :references, :null => false, :limit => 4
332
+ belongs_to :user
333
+ end
334
+ Foo.auto_upgrade!
335
+ assert_equal 4, Foo.db_fields[:user_id].limit
336
+ assert_equal false, Foo.db_fields[:user_id].null
337
+ end
338
+ end
339
+
340
+ describe 'relation #habtm' do
341
+ it 'creates a join table with indexes for has_and_belongs_to_many relations' do
342
+ tables = Tool.connection.tables
343
+ assert_includes tables, 'purposes_tools'
344
+
345
+ index = 'index_purposes_tools_on_tool_id_and_purpose_id'
346
+ assert_includes Tool.connection.indexes('purposes_tools').map(&:name), index
347
+
348
+ # Ensure that join table is not deleted on subsequent upgrade
349
+ Tool.auto_upgrade!
350
+ assert_includes tables, 'purposes_tools'
351
+ assert_includes Tool.connection.indexes('purposes_tools').map(&:name), index
352
+ end
353
+
354
+ it 'drops join table if has_and_belongs_to_many relation is deleted' do
355
+ Tool.schema_tables.delete('purposes_tools')
356
+ refute_includes ActiveRecord::Base.schema_tables, 'purposes_tools'
357
+
358
+ ActiveRecord::Base.clear_tables!
359
+ refute_includes Tool.connection.tables, 'purposes_tools'
360
+ end
361
+
362
+ it 'has_and_belongs_to_many with custom join_table and foreign keys' do
363
+ class Foo < ActiveRecord::Base
364
+ has_and_belongs_to_many :watchers, :join_table => :watching, :foreign_key => :custom_foo_id, :association_foreign_key => :customer_id
365
+ end
366
+ Foo.auto_upgrade!
367
+ assert_includes conn.tables, 'watching'
368
+
369
+ cols = conn.columns('watching').map(&:name)
370
+ refute_includes cols, 'id'
371
+ assert_includes cols, 'custom_foo_id'
372
+ assert_includes cols, 'customer_id'
373
+ end
374
+
375
+ it 'creates a join table with indexes with long indexes names' do
376
+ class Foo < ActiveRecord::Base
377
+ has_and_belongs_to_many :people, :join_table => :long_people,
378
+ :foreign_key => :custom_long_long_long_long_id,
379
+ :association_foreign_key => :customer_super_long_very_long_trust_me_id
380
+ end
381
+ Foo.auto_upgrade!
382
+ index_name = 'index_long_people_on_custom_long_long_long_long_id_and_customer_super_long_very_long_trust_me_id'[0...conn.index_name_length]
383
+ assert_includes conn.tables, 'people'
384
+ assert_includes conn.indexes(:long_people).map(&:name), index_name
385
+ end
386
+
387
+ it 'adds unique index' do
388
+ page = Page.create(:title => 'Foo')
389
+ photogallery = Photogallery.create(:title => 'Bar')
390
+ assert photogallery.valid?
391
+
392
+ photogallery.pages << page
393
+ refute_empty Photogallery.queries
394
+ assert_includes photogallery.reload.pages, page
395
+ assert_raises(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid){ photogallery.pages << page }
396
+ end
397
+ end
398
+
399
+ it 'should add multiple index' do
400
+ class Foo < ActiveRecord::Base
401
+ key :name, :surname, :index => true
402
+ end
403
+ Foo.auto_upgrade!
404
+ assert_includes Foo.db_indexes, 'index_foos_on_name'
405
+ assert_includes Foo.db_indexes, 'index_foos_on_surname'
406
+ end
407
+
408
+ it 'should create a unique index' do
409
+ class Foo < ActiveRecord::Base
410
+ key :name, :surname
411
+ add_index([:name, :surname], :unique => true)
412
+ end
413
+ Foo.auto_upgrade!
414
+ db_indexes = Foo.connection.indexes('foos')[0]
415
+ assert_equal 'index_foos_on_name_and_surname', db_indexes.name
416
+ assert db_indexes.unique
417
+ assert_equal %w[name surname], db_indexes.columns.sort
418
+ end
419
+
420
+ it 'should change #limit' do
421
+ class Foo < ActiveRecord::Base
422
+ key :number, :as => :integer
423
+ key :string, :limit => 100
424
+ end
425
+ Foo.auto_upgrade!
426
+ assert_match /CREATE TABLE/, Foo.queries
427
+
428
+ Foo.auto_upgrade!
429
+ refute_match /alter/i, Foo.queries
430
+
431
+ # According to this:
432
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L476-487
433
+ Foo.key :number, :as => :integer, :limit => 4
434
+ Foo.auto_upgrade!
435
+ case conn.adapter_name
436
+ when /sqlite/i
437
+ # In sqlite there is a difference between limit: 4 and limit: 11
438
+ assert_match 'altered', Foo.queries
439
+ assert_equal 4, Foo.db_fields[:number].limit
440
+ assert_equal 4, Foo.schema_fields[:number].limit
441
+ when /mysql/i
442
+ # In mysql according to this: http://goo.gl/bjZE7 limit: 4 is same of limit:11
443
+ assert_empty Foo.queries
444
+ assert_equal 4, Foo.db_fields[:number].limit
445
+ assert_equal 4, Foo.schema_fields[:number].limit
446
+ when /postgres/i
447
+ # In postgres limit: 4 will be translated to nil
448
+ assert_match /ALTER COLUMN "number" TYPE integer$/, Foo.queries
449
+ assert_equal nil, Foo.db_fields[:number].limit
450
+ assert_equal 4, Foo.schema_fields[:number].limit
451
+ end
452
+
453
+ # Change limit to string
454
+ Foo.key :string, :limit => 255
455
+ Foo.auto_upgrade!
456
+ refute_empty Foo.queries
457
+ assert_equal 255, Foo.db_fields[:string].limit
458
+ end
459
+
460
+ it 'should change #null' do
461
+ class Foo < ActiveRecord::Base
462
+ key :string
463
+ end
464
+ Foo.auto_upgrade!
465
+ assert Foo.db_fields[:string].null
466
+
467
+ # Same as above
468
+ Foo.key :string, :null => true
469
+ Foo.auto_upgrade!
470
+ refute_match /alter/i, Foo.queries
471
+ assert Foo.db_fields[:string].null
472
+
473
+ Foo.key :string, :null => nil
474
+ Foo.auto_upgrade!
475
+ refute_match /alter/i, Foo.queries
476
+ assert Foo.db_fields[:string].null
477
+
478
+ Foo.key :string, :null => false
479
+ Foo.auto_upgrade!
480
+ assert_match /alter/i, Foo.queries
481
+ refute Foo.db_fields[:string].null
482
+ end
483
+
484
+ it 'should change #scale #precision' do
485
+ class Foo < ActiveRecord::Base
486
+ field :currency, :as => :decimal, :precision => 8, :scale => 2
487
+ end
488
+ Foo.auto_upgrade!
489
+ assert_equal 8, Foo.db_fields[:currency].precision
490
+ assert_equal 2, Foo.db_fields[:currency].scale
491
+ assert_equal 8, Foo.db_fields[:currency].limit
492
+
493
+ Foo.auto_upgrade!
494
+ refute_match /alter/i, Foo.queries
495
+
496
+ Foo.field :currency, :as => :decimal, :precision => 4, :scale => 2, :limit => 5
497
+ Foo.auto_upgrade!
498
+ assert_match /alter/i, Foo.queries
499
+ assert_equal 4, Foo.db_fields[:currency].precision
500
+ assert_equal 2, Foo.db_fields[:currency].scale
501
+ assert_equal 4, Foo.db_fields[:currency].limit
502
+ end
503
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_record
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 0
10
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Davide D'Agostino
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-01-22 00:00:00 Z
18
+ date: 2012-02-17 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activerecord
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
25
25
  requirements:
26
- - - ~>
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  hash: 15
29
29
  segments:
@@ -55,9 +55,9 @@ files:
55
55
  - lib/mini_record/auto_schema.rb
56
56
  - lib/mini_record/version.rb
57
57
  - mini_record.gemspec
58
- - spec/mini_record_spec.rb
59
- - spec/models.rb
60
- - spec/spec_helper.rb
58
+ - test/helper.rb
59
+ - test/models.rb
60
+ - test/test_mini_record.rb
61
61
  homepage: https://github.com/DAddYE/mini_record
62
62
  licenses: []
63
63
 
@@ -92,7 +92,7 @@ signing_key:
92
92
  specification_version: 3
93
93
  summary: MiniRecord is a micro gem that allow you to write schema inside your model as you can do in DataMapper.
94
94
  test_files:
95
- - spec/mini_record_spec.rb
96
- - spec/models.rb
97
- - spec/spec_helper.rb
95
+ - test/helper.rb
96
+ - test/models.rb
97
+ - test/test_mini_record.rb
98
98
  has_rdoc:
@@ -1,296 +0,0 @@
1
- require File.expand_path('../spec_helper.rb', __FILE__)
2
-
3
- describe MiniRecord do
4
-
5
- before do
6
- ActiveRecord::Base.descendants.each { |klass| Object.send(:remove_const, klass.to_s) }
7
- ActiveSupport::DescendantsTracker.direct_descendants(ActiveRecord::Base).clear
8
- load File.expand_path('../models.rb', __FILE__)
9
- ActiveRecord::Base.auto_upgrade!
10
- end
11
-
12
- it 'has #schema inside model' do
13
- Person.table_name.must_equal 'people'
14
- Person.db_columns.sort.must_equal %w[created_at id name updated_at]
15
- Person.column_names.sort.must_equal Person.db_columns.sort
16
- Person.column_names.sort.must_equal Person.schema_columns.sort
17
- person = Person.create(:name => 'foo')
18
- person.name.must_equal 'foo'
19
- proc { person.surname }.must_raise NoMethodError
20
-
21
- # Test the timestamp columns exist
22
- person.must_respond_to :created_at
23
- person.must_respond_to :updated_at
24
-
25
- # Add a column without lost data
26
- Person.class_eval do
27
- schema do |p|
28
- p.string :name
29
- p.string :surname
30
- end
31
- timestamps
32
- end
33
- Person.auto_upgrade!
34
- Person.count.must_equal 1
35
- person = Person.last
36
- person.name.must_equal 'foo'
37
- person.surname.must_be_nil
38
- person.update_attribute(:surname, 'bar')
39
- Person.db_columns.sort.must_equal %w[created_at id name surname updated_at]
40
- # Person.column_names.must_equal Person.db_columns
41
-
42
- # Remove a column without lost data
43
- Person.class_eval do
44
- schema do |p|
45
- p.string :name
46
- end
47
- timestamps
48
- end
49
- Person.auto_upgrade!
50
- person = Person.last
51
- person.name.must_equal 'foo'
52
- proc { person.surname }.must_raise NoMethodError
53
- Person.db_columns.sort.must_equal %w[created_at id name updated_at]
54
- Person.column_names.sort.must_equal Person.db_columns.sort
55
- Person.column_names.sort.must_equal Person.schema_columns.sort
56
-
57
- # Change column without lost data
58
- Person.class_eval do
59
- schema do |p|
60
- p.text :name
61
- end
62
- end
63
- person = Person.last
64
- person.name.must_equal 'foo'
65
- end
66
-
67
- it 'has #key,col,property,attribute inside model' do
68
- Post.column_names.sort.must_equal Post.db_columns
69
- Category.column_names.sort.must_equal Category.schema_columns
70
-
71
- # Check default properties
72
- category = Category.create(:title => 'category')
73
- post = Post.create(:title => 'foo', :body => 'bar', :category_id => category.id)
74
- post = Post.first
75
- post.title.must_equal 'foo'
76
- post.body.must_equal 'bar'
77
- post.category.must_equal category
78
-
79
-
80
- # Remove a column
81
- Post.reset_table_definition!
82
- Post.class_eval do
83
- col :name
84
- col :category, :as => :references
85
- end
86
- Post.auto_upgrade!
87
- post = Post.first
88
- post.name.must_be_nil
89
- post.category.must_equal category
90
- proc { post.title }.must_raise ActiveModel::MissingAttributeError
91
- end
92
-
93
- it 'has indexes inside model' do
94
- # Check indexes
95
- Animal.db_indexes.size.must_be :>, 0
96
- Animal.db_indexes.must_equal Animal.indexes.keys.sort
97
-
98
- indexes_was = Animal.db_indexes
99
-
100
- # Remove an index
101
- Animal.indexes.delete(indexes_was.pop)
102
- Animal.auto_upgrade!
103
- Animal.indexes.keys.sort.must_equal indexes_was
104
- Animal.db_indexes.must_equal indexes_was
105
-
106
- # Add a new index
107
- Animal.class_eval do
108
- col :category, :as => :references, :index => true
109
- end
110
- Animal.auto_upgrade!
111
- Animal.db_columns.must_include "category_id"
112
- Animal.db_indexes.must_equal((indexes_was << "index_animals_on_category_id").sort)
113
- end
114
-
115
- it 'works with STI' do
116
- class Dog < Pet; end
117
- class Cat < Pet; end
118
- ActiveRecord::Base.auto_upgrade!
119
-
120
- # Check inheritance column
121
- Pet.db_columns.must_include "type"
122
-
123
- # Now, let's we know if STI is working
124
- Pet.create(:name => "foo")
125
- Dog.create(:name => "bar")
126
- Dog.count.must_equal 1
127
- Dog.first.name.must_equal "bar"
128
- Pet.count.must_equal 2
129
- Pet.all.map(&:name).must_equal ["foo", "bar"]
130
-
131
- # Check that this doesn't break things
132
- Dog.first.name.must_equal "bar"
133
-
134
- # What's happen if we change schema?
135
- Dog.table_definition.must_equal Pet.table_definition
136
- Dog.indexes.must_equal Pet.indexes
137
- Dog.class_eval do
138
- col :bau
139
- end
140
- ActiveRecord::Base.auto_upgrade!
141
- Dog.schema_columns.must_include "bau"
142
- Pet.db_columns.must_include "bau"
143
- # Dog.new.must_respond_to :bau
144
- # Cat.new.must_respond_to :bau
145
- end
146
-
147
- it 'works with custom inheritance column' do
148
- class User < ActiveRecord::Base
149
- col :name
150
- col :surname
151
- col :role
152
- def self.inheritance_column; 'role'; end
153
- end
154
-
155
- class Administrator < User; end
156
- class Customer < User; end
157
-
158
- User.auto_upgrade!
159
- User.inheritance_column.must_equal 'role'
160
- Administrator.create(:name => "Davide", :surname => 'DAddYE')
161
- Customer.create(:name => "Foo", :surname => "Bar")
162
- Administrator.count.must_equal 1
163
- Administrator.first.name.must_equal "Davide"
164
- Customer.count.must_equal 1
165
- Customer.first.name.must_equal "Foo"
166
- User.count.must_equal 2
167
- User.first.role.must_equal "Administrator"
168
- User.last.role.must_equal "Customer"
169
- end
170
-
171
- it 'allow multiple columns definitions' do
172
- class Fake < ActiveRecord::Base
173
- col :name, :surname
174
- col :category, :group, :as => :references
175
- end
176
- Fake.auto_upgrade!
177
- Fake.create(:name => 'foo', :surname => 'bar', :category_id => 1, :group_id => 2)
178
- fake = Fake.first
179
- fake.name.must_equal 'foo'
180
- fake.surname.must_equal 'bar'
181
- fake.category_id.must_equal 1
182
- fake.group_id.must_equal 2
183
- end
184
-
185
- it 'creates a column and index based on belongs_to relation' do
186
- Article.create(:title => 'Hello', :publisher_id => 1)
187
- Article.first.tap do |a|
188
- a.title.must_equal 'Hello'
189
- a.publisher_id.must_equal 1
190
- end
191
- Article.db_indexes.must_include 'index_articles_on_publisher_id'
192
- # Ensure that associated field/index is not deleted on upgrade
193
- Article.auto_upgrade!
194
- Article.first.publisher_id.must_equal 1
195
- Article.db_indexes.must_include 'index_articles_on_publisher_id'
196
- end
197
-
198
- it 'removes a column and index when belongs_to relation is removed' do
199
- class Foo < ActiveRecord::Base
200
- key :name
201
- belongs_to :image, :polymorphic => true
202
- end
203
- Foo.auto_upgrade!
204
- Foo.db_columns.must_include 'name'
205
- Foo.db_columns.must_include 'image_type'
206
- Foo.db_columns.must_include 'image_id'
207
- Foo.db_indexes.must_include 'index_foos_on_image_id_and_image_type'
208
- Foo.class_eval do
209
- reset_table_definition!
210
- reflections.clear
211
- indexes.clear
212
- key :name
213
- end
214
- Foo.auto_upgrade!
215
- Foo.db_columns.must_include 'name'
216
- Foo.db_columns.wont_include 'image_type'
217
- Foo.db_columns.wont_include 'image_id'
218
- Foo.db_indexes.must_be_empty
219
- end
220
-
221
- it 'creates columns and index based on belongs_to polymorphic relation' do
222
- Attachment.create(:name => 'Avatar', :attachable_id => 1, :attachable_type => 'Post')
223
- Attachment.first.tap do |attachment|
224
- attachment.name.must_equal 'Avatar'
225
- attachment.attachable_id.must_equal 1
226
- attachment.attachable_type.must_equal 'Post'
227
- end
228
- index = 'index_attachments_on_attachable_id_and_attachable_type'
229
- Attachment.db_indexes.must_include index
230
- # Ensure that associated fields/indexes are not deleted on subsequent upgrade
231
- Attachment.auto_upgrade!
232
- Attachment.first.attachable_id.must_equal 1
233
- Attachment.first.attachable_type.must_equal 'Post'
234
- Attachment.db_indexes.must_include index
235
- end
236
-
237
- it 'creates a join table with indexes for has_and_belongs_to_many relations' do
238
- tables = Tool.connection.tables
239
- tables.must_include('purposes_tools')
240
- index = 'index_purposes_tools_on_purposes_tool_id_and_purpose_id'
241
- Tool.connection.indexes('purposes_tools').map(&:name).must_include index
242
- # Ensure that join table is not deleted on subsequent upgrade
243
- Tool.auto_upgrade!
244
- tables.must_include('purposes_tools')
245
- Tool.connection.indexes('purposes_tools').map(&:name).must_include index
246
- end
247
-
248
- it 'drops join table if has_and_belongs_to_many relation is deleted' do
249
- Tool.schema_tables.delete('purposes_tools')
250
- ActiveRecord::Base.schema_tables.wont_include('purposes_tools')
251
- ActiveRecord::Base.clear_tables!
252
- Tool.connection.tables.wont_include('purposes_tools')
253
- end
254
-
255
- it 'has_and_belongs_to_many with custom join_table and foreign keys' do
256
- class Foo < ActiveRecord::Base
257
- has_and_belongs_to_many :watchers, :join_table => :watchers, :foreign_key => :custom_foo_id, :association_foreign_key => :customer_id
258
- end
259
- Foo.auto_upgrade!
260
- conn = ActiveRecord::Base.connection
261
- conn.tables.must_include 'watchers'
262
- cols = conn.columns('watchers').map(&:name)
263
- cols.wont_include 'id'
264
- cols.must_include 'custom_foo_id'
265
- cols.must_include 'customer_id'
266
- end
267
-
268
- it 'should support #belongs_to with :class_name' do
269
- Task.schema_columns.must_include 'author_id'
270
- Task.db_columns.must_include 'author_id'
271
- end
272
-
273
- it 'should support #belongs_to with :foreign_key' do
274
- Activity.schema_columns.must_include 'custom_id'
275
- Activity.db_columns.must_include 'custom_id'
276
- end
277
-
278
- it 'should memonize in schema relationships' do
279
- conn = ActiveRecord::Base.connection
280
- conn.create_table('foos')
281
- conn.add_column :foos, :name, :string
282
- conn.add_column :foos, :bar_id, :integer
283
- conn.add_index :foos, :bar_id
284
- class Foo < ActiveRecord::Base
285
- col :name
286
- belongs_to :bar
287
- end
288
- Foo.db_columns.must_include 'name'
289
- Foo.db_columns.must_include 'bar_id'
290
- Foo.db_indexes.must_include 'index_foos_on_bar_id'
291
- Foo.auto_upgrade!
292
- Foo.schema_columns.must_include 'name'
293
- Foo.schema_columns.must_include 'bar_id'
294
- Foo.indexes.must_include 'index_foos_on_bar_id'
295
- end
296
- end
data/spec/spec_helper.rb DELETED
@@ -1,26 +0,0 @@
1
- require 'rubygems' unless defined?(Gem)
2
- require 'bundler/setup'
3
- require 'mini_record'
4
- require 'minitest/autorun'
5
-
6
- module SpecHelper
7
- module ClassMethods
8
- def db_columns
9
- connection.columns(table_name).map(&:name).sort
10
- end
11
-
12
- def db_indexes
13
- connection.indexes(table_name).map(&:name).sort
14
- end
15
-
16
- def schema_columns
17
- table_definition.columns.map { |c| c.name.to_s }.sort
18
- end
19
-
20
- def reset!
21
- reset
22
- end
23
- end
24
- end
25
-
26
- ActiveRecord::Base.extend(SpecHelper::ClassMethods)