public
Description: Fork of DataMapper 0.3 with patches to fix major show-stopping bugs
Clone URL: git://github.com/cardmagic/dm-works.git
Fix daesan's bug.

git-svn-id: http://datamapper.rubyforge.org/svn/trunk@671 
b9f95e1d-c398-435d-95f5-378b83d2b11d
ssmoot (author)
Thu Jan 03 19:37:49 -0800 2008
commit  23242bb74faf729053bc31acf68c91a99ea05478
tree    af6042a214838487a60fad2aeef4f38db3702a27
parent  b7c21901e527c226981f2235635195e71ab11611
...
294
295
296
297
298
 
 
 
 
 
 
 
 
 
 
 
 
299
300
301
302
303
304
305
306
...
294
295
296
 
 
297
298
299
300
301
302
303
304
305
306
307
308
309
 
 
 
 
310
311
312
0
@@ -294,13 +294,19 @@ module DataMapper
0
           "INSERT INTO #{table.to_sql}"
0
         end
0
         
0
- insert_id = connection do |db|
0
- db.create_command(sql).execute_non_query(values).last_insert_row
0
+ result = connection do |db|
0
+ db.create_command(sql).execute_non_query(values)
0
+ end
0
+
0
+ if result.to_i > 0
0
+ instance.instance_variable_set(:@new_record, false)
0
+ instance.key = result.last_insert_row if table.key.serial? && !attributes.include?(table.key.name)
0
+ database_context.identity_map.set(instance)
0
+ callback(instance, :after_create)
0
+ return true
0
+ else
0
+ return false
0
         end
0
- instance.instance_variable_set(:@new_record, false)
0
- instance.key = insert_id if table.key.serial? && !attributes.include?(table.key.name)
0
- database_context.identity_map.set(instance)
0
- callback(instance, :after_create)
0
       end
0
       
