tenacity 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/EXTEND.rdoc +9 -13
  2. data/Rakefile +6 -0
  3. data/history.txt +17 -0
  4. data/lib/tenacity.rb +13 -9
  5. data/lib/tenacity/associate_proxy.rb +56 -0
  6. data/lib/tenacity/associates_proxy.rb +5 -3
  7. data/lib/tenacity/association.rb +81 -9
  8. data/lib/tenacity/associations/belongs_to.rb +28 -16
  9. data/lib/tenacity/associations/has_many.rb +113 -53
  10. data/lib/tenacity/associations/has_one.rb +33 -14
  11. data/lib/tenacity/class_methods.rb +117 -9
  12. data/lib/tenacity/errors.rb +9 -0
  13. data/lib/tenacity/instance_methods.rb +40 -3
  14. data/lib/tenacity/orm_ext/activerecord.rb +114 -95
  15. data/lib/tenacity/orm_ext/couchrest.rb +132 -113
  16. data/lib/tenacity/orm_ext/datamapper.rb +138 -112
  17. data/lib/tenacity/orm_ext/helpers.rb +36 -0
  18. data/lib/tenacity/orm_ext/mongo_mapper.rb +102 -84
  19. data/lib/tenacity/orm_ext/mongoid.rb +106 -87
  20. data/lib/tenacity/orm_ext/sequel.rb +137 -110
  21. data/lib/tenacity/version.rb +1 -1
  22. data/tenacity.gemspec +2 -1
  23. data/test/association_features/belongs_to_test.rb +46 -1
  24. data/test/association_features/has_many_test.rb +187 -2
  25. data/test/association_features/has_one_test.rb +57 -2
  26. data/test/associations/belongs_to_test.rb +41 -7
  27. data/test/associations/has_many_test.rb +59 -10
  28. data/test/associations/has_one_test.rb +57 -2
  29. data/test/fixtures/active_record_car.rb +5 -4
  30. data/test/fixtures/active_record_climate_control_unit.rb +1 -0
  31. data/test/fixtures/active_record_engine.rb +1 -0
  32. data/test/fixtures/active_record_has_many_target.rb +7 -0
  33. data/test/fixtures/active_record_has_one_target.rb +7 -0
  34. data/test/fixtures/active_record_object.rb +19 -0
  35. data/test/fixtures/couch_rest_has_many_target.rb +7 -0
  36. data/test/fixtures/couch_rest_has_one_target.rb +7 -0
  37. data/test/fixtures/couch_rest_object.rb +14 -0
  38. data/test/fixtures/data_mapper_has_many_target.rb +23 -3
  39. data/test/fixtures/data_mapper_has_one_target.rb +23 -3
  40. data/test/fixtures/data_mapper_object.rb +14 -0
  41. data/test/fixtures/mongo_mapper_air_filter.rb +6 -0
  42. data/test/fixtures/mongo_mapper_alternator.rb +7 -0
  43. data/test/fixtures/mongo_mapper_autosave_false_has_many_target.rb +8 -0
  44. data/test/fixtures/mongo_mapper_autosave_false_has_one_target.rb +8 -0
  45. data/test/fixtures/mongo_mapper_autosave_true_has_many_target.rb +8 -0
  46. data/test/fixtures/mongo_mapper_autosave_true_has_one_target.rb +8 -0
  47. data/test/fixtures/mongo_mapper_circuit_board.rb +6 -0
  48. data/test/fixtures/mongo_mapper_dashboard.rb +5 -2
  49. data/test/fixtures/mongo_mapper_has_many_target.rb +7 -0
  50. data/test/fixtures/mongo_mapper_has_one_target.rb +7 -0
  51. data/test/fixtures/mongo_mapper_object.rb +14 -0
  52. data/test/fixtures/mongo_mapper_wheel.rb +2 -0
  53. data/test/fixtures/mongo_mapper_windows.rb +6 -0
  54. data/test/fixtures/mongoid_has_many_target.rb +7 -0
  55. data/test/fixtures/mongoid_has_one_target.rb +7 -0
  56. data/test/fixtures/mongoid_object.rb +14 -0
  57. data/test/fixtures/sequel_has_many_target.rb +7 -0
  58. data/test/fixtures/sequel_has_one_target.rb +7 -0
  59. data/test/fixtures/sequel_object.rb +14 -0
  60. data/test/helpers/active_record_test_helper.rb +87 -8
  61. data/test/helpers/couch_rest_test_helper.rb +7 -0
  62. data/test/helpers/data_mapper_test_helper.rb +41 -3
  63. data/test/helpers/sequel_test_helper.rb +65 -9
  64. data/test/orm_ext/activerecord_test.rb +1 -1
  65. data/test/orm_ext/datamapper_test.rb +33 -24
  66. data/test/orm_ext/mongo_mapper_test.rb +6 -6
  67. data/test/orm_ext/mongoid_test.rb +6 -6
  68. data/test/orm_ext/sequel_test.rb +1 -1
  69. data/test/test_helper.rb +18 -9
  70. metadata +119 -55
