composite_primary_keys 0.3.2 → 0.3.3

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.
@@ -34,7 +34,10 @@ unless defined?(ActiveRecord)
34
34
  end
35
35
  end
36
36
 
37
+ require 'composite_primary_keys/fixtures'
37
38
  require 'composite_primary_keys/composite_arrays'
39
+ require 'composite_primary_keys/associations'
40
+ require 'composite_primary_keys/reflection'
38
41
  require 'composite_primary_keys/base'
39
42
 
40
43
  ActiveRecord::Base.class_eval do
@@ -0,0 +1,4 @@
1
+ module ActiveRecord
2
+ class Base
3
+ end
4
+ end
@@ -1,5 +1,8 @@
1
1
  module CompositePrimaryKeys
2
2
  module ActiveRecord #:nodoc:
3
+ class CompositeKeyError < StandardError #:nodoc:
4
+ end
5
+
3
6
  module Base #:nodoc:
4
7
 
5
8
  INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
@@ -51,7 +54,7 @@ module CompositePrimaryKeys
51
54
  end
52
55
 
53
56
  def id_before_type_cast #:nodoc:
54
- raise CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
57
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::NOT_IMPLEMENTED_YET
55
58
  end
56
59
 
57
60
  def quoted_id #:nodoc:
@@ -62,12 +65,14 @@ module CompositePrimaryKeys
62
65
  end
63
66
 
64
67
  # Sets the primary ID.
65
- def id=(value)
66
- ids = id.split(value) if value.is_a?(String)
68
+ def id=(ids)
69
+ ids = ids.split(ID_SEP) if ids.is_a?(String)
70
+ ids.flatten!
67
71
  unless ids.is_a?(Array) and ids.length == self.class.primary_keys.length
68
72
  raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
69
73
  end
70
- ids.each {|id| write_attribute(self.class.primary_key , id)}
74
+ [primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
75
+ id
71
76
  end
72
77
 
73
78
  # Deletes the record in the database and freezes this instance to reflect that no changes should
@@ -96,6 +101,36 @@ module CompositePrimaryKeys
96
101
  end
97
102
  end
98
103
 
104
+ # Allows +attr_name+ to be the list of primary_keys, and returns the id
105
+ # of the object
106
+ # e.g. @object[@object.class.primary_key] => [1,1]
107
+ def [](attr_name)
108
+ if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
109
+ attr_name = attr_name.split(ID_SEP)
110
+ end
111
+ attr_name.is_a?(Array) ?
112
+ attr_name.map {|name| read_attribute(name)} :
113
+ read_attribute(attr_name)
114
+ end
115
+
116
+ # Updates the attribute identified by <tt>attr_name</tt> with the specified +value+.
117
+ # (Alias for the protected write_attribute method).
118
+ def []=(attr_name, value)
119
+ if attr_name.is_a?(String) and attr_name != attr_name.split(ID_SEP).first
120
+ attr_name = attr_name.split(ID_SEP)
121
+ end
122
+ if attr_name.is_a? Array
123
+ value = value.split(ID_SEP) if value.is_a? String
124
+ unless value.length == attr_name.length
125
+ raise "Number of attr_names and values do not match"
126
+ end
127
+ #breakpoint
128
+ [attr_name, value].transpose.map {|name,val| write_attribute(name.to_s, val)}
129
+ else
130
+ write_attribute(attr_name, value)
131
+ end
132
+ end
133
+
99
134
  # Define an attribute reader method. Cope with nil column.
100
135
  def define_read_method(symbol, attr_name, column)
101
136
  cast_code = column.type_cast_code('v') if column
@@ -146,6 +181,25 @@ module CompositePrimaryKeys
146
181
  )
147
182
  return true
148
183
  end
184
+
185
+ # Creates a new record with values matching those of the instance attributes.
186
+ def create
187
+ if self.id.nil?
188
+ raise CompositeKeyError, "Composite keys do not generated ids from sequences, you must provide id values"
189
+ end
190
+
191
+ self.id = connection.insert(
192
+ "INSERT INTO #{self.class.table_name} " +
193
+ "(#{quoted_column_names.join(', ')}) " +
194
+ "VALUES(#{attributes_with_quotes.values.join(', ')})",
195
+ "#{self.class.name} Create",
196
+ self.class.primary_key, self.id
197
+ )
198
+
199
+ @new_record = false
200
+
201
+ return true
202
+ end
149
203
  end
150
204
 
151
205
  module CompositeClassMethods
@@ -207,40 +261,44 @@ module CompositePrimaryKeys
207
261
  # Lazy-set the sequence name to the connection's default. This method
208
262
  # is only ever called once since set_sequence_name overrides it.
209
263
  def sequence_name #:nodoc:
210
- raise CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
264
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
211
265
  end
212
266
 
213
267
  def reset_sequence_name #:nodoc:
214
- raise CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
268
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
215
269
  end
216
270
 
217
271
  def set_primary_key(value = nil, &block)
218
- raise CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
272
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
219
273
  end
220
274
 
221
275
  private
222
276
  def find_one(id, options)
223
- raise CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
277
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
224
278
  end
225
279
 
226
280
  def find_some(ids, options)
227
- raise CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
281
+ raise CompositeKeyError, CompositePrimaryKeys::ActiveRecord::Base::INVALID_FOR_COMPOSITE_KEYS
228
282
  end
229
283
 
230
284
  def find_from_ids(ids, options)
231
285
  conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
232
286
  # if ids is just a flat list, then its size must = primary_key.length (one id per primary key, in order)
233
287
  # if ids is list of lists, then each inner list must follow rule above
234
- #if ids.first.is_a?(String) - find '2,1' -> find_from_ids ['2,1']
235
- ids = ids[0].split(';').map {|id_set| id_set.split ','} if ids.first.is_a? String
236
- ids = [ids] if not ids.first.kind_of?(Array)
237
288
 
289
+ if ids.first.is_a? String
290
+ # find '2,1' -> ids = ['2,1']
291
+ # find '2,1;7,3' -> ids = ['2,1;7,3']
292
+ ids = ids.first.split(ID_SET_SEP).map {|id_set| id_set.split(ID_SEP).to_composite_ids}
293
+ # find '2,1;7,3' -> ids = [['2','1'],['7','3']], inner [] are CompositeIds
294
+ end
295
+ ids = [ids.to_composite_ids] if not ids.first.kind_of?(Array)
238
296
  ids.each do |id_set|
