dm-accepts_nested_attributes_for 1.2.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.
Files changed (58) hide show
  1. data/CHANGELOG +970 -0
  2. data/Gemfile +84 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +94 -0
  5. data/Rakefile +25 -0
  6. data/TODO +6 -0
  7. data/VERSION +1 -0
  8. data/dm-accepts_nested_attributes.gemspec +114 -0
  9. data/lib/dm-accepts_nested_attributes.rb +13 -0
  10. data/lib/dm-accepts_nested_attributes/model.rb +144 -0
  11. data/lib/dm-accepts_nested_attributes/relationship.rb +82 -0
  12. data/lib/dm-accepts_nested_attributes/resource.rb +382 -0
  13. data/lib/dm-accepts_nested_attributes/version.rb +7 -0
  14. data/spec/accepts_nested_attributes_for_spec.rb +408 -0
  15. data/spec/assign_nested_attributes_for_spec.rb +101 -0
  16. data/spec/comb/1-1_disjoint_spec.rb +67 -0
  17. data/spec/comb/1-1_overlapping_spec.rb +66 -0
  18. data/spec/comb/1-1_subset_spec.rb +65 -0
  19. data/spec/comb/1-1_superset_spec.rb +67 -0
  20. data/spec/comb/1-m_disjoint_spec.rb +71 -0
  21. data/spec/comb/1-m_overlapping_spec.rb +70 -0
  22. data/spec/comb/1-m_subset_spec.rb +65 -0
  23. data/spec/comb/1-m_superset_spec.rb +71 -0
  24. data/spec/comb/m-1_disjoint_spec.rb +71 -0
  25. data/spec/comb/m-1_overlapping_spec.rb +70 -0
  26. data/spec/comb/m-1_subset_spec.rb +65 -0
  27. data/spec/comb/m-1_superset_spec.rb +71 -0
  28. data/spec/comb/n-m_composite_spec.rb +141 -0
  29. data/spec/comb/n-m_surrogate_spec.rb +154 -0
  30. data/spec/many_to_many_composite_spec.rb +120 -0
  31. data/spec/many_to_many_spec.rb +129 -0
  32. data/spec/many_to_one_composite_spec.rb +120 -0
  33. data/spec/many_to_one_spec.rb +101 -0
  34. data/spec/one_to_many_composite_spec.rb +120 -0
  35. data/spec/one_to_many_spec.rb +100 -0
  36. data/spec/one_to_one_composite_spec.rb +150 -0
  37. data/spec/one_to_one_spec.rb +115 -0
  38. data/spec/rcov.opts +6 -0
  39. data/spec/resource_spec.rb +65 -0
  40. data/spec/shared/many_to_many_composite_spec.rb +149 -0
  41. data/spec/shared/many_to_many_spec.rb +146 -0
  42. data/spec/shared/many_to_one_composite_spec.rb +160 -0
  43. data/spec/shared/many_to_one_spec.rb +130 -0
  44. data/spec/shared/one_to_many_composite_spec.rb +159 -0
  45. data/spec/shared/one_to_many_spec.rb +107 -0
  46. data/spec/shared/one_to_one_composite_spec.rb +114 -0
  47. data/spec/shared/one_to_one_spec.rb +111 -0
  48. data/spec/spec.opts +4 -0
  49. data/spec/spec_helper.rb +50 -0
  50. data/spec/update_dirty_spec.rb +113 -0
  51. data/spec/update_multiple_spec.rb +79 -0
  52. data/tasks/changelog.rake +20 -0
  53. data/tasks/ci.rake +1 -0
  54. data/tasks/local_gemfile.rake +18 -0
  55. data/tasks/spec.rake +22 -0
  56. data/tasks/yard.rake +9 -0
  57. data/tasks/yardstick.rake +19 -0
  58. metadata +216 -0
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe "N:M (surrogate PK)" do
4
+ before(:all) do
5
+ class ::Person
6
+ include DataMapper::Resource
7
+ extend ConstraintSupport
8
+
9
+ property :id, Serial, :key => true
10
+ property :audit_id, Integer, :key => true, :min => 0
11
+ property :name, String, :required => true
12
+
13
+ has n, :memberships, constraint(:destroy)
14
+ has n, :projects, :through => :memberships
15
+ end
16
+
17
+ class ::Project
18
+ include DataMapper::Resource
19
+ extend ConstraintSupport
20
+
21
+ property :id, Serial, :key => true
22
+ property :audit_id, Integer, :key => true, :min => 0
23
+ property :name, String, :required => true
24
+
25
+ has n, :memberships, constraint(:destroy)
26
+ has n, :people, :through => :memberships
27
+ end
28
+
29
+ class ::Membership
30
+ include DataMapper::Resource
31
+
32
+ # keep properties unordered
33
+ property :person_audit_id, Integer, :required => true, :min => 0
34
+ property :project_audit_id, Integer, :required => true, :min => 0
35
+ property :id, Serial, :key => true
36
+ property :project_id, Integer, :required => true, :min => 0
37
+ property :person_id, Integer, :required => true, :min => 0
38
+ property :role, String
39
+
40
+ belongs_to :person
41
+ belongs_to :project
42
+ end
43
+
44
+ DataMapper.auto_migrate!
45
+ end
46
+
47
+ before(:each) do
48
+ Membership.all.destroy!
49
+ Project.all.destroy!
50
+ Person.all.destroy!
51
+ end
52
+
53
+ describe "Person.accepts_nested_attributes_for(:projects)" do
54
+ before(:all) do
55
+ Person.accepts_nested_attributes_for :projects
56
+ end
57
+
58
+ it "should allow to update an existing project via Person#projects_attributes" do
59
+ pending_if "#{DataMapper::Spec.adapter_name} doesn't support M2M", !HAS_M2M_SUPPORT do
60
+ person1 = Person.create(:id => 1, :audit_id => 10, :name => 'Martin')
61
+ project1 = Project.create(:id => 100, :audit_id => 1000, :name => 'foo')
62
+ project2 = Project.create(:id => 200, :audit_id => 2000, :name => 'bar')
63
+ Membership.create(:id => 10000, :person => person1, :project => project1, :role => 'foo-maintainer')
64
+ Membership.create(:id => 20000, :person => person1, :project => project2, :role => 'bar-contributor')
65
+ person1.reload
66
+
67
+ person2 = Person.create(:id => 2, :audit_id => 20, :name => 'John')
68
+ project3 = Project.create(:id => 300, :audit_id => 3000, :name => 'qux')
69
+ project4 = Project.create(:id => 400, :audit_id => 4000, :name => 'baz')
70
+ Membership.create(:id => 30000, :person => person2, :project => project3, :role => 'qux-maintainer')
71
+ Membership.create(:id => 40000, :person => person2, :project => project4, :role => 'baz-contributor')
72
+ person2.reload
73
+
74
+ Person.all.size.should == 2
75
+ Project.all.size.should == 4
76
+ Membership.all.size.should == 4
77
+
78
+ person1.projects_attributes = [{ :id => 100, :audit_id => 1000, :name => 'still foo' }]
79
+ person1.save.should be_true
80
+
81
+ Person.all.map { |p| [p.id, p.audit_id, p.name] }.should == [
82
+ [1, 10, 'Martin'],
83
+ [2, 20, 'John'],
84
+ ]
85
+ Project.all.map { |p| [p.id, p.audit_id, p.name] }.should == [
86
+ [100, 1000, 'still foo'],
87
+ [200, 2000, 'bar'],
88
+ [300, 3000, 'qux'],
89
+ [400, 4000, 'baz'],
90
+ ]
91
+ Membership.all.map { |m| [m.person_id, m.person_audit_id, m.project_id, m.project_audit_id, m.role] }.should == [
92
+ [1, 10, 100, 1000, 'foo-maintainer'],
93
+ [1, 10, 200, 2000, 'bar-contributor'],
94
+ [2, 20, 300, 3000, 'qux-maintainer'],
95
+ [2, 20, 400, 4000, 'baz-contributor'],
96
+ ]
97
+ end
98
+ end
99
+
100
+ it "should allow to create a new project via Person#projects_attributes" do
101
+ pending_if "#{DataMapper::Spec.adapter_name} doesn't support M2M", !HAS_M2M_SUPPORT do
102
+ person1 = Person.create(:id => 1, :audit_id => 10, :name => 'Martin')
103
+ project1 = Project.create(:id => 100, :audit_id => 1000, :name => 'foo')
104
+ project2 = Project.create(:id => 200, :audit_id => 2000, :name => 'bar')
105
+ Membership.create(:id => 10000, :person => person1, :project => project1, :role => 'foo-maintainer')
106
+ Membership.create(:id => 20000, :person => person1, :project => project2, :role => 'bar-contributor')
107
+ person1.reload
108
+
109
+ person2 = Person.create(:id => 2, :audit_id => 20, :name => 'John')
110
+ project3 = Project.create(:id => 300, :audit_id => 3000, :name => 'qux')
111
+ project4 = Project.create(:id => 400, :audit_id => 4000, :name => 'baz')
112
+ Membership.create(:id => 30000, :person => person2, :project => project3, :role => 'qux-maintainer')
113
+ Membership.create(:id => 40000, :person => person2, :project => project4, :role => 'baz-contributor')
114
+ person2.reload
115
+
116
+ Person.all.size.should == 2
117
+ Project.all.size.should == 4
118
+ Membership.all.size.should == 4
119
+
120
+ person1.projects_attributes = [{ :id => 500, :audit_id => 5000, :name => 'fibble' }]
121
+ person1.save.should be_true
122
+
123
+ Person.all.map { |p| [p.id, p.audit_id, p.name] }.should == [
124
+ [1, 10, 'Martin'],
125
+ [2, 20, 'John'],
126
+ ]
127
+ Project.all.map { |p| [p.id, p.audit_id, p.name] }.should == [
128
+ [100, 1000, 'foo'],
129
+ [200, 2000, 'bar'],
130
+ [300, 3000, 'qux'],
131
+ [400, 4000, 'baz'],
132
+ [500, 5000, 'fibble'],
133
+ ]
134
+
135
+ ids = [10000, 20000, 30000, 40000]
136
+ Membership.all(:id => ids).map { |m|
137
+ [m.id, m.person_id, m.person_audit_id, m.project_id, m.project_audit_id, m.role]
138
+ }.should == [
139
+ [10000, 1, 10, 100, 1000, 'foo-maintainer'],
140
+ [20000, 1, 10, 200, 2000, 'bar-contributor'],
141
+ [30000, 2, 20, 300, 3000, 'qux-maintainer'],
142
+ [40000, 2, 20, 400, 4000, 'baz-contributor'],
143
+ ]
144
+
145
+ # exclude the serial property
146
+ Membership.all(:id.not => ids).map { |m|
147
+ [m.person_id, m.person_audit_id, m.project_id, m.project_audit_id, m.role]
148
+ }.should == [
149
+ [1, 10, 500, 5000, nil],
150
+ ]
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Person.has(n, :projects, :through => :memberships) with CPK;" do
4
+
5
+ before(:all) do
6
+ class ::Person
7
+
8
+ include DataMapper::Resource
9
+ extend ConstraintSupport
10
+
11
+ property :id, Serial, :key => true
12
+ property :audit_id, Integer, :key => true, :min => 0
13
+ property :name, String, :required => true
14
+
15
+ has n, :memberships, constraint(:destroy)
16
+ has n, :projects, :through => :memberships
17
+
18
+ end
19
+
20
+ class ::Project
21
+
22
+ include DataMapper::Resource
23
+ extend ConstraintSupport
24
+
25
+ property :id, Serial, :key => true
26
+ property :audit_id, Integer, :key => true, :min => 0
27
+ property :name, String, :required => true
28
+
29
+ has n, :memberships, constraint(:destroy)
30
+ has n, :people, :through => :memberships
31
+
32
+ end
33
+
34
+ class ::Membership
35
+
36
+ include DataMapper::Resource
37
+
38
+ property :person_id, Integer, :key => true, :min => 0
39
+ property :person_audit_id, Integer, :key => true, :min => 0
40
+ property :project_id, Integer, :key => true, :min => 0
41
+ property :project_audit_id, Integer, :key => true, :min => 0
42
+ property :role, String, :required => false
43
+
44
+ belongs_to :person, :key => true
45
+ belongs_to :project, :key => true
46
+
47
+ end
48
+
49
+ DataMapper.auto_migrate!
50
+
51
+ end
52
+
53
+ before(:each) do
54
+ Membership.all.destroy!
55
+ Project.all.destroy!
56
+ Person.all.destroy!
57
+ end
58
+
59
+
60
+ describe "Person.accepts_nested_attributes_for(:projects)" do
61
+
62
+ before(:all) do
63
+ Person.accepts_nested_attributes_for :projects
64
+ end
65
+
66
+ it_should_behave_like "every accessible many_to_many composite association"
67
+ it_should_behave_like "every accessible many_to_many composite association with no reject_if proc"
68
+ it_should_behave_like "every accessible many_to_many composite association with :allow_destroy => false"
69
+
70
+ end
71
+
72
+ describe "Person.accepts_nested_attributes_for(:projects, :allow_destroy => false)" do
73
+
74
+ before(:all) do
75
+ Person.accepts_nested_attributes_for :projects, :allow_destroy => false
76
+ end
77
+
78
+ it_should_behave_like "every accessible many_to_many composite association"
79
+ it_should_behave_like "every accessible many_to_many composite association with no reject_if proc"
80
+ it_should_behave_like "every accessible many_to_many composite association with :allow_destroy => false"
81
+
82
+ end
83
+
84
+ describe "Person.accepts_nested_attributes_for(:projects, :allow_destroy = true)" do
85
+
86
+ before(:all) do
87
+ Person.accepts_nested_attributes_for :projects, :allow_destroy => true
88
+ end
89
+
90
+ it_should_behave_like "every accessible many_to_many composite association"
91
+ it_should_behave_like "every accessible many_to_many composite association with no reject_if proc"
92
+ it_should_behave_like "every accessible many_to_many composite association with :allow_destroy => true"
93
+
94
+ end
95
+
96
+ describe "Person.accepts_nested_attributes_for(:projects, :reject_if => lambda { |attrs| true })" do
97
+
98
+ before(:all) do
99
+ Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| true }
100
+ end
101
+
102
+ it_should_behave_like "every accessible many_to_many composite association"
103
+ it_should_behave_like "every accessible many_to_many composite association with a valid reject_if proc"
104
+ it_should_behave_like "every accessible many_to_many composite association with :allow_destroy => false"
105
+
106
+ end
107
+
108
+ describe "Person.accepts_nested_attributes_for(:projects, :reject_if => lambda { |attrs| false })" do
109
+
110
+ before(:all) do
111
+ Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| false }
112
+ end
113
+
114
+ it_should_behave_like "every accessible many_to_many composite association"
115
+ it_should_behave_like "every accessible many_to_many composite association with no reject_if proc"
116
+ it_should_behave_like "every accessible many_to_many composite association with :allow_destroy => false"
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,129 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Person.has(n, :projects, :through => :project_memberships);" do
4
+
5
+ before(:all) do
6
+
7
+ class ::Person
8
+
9
+ include DataMapper::Resource
10
+ extend ConstraintSupport
11
+
12
+ property :id, Serial
13
+ property :name, String, :required => true
14
+
15
+ has n, :project_memberships, constraint(:destroy)
16
+ has n, :projects, :through => :project_memberships
17
+ has n, :tasks, :through => :projects
18
+
19
+ end
20
+
21
+ class ::Project
22
+
23
+ include DataMapper::Resource
24
+ extend ConstraintSupport
25
+
26
+ property :id, Serial
27
+ property :name, String, :required => true
28
+
29
+ has n, :project_memberships, constraint(:destroy)
30
+ has n, :people, :through => :project_memberships
31
+ has n, :tasks, constraint(:destroy)
32
+
33
+ end
34
+
35
+ class ::ProjectMembership
36
+
37
+ include DataMapper::Resource
38
+
39
+ property :id, Serial
40
+
41
+ belongs_to :person
42
+ belongs_to :project
43
+
44
+ end
45
+
46
+ class ::Task
47
+
48
+ include DataMapper::Resource
49
+
50
+ property :id, Serial
51
+ property :name, String, :required => true
52
+
53
+ belongs_to :project
54
+
55
+ end
56
+
57
+ DataMapper.auto_migrate!
58
+
59
+ end
60
+
61
+ before(:each) do
62
+ ProjectMembership.all.destroy!
63
+ Task.all.destroy!
64
+ Project.all.destroy!
65
+ Person.all.destroy!
66
+ end
67
+
68
+
69
+ describe "Person.accepts_nested_attributes_for(:projects)" do
70
+
71
+ before(:all) do
72
+ Person.accepts_nested_attributes_for :projects
73
+ end
74
+
75
+ it_should_behave_like "every accessible many_to_many association"
76
+ it_should_behave_like "every accessible many_to_many association with no reject_if proc"
77
+ it_should_behave_like "every accessible many_to_many association with :allow_destroy => false"
78
+
79
+ end
80
+
81
+ describe "Person.accepts_nested_attributes_for(:projects, :allow_destroy => false)" do
82
+
83
+ before(:all) do
84
+ Person.accepts_nested_attributes_for :projects, :allow_destroy => false
85
+ end
86
+
87
+ it_should_behave_like "every accessible many_to_many association"
88
+ it_should_behave_like "every accessible many_to_many association with no reject_if proc"
89
+ it_should_behave_like "every accessible many_to_many association with :allow_destroy => false"
90
+
91
+ end
92
+
93
+ describe "Person.accepts_nested_attributes_for(:projects, :allow_destroy = true)" do
94
+
95
+ before(:all) do
96
+ Person.accepts_nested_attributes_for :projects, :allow_destroy => true
97
+ end
98
+
99
+ it_should_behave_like "every accessible many_to_many association"
100
+ it_should_behave_like "every accessible many_to_many association with no reject_if proc"
101
+ it_should_behave_like "every accessible many_to_many association with :allow_destroy => true"
102
+
103
+ end
104
+
105
+ describe "Person.accepts_nested_attributes_for(:projects, :reject_if => lambda { |attrs| true })" do
106
+
107
+ before(:all) do
108
+ Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| true }
109
+ end
110
+
111
+ it_should_behave_like "every accessible many_to_many association"
112
+ it_should_behave_like "every accessible many_to_many association with a valid reject_if proc"
113
+ it_should_behave_like "every accessible many_to_many association with :allow_destroy => false"
114
+
115
+ end
116
+
117
+ describe "Person.accepts_nested_attributes_for(:projects, :reject_if => lambda { |attrs| false })" do
118
+
119
+ before(:all) do
120
+ Person.accepts_nested_attributes_for :projects, :reject_if => lambda { |attrs| false }
121
+ end
122
+
123
+ it_should_behave_like "every accessible many_to_many association"
124
+ it_should_behave_like "every accessible many_to_many association with no reject_if proc"
125
+ it_should_behave_like "every accessible many_to_many association with :allow_destroy => false"
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ProjectMembership.belongs_to(:person) with CPK;" do
4
+
5
+ before(:all) do
6
+ class ::Person
7
+
8
+ include DataMapper::Resource
9
+ extend ConstraintSupport
10
+
11
+ property :id, Serial, :key => true
12
+ property :audit_id, Integer, :key => true, :min => 0
13
+ property :name, String, :required => true
14
+
15
+ has n, :memberships, constraint(:destroy)
16
+ has n, :projects, :through => :memberships
17
+
18
+ end
19
+
20
+ class ::Project
21
+
22
+ include DataMapper::Resource
23
+ extend ConstraintSupport
24
+
25
+ property :id, Serial, :key => true
26
+ property :audit_id, Integer, :key => true, :min => 0
27
+ property :name, String, :required => true
28
+
29
+ has n, :memberships, constraint(:destroy)
30
+ has n, :people, :through => :memberships
31
+
32
+ end
33
+
34
+ class ::Membership
35
+
36
+ include DataMapper::Resource
37
+
38
+ property :person_id, Integer, :key => true, :min => 0
39
+ property :person_audit_id, Integer, :key => true, :min => 0
40
+ property :project_id, Integer, :key => true, :min => 0
41
+ property :project_audit_id, Integer, :key => true, :min => 0
42
+ property :role, String, :required => false
43
+
44
+ belongs_to :person, :key => true
45
+ belongs_to :project, :key => true
46
+
47
+ end
48
+
49
+ DataMapper.auto_migrate!
50
+
51
+ end
52
+
53
+ before(:each) do
54
+ Membership.all.destroy!
55
+ Project.all.destroy!
56
+ Person.all.destroy!
57
+ end
58
+
59
+
60
+ describe "Membership.accepts_nested_attributes_for(:person)" do
61
+
62
+ before(:all) do
63
+ Membership.accepts_nested_attributes_for :person
64
+ end
65
+
66
+ it_should_behave_like "every accessible many_to_one composite association"
67
+ it_should_behave_like "every accessible many_to_one composite association with no reject_if proc"
68
+ it_should_behave_like "every accessible many_to_one composite association with :allow_destroy => false"
69
+
70
+ end
71
+
72
+ describe "Membership.accepts_nested_attributes_for(:person, :allow_destroy => false)" do
73
+
74
+ before(:all) do
75
+ Membership.accepts_nested_attributes_for :person, :allow_destroy => false
76
+ end
77
+
78
+ it_should_behave_like "every accessible many_to_one composite association"
79
+ it_should_behave_like "every accessible many_to_one composite association with no reject_if proc"
80
+ it_should_behave_like "every accessible many_to_one composite association with :allow_destroy => false"
81
+
82
+ end
83
+
84
+ describe "Membership.accepts_nested_attributes_for(:person, :allow_destroy = true)" do
85
+
86
+ before(:all) do
87
+ Membership.accepts_nested_attributes_for :person, :allow_destroy => true
88
+ end
89
+
90
+ it_should_behave_like "every accessible many_to_one composite association"
91
+ it_should_behave_like "every accessible many_to_one composite association with no reject_if proc"
92
+ it_should_behave_like "every accessible many_to_one composite association with :allow_destroy => true"
93
+
94
+ end
95
+
96
+ describe "Membership.accepts_nested_attributes_for(:person, :reject_if => lambda { |attrs| true })" do
97
+
98
+ before(:all) do
99
+ Membership.accepts_nested_attributes_for :person, :reject_if => lambda { |attrs| true }
100
+ end
101
+
102
+ it_should_behave_like "every accessible many_to_one composite association"
103
+ it_should_behave_like "every accessible many_to_one composite association with a valid reject_if proc"
104
+ it_should_behave_like "every accessible many_to_one composite association with :allow_destroy => false"
105
+
106
+ end
107
+
108
+ describe "Membership.accepts_nested_attributes_for(:person, :reject_if => lambda { |attrs| false })" do
109
+
110
+ before(:all) do
111
+ Membership.accepts_nested_attributes_for :person, :reject_if => lambda { |attrs| false }
112
+ end
113
+
114
+ it_should_behave_like "every accessible many_to_one composite association"
115
+ it_should_behave_like "every accessible many_to_one composite association with no reject_if proc"
116
+ it_should_behave_like "every accessible many_to_one composite association with :allow_destroy => false"
117
+
118
+ end
119
+
120
+ end