@@ -0,0 +1,36 @@
1
+ module Tenacity
2
+ module OrmExt
3
+ module Helpers #:nodoc:
4
+
5
+ def id_class_for(association)
6
+ if association.polymorphic?
7
+ String
8
+ elsif association.type == :belongs_to
9
+ association.source._t_id_type
10
+ else
11
+ association.associate_class._t_id_type
12
+ end
13
+ end
14
+
15
+ def _t_serialize_ids(ids)
16
+ if ids.respond_to?(:map)
17
+ ids.map { |id| _t_serialize(id) }
18
+ else
19
+ _t_serialize(ids)
20
+ end
21
+ end
22
+
23
+ def _t_serialize_id_for_sql(id)
24
+ return id if id.nil?
25
+
26
+ serialized_id = _t_serialize(id)
27
+ if serialized_id.class == String
28
+ "'#{serialized_id}'"
29
+ else
30
+ serialized_id
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -1,105 +1,123 @@
1
1
  module Tenacity
2
- # Tenacity relationships on MongoMapper objects require no special keys
3
- # defined on the object. Tenacity will define the keys that it needs
4
- # to support the relationships. Take the following class for example:
5
- #
6
- # class Car < ActiveRecord::Base
7
- # include MongoMapper::Document
8
- # include Tenacity
9
- #
10
- # t_has_many :wheels
11
- # t_has_one :dashboard
12
- # t_belongs_to :driver
13
- # end
14
- #
15
- # == t_belongs_to
16
- #
17
- # The +t_belongs_to+ association will define a key named after the association.
18
- # The example above will create a key named <tt>:driver_id</tt>
19
- #
20
- #
21
- # == t_has_one
22
- #
23
- # The +t_has_one+ association will not define any new keys on the object, since
24
- # the associated object holds the foreign key.
25
- #
26
- #
27
- # == t_has_many
28
- #
29
- # The +t_has_many+ association will define a key named after the association.
30
- # The example above will create a key named <tt>:wheels_ids</tt>
31
- #
32
- module MongoMapper
33
-
34
- def self.setup(model) #:nodoc:
35
- require 'mongo_mapper'
36
- if model.included_modules.include?(::MongoMapper::Document)
37
- model.send :include, MongoMapper::InstanceMethods
38
- model.extend MongoMapper::ClassMethods
39
- end
40
- rescue LoadError
41
- # MongoMapper not available
42
- end
2
+ module OrmExt
3
+ # Tenacity relationships on MongoMapper objects require no special keys
4
+ # defined on the object. Tenacity will define the keys that it needs
5
+ # to support the relationships. Take the following class for example:
6
+ #
7
+ # class Car < ActiveRecord::Base
8
+ # include MongoMapper::Document
9
+ # include Tenacity
10
+ #
11
+ # t_has_many :wheels
12
+ # t_has_one :dashboard
13
+ # t_belongs_to :driver
14
+ # end
15
+ #
16
+ # == t_belongs_to
17
+ #
18
+ # The +t_belongs_to+ association will define a key named after the association.
19
+ # The example above will create a key named <tt>:driver_id</tt>
20
+ #
21
+ #
22
+ # == t_has_one
23
+ #
24
+ # The +t_has_one+ association will not define any new keys on the object, since
25
+ # the associated object holds the foreign key.
26
+ #
27
+ #
28
+ # == t_has_many
29
+ #
30
+ # The +t_has_many+ association will define a key named after the association.
31
+ # The example above will create a key named <tt>:wheels_ids</tt>
32
+ #
33
+ module MongoMapper
43
34
 