239
297
  unless id_set.is_a?(Array)
240
298
  raise "Ids must be in an Array, instead received: #{id_set.inspect}"
241
299
  end
242
300
  unless id_set.length == primary_keys.length
243
- raise "Incorrect number of primary keys for #{class_name}: #{primary_keys.inspect}"
301
+ raise "#{id_set.inspect}: Incorrect number of primary keys for #{class_name}: #{primary_keys.inspect}"
244
302
  end
245
303
  end
246
304
 
@@ -1,5 +1,6 @@
1
1
  module CompositePrimaryKeys
2
2
  ID_SEP = ','
3
+ ID_SET_SEP = ';'
3
4
  module ArrayExtension
4
5
  def to_composite_keys
5
6
  CompositeKeys.new(self)
@@ -1,600 +1,9 @@
1
- require 'erb'
2
- require 'yaml'
3
- require 'csv'
4
-
5
- module YAML #:nodoc:
6
- class Omap #:nodoc:
7
- def keys; map { |k, v| k } end
8
- def values; map { |k, v| v } end
9
- end
10
- end
11
-
12
- class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
13
- end
14
-
15
- # Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavours:
16
- #
17
- # 1. YAML fixtures
18
- # 2. CSV fixtures
19
- # 3. Single-file fixtures
20
- #
21
- # = YAML fixtures
22
- #
23
- # This type of fixture is in YAML format and the preferred default. YAML is a file format which describes data structures
24
- # in a non-verbose, humanly-readable format. It ships with Ruby 1.8.1+.
25
- #
26
- # Unlike single-file fixtures, YAML fixtures are stored in a single file per model, which are placed in the directory appointed
27
- # by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
28
- # put your files in <your-rails-app>/test/fixtures/). The fixture file ends with the .yml file extension (Rails example:
29
- # "<your-rails-app>/test/fixtures/web_sites.yml"). The format of a YAML fixture file looks like this:
30
- #
31
- # rubyonrails:
32
- # id: 1
33
- # name: Ruby on Rails
34
- # url: http://www.rubyonrails.org
35
- #
36
- # google:
37
- # id: 2
38
- # name: Google
39
- # url: http://www.google.com
40
- #
41
- # This YAML fixture file includes two fixtures. Each YAML fixture (ie. record) is given a name and is followed by an
42
- # indented list of key/value pairs in the "key: value" format. Records are separated by a blank line for your viewing
43
- # pleasure.
44
- #
45
- # Note that YAML fixtures are unordered. If you want ordered fixtures, use the omap YAML type. See http://yaml.org/type/omap.html
46
- # for the specification. You will need ordered fixtures when you have foreign key constraints on keys in the same table.
47
- # This is commonly needed for tree structures. Example:
48
- #
49
- # --- !omap
50
- # - parent:
51
- # id: 1
52
- # parent_id: NULL
53
- # title: Parent
54
- # - child:
55
- # id: 2
56
- # parent_id: 1
57
- # title: Child
58
- #
59
- # = CSV fixtures
60
- #
61
- # Fixtures can also be kept in the Comma Separated Value format. Akin to YAML fixtures, CSV fixtures are stored
62
- # in a single file, but instead end with the .csv file extension (Rails example: "<your-rails-app>/test/fixtures/web_sites.csv")
63
- #
64
- # The format of this type of fixture file is much more compact than the others, but also a little harder to read by us
65
- # humans. The first line of the CSV file is a comma-separated list of field names. The rest of the file is then comprised
66
- # of the actual data (1 per line). Here's an example:
67
- #
68
- # id, name, url
69
- # 1, Ruby On Rails, http://www.rubyonrails.org
70
- # 2, Google, http://www.google.com
71
- #
72
- # Should you have a piece of data with a comma character in it, you can place double quotes around that value. If you
73
- # need to use a double quote character, you must escape it with another double quote.
74
- #
75
- # Another unique attribute of the CSV fixture is that it has *no* fixture name like the other two formats. Instead, the
76
- # fixture names are automatically generated by deriving the class name of the fixture file and adding an incrementing
77
- # number to the end. In our example, the 1st fixture would be called "web_site_1" and the 2nd one would be called
78
- # "web_site_2".
79
- #
80
- # Most databases and spreadsheets support exporting to CSV format, so this is a great format for you to choose if you
81
- # have existing data somewhere already.
82
- #
83
- # = Single-file fixtures
84
- #
85
- # This type of fixtures was the original format for Active Record that has since been deprecated in favor of the YAML and CSV formats.
86
- # Fixtures for this format are created by placing text files in a sub-directory (with the name of the model) to the directory
87
- # appointed by <tt>Test::Unit::TestCase.fixture_path=(path)</tt> (this is automatically configured for Rails, so you can just
88
- # put your files in <your-rails-app>/test/fixtures/<your-model-name>/ -- like <your-rails-app>/test/fixtures/web_sites/ for the WebSite
89
- # model).
90
- #
91
- # Each text file placed in this directory represents a "record". Usually these types of fixtures are named without
92
- # extensions, but if you are on a Windows machine, you might consider adding .txt as the extension. Here's what the
93
- # above example might look like:
94
- #
95
- # web_sites/google
96
- # web_sites/yahoo.txt
97
- # web_sites/ruby-on-rails
98
- #
99
- # The file format of a standard fixture is simple. Each line is a property (or column in db speak) and has the syntax
100
- # of "name => value". Here's an example of the ruby-on-rails fixture above:
101
- #
102
- # id => 1
103
- # name => Ruby on Rails
104
- # url => http://www.rubyonrails.org
105
- #
106
- # = Using Fixtures
107
- #
108
- # Since fixtures are a testing construct, we use them in our unit and functional tests. There are two ways to use the
109
- # fixtures, but first let's take a look at a sample unit test found:
110
- #
111
- # require 'web_site'
112
- #
113
- # class WebSiteTest < Test::Unit::TestCase
114
- # def test_web_site_count
115
- # assert_equal 2, WebSite.count
116
- # end
117
- # end
118
- #
119
- # As it stands, unless we pre-load the web_site table in our database with two records, this test will fail. Here's the
120
- # easiest way to add fixtures to the database:
121
- #
122
- # ...
123
- # class WebSiteTest < Test::Unit::TestCase
124
- # fixtures :web_sites # add more by separating the symbols with commas
125
- # ...
126
- #
127
- # By adding a "fixtures" method to the test case and passing it a list of symbols (only one is shown here tho), we trigger
128
- # the testing environment to automatically load the appropriate fixtures into the database before each test.
129
- # To ensure consistent data, the environment deletes the fixtures before running the load.
130
- #
131
- # In addition to being available in the database, the fixtures are also loaded into a hash stored in an instance variable
132
- # of the test case. It is named after the symbol... so, in our example, there would be a hash available called
133
- # @web_sites. This is where the "fixture name" comes into play.
134
- #
135
- # On top of that, each record is automatically "found" (using Model.find(id)) and placed in the instance variable of its name.
136
- # So for the YAML fixtures, we'd get @rubyonrails and @google, which could be interrogated using regular Active Record semantics:
137
- #
138
- # # test if the object created from the fixture data has the same attributes as the data itself
139
- # def test_find
140
- # assert_equal @web_sites["rubyonrails"]["name"], @rubyonrails.name
141
- # end
142
- #
143
- # As seen above, the data hash created from the YAML fixtures would have @web_sites["rubyonrails"]["url"] return
144
- # "http://www.rubyonrails.org" and @web_sites["google"]["name"] would return "Google". The same fixtures, but loaded
145
- # from a CSV fixture file, would be accessible via @web_sites["web_site_1"]["name"] == "Ruby on Rails" and have the individual
146
- # fixtures available as instance variables @web_site_1 and @web_site_2.
147
- #
148
- # If you do not wish to use instantiated fixtures (usually for performance reasons) there are two options.
149
- #
150
- # - to completely disable instantiated fixtures:
151
- # self.use_instantiated_fixtures = false
152
- #
153
- # - to keep the fixture instance (@web_sites) available, but do not automatically 'find' each instance:
154
- # self.use_instantiated_fixtures = :no_instances
155
- #
156
- # Even if auto-instantiated fixtures are disabled, you can still access them
157
- # by name via special dynamic methods. Each method has the same name as the
158
- # model, and accepts the name of the fixture to instantiate:
159
- #
160
- # fixtures :web_sites
161
- #
162
- # def test_find
163
- # assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
164
- # end
165
- #
166
- # = Dynamic fixtures with ERb
167
- #
168
- # Some times you don't care about the content of the fixtures as much as you care about the volume. In these cases, you can
169
- # mix ERb in with your YAML or CSV fixtures to create a bunch of fixtures for load testing, like:
170
- #
171
- # <% for i in 1..1000 %>
172
- # fix_<%= i %>:
173
- # id: <%= i %>
174
- # name: guy_<%= 1 %>
175
- # <% end %>
176
- #
177
- # This will create 1000 very simple YAML fixtures.
178
- #
179
- # Using ERb, you can also inject dynamic values into your fixtures with inserts like <%= Date.today.strftime("%Y-%m-%d") %>.
180
- # This is however a feature to be used with some caution. The point of fixtures are that they're stable units of predictable
181
- # sample data. If you feel that you need to inject dynamic values, then perhaps you should reexamine whether your application
182
- # is properly testable. Hence, dynamic values in fixtures are to be considered a code smell.
183
- #
184
- # = Transactional fixtures
185
- #
186
- # TestCases can use begin+rollback to isolate their changes to the database instead of having to delete+insert for every test case.
187
- # They can also turn off auto-instantiation of fixture data since the feature is costly and often unused.
188
- #
189
- # class FooTest < Test::Unit::TestCase
190
- # self.use_transactional_fixtures = true
191
- # self.use_instantiated_fixtures = false
192
- #
193
- # fixtures :foos
194
- #
195
- # def test_godzilla
196
- # assert !Foo.find(:all).empty?
197
- # Foo.destroy_all
198
- # assert Foo.find(:all).empty?
199
- # end
200
- #
201
- # def test_godzilla_aftermath
202
- # assert !Foo.find(:all).empty?
203
- # end
204
- # end
205
- #
206
- # If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
207
- # then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
208
- #
209
- # In order to use instantiated fixtures with preloaded data, set +self.pre_loaded_fixtures+ to true. This will provide
210
- # access to fixture data for every table that has been loaded through fixtures (depending on the value of +use_instantiated_fixtures+)
211
- #
212
- # When *not* to use transactional fixtures:
213
- # 1. You're testing whether a transaction works correctly. Nested transactions don't commit until all parent transactions commit,
214
- # particularly, the fixtures transaction which is begun in setup and rolled back in teardown. Thus, you won't be able to verify
215
- # the results of your transaction until Active Record supports nested transactions or savepoints (in progress.)
216
- # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM.
217
- # Use InnoDB, MaxDB, or NDB instead.
218
- class Fixtures < YAML::Omap
219
- DEFAULT_FILTER_RE = /\.ya?ml$/
220
-
221
- def self.instantiate_fixtures(object, table_name, fixtures, load_instances=true)
222
- object.instance_variable_set "@#{table_name.to_s.gsub('.','_')}", fixtures
223
- if load_instances
224
- ActiveRecord::Base.silence do
225
- fixtures.each do |name, fixture|
226
- begin
227
- object.instance_variable_set "@#{name}", fixture.find
228
- rescue FixtureClassNotFound
229
- nil
230
- end
231
- end
232
- end
233
- end
234
- end
235
-
236
- def self.instantiate_all_loaded_fixtures(object, load_instances=true)
237
- all_loaded_fixtures.each do |table_name, fixtures|
238
- Fixtures.instantiate_fixtures(object, table_name, fixtures, load_instances)
239
- end
240
- end
241
-
242
- cattr_accessor :all_loaded_fixtures
243
- self.all_loaded_fixtures = {}
244
-
245
- def self.create_fixtures(fixtures_directory, table_names, class_names = {})
246
- table_names = [table_names].flatten.map { |n| n.to_s }
247
- connection = block_given? ? yield : ActiveRecord::Base.connection
248
- ActiveRecord::Base.silence do
249
- fixtures_map = {}
250
- fixtures = table_names.map do |table_name|
251
- fixtures_map[table_name] = Fixtures.new(connection, File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(fixtures_directory, table_name.to_s))
252
- end
253
- all_loaded_fixtures.merge! fixtures_map
254
-
255
- connection.transaction do
256
- fixtures.reverse.each { |fixture| fixture.delete_existing_fixtures }
257
- fixtures.each { |fixture| fixture.insert_fixtures }
258
-
259
- # Cap primary key sequences to max(pk).
260
- if connection.respond_to?(:reset_pk_sequence!)
261
- table_names.each do |table_name|
262
- connection.reset_pk_sequence!(table_name)
263
- end
264
- end
265
- end
266
-
267
- return fixtures.size > 1 ? fixtures : fixtures.first
268
- end
269
- end
270
-
271
-
272
- attr_reader :table_name
273
-
274
- def initialize(connection, table_name, class_name, fixture_path, file_filter = DEFAULT_FILTER_RE)
275
- @connection, @table_name, @fixture_path, @file_filter = connection, table_name, fixture_path, file_filter
276
- @class_name = class_name ||
277
- (ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
278
- @table_name = ActiveRecord::Base.table_name_prefix + @table_name + ActiveRecord::Base.table_name_suffix
279
- read_fixture_files
280
- end
281
-
282
- def delete_existing_fixtures
283
- @connection.delete "DELETE FROM #{@table_name}", 'Fixture Delete'
284
- end
285
-
286
- def insert_fixtures
287
- values.each do |fixture|
288
- @connection.execute "INSERT INTO #{@table_name} (#{fixture.key_list}) VALUES (#{fixture.value_list})", 'Fixture Insert'
289
- end
290
- end
291
-
292
- private
293
-
294
- def read_fixture_files
295
- if File.file?(yaml_file_path)
296
- # YAML fixtures
297
- begin
298
- yaml_string = ""
299
- Dir["#{@fixture_path}/**/*.yml"].select {|f| test(?f,f) }.each do |subfixture_path|
300
- yaml_string << IO.read(subfixture_path)
301
- end
302
- yaml_string << IO.read(yaml_file_path)
303
-
304
- if yaml = YAML::load(erb_render(yaml_string))
305
- yaml = yaml.value if yaml.respond_to?(:type_id) and yaml.respond_to?(:value)
306
- yaml.each do |name, data|
307
- self[name] = Fixture.new(data, @class_name)
308
- end
309
- end
310
- rescue Exception=>boom
311
- raise Fixture::FormatError, "a YAML error occured parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{boom.class}: #{boom}"
312
- end
313
- elsif File.file?(csv_file_path)
314
- # CSV fixtures
315
- reader = CSV::Reader.create(erb_render(IO.read(csv_file_path)))
316
- header = reader.shift
317
- i = 0
318
- reader.each do |row|
319
- data = {}
320
- row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
321
- self["#{Inflector::underscore(@class_name)}_#{i+=1}"]= Fixture.new(data, @class_name)
322
- end
323
- elsif File.file?(deprecated_yaml_file_path)
324
- raise Fixture::FormatError, ".yml extension required: rename #{deprecated_yaml_file_path} to #{yaml_file_path}"
325
- else
326
- # Standard fixtures
327
- Dir.entries(@fixture_path).each do |file|
328
- path = File.join(@fixture_path, file)
329
- if File.file?(path) and file !~ @file_filter
330
- self[file] = Fixture.new(path, @class_name)
331
- end
332
- end
333
- end
334
- end
335
-
336
- def yaml_file_path
337
- "#{@fixture_path}.yml"
338
- end
339
-
340
- def deprecated_yaml_file_path
341
- "#{@fixture_path}.yaml"
342
- end
343
-
344
- def csv_file_path
345
- @fixture_path + ".csv"
346
- end
347
-
348
- def yaml_fixtures_key(path)
349
- File.basename(@fixture_path).split(".").first
350
- end
351
-
352
- def erb_render(fixture_content)
353
- ERB.new(fixture_content).result
354
- end
355
- end
356
-
357
1
  class Fixture #:nodoc:
358
- include Enumerable
359
- class FixtureError < StandardError#:nodoc:
360
- end
361
- class FormatError < FixtureError#:nodoc:
362
- end
363
-
364
- def initialize(fixture, class_name)
365
- case fixture
366
- when Hash, YAML::Omap
367
- @fixture = fixture
368
- when String
369
- @fixture = read_fixture_file(fixture)
370
- else
371
- raise ArgumentError, "Bad fixture argument #{fixture.inspect}"
372
- end
373
-
374
- @class_name = class_name
375
- end
376
-
377
- def each
378
- @fixture.each { |item| yield item }
379
- end
380
-
381
2
  def [](key)
382
- @fixture[key]
383
- end
384
-
385
- def to_hash
386
- @fixture
387
- end
388
-
389
- def key_list
390
- columns = @fixture.keys.collect{ |column_name| ActiveRecord::Base.connection.quote_column_name(column_name) }
391
- columns.join(", ")
392
- end
393
-
394
- def value_list
395
- @fixture.values.map { |v| ActiveRecord::Base.connection.quote(v).gsub('\\n', "\n").gsub('\\r', "\r") }.join(", ")
396
- end
397
-
398
- def find
399
- klass = @class_name.is_a?(Class) ? @class_name : Object.const_get(@class_name) rescue nil
400
- if klass
401
- klass.find(self[klass.primary_key])
402
- else
403
- raise FixtureClassNotFound, "The class #{@class_name.inspect} was not found."
3
+ if key.is_a? Array
4
+ return key.map {|a_key| self[a_key.to_s]}.
5
+ to_composite_ids.to_s
404
6
  end
7
+ @fixture[key]
405
8
  end
406
-
407
- private
408
- def read_fixture_file(fixture_file_path)
409
- IO.readlines(fixture_file_path).inject({}) do |fixture, line|
410
- # Mercifully skip empty lines.
411
- next if line =~ /^\s*$/
412
-
413
- # Use the same regular expression for attributes as Active Record.
414
- unless md = /^\s*([a-zA-Z][-_\w]*)\s*=>\s*(.+)\s*$/.match(line)
415
- raise FormatError, "#{fixture_file_path}: fixture format error at '#{line}'. Expecting 'key => value'."
416
- end
417
- key, value = md.captures
418
-
419
- # Disallow duplicate keys to catch typos.
420
- raise FormatError, "#{fixture_file_path}: duplicate '#{key}' in fixture." if fixture[key]
421
- fixture[key] = value.strip
422
- fixture
423
- end
424
- end
425
- end
426
-
427
- module Test #:nodoc:
428
- module Unit #:nodoc:
429
- class TestCase #:nodoc:
430
- cattr_accessor :fixture_path
431
- class_inheritable_accessor :fixture_table_names
432
- class_inheritable_accessor :fixture_class_names
433
- class_inheritable_accessor :use_transactional_fixtures
434
- class_inheritable_accessor :use_instantiated_fixtures # true, false, or :no_instances
435
- class_inheritable_accessor :pre_loaded_fixtures
436
-
437
- self.fixture_table_names = []
438
- self.use_transactional_fixtures = false
439
- self.use_instantiated_fixtures = true
440
- self.pre_loaded_fixtures = false
441
-
442
- self.fixture_class_names = {}
443
-
444
- @@already_loaded_fixtures = {}
445
- self.fixture_class_names = {}
446
-
447
- def self.set_fixture_class(class_names = {})
448
- self.fixture_class_names = self.fixture_class_names.merge(class_names)
449
- end
450
-
451
- def self.fixtures(*table_names)
452
- table_names = table_names.flatten.map { |n| n.to_s }
453
- self.fixture_table_names |= table_names
454
- require_fixture_classes(table_names)
455
- setup_fixture_accessors(table_names)
456
- end
457
-
458
- def self.require_fixture_classes(table_names=nil)
459
- (table_names || fixture_table_names).each do |table_name|
460
- file_name = table_name.to_s
461
- file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names
462
- begin
463
- require file_name
464
- rescue LoadError
465
- # Let's hope the developer has included it himself
466
- end
467
- end
468
- end
469
-
470
- def self.setup_fixture_accessors(table_names=nil)
471
- (table_names || fixture_table_names).each do |table_name|
472
- table_name = table_name.to_s.tr('.','_')
473
- define_method(table_name) do |fixture, *optionals|
474
- force_reload = optionals.shift
475
- @fixture_cache[table_name] ||= Hash.new
476
- @fixture_cache[table_name][fixture] = nil if force_reload
477
- if @loaded_fixtures[table_name][fixture.to_s]
478
- @fixture_cache[table_name][fixture] ||= @loaded_fixtures[table_name][fixture.to_s].find
479
- else
480
- raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
481
- end
482
- end
483
- end
484
- end
485
-
486
- def self.uses_transaction(*methods)
487
- @uses_transaction ||= []
488
- @uses_transaction.concat methods.map { |m| m.to_s }
489
- end
490
-
491
- def self.uses_transaction?(method)
492
- @uses_transaction && @uses_transaction.include?(method.to_s)
493
- end
494
-
495
- def use_transactional_fixtures?
496
- use_transactional_fixtures &&
497
- !self.class.uses_transaction?(method_name)
498
- end
499
-
500
- def setup_with_fixtures
501
- if pre_loaded_fixtures && !use_transactional_fixtures
502
- raise RuntimeError, 'pre_loaded_fixtures requires use_transactional_fixtures'
503
- end
504
-
505
- @fixture_cache = Hash.new
506
-
507
- # Load fixtures once and begin transaction.
508
- if use_transactional_fixtures?
509
- if @@already_loaded_fixtures[self.class]
510
- @loaded_fixtures = @@already_loaded_fixtures[self.class]
511
- else
512
- load_fixtures
513
- @@already_loaded_fixtures[self.class] = @loaded_fixtures
514
- end
515
- ActiveRecord::Base.lock_mutex
516
- ActiveRecord::Base.connection.begin_db_transaction
517
-
518
- # Load fixtures for every test.
519
- else
520
- @@already_loaded_fixtures[self.class] = nil
521
- load_fixtures
522
- end
523
-
524
- # Instantiate fixtures for every test if requested.
525
- instantiate_fixtures if use_instantiated_fixtures
526
- end
527
-
528
- alias_method :setup, :setup_with_fixtures
529
-
530
- def teardown_with_fixtures
531
- # Rollback changes.
532
- if use_transactional_fixtures?
533
- ActiveRecord::Base.connection.rollback_db_transaction
534
- ActiveRecord::Base.unlock_mutex
535
- end
536
- ActiveRecord::Base.verify_active_connections!
537
- end
538
-
539
- alias_method :teardown, :teardown_with_fixtures
540
-
541
- def self.method_added(method)
542
- case method.to_s
543
- when 'setup'
544
- unless method_defined?(:setup_without_fixtures)
545
- alias_method :setup_without_fixtures, :setup
546
- define_method(:setup) do
547
- setup_with_fixtures
548
- setup_without_fixtures
549
- end
550
- end
551
- when 'teardown'
552
- unless method_defined?(:teardown_without_fixtures)
553
- alias_method :teardown_without_fixtures, :teardown
554
- define_method(:teardown) do
555
- teardown_without_fixtures
556
- teardown_with_fixtures
557
- end
558
- end
559
- end
560
- end
561
-
562
- private
563
- def load_fixtures
564
- @loaded_fixtures = {}
565
- fixtures = Fixtures.create_fixtures(fixture_path, fixture_table_names, fixture_class_names)
566
- unless fixtures.nil?
567
- if fixtures.instance_of?(Fixtures)
568
- @loaded_fixtures[fixtures.table_name] = fixtures
569
- else
570
- fixtures.each { |f| @loaded_fixtures[f.table_name] = f }
571
- end
572
- end
573
- end
574
-
575
- # for pre_loaded_fixtures, only require the classes once. huge speed improvement
576
- @@required_fixture_classes = false
577
-
578
- def instantiate_fixtures
579
- if pre_loaded_fixtures
580
- raise RuntimeError, 'Load fixtures before instantiating them.' if Fixtures.all_loaded_fixtures.empty?
581
- unless @@required_fixture_classes
582
- self.class.require_fixture_classes Fixtures.all_loaded_fixtures.keys
583
- @@required_fixture_classes = true
584
- end
585
- Fixtures.instantiate_all_loaded_fixtures(self, load_instances?)
586
- else
587
- raise RuntimeError, 'Load fixtures before instantiating them.' if @loaded_fixtures.nil?
588
- @loaded_fixtures.each do |table_name, fixtures|
589
- Fixtures.instantiate_fixtures(self, table_name, fixtures, load_instances?)
590
- end
591
- end
592
- end
593
-
594
- def load_instances?
595
- use_instantiated_fixtures != :no_instances
596
- end
597
- end
598
-
599
- end
600
- end
9
+ end
@@ -0,0 +1,19 @@
1
+ module ActiveRecord
2
+ module Reflection
3
+ class AssociationReflection
4
+ def primary_key_name
5
+ return @primary_key_name if @primary_key_name
6
+ case
7
+ when macro == :belongs_to
8
+ @primary_key_name = options[:foreign_key] || class_name.foreign_key
9
+ when options[:as]
10
+ @primary_key_name = options[:foreign_key] || "#{options[:as]}_id"
11
+ else
12
+ @primary_key_name = options[:foreign_key] || active_record.name.foreign_key
13
+ end
14
+ @primary_key_name = @primary_key_name.to_composite_keys.to_s if @primary_key_name.is_a? Array
15
+ @primary_key_name
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 3
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -8,7 +8,6 @@ require 'active_support/binding_of_caller'
8
8
  require 'active_support/breakpoint'
9
9
  require 'connection'
10
10
  require 'composite_primary_keys'
11
- require 'composite_primary_keys/fixtures'
12
11
 
13
12
  QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') unless Object.const_defined?(:QUOTED_TYPE)
14
13
 
@@ -63,11 +62,12 @@ protected
63
62
  end
64
63
 
65
64
  def first_id
66
- (1..@primary_keys.length).map {|num| 1}
65
+ ids = (1..@primary_keys.length).map {|num| 1}
66
+ composite? ? ids.to_composite_ids : ids.first
67
67
  end
68
68
 
69
69
  def first_id_str
70
- first_id.join(CompositePrimaryKeys::ID_SEP)
70
+ composite? ? first_id.join(CompositePrimaryKeys::ID_SEP) : first_id.to_s
71
71
  end
72
72
 
73
73
  def composite?
@@ -0,0 +1,44 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/product'
3
+ require 'fixtures/tariff'
4
+ require 'fixtures/product_tariff'
5
+
6
+ class AssociationTest < Test::Unit::TestCase
7
+ fixtures :products, :tariffs, :product_tariffs
8
+
9
+ def setup
10
+ super
11
+ @first_product = products(:first_product)
12
+ @flat = tariffs(:flat)
13
+ @free = tariffs(:free)
14
+ @first_flat = product_tariffs(:first_flat)
15
+ end
16
+
17
+ def test_setup
18
+ assert_not_nil @first_product
19
+ assert_not_nil @flat
20
+ assert_not_nil @free
21
+ assert_not_nil @first_flat
22
+ end
23
+
24
+ def test_products
25
+ assert_not_nil @first_product.product_tariffs
26
+ assert_equal 2, @first_product.product_tariffs.length
27
+ assert_not_nil @first_product.tariffs
28
+ assert_equal 2, @first_product.tariffs.length
29
+ end
30
+
31
+ def test_product_tariffs
32
+ assert_not_nil @first_flat.product
33
+ assert_not_nil @first_flat.tariff
34
+ assert_equal Product, @first_flat.product.class
35
+ assert_equal Tariff, @first_flat.tariff.class
36
+ end
37
+
38
+ def test_tariffs
39
+ assert_not_nil @flat.product_tariffs
40
+ assert_equal 2, @flat.product_tariffs.length
41
+ assert_not_nil @flat.products
42
+ assert_equal 2, @flat.products.length
43
+ end
44
+ end
@@ -0,0 +1,85 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/reference_type'
3
+ require 'fixtures/reference_code'
4
+ require 'fixtures/product'
5
+ require 'fixtures/tariff'
6
+ require 'fixtures/product_tariff'
7
+
8
+ class AttributesTest < Test::Unit::TestCase
9
+ fixtures :reference_types, :reference_codes, :products, :tariffs, :product_tariffs
10
+
11
+ CLASSES = {
12
+ :single => {
13
+ :class => ReferenceType,
14
+ :primary_keys => [:reference_type_id],
15
+ },
16
+ :dual => {
17
+ :class => ReferenceCode,
18
+ :primary_keys => [:reference_type_id, :reference_code],
19
+ },
20
+ }
21
+
22
+ def setup
23
+ super
24
+ self.class.classes = CLASSES
25
+ end
26
+
27
+ def test_brackets
28
+ testing_with do
29
+ @first.attributes.each_pair do |attr_name, value|
30
+ assert_equal value, @first[attr_name]
31
+ end
32
+ end
33
+ end
34
+
35
+ def test_brackets_primary_key
36
+ testing_with do
37
+ assert_equal @first.id, @first[@primary_keys]
38
+ assert_equal @first.id, @first[@first.class.primary_key]
39
+ end
40
+ end
41
+
42
+ def test_brackets_assignment
43
+ testing_with do
44
+ @first.attributes.each_pair do |attr_name, value|
45
+ @first[attr_name]= !value.nil? ? value * 2 : '1'
46
+ assert_equal !value.nil? ? value * 2 : '1', @first[attr_name]
47
+ end
48
+ end
49
+ end
50
+
51
+ def test_brackets_foreign_key_assignment
52
+ @flat = tariffs(:flat)
53
+ @second_free = product_tariffs(:second_free)
54
+ @second_free_fk = [:tariff_id, :tariff_start_date]
55
+ @second_free[key = @second_free_fk] = @flat.id
56
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
57
+ assert_equal @flat.id, @second_free[key]
58
+ @second_free[key = @second_free_fk.to_composite_ids] = @flat.id
59
+ assert_equal @flat.id, @second_free[key]
60
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
61
+ @second_free[key = @second_free_fk.to_composite_ids] = @flat.id.to_s
62
+ assert_equal @flat.id, @second_free[key]
63
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
64
+ @second_free[key = @second_free_fk.to_composite_ids] = @flat.id.to_s
65
+ assert_equal @flat.id, @second_free[key]
66
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
67
+ @second_free[key = @second_free_fk.to_composite_ids.to_s] = @flat.id
68
+ assert_equal @flat.id, @second_free[key]
69
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
70
+ @second_free[key = @second_free_fk.to_composite_ids.to_s] = @flat.id.to_s
71
+ assert_equal @flat.id, @second_free[key]
72
+ compare_indexes('@flat', @flat.class.primary_key, '@second_free', @second_free_fk)
73
+ end
74
+ private
75
+ def compare_indexes(obj_name1, indexes1, obj_name2, indexes2)
76
+ obj1, obj2 = eval "[#{obj_name1}, #{obj_name2}]"
77
+ indexes1.length.times do |key_index|
78
+ assert_equal obj1[indexes1[key_index].to_s],
79
+ obj2[indexes2[key_index].to_s],
80
+ "#{obj_name1}[#{indexes1[key_index]}]=#{obj1[indexes1[key_index].to_s].inspect} != " +
81
+ "#{obj_name2}[#{indexes2[key_index]}]=#{obj2[indexes2[key_index].to_s].inspect}; " +
82
+ "#{obj_name2} = #{obj2.inspect}"
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,52 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/reference_type'
3
+ require 'fixtures/reference_code'
4
+
5
+ class DummyTest < Test::Unit::TestCase
6
+ fixtures :reference_types, :reference_codes
7
+
8
+ CLASSES = {
9
+ :single => {
10
+ :class => ReferenceType,
11
+ :primary_keys => [:reference_type_id],
12
+ :create => {:reference_type_id => 10, :type_label => 'NEW_TYPE', :abbreviation => 'New Type'}
13
+ },
14
+ :dual => {
15
+ :class => ReferenceCode,
16
+ :primary_keys => [:reference_type_id, :reference_code],
17
+ :create => {:reference_type_id => 1, :reference_code => 20, :code_label => 'NEW_CODE', :abbreviation => 'New Code'}
18
+ },
19
+ }
20
+
21
+ def setup
22
+ super
23
+ self.class.classes = CLASSES
24
+ end
25
+
26
+ def test_setup
27
+ testing_with do
28
+ assert_not_nil @klass_info[:create]
29
+ end
30
+ end
31
+
32
+ def test_create
33
+ testing_with do
34
+ assert new_obj = @klass.create(@klass_info[:create])
35
+ assert !new_obj.new_record?
36
+ end
37
+ end
38
+
39
+ def test_create_no_id
40
+ testing_with do
41
+ begin
42
+ @obj = @klass.create(@klass_info[:create].block(@klass.primary_key))
43
+ @successful = !composite?
44
+ rescue CompositePrimaryKeys::ActiveRecord::CompositeKeyError
45
+ @successful = false
46
+ rescue
47
+ flunk "Incorrect exception raised: #{$!}, #{$!.class}"
48
+ end
49
+ assert_equal composite?, !@successful, "Create should have failed for composites; #{@obj.inspect}"
50
+ end
51
+ end
52
+ end
@@ -17,6 +17,7 @@ class DummyTest < Test::Unit::TestCase
17
17
  }