0
       MAGIC_PROPERTIES = {
...
376
377
378
379
 
 
380
381
382
 
383
384
385
...
376
377
378
 
379
380
381
382
383
384
385
386
387
0
@@ -376,10 +376,12 @@ module DataMapper
0
                 qualify_columns = qualify_columns?
0
                 @columns_for_select = []
0
                 
0
- columns.each_with_index do |column,i|
0
+ i = 0
0
+ columns.each do |column|
0
                   class_for_loader = column.table.klass
0
                   @loaders[class_for_loader].add_column(column, i) if class_for_loader
0
                   @columns_for_select << column.to_sql(qualify_columns)
0
+ i += 1
0
                 end
0
                 
0
                 @columns_for_select
...
103
104
105
106
 
107
108
109
...
103
104
105
 
106
107
108
109
0
@@ -103,7 +103,7 @@ module DataMapper
0
 
0
               @instance.database_context.all(association.constant, association.associated_table.key.to_sym => set.keys).each do |assoc|
0
                 set[assoc.key].each do |primary_instance|
0
- primary_instance.send(setter_method, assoc)
0
+ primary_instance.send("#{@association_name}_association").shallow_append(assoc)
0
                 end
0
               end
0
 
...
30
31
32
33
 
34
35
36
...
47
48
49
50
 
51
52
53
54
 
55
56
57
58
 
 
59
60
61
62
63
64
 
 
65
66
67
 
68
69
70
71
 
72
73
74
75
76
77
78
79
80
 
 
 
 
81
82
83
...
120
121
122
123
 
 
 
 
 
124
125
126
...
154
155
156
157
158
159
160
...
165
166
167
168
169
170
 
 
 
 
 
 
 
 
 
 
171
172
173
...
188
189
190
 
 
 
 
 
 
 
 
191
192
193
...
30
31
32
 
33
34
35
36
...
47
48
49
 
50
51
52
53
 
54
55
56
 
 
57
58
59
60
61
62
63
64
65
66
67
68
 
69
70
71
 
 
72
73
74
75
76
77
 
 
 
 
78
79
80
81
82
83
84
...
121
122
123
 
124
125
126
127
128
129
130
131
...
159
160
161
 
162
163
164
...
169
170
171
 
 
172
173
174
175
176
177
178
179
180
181
182
183
184
185
...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
0
@@ -30,7 +30,7 @@ module DataMapper
0
       end
0
       
0
       def to_disassociate_sql
0
- "UPDATE #{associated_table.to_sql} SET #{foreign_key_column.to_sql} = NULL WHERE #{foreign_key_column.to_sql} = ?"
0
+ "UPDATE #{associated_table.to_sql} SET #{foreign_key_column.to_sql} = NULL WHERE #{foreign_key_column.to_sql} = ? AND #{associated_table.key} NOT IN ?"
0
       end
0
       
0
       def instance_variable_name
0
@@ -47,37 +47,38 @@ module DataMapper
0
         
0
         # Returns true if the association has zero items
0
         def nil?
0
- @items.empty?
0
+ loaded_members.blank?
0
         end
0
         
0
         def dirty?
0
- @items && @items.any? { |item| item.dirty? }
0
+ loaded_members.any? { |member| member.dirty? }
0
         end
0
         
0
- def validate_recursively(event, cleared)
0
- @items.blank? || @items.all? { |item| cleared.include?(item) || item.validate_recursively(event, cleared) }
0
+ def validate_recursively(event, cleared)
0
+ loaded_members.all? { |member| cleared.include?(member) || member.validate_recursively(event, cleared) }
0
         end
0
         
0
         def save_without_validation(database_context)
0
           
0
           adapter = @instance.database_context.adapter
0
           
0
+ members = loaded_members
0
+
0
           adapter.connection do |db|
0
             command = db.create_command(association.to_disassociate_sql)
0
- command.execute_non_query(@instance.key)
0
+ command.execute_non_query(@instance.key, members.map { |member| member.key }.compact)
0
           end
0
           
0
- unless @items.nil? || @items.empty?
0
-
0
+ unless members.blank?
0
             
0
             setter_method = "#{@association_name}=".to_sym
0
             ivar_name = association.foreign_key_column.instance_variable_name
0
             original_value_name = association.foreign_key_column.name
0
             
0
- @items.each do |item|
0
- item.original_values.delete(original_value_name)
0
- item.instance_variable_set(ivar_name, @instance.key)
0
- @instance.database_context.adapter.save_without_validation(database_context, item)
0
+ members.each do |member|
0
+ member.original_values.delete(original_value_name)
0
+ member.instance_variable_set(ivar_name, @instance.key)
0
+ @instance.database_context.adapter.save_without_validation(database_context, member)
0
             end
0
           end
0
         end
0
@@ -120,7 +121,11 @@ module DataMapper
0
         end
0
         
0
         def shallow_append(member)
0
- self.items << member
0
+ if @items
0
+ self.items << member
0
+ else
0
+ pending_members << member
0
+ end
0
           return self
0
         end
0
         
0
@@ -154,7 +159,6 @@ module DataMapper
0
           @items || begin
0
             if @instance.loaded_set.nil?
0
               @items = Support::TypedSet.new(association.associated_constant)
0
- return @items
0
             else
0
               associated_items = fetch_sets
0
               
0
@@ -165,9 +169,17 @@ module DataMapper
0
               @instance.loaded_set.each do |entry|
0
                 entry.send(setter_method, associated_items[entry.key])
0
               end # @instance.loaded_set.each
0
-
0
- return @items
0
             end # if @instance.loaded_set.nil?
0
+
0
+ if @pending_members
0
+ pending_members.each do |member|
0
+ @items << member
0
+ end
0
+
0
+ pending_members.clear
0
+ end
0
+
0
+ return @items
0
           end # begin
0
         end # def items
0
         
0
@@ -188,6 +200,14 @@ module DataMapper
0
         end
0
         
0
         private
0
+ def loaded_members
0
+ pending_members + @items
0
+ end
0
+
0
+ def pending_members
0
+ @pending_members || @pending_members = Support::TypedSet.new(association.associated_constant)
0
+ end
0
+
0
         def fetch_sets
0
           finder_options = { association.foreign_key_column.to_sym => @instance.loaded_set.map { |item| item.key } }
0
           finder_options.merge!(association.finder_options)
...
7
8
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
11
12
13
 
14
15
 
16
17
18
...
27
28
29
30
31
 
32
33
34
 
35
36
37
38
39
40
 
 
 
 
 
 
 
 
 
 
41
42
43
44
...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 
34
35
 
36
37
38
39
...
48
49
50
 
 
51
52
53
 
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
0
@@ -7,12 +7,33 @@ module DataMapper
0
     end
0
     
0
     def attributes
0
+ __get_attributes(true)
0
+ end
0
+
0
+ # Mass-assign mapped fields.
0
+ def attributes=(values_hash)
0
+ __set_attributes(values_hash, true)
0
+ end
0
+
0
+ private
0
+
0
+ def __method_defined?(name, public_only = true)
0
+ if public_only
0
+ self.class.public_method_defined?(name)
0
+ else
0
+ self.class.private_method_defined?(name) ||
0
+ self.class.protected_method_defined?(name) ||
0
+ self.class.public_method_defined?(name)
0
+ end
0
+ end
0
+
0
+ def __get_attributes(public_only)
0
       pairs = {}
0
       
0
       self.class::ATTRIBUTES.each do |name|
0
- getter = if self.class.public_method_defined?(name)
0
+ getter = if __method_defined?(name, public_only)
0
           name
0
- elsif self.class.public_method_defined?(name.to_s.ensure_ends_with('?'))
0
+ elsif __method_defined?(name.to_s.ensure_ends_with('?'), public_only)
0
           name.to_s.ensure_ends_with('?')
0
         else
0
           nil
0
@@ -27,17 +48,26 @@ module DataMapper
0
       pairs
0
     end
0
     
0
- # Mass-assign mapped fields.
0
- def attributes=(values_hash)
0
+ def __set_attributes(values_hash, public_only)
0
       values_hash.each_pair do |k,v|
0
         setter_name = k.to_s.sub(/\?$/, '').ensure_ends_with('=')
0
- if self.class.public_method_defined?(setter_name)
0
+ if __method_defined?(setter_name, public_only)
0
           send(setter_name, v)
0
         end
0
       end
0
       
0
       self
0
     end
0
+
0
+ # return all attributes, regardless of their visibility
0
+ def private_attributes
0
+ __get_attributes(false)
0
+ end
0
+
0
+ # private method for setting any/all attribute values, regardless of visibility
0
+ def private_attributes=(values_hash)
0
+ __set_attributes(values_hash, false)
0
+ end
0
   end
0
   
0
 end
0
\ No newline at end of file
...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
...
455
456
457
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
459
0
@@ -455,33 +455,5 @@ module DataMapper
0
       
0
       results
0
     end
0
-
0
- private
0
-
0
- # return all attributes, regardless of their visibility
0
- def private_attributes
0
- pairs = {}
0
-
0
- database_context.table(self).columns.each do |column|
0
- lazy_load!(column.name) if column.lazy?
0
- value = instance_variable_get(column.instance_variable_name)
0
- pairs[column.name] = column.type == :class ? value.to_s : value
0
- end
0
-
0
- pairs
0
- end
0
-
0
- # private method for setting any/all attribute values, regardless of visibility
0
- def private_attributes=(values_hash)
0
- table = database_context.table(self.class)
0
-
0
- values_hash.each_pair do |key, value|
0
- if respond_to?(key)
0
- send("#{key}=", value)
0
- elsif column = table[key]
0
- instance_variable_set(column.instance_variable_name, value)
0
- end
0
- end
0
- end
0
   end
0
 end
...
8
9
10
11
 
12
13
14
...
29
30
31
32
 
33
34
 
35
36
...
8
9
10
 
11
12
13
14
...
29
30
31
 
32
33
 
34
35
36
0
@@ -8,7 +8,7 @@ module DataMapper
0
   module Support
0
     
0
     # Extends Array to include an instance method for grouping objects
0
- module Enumerable
0
+ module EnumerableExtensions
0
       
0
       # Group a collection of elements into groups within a
0
       # Hash. The value returned by the block passed to group_by
0
@@ -29,7 +29,7 @@ module DataMapper
0
   end # module Support
0
 end # module DataMapper
0
 
0
-# Extend Array with DataMapper::Support::Enumerable
0
+# Extend Array with DataMapper::Support::EnumerableExtensions
0
 class Array #:nodoc:
0
- include DataMapper::Support::Enumerable
0
+ include DataMapper::Support::EnumerableExtensions
0
 end
0
\ No newline at end of file
...
42
43
44
 
45
46
47
48
 
 
 
 
 
 
 
49
50
51
...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
0
@@ -42,10 +42,18 @@ module DataMapper
0
       def empty?
0
         @set.empty?
0
       end
0
+ alias blank? empty?
0
       
0
       def clear
0
         @set.clear
0
       end
0
+
0
+ def +(other)
0
+ x = self.class.new(*@types)
0
+ each { |entry| x << entry }
0
+ other.each { |entry| x << entry } unless other.blank?
0
+ return x
0
+ end
0
     end
0
   end
0
 end
...
15
16
17
18
 
19
20
21
...
15
16
17
 
18
19
20
21
0
@@ -15,7 +15,7 @@ end
0
 
0
 profile do
0
   1000.times do
0
- database.query("SELECT * FROM zoos")
0
+ Zoo.all.each { |zoo| zoo.name; zoo.exhibits.entries }
0
   end
0
 end
0
 
...
30
31
32
 
 
 
 
 
 
33
34
35
...
30
31
32
33
34
35
36
37
38
39
40
41
0
@@ -30,6 +30,12 @@ describe DataMapper::Associations::HasManyAssociation do
0
     section.project.should be_nil
0
   end
0
   
0
+ it "assignment should not force associated items to load" do
0
+ dallas = Zoo.first(:name => 'Dallas')
0
+ Exhibit.new(:name => 'Weasel World!', :zoo => dallas)
0
+ dallas.exhibits.instance_variable_get('@items').should be_nil
0
+ end
0
+
0
   it "should return an empty Enumerable for new objects" do
0
     project = Project.new
0
     project.sections.should be_a_kind_of(Enumerable)
...
17
18
19
 
 
 
 
20
21
22
...
17
18
19
20
21
22
23
24
25
26
0
@@ -17,6 +17,10 @@ class Tomato
0
   
0
   property :name, :string
0
   
0
+ def heal!
0
+ @bruised = false
0
+ end
0
+
0
   def bruised?
0
     @bruised
0
   end
...
7
8
9
 
 
10
11
...
7
8
9
10
11
12
13
0
@@ -7,4 +7,6 @@ class User < DataMapper::Base
0
   property :name, :string
0
   property :email, :string, :format => :email_address
0
   has_many :comments, :class => 'Comment', :foreign_key => 'user_id'
0
+
0
+ after_create { false }
0
 end
0
\ No newline at end of file
...
295
296
297
 
 
 
 
 
 
298
299
300
...
318
319
320
 
 
321
322
323
324
325
 
 
326
327
328
...
295
296
297
298
299
300
301
302
303
304
305
306
...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
0
@@ -295,6 +295,12 @@ describe 'Properties' do
0
     end.should raise_error(ArgumentError)
0
   end
0
   
0
+ it "should return true on saving a new record" do
0
+ bob = User.new(:name => 'bob', :email => 'bob@example.com')
0
+ bob.save!.should == true
0
+ bob.destroy!
0
+ end
0
+
0
   it "should assign to public setters" do
0
     x = Project.new
0
     x.attributes = { :set_us_up_the_bomb => true }
0
@@ -318,11 +324,15 @@ describe 'Properties' do
0
     x.save!
0
     
0
     x2 = Tomato.first(:name => 'Bob')
0
+ x2.should_not == x
0
+ x2.heal!
0
     x2.should == x
0
     x2.name.should eql('Bob')
0
     x2.should_not be_initialized
0
     
0
     x3 = Tomato.get(x.key)
0
+ x3.should_not == x
0
+ x3.heal!
0
     x3.should == x
0
     x3.name.should eql('Bob')
0
     x3.should_not be_initialized
...
41
42
43
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
45
...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
0
@@ -41,4 +41,26 @@ describe DataMapper::Support::TypedSet do
0
     s.entries.last.should eql(30)
0
   end
0
   
0
+ it "should respond to blank?" do
0
+ s = DataMapper::Support::TypedSet.new(Numeric)
0
+ s.should be_blank
0
+
0
+ s << 4
0
+ s.should_not be_blank
0
+ end
0
+
0
+ it "should return the combined entries for two sets" do
0
+ a = DataMapper::Support::TypedSet.new(Numeric)
0
+ b = DataMapper::Support::TypedSet.new(Numeric)
0
+
0
+ a << 1 << 2 << 3
0
+ b << 4 << 5 << 6 << 3
0
+
0
+ c = (a + b)
0
+ c.should have(6).entries
0
+ c.entries.should == [ 1, 2, 3, 4, 5, 6 ]
0
+
0
+ lambda { (c + nil) }.should_not raise_error
0
+ end
0
+
0
 end
0
\ No newline at end of file

Comments

    No one has commented yet.