44
- module ClassMethods #:nodoc:
45
- def _t_find(id)
46
- find(id)
35
+ def self.setup(model) #:nodoc:
36
+ require 'mongo_mapper'
37
+ if model.included_modules.include?(::MongoMapper::Document)
38
+ model.send :include, MongoMapper::InstanceMethods
39
+ model.extend MongoMapper::ClassMethods
40
+ end
41
+ rescue LoadError
42
+ # MongoMapper not available
47
43
  end
48
44
 
49
- def _t_find_bulk(ids=[])
50
- find(ids)
51
- end
45
+ module ClassMethods #:nodoc:
46
+ include Tenacity::OrmExt::Helpers
52
47
 
53
- def _t_find_first_by_associate(property, id)
54
- first(property => id.to_s)
55
- end
48
+ def _t_id_type
49
+ String
50
+ end
56
51
 
57
- def _t_find_all_by_associate(property, id)
58
- all(property => id.to_s)
59
- end
52
+ def _t_find(id)
53
+ find(_t_serialize(id))
54
+ end
60
55
 
61
- def _t_initialize_has_many_association(association)
62
- unless self.respond_to?(association.foreign_keys_property)
63
- key association.foreign_keys_property, Array
64
- after_save { |record| _t_save_associates(record, association) }
56
+ def _t_find_bulk(ids=[])
57
+ find(_t_serialize_ids(ids))
65
58
  end
66
- end
67
59
 
68
- def _t_initialize_belongs_to_association(association)
69
- unless self.respond_to?(association.foreign_key)
70
- key association.foreign_key, String
71
- before_save { |record| _t_stringify_belongs_to_value(record, association) }
60
+ def _t_find_first_by_associate(property, id)
61
+ first(property => _t_serialize(id))
72
62
  end
73
- end
74
63
 
75
- def _t_delete(ids, run_callbacks=true)
76
- if run_callbacks
77
- destroy(ids)
78
- else
79
- delete(ids)
64
+ def _t_find_all_by_associate(property, id)
65
+ all(property => _t_serialize(id))
80
66
  end
81
- end
82
- end
83
67
 
84
- module InstanceMethods #:nodoc:
85
- def _t_reload
86
- reload
87
- rescue ::MongoMapper::DocumentNotFound
88
- nil
89
- end
68
+ def _t_initialize_tenacity
69
+ after_save { |record| record._t_save_autosave_associations }
70
+ end
90
71
 
91
- def _t_associate_many(association, associate_ids)
92
- self.send(association.foreign_keys_property + '=', associate_ids.map { |associate_id| associate_id.to_s })
93
- end
72
+ def _t_initialize_has_one_association(association)
73
+ after_destroy { |record| record._t_cleanup_has_one_association(association) }
74
+ end
75
+
76
+ def _t_initialize_has_many_association(association)
77
+ unless self.respond_to?(association.foreign_keys_property)
78
+ key association.foreign_keys_property, Array
79
+ after_save { |record| _t_save_associates(record, association) }
80
+ after_destroy { |record| record._t_cleanup_has_many_association(association) }
81
+ end
82
+ end
83
+
84
+ def _t_initialize_belongs_to_association(association)
85
+ unless self.respond_to?(association.foreign_key)
86
+ key association.foreign_key, id_class_for(association)
87
+ key association.polymorphic_type, String if association.polymorphic?
88
+ after_destroy { |record| record._t_cleanup_belongs_to_association(association) }
89
+ end
90
+ end
94
91
 
95
- def _t_get_associate_ids(association)
96
- self.send(association.foreign_keys_property)
92
+ def _t_delete(ids, run_callbacks=true)
93
+ if run_callbacks
94
+ destroy(_t_serialize_ids(ids))
95
+ else
96
+ delete(_t_serialize_ids(ids))
97
+ end
98
+ end
97
99
  end
98
100
 