18
18
 
19
19
  def setup
20
+ super
20
21
  self.class.classes = CLASSES
21
22
  end
22
23
 
@@ -40,6 +40,16 @@ class FindTest < Test::Unit::TestCase
40
40
  end
41
41
  end
42
42
 
43
+ def test_find_composite_ids
44
+ testing_with do
45
+ found = @klass.find(first_id) # e.g. find([1,1].to_composite_ids)
46
+ assert found
47
+ assert_equal @klass, found.class
48
+ assert_equal found, @klass.find(found.id)
49
+ assert_equal found, @klass.find(found.to_param)
50
+ end
51
+ end
52
+
43
53
  def test_to_param
44
54
  testing_with do
45
55
  assert_equal first_id_str, @first.to_param.to_s
@@ -1,30 +1,2 @@
1
- DROP TABLE accounts;
2
- DROP TABLE funny_jokes;
3
- DROP TABLE companies;
4
- DROP TABLE topics;
5
- DROP TABLE developers;
6
- DROP TABLE projects;
7
- DROP TABLE developers_projects;
8
- DROP TABLE customers;
9
- DROP TABLE orders;
10
- DROP TABLE movies;
11
- DROP TABLE subscribers;
12
- DROP TABLE booleantests;
13
- DROP TABLE auto_id_tests;
14
- DROP TABLE entrants;
15
- DROP TABLE colnametests;
16
- DROP TABLE mixins;
17
- DROP TABLE people;
18
- DROP TABLE readers;
19
- DROP TABLE binaries;
20
- DROP TABLE computers;
21
- DROP TABLE tasks;
22
- DROP TABLE posts;
23
- DROP TABLE comments;
24
- DROP TABLE authors;
25
- DROP TABLE categories;
26
- DROP TABLE categories_posts;
27
- DROP TABLE fk_test_has_fk;
28
- DROP TABLE fk_test_has_pk;
29
- DROP TABLE keyboards;
30
- DROP TABLE legacy_things;
1
+ DROP TABLE reference_codes;
2
+ DROP TABLE reference_types;
@@ -14,3 +14,24 @@ CREATE TABLE `reference_codes` (
14
14
  `description` varchar(50) default NULL,
15
15
  PRIMARY KEY (`reference_type_id`,`reference_code`)
16
16
  ) TYPE=InnoDB;
