mini_record 0.3.0 → 0.3.1

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/.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)