99
- def _t_clear_associates(association)
100
- self.send(association.foreign_keys_property + '=', [])
101
+ module InstanceMethods #:nodoc:
102
+ def _t_reload
103
+ reload
104
+ rescue ::MongoMapper::DocumentNotFound
105
+ nil
106
+ end
107
+
108
+ def _t_associate_many(association, associate_ids)
109
+ self.send(association.foreign_keys_property + '=', associate_ids)
110
+ end
111
+
112
+ def _t_get_associate_ids(association)
113
+ self.send(association.foreign_keys_property)
114
+ end
115
+
116
+ def _t_clear_associates(association)
117
+ self.send(association.foreign_keys_property + '=', [])
118
+ end
101
119
  end
102
- end
103
120
 
121
+ end
104
122
  end
105
123
  end
@@ -1,108 +1,127 @@
1
1
  module Tenacity
2
- # Tenacity relationships on Mongoid objects require no special keys
3
- # defined on the object. Tenacity will define the keys that it needs
4
- # to support the relationships. Take the following class for example:
5
- #
6
- # class Car
7
- # include Mongoid::Document
8
- # include Tenacity
9
- #
10
- # t_has_many :wheels
11
- # t_has_one :dashboard
12
- # t_belongs_to :driver
13
- # end
14
- #
15
- # == t_belongs_to
16
- #
17
- # The +t_belongs_to+ association will define a key named after the association.
18
- # The example above will create a key named <tt>:driver_id</tt>
19
- #
20
- #
21
- # == t_has_one
22
- #
23
- # The +t_has_one+ association will not define any new keys on the object, since
24
- # the associated object holds the foreign key.
25
- #
26
- #
27
- # == t_has_many
28
- #
29
- # The +t_has_many+ association will define a key named after the association.
30
- # The example above will create a key named <tt>:wheels_ids</tt>
31
- #
32
- module Mongoid
33
-
34
- def self.setup(model) #:nodoc:
35
- require 'mongoid'
36
- if model.included_modules.include?(::Mongoid::Document)
37
- model.send :include, Mongoid::InstanceMethods
38
- model.extend Mongoid::ClassMethods
39
- end
40
- rescue LoadError
41
- # Mongoid not available
42
- end
2
+ module OrmExt
3
+ # Tenacity relationships on Mongoid objects require no special keys
4
+ # defined on the object. Tenacity will define the keys that it needs
5
+ # to support the relationships. Take the following class for example:
6
+ #
7
+ # class Car
8
+ # include Mongoid::Document
9
+ # include Tenacity
10
+ #
11
+ # t_has_many :wheels
12
+ # t_has_one :dashboard
13
+ # t_belongs_to :driver
14
+ # end
15
+ #
16
+ # == t_belongs_to
17
+ #
18
+ # The +t_belongs_to+ association will define a key named after the association.
19
+ # The example above will create a key named <tt>:driver_id</tt>
20
+ #
21
+ #
22
+ # == t_has_one
23
+ #
24
+ # The +t_has_one+ association will not define any new keys on the object, since
25
+ # the associated object holds the foreign key.
26
+ #
27
+ #
28
+ # == t_has_many
29
+ #
30
+ # The +t_has_many+ association will define a key named after the association.
31
+ # The example above will create a key named <tt>:wheels_ids</tt>
32
+ #
33
+ module Mongoid
43
34
 
44
- module ClassMethods #:nodoc:
45
- def _t_find(id)
46
- (id.nil? || id.to_s.strip == "") ? nil : find(id)
47
- rescue ::Mongoid::Errors::DocumentNotFound
48
- nil
35
+ def self.setup(model) #:nodoc:
36
+ require 'mongoid'
37
+ if model.included_modules.include?(::Mongoid::Document)
38
+ model.send :include, Mongoid::InstanceMethods
39
+ model.extend Mongoid::ClassMethods
40
+ end
41
+ rescue LoadError
42
+ # Mongoid not available
49
43
  end
50
44
 
51
- def _t_find_bulk(ids)
52
- find(ids)
53
- rescue ::Mongoid::Errors::DocumentNotFound
54
- []
55
- end
45
+ module ClassMethods #:nodoc:
46
+ include Tenacity::OrmExt::Helpers
56
47
 
57
- def _t_find_first_by_associate(property, id)
58
- find(:first, :conditions => { property => id })
59
- end
48
+ def _t_id_type
49
+ String
50
+ end
60
51
 