17
+
18
+ CREATE TABLE `products` (
19
+ `id` int(11) NOT NULL auto_increment,
20
+ `name` varchar(50) default NULL,
21
+ PRIMARY KEY (`id`)
22
+ ) TYPE=InnoDB;
23
+
24
+ CREATE TABLE `tariffs` (
25
+ `tariff_id` int(11) NOT NULL,
26
+ `start_date` date NOT NULL,
27
+ `amount` integer(11) default NULL,
28
+ PRIMARY KEY (`tariff_id`,`start_date`)
29
+ ) TYPE=InnoDB;
30
+
31
+ CREATE TABLE `product_tariffs` (
32
+ `product_id` int(11) NOT NULL,
33
+ `tariff_id` int(11) NOT NULL,
34
+ `tariff_start_date` date NOT NULL,
35
+ PRIMARY KEY (`product_id`,`tariff_id`,`tariff_start_date`)
36
+ ) TYPE=InnoDB;
37
+
@@ -0,0 +1,5 @@
1
+ class Product < ActiveRecord::Base
2
+ set_primary_key :id # redundant
3
+ has_many :product_tariffs, :foreign_key => :product_id
4
+ has_many :tariffs, :through => :product_tariffs, :foreign_key => :product_id
5
+ end
@@ -0,0 +1,5 @@
1
+ class ProductTariff < ActiveRecord::Base
2
+ set_primary_keys :product_id, :tariff_id, :tariff_start_date
3
+ belongs_to :product, :foreign_key => :product_id
4
+ belongs_to :tariff, :foreign_key => [:tariff_id, :tariff_start_date]
5
+ end
@@ -0,0 +1,12 @@
1
+ first_flat:
2
+ product_id: 1
3
+ tariff_id: 1
4
+ tariff_start_date: <%= Date.today.to_s(:db) %>
5
+ first_free:
6
+ product_id: 1
7
+ tariff_id: 2
8
+ tariff_start_date: <%= Date.today.to_s(:db) %>
9
+ second_free:
10
+ product_id: 2
11
+ tariff_id: 2
12
+ tariff_start_date: <%= Date.today.to_s(:db) %>
@@ -0,0 +1,6 @@
1
+ first_product:
2
+ id: 1
3
+ name: Product One
4
+ second_product:
5
+ id: 2
6
+ name: Product Two
@@ -0,0 +1,4 @@
1
+ class Tariff < ActiveRecord::Base
2
+ set_primary_keys [:tariff_id, :start_date]
3
+ has_many :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
4
+ end
@@ -0,0 +1,13 @@
1
+ flat:
2
+ tariff_id: 1
3
+ start_date: <%= Date.today.to_s(:db) %>
4
+ amount: 50
5
+ free:
6
+ tariff_id: 2
7
+ start_date: <%= Date.today.to_s(:db) %>
8
+ amount: 0
9
+ flat_future:
10
+ tariff_id: 1
11
+ start_date: <%= Date.today.next.to_s(:db) %>
12
+ amount: 100
13
+
@@ -42,6 +42,33 @@ class IdsTest < Test::Unit::TestCase
42
42
  end
