ackbar 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +39 -0
- data/README +88 -0
- data/Rakefile +75 -0
- data/TODO +14 -0
- data/kirbybase_adapter.rb +1275 -0
- data/test/001_schema_migration_test.rb +32 -0
- data/test/ar_base_tests_runner.rb +415 -0
- data/test/ar_model_adaptation.rb +98 -0
- data/test/connection.rb +27 -0
- data/test/create_dbs_for_ar_tests.rb +171 -0
- data/test/fixtures/authors.yml +6 -0
- data/test/fixtures/authors_books.yml +8 -0
- data/test/fixtures/books.yml +4 -0
- data/test/fixtures/pages.yml +98 -0
- data/test/fixtures/publishers.yml +7 -0
- data/test/kb_associations_test.rb +107 -0
- data/test/kb_basics_test.rb +204 -0
- data/test/kb_schema_test.rb +169 -0
- data/test/kb_sql_to_code_test.rb +79 -0
- data/test/kb_stdlib_extensions_test.rb +38 -0
- data/test/model.rb +27 -0
- data/test/schema.rb +41 -0
- data/test/test_helper.rb +49 -0
- metadata +89 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
###############################################################################
|
2
|
+
# DB Schema Migration for testing ActiveKirby
|
3
|
+
require 'active_record/migration'
|
4
|
+
|
5
|
+
class SchemaMigrationTest < ActiveRecord::Migration
|
6
|
+
def self.up
|
7
|
+
create_table "pages", :force => true do |t|
|
8
|
+
t.column "book_id", :integer
|
9
|
+
t.column "page_num", :integer
|
10
|
+
t.column "content", :text
|
11
|
+
end
|
12
|
+
|
13
|
+
remove_index(:delete_me_in_migration, :junk)
|
14
|
+
rename_column(:delete_me_in_migration, :more_junk, :less_junk)
|
15
|
+
change_column(:delete_me_in_migration, :junk, :string)
|
16
|
+
remove_column(:delete_me_in_migration, :junk_yard)
|
17
|
+
|
18
|
+
drop_table(:delete_me_in_migration)
|
19
|
+
|
20
|
+
add_column(:publishers, :address, :string)
|
21
|
+
add_index(:publishers, :name, :unique)
|
22
|
+
|
23
|
+
# test belong_to (book) and has_one (book)
|
24
|
+
create_table 'errata', :force => true do |t|
|
25
|
+
t.column 'book_id', :integer
|
26
|
+
t.column 'contents', :string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.down
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,415 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
@@AR_PATH = Gem.latest_load_paths.grep(/activerecord/)[0]
|
4
|
+
@@AR_TESTS_PATH = File.expand_path(File.join(@@AR_PATH, '../test'))
|
5
|
+
$LOAD_PATH << @@AR_TESTS_PATH
|
6
|
+
|
7
|
+
################################################################################
|
8
|
+
### Start requiring ActiveRecords test files ###################################
|
9
|
+
# There are 663 tests, 2188 assertions in the AR test suite (sqlite)
|
10
|
+
|
11
|
+
################################################################################
|
12
|
+
# ActiveRecord::Base basics tests
|
13
|
+
require File.join(@@AR_TESTS_PATH, 'base_test.rb')
|
14
|
+
class BasicsTest
|
15
|
+
# too much SQL
|
16
|
+
remove_method :test_count_with_join
|
17
|
+
end
|
18
|
+
|
19
|
+
################################################################################
|
20
|
+
# ActiveRecord::Associations tests
|
21
|
+
require File.join(@@AR_TESTS_PATH, 'associations_test.rb')
|
22
|
+
|
23
|
+
class AssociationsTest
|
24
|
+
# We use code blocks (procs) which can't be dumped with Marshal
|
25
|
+
remove_method :test_storing_in_pstore
|
26
|
+
end
|
27
|
+
|
28
|
+
class HasAndBelongsToManyAssociationsTest
|
29
|
+
# Joins not supported
|
30
|
+
remove_method :test_adding_uses_default_values_on_join_table
|
31
|
+
remove_method :test_adding_uses_explicit_values_on_join_table
|
32
|
+
remove_method :test_additional_columns_from_join_table
|
33
|
+
end
|
34
|
+
|
35
|
+
class HasManyAssociationsTest
|
36
|
+
# :group option (GROUP BY statement) not supported
|
37
|
+
remove_method :test_find_grouped
|
38
|
+
# transactions not supported
|
39
|
+
remove_method :test_dependence_with_transaction_support_on_failure
|
40
|
+
end
|
41
|
+
|
42
|
+
class HasAndBelongsToManyAssociationsTest
|
43
|
+
# just changes the last select count to work through KB select blocks
|
44
|
+
def test_update_attributes_after_push_without_duplicate_join_table_rows
|
45
|
+
developer = Developer.new("name" => "Kano")
|
46
|
+
project = SpecialProject.create("name" => "Special Project")
|
47
|
+
assert developer.save
|
48
|
+
developer.projects << project
|
49
|
+
developer.update_attribute("name", "Bruza")
|
50
|
+
# assert_equal 1, Developer.connection.select_value(<<-end_sql).to_i
|
51
|
+
# SELECT count(*) FROM developers_projects
|
52
|
+
# WHERE project_id = #{project.id}
|
53
|
+
# AND developer_id = #{developer.id}
|
54
|
+
# end_sql
|
55
|
+
num_rows = Developer.connection.db.get_table(:developers_projects).select do |rec|
|
56
|
+
rec.project_id == project.id and rec.developer_id == developer.id
|
57
|
+
end.size
|
58
|
+
assert_equal 1, num_rows
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_removing_associations_on_destroy
|
62
|
+
david = DeveloperWithBeforeDestroyRaise.find(1)
|
63
|
+
assert !david.projects.empty?
|
64
|
+
assert_nothing_raised { david.destroy }
|
65
|
+
assert david.projects.empty?
|
66
|
+
assert DeveloperWithBeforeDestroyRaise.connection.db.get_table(:developers_projects).select{|rec| rec.developer_id == 1}.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
require File.join(@@AR_TESTS_PATH, 'associations_extensions_test.rb')
|
72
|
+
|
73
|
+
class AssociationsExtensionsTest
|
74
|
+
# Procs can't be marshalled
|
75
|
+
remove_method :test_marshalling_extensions
|
76
|
+
remove_method :test_marshalling_named_extensions
|
77
|
+
end
|
78
|
+
|
79
|
+
require File.join(@@AR_TESTS_PATH, 'deprecated_associations_test.rb')
|
80
|
+
|
81
|
+
class DeprecatedAssociationsTest
|
82
|
+
remove_method :test_has_many_dependence_with_transaction_support_on_failure
|
83
|
+
remove_method :test_storing_in_pstore
|
84
|
+
end
|
85
|
+
|
86
|
+
################################################################################
|
87
|
+
# Finder tests
|
88
|
+
require File.join(@@AR_TESTS_PATH, 'finder_test.rb')
|
89
|
+
|
90
|
+
class FinderTest
|
91
|
+
# we don't allow full SQL, but might as well check the block format
|
92
|
+
def test_count_by_sql
|
93
|
+
assert_raises(ActiveRecord::StatementInvalid) { Entrant.count_by_sql("SELECT COUNT(*) FROM entrant") }
|
94
|
+
assert_equal 0, Entrant.count(lambda{|rec| rec.recno > 3})
|
95
|
+
# this is just too wierd: assert_equal 1, Entrant.count([lambda{|rec| rec.recno > 2}])
|
96
|
+
assert_equal 2, Entrant.count{|rec| rec.recno > 1}
|
97
|
+
end
|
98
|
+
remove_method :test_find_with_entire_select_statement
|
99
|
+
remove_method :test_find_with_prepared_select_statement
|
100
|
+
remove_method :test_select_value
|
101
|
+
remove_method :test_select_values
|
102
|
+
remove_method :test_find_all_with_join
|
103
|
+
end
|
104
|
+
|
105
|
+
require File.join(@@AR_TESTS_PATH, 'deprecated_finder_test.rb')
|
106
|
+
|
107
|
+
class DeprecatedFinderTest
|
108
|
+
remove_method :test_count_by_sql
|
109
|
+
end
|
110
|
+
|
111
|
+
################################################################################
|
112
|
+
# Schema & Migrations tests
|
113
|
+
|
114
|
+
require File.join(@@AR_TESTS_PATH, 'ar_schema_test.rb')
|
115
|
+
|
116
|
+
class ActiveRecordSchemaTest
|
117
|
+
def test_schema_define
|
118
|
+
ActiveRecord::Schema.define(:version => 7) do
|
119
|
+
create_table :fruits do |t|
|
120
|
+
t.column :color, :string
|
121
|
+
t.column :fruit_size, :string # NOTE: "size" is reserved in Oracle
|
122
|
+
t.column :texture, :string
|
123
|
+
t.column :flavor, :string
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
assert_nothing_raised { @connection.get_table(:fruits).select }
|
128
|
+
assert_nothing_raised { @connection.get_table(:schema_info).select }
|
129
|
+
assert_equal 7, @connection.get_table(:schema_info).select[0].version
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
require File.join(@@AR_TESTS_PATH, 'migration_test.rb')
|
134
|
+
|
135
|
+
class MigrationTest
|
136
|
+
def teardown
|
137
|
+
ActiveRecord::Base.connection.initialize_schema_information
|
138
|
+
ActiveRecord::Base.connection.get_table(:schema_info).update_all {|rec| rec.version = 0}
|
139
|
+
|
140
|
+
Reminder.connection.drop_table("reminders") rescue nil
|
141
|
+
Reminder.connection.drop_table("people_reminders") rescue nil
|
142
|
+
Reminder.connection.drop_table("prefix_reminders_suffix") rescue nil
|
143
|
+
Reminder.reset_column_information
|
144
|
+
|
145
|
+
Person.connection.remove_column("people", "last_name") rescue nil
|
146
|
+
Person.connection.remove_column("people", "bio") rescue nil
|
147
|
+
Person.connection.remove_column("people", "age") rescue nil
|
148
|
+
Person.connection.remove_column("people", "height") rescue nil
|
149
|
+
Person.connection.remove_column("people", "birthday") rescue nil
|
150
|
+
Person.connection.remove_column("people", "favorite_day") rescue nil
|
151
|
+
Person.connection.remove_column("people", "male") rescue nil
|
152
|
+
Person.connection.remove_column("people", "administrator") rescue nil
|
153
|
+
Person.reset_column_information
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_create_table_with_not_null_column
|
157
|
+
Person.connection.create_table :testings do |t|
|
158
|
+
t.column :foo, :string, :null => false
|
159
|
+
end
|
160
|
+
|
161
|
+
# ArgumentError and not ActiveRecord::StatementInvalid because we're inserting directly to the db.
|
162
|
+
# Still showns that this field is required
|
163
|
+
assert_raises(ArgumentError) do
|
164
|
+
Person.connection.get_table(:testings).insert :foo => nil
|
165
|
+
end
|
166
|
+
ensure
|
167
|
+
Person.connection.drop_table :testings rescue nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_add_column_not_null_with_default
|
171
|
+
Person.connection.create_table :testings do |t|
|
172
|
+
t.column :foo, :string
|
173
|
+
end
|
174
|
+
Person.connection.add_column :testings, :bar, :string, :null => false, :default => "default"
|
175
|
+
|
176
|
+
# changed from ActiveRecord::StatementInvalid as we're operating directly on
|
177
|
+
# the database, and that is what KB spits out. Still, it validates that the
|
178
|
+
# field is now required (not null)
|
179
|
+
assert_raises(ArgumentError) do
|
180
|
+
Person.connection.get_table(:testings).insert :foo => 'hello', :bar => nil
|
181
|
+
end
|
182
|
+
ensure
|
183
|
+
Person.connection.drop_table :testings rescue nil
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_add_column_not_null_without_default
|
187
|
+
Person.connection.create_table :testings do |t|
|
188
|
+
t.column :foo, :string
|
189
|
+
end
|
190
|
+
Person.connection.add_column :testings, :bar, :string, :null => false
|
191
|
+
|
192
|
+
assert_raises(ArgumentError) do
|
193
|
+
Person.connection.get_table(:testings).insert :foo => 'hello', :bar => nil
|
194
|
+
end
|
195
|
+
ensure
|
196
|
+
Person.connection.drop_table :testings rescue nil
|
197
|
+
end
|
198
|
+
|
199
|
+
# KirbyBase only supports one index per column, so created new column
|
200
|
+
# (middle_name) for those tests. Also, KirbyBase does not support named
|
201
|
+
# indexes, so those tests were disabled.
|
202
|
+
def test_add_index
|
203
|
+
Person.connection.add_column "people", "last_name", :string
|
204
|
+
Person.connection.add_column "people", "middle_name", :string
|
205
|
+
Person.connection.add_column "people", "administrator", :boolean
|
206
|
+
|
207
|
+
assert_nothing_raised { Person.connection.add_index("people", "last_name") }
|
208
|
+
assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
|
209
|
+
|
210
|
+
assert_nothing_raised { Person.connection.add_index("people", ["middle_name", "first_name"]) }
|
211
|
+
assert_nothing_raised { Person.connection.remove_index("people", "last_name") }
|
212
|
+
|
213
|
+
# assert_nothing_raised { Person.connection.add_index("people", %w(last_name middle_name administrator), :name => "named_admin") }
|
214
|
+
# assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_rename_table
|
218
|
+
begin
|
219
|
+
ActiveRecord::Base.connection.create_table :octopuses do |t|
|
220
|
+
t.column :url, :string
|
221
|
+
end
|
222
|
+
ActiveRecord::Base.connection.rename_table :octopuses, :octopi
|
223
|
+
|
224
|
+
assert_nothing_raised do
|
225
|
+
ActiveRecord::Base.connection.get_table(:octopi).insert :url => 'http://www.foreverflying.com/octopus-black7.jpg'
|
226
|
+
end
|
227
|
+
|
228
|
+
assert_equal 'http://www.foreverflying.com/octopus-black7.jpg',
|
229
|
+
ActiveRecord::Base.connection.get_table(:octopi).select{|r|r.recno == 1}.first.url
|
230
|
+
|
231
|
+
ensure
|
232
|
+
ActiveRecord::Base.connection.drop_table :octopuses rescue nil
|
233
|
+
ActiveRecord::Base.connection.drop_table :octopi rescue nil
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Since this test uses aboolean field with a default, we need to override the
|
238
|
+
# change_column statement to use FalseClass rather than 0.
|
239
|
+
# In real life migrations, this should be guarded with an if current_adapter ...
|
240
|
+
def test_change_column_with_new_default
|
241
|
+
Person.connection.add_column "people", "administrator", :boolean, :default => true
|
242
|
+
Person.reset_column_information
|
243
|
+
assert Person.new.administrator?
|
244
|
+
|
245
|
+
assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
|
246
|
+
Person.reset_column_information
|
247
|
+
assert !Person.new.administrator?
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
################################################################################
|
252
|
+
# Misc tests
|
253
|
+
|
254
|
+
require File.join(@@AR_TESTS_PATH, 'inheritance_test.rb')
|
255
|
+
|
256
|
+
class InheritanceTest
|
257
|
+
# not supporting non-integer primary keys just yet
|
258
|
+
remove_method :test_inheritance_without_mapping
|
259
|
+
|
260
|
+
def test_a_bad_type_column
|
261
|
+
recno = Company.table.insert :mame => 'bad_class!', :type => 'Not happening'
|
262
|
+
assert_raises(ActiveRecord::SubclassNotFound) { Company.find(recno) }
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
require File.join(@@AR_TESTS_PATH, 'method_scoping_test.rb')
|
267
|
+
|
268
|
+
class MethodScopingTest
|
269
|
+
# changed the LIKE clause to ruby block
|
270
|
+
def test_scoped_count
|
271
|
+
Developer.with_scope(:find => { :conditions => "name = 'David'" }) do
|
272
|
+
assert_equal 1, Developer.count
|
273
|
+
end
|
274
|
+
|
275
|
+
Developer.with_scope(:find => { :conditions => 'salary = 100000' }) do
|
276
|
+
assert_equal 8, Developer.count
|
277
|
+
# assert_equal 1, Developer.count("name LIKE 'fixture_1%'")
|
278
|
+
assert_equal 1, Developer.count(lambda{|rec| rec.name =~ /fixture_1.*/})
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class HasAndBelongsToManyScopingTest
|
284
|
+
# we don't use the nested scopes
|
285
|
+
remove_method :test_raise_on_nested_scope
|
286
|
+
end
|
287
|
+
|
288
|
+
require File.join(@@AR_TESTS_PATH, 'pk_test.rb')
|
289
|
+
|
290
|
+
# Strings not supported for primary keys
|
291
|
+
class PrimaryKeysTest
|
292
|
+
remove_method :test_string_key
|
293
|
+
remove_method :test_find_with_more_than_one_string_key
|
294
|
+
end
|
295
|
+
|
296
|
+
require File.join(@@AR_TESTS_PATH, 'reflection_test.rb')
|
297
|
+
|
298
|
+
# We don't keep limits on Strings (and others). Using plain Ruby types.
|
299
|
+
class ReflectionTest
|
300
|
+
remove_method :test_column_string_type_and_limit
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
################################################################################
|
305
|
+
# Require all other test files not specifically handled above
|
306
|
+
|
307
|
+
ar_test_files = Dir[@@AR_TESTS_PATH + '/*_test.rb']
|
308
|
+
# Remove things we don't support
|
309
|
+
%w{
|
310
|
+
aaa_create_tables_test.rb
|
311
|
+
transactions_test.rb
|
312
|
+
associations_go_eager_test.rb
|
313
|
+
mixin_test.rb
|
314
|
+
mixin_nested_set_test.rb
|
315
|
+
}.each {|test_file| ar_test_files.delete File.join(@@AR_TESTS_PATH, test_file)}
|
316
|
+
ar_test_files.each {|test_file| require test_file}
|
317
|
+
|
318
|
+
class BinaryTest
|
319
|
+
def setup
|
320
|
+
Binary.table.clear
|
321
|
+
@data = File.read(BINARY_FIXTURE_PATH).freeze
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class FixturesTest
|
326
|
+
def test_inserts
|
327
|
+
topics = create_fixtures("topics")
|
328
|
+
# firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'David'")
|
329
|
+
firstRow = ActiveRecord::Base.connection.db.get_table(:topics).select{|rec| rec.author_name == 'David'}.first
|
330
|
+
assert_equal("The First Topic", firstRow["title"])
|
331
|
+
|
332
|
+
# secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM topics WHERE author_name = 'Mary'")
|
333
|
+
secondRow = ActiveRecord::Base.connection.db.get_table(:topics).select{|rec| rec.author_name == 'Mary'}.first
|
334
|
+
assert_nil(secondRow["author_email_address"])
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_inserts_with_pre_and_suffix
|
338
|
+
ActiveRecord::Base.connection.create_table :prefix_topics_suffix do |t|
|
339
|
+
t.column :title, :string
|
340
|
+
t.column :author_name, :string
|
341
|
+
t.column :author_email_address, :string
|
342
|
+
t.column :written_on, :datetime
|
343
|
+
t.column :bonus_time, :time
|
344
|
+
t.column :last_read, :date
|
345
|
+
t.column :content, :text
|
346
|
+
t.column :approved, :boolean, :default => 1
|
347
|
+
t.column :replies_count, :integer, :default => 0
|
348
|
+
t.column :parent_id, :integer
|
349
|
+
t.column :type, :string, :limit => 50
|
350
|
+
end
|
351
|
+
|
352
|
+
# Store existing prefix/suffix
|
353
|
+
old_prefix = ActiveRecord::Base.table_name_prefix
|
354
|
+
old_suffix = ActiveRecord::Base.table_name_suffix
|
355
|
+
|
356
|
+
# Set a prefix/suffix we can test against
|
357
|
+
ActiveRecord::Base.table_name_prefix = 'prefix_'
|
358
|
+
ActiveRecord::Base.table_name_suffix = '_suffix'
|
359
|
+
|
360
|
+
topics = create_fixtures("topics")
|
361
|
+
|
362
|
+
# Restore prefix/suffix to its previous values
|
363
|
+
ActiveRecord::Base.table_name_prefix = old_prefix
|
364
|
+
ActiveRecord::Base.table_name_suffix = old_suffix
|
365
|
+
|
366
|
+
# firstRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'David'")
|
367
|
+
firstRow = ActiveRecord::Base.connection.db.get_table(:prefix_topics_suffix).select{|rec| rec.author_name == 'David'}.first
|
368
|
+
assert_equal("The First Topic", firstRow["title"])
|
369
|
+
|
370
|
+
# secondRow = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
|
371
|
+
secondRow = ActiveRecord::Base.connection.db.get_table(:prefix_topics_suffix).select{|rec| rec.author_name == 'Mary'}.first
|
372
|
+
assert_nil(secondRow["author_email_address"])
|
373
|
+
ensure
|
374
|
+
ActiveRecord::Base.connection.drop_table :prefix_topics_suffix rescue nil
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# Too SQL specific
|
379
|
+
class TestColumnAlias
|
380
|
+
# can't remove_method, because it's the only one in the textcase
|
381
|
+
def test_column_alias() end
|
382
|
+
end
|
383
|
+
|
384
|
+
################################################################################
|
385
|
+
# Introduce my adaptation of the model classes (override SQL with blocks)
|
386
|
+
require 'ar_model_adaptation'
|
387
|
+
|
388
|
+
# schema_test and schema_dumper_test require from relative URLs, which means they
|
389
|
+
# override my changes. So the changes are reintroduced here.
|
390
|
+
module ActiveRecord #:nodoc:
|
391
|
+
class Schema
|
392
|
+
def self.define(info={}, &block)
|
393
|
+
instance_eval(&block)
|
394
|
+
|
395
|
+
unless info.empty?
|
396
|
+
initialize_schema_information
|
397
|
+
ActiveRecord::Base.connection.get_table(ActiveRecord::Migrator.schema_info_table_name.to_sym).update_all(info)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
class SchemaDumper
|
403
|
+
def initialize(connection)
|
404
|
+
@connection = connection
|
405
|
+
@types = @connection.native_database_types
|
406
|
+
@info = @connection.get_table(:schema_info).select[0] rescue nil
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
# This is required as KirbyBase does not support transactions.
|
412
|
+
ObjectSpace.each_object(Class) do |test|
|
413
|
+
test.use_transactional_fixtures = false if test < Test::Unit::TestCase
|
414
|
+
end
|
415
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Associations
|
3
|
+
module ClassMethods
|
4
|
+
def remove_association *names
|
5
|
+
if names.length == 1
|
6
|
+
assocs = @inheritable_attributes[:associations].select{ |a| a.name == names[0] }
|
7
|
+
assocs.each {|assoc| @inheritable_attributes[:associations].delete assoc }
|
8
|
+
else
|
9
|
+
names.each {|assoc| remove_association(assoc)}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def has_and_belongs_to_many_without_method_redefinition(association_id, options = {}, &extension)
|
13
|
+
options.assert_valid_keys(
|
14
|
+
:class_name, :table_name, :foreign_key, :association_foreign_key, :conditions, :include,
|
15
|
+
:join_table, :finder_sql, :delete_sql, :insert_sql, :order, :uniq, :before_add, :after_add,
|
16
|
+
:before_remove, :after_remove, :extend
|
17
|
+
)
|
18
|
+
|
19
|
+
options[:extend] = create_extension_module(association_id, extension) if block_given?
|
20
|
+
|
21
|
+
association_name, association_class_name, association_class_primary_key_name =
|
22
|
+
associate_identification(association_id, options[:class_name], options[:foreign_key])
|
23
|
+
|
24
|
+
require_association_class(association_class_name)
|
25
|
+
|
26
|
+
options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(association_class_name))
|
27
|
+
|
28
|
+
add_multiple_associated_save_callbacks(association_name)
|
29
|
+
|
30
|
+
collection_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasAndBelongsToManyAssociation)
|
31
|
+
|
32
|
+
add_association_callbacks(association_name, options)
|
33
|
+
|
34
|
+
# deprecated api
|
35
|
+
deprecated_collection_count_method(association_name)
|
36
|
+
deprecated_add_association_relation(association_name)
|
37
|
+
deprecated_remove_association_relation(association_name)
|
38
|
+
deprecated_has_collection_method(association_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Company < ActiveRecord::Base
|
45
|
+
set_sequence_name nil
|
46
|
+
end
|
47
|
+
|
48
|
+
class Firm
|
49
|
+
remove_association :clients, :clients_of_firm, :clients_using_sql, :clients_using_counter_sql,
|
50
|
+
:clients_using_zero_counter_sql, :no_clients_using_counter_sql
|
51
|
+
|
52
|
+
has_many :clients, :order => "id", :dependent => true, :counter_sql =>
|
53
|
+
lambda {|rec, firm| rec.firm_id == 1 and ['Client', 'SpecialClient', 'VerySpecialClient'].include?(rec.type) }
|
54
|
+
# "SELECT COUNT(*) FROM companies WHERE firm_id = 1 " +
|
55
|
+
# "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )"
|
56
|
+
|
57
|
+
has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id"
|
58
|
+
has_many :clients_using_sql, :class_name => "Client",
|
59
|
+
:finder_sql => lambda{|rec, firm| rec.client_of == firm.id} # 'SELECT * FROM companies WHERE client_of = #{id}'
|
60
|
+
has_many :clients_using_counter_sql, :class_name => "Client",
|
61
|
+
:finder_sql => lambda{|rec, firm| rec.client_of == firm.id}, # 'SELECT * FROM companies WHERE client_of = #{id}',
|
62
|
+
:counter_sql => lambda{|rec, firm| rec.client_of == firm.id} # 'SELECT COUNT(*) FROM companies WHERE client_of = #{id}'
|
63
|
+
has_many :clients_using_zero_counter_sql, :class_name => "Client",
|
64
|
+
:finder_sql => lambda{|rec, firm| rec.client_of == id}, # 'SELECT * FROM companies WHERE client_of = #{id}'
|
65
|
+
:counter_sql => lambda{|rec, firm| false } # 'SELECT 0 FROM companies WHERE client_of = #{id}'
|
66
|
+
has_many :no_clients_using_counter_sql, :class_name => "Client",
|
67
|
+
:finder_sql => lambda{|rec, firm| rec.client_of == 1000}, # 'SELECT * FROM companies WHERE client_of = 1000'
|
68
|
+
:counter_sql => lambda{|rec, firm| rec.client_of == 1000} # 'SELECT COUNT(*) FROM companies WHERE client_of = 1000'
|
69
|
+
end
|
70
|
+
|
71
|
+
class Client < Company
|
72
|
+
belongs_to :firm_with_condition, :class_name => "Firm", :foreign_key => "client_of", :conditions => "1 = 1"
|
73
|
+
end
|
74
|
+
|
75
|
+
# module MyApplication
|
76
|
+
# module Business
|
77
|
+
# class Firm
|
78
|
+
# has_many :clients_using_sql, :class_name => "Client",
|
79
|
+
# :finder_sql => lambda{|rec, firm| rec.client_of == firm.id} # 'SELECT * FROM companies WHERE client_of = #{id}'
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
|
84
|
+
class Project
|
85
|
+
remove_association :developers_with_finder_sql, :developers_by_sql
|
86
|
+
|
87
|
+
## Unfortunately calling habtm with the same name again will cause some method
|
88
|
+
# redefinition loop (see associations.rb for the dynamic method redefinition).
|
89
|
+
# So we have to go through loops to redefine the exact methods.
|
90
|
+
has_and_belongs_to_many_without_method_redefinition :developers_with_finder_sql, :class_name => "Developer",
|
91
|
+
# :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id}'
|
92
|
+
:finder_sql => lambda{|join, project| join.project_id == project.id } # this is run on the join table
|
93
|
+
|
94
|
+
has_and_belongs_to_many_without_method_redefinition :developers_by_sql, :class_name => "Developer",
|
95
|
+
# :delete_sql => "DELETE FROM developers_projects WHERE project_id = \#{id} AND developer_id = \#{record.id}"
|
96
|
+
:delete_sql => lambda{|join, project, developer| join.project_id == project.id and join.developer_id == developer.id}
|
97
|
+
end
|
98
|
+
|