61
- def _t_find_all_by_associate(property, id)
62
- find(:all, :conditions => { property => id })
63
- end
52
+ def _t_find(id)
53
+ (id.nil? || id.to_s.strip == "") ? nil : find(_t_serialize(id))
54
+ rescue ::Mongoid::Errors::DocumentNotFound
55
+ nil
56
+ end
64
57
 
65
- def _t_initialize_has_many_association(association)
66
- unless self.respond_to?(association.foreign_keys_property)
67
- field association.foreign_keys_property, :type => Array
68
- after_save { |record| self.class._t_save_associates(record, association) }
58
+ def _t_find_bulk(ids)
59
+ docs = find(_t_serialize_ids(ids))
60
+ docs.respond_to?(:each) ? docs : [docs]
61
+ rescue ::Mongoid::Errors::DocumentNotFound
62
+ []
69
63
  end
70
- end
71
64
 
72
- def _t_initialize_belongs_to_association(association)
73
- unless self.respond_to?(association.foreign_key)
74
- field association.foreign_key, :type => String
75
- before_save { |record| self.class._t_stringify_belongs_to_value(record, association) }
65
+ def _t_find_first_by_associate(property, id)
66
+ find(:first, :conditions => { property => _t_serialize(id) })
76
67
  end
77
- end
78
68
 
79
- def _t_delete(ids, run_callbacks=true)
80
- docs = _t_find_bulk(ids)
81
- if run_callbacks
82
- docs.each { |doc| doc.destroy }
83
- else
84
- docs.each { |doc| doc.delete }
69
+ def _t_find_all_by_associate(property, id)
70
+ find(:all, :conditions => { property => _t_serialize(id) })
85
71
  end
86
- end
87
- end
88
72
 
89
- module InstanceMethods #:nodoc:
90
- def _t_reload
91
- reload
92
- end
73
+ def _t_initialize_tenacity
74
+ after_save { |record| record._t_save_autosave_associations }
75
+ end
93
76
 
94
- def _t_associate_many(association, associate_ids)
95
- self.send(association.foreign_keys_property + '=', associate_ids.map { |associate_id| associate_id.to_s })
96
- end
77
+ def _t_initialize_has_one_association(association)
78
+ after_destroy { |record| record._t_cleanup_has_one_association(association) }
79
+ end
80
+
81
+ def _t_initialize_has_many_association(association)
82
+ unless self.respond_to?(association.foreign_keys_property)
83
+ field association.foreign_keys_property, :type => Array
84
+ after_save { |record| self.class._t_save_associates(record, association) }
85
+ after_destroy { |record| record._t_cleanup_has_many_association(association) }
86
+ end
87
+ end
88
+
89
+ def _t_initialize_belongs_to_association(association)
90
+ unless self.respond_to?(association.foreign_key)
91
+ field association.foreign_key, :type => id_class_for(association)
92
+ field association.polymorphic_type, :type => String if association.polymorphic?
93
+ after_destroy { |record| record._t_cleanup_belongs_to_association(association) }
94
+ end
95
+ end
97
96
 
98
- def _t_get_associate_ids(association)
99
- self.send(association.foreign_keys_property)
97
+ def _t_delete(ids, run_callbacks=true)
98
+ docs = _t_find_bulk(ids)
99
+ if run_callbacks
100
+ docs.each { |doc| doc.destroy }
101
+ else
102
+ docs.each { |doc| doc.delete }
103
+ end
104
+ end
100
105
  end
101
106
 
102
- def _t_clear_associates(association)
103
- self.send(association.foreign_keys_property + '=', [])
107
+ module InstanceMethods #:nodoc:
108
+ def _t_reload
109
+ reload
110
+ end
111
+
112
+ def _t_associate_many(association, associate_ids)
113
+ self.send(association.foreign_keys_property + '=', associate_ids)
114
+ end
115
+
116
+ def _t_get_associate_ids(association)
117
+ self.send(association.foreign_keys_property)
118
+ end
119
+
120
+ def _t_clear_associates(association)
121
+ self.send(association.foreign_keys_property + '=', [])
122
+ end
104
123
  end
105
- end
106
124
 
125
+ end
107
126
  end
108
127
  end