43
43
  end
44
44
 
45
+ def test_set_ids_string
46
+ testing_with do
47
+ array = @primary_keys.collect {|key| 5}
48
+ expected = composite? ? array.to_composite_keys : array.first
49
+ @first.id = expected.to_s
50
+ assert_equal expected, @first.id
51
+ end
52
+ end
53
+
54
+ def test_set_ids_array
55
+ testing_with do
56
+ array = @primary_keys.collect {|key| 5}
57
+ expected = composite? ? array.to_composite_keys : array.first
58
+ @first.id = expected
59
+ assert_equal expected, @first.id
60
+ end
61
+ end
62
+
63
+ def test_set_ids_comp
64
+ testing_with do
65
+ array = @primary_keys.collect {|key| 5}
66
+ expected = composite? ? array.to_composite_keys : array.first
67
+ @first.id = expected
68
+ assert_equal expected, @first.id
69
+ end
70
+ end
71
+
45
72
  def test_primary_keys
46
73
  testing_with do
47
74
  if composite?
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: composite_primary_keys
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.2
7
- date: 2006-07-23 00:00:00 +02:00
6
+ version: 0.3.3
7
+ date: 2006-07-30 00:00:00 +02:00
8
8
  summary: Support for composite primary keys in ActiveRecords
9
9
  require_paths:
10
10
  - lib
@@ -34,10 +34,12 @@ files:
34
34
  - CHANGELOG
35
35
  - lib/composite_primary_keys
36
36
  - lib/composite_primary_keys.rb
37
- - lib/composite_primary_keys/fixtures.rb
38
37
  - lib/composite_primary_keys/composite_arrays.rb
39
38
  - lib/composite_primary_keys/version.rb
40
39
  - lib/composite_primary_keys/base.rb
40
+ - lib/composite_primary_keys/fixtures.rb
41
+ - lib/composite_primary_keys/reflection.rb
42
+ - lib/composite_primary_keys/associations.rb
41
43
  - test/connections
42
44
  - test/fixtures
43
45
  - test/composite_arrays_test.rb
@@ -51,6 +53,9 @@ files:
51
53
  - test/pagination_test.rb
52
54
  - test/dummy_test.rb
53
55
  - test/clone_test.rb
56
+ - test/associations_test.rb
57
+ - test/attributes_test.rb
58
+ - test/create_test.rb
54
59
  - test/connections/native_mysql
55
60
  - test/connections/native_mysql/connection.rb
56
61
  - test/fixtures/reference_type.rb
@@ -58,10 +63,14 @@ files:
58
63
  - test/fixtures/reference_types.yml
59
64
  - test/fixtures/reference_codes.yml
60
65
  - test/fixtures/db_definitions
66
+ - test/fixtures/product.rb
67
+ - test/fixtures/product_tariff.rb
68
+ - test/fixtures/tariff.rb
69
+ - test/fixtures/products.yml
70
+ - test/fixtures/tariffs.yml
71
+ - test/fixtures/product_tariffs.yml
61
72
  - test/fixtures/db_definitions/mysql.drop.sql
62
73
  - test/fixtures/db_definitions/mysql.sql
63
- - test/fixtures/db_definitions/mysql2.drop.sql
64
- - test/fixtures/db_definitions/mysql2.sql
65
74
  test_files: []
66
75
 
67
76
  rdoc_options:
@@ -1,2 +0,0 @@
1
- DROP TABLE courses;
2
-
@@ -1,5 +0,0 @@
1
- CREATE TABLE `courses` (
2
- `id` INTEGER NOT NULL PRIMARY KEY,
3
- `name` VARCHAR(255) NOT NULL
4
- ) TYPE=InnoDB;
5
-