relaxdb 0.3.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/LICENSE +20 -0
  2. data/README.textile +200 -0
  3. data/Rakefile +63 -0
  4. data/docs/spec_results.html +1059 -0
  5. data/lib/more/atomic_bulk_save_support.rb +18 -0
  6. data/lib/more/grapher.rb +48 -0
  7. data/lib/relaxdb.rb +50 -0
  8. data/lib/relaxdb/all_delegator.rb +44 -0
  9. data/lib/relaxdb/belongs_to_proxy.rb +29 -0
  10. data/lib/relaxdb/design_doc.rb +57 -0
  11. data/lib/relaxdb/document.rb +600 -0
  12. data/lib/relaxdb/extlib.rb +24 -0
  13. data/lib/relaxdb/has_many_proxy.rb +101 -0
  14. data/lib/relaxdb/has_one_proxy.rb +42 -0
  15. data/lib/relaxdb/migration.rb +40 -0
  16. data/lib/relaxdb/migration_version.rb +21 -0
  17. data/lib/relaxdb/net_http_server.rb +61 -0
  18. data/lib/relaxdb/paginate_params.rb +53 -0
  19. data/lib/relaxdb/paginator.rb +88 -0
  20. data/lib/relaxdb/query.rb +76 -0
  21. data/lib/relaxdb/references_many_proxy.rb +97 -0
  22. data/lib/relaxdb/relaxdb.rb +250 -0
  23. data/lib/relaxdb/server.rb +109 -0
  24. data/lib/relaxdb/taf2_curb_server.rb +63 -0
  25. data/lib/relaxdb/uuid_generator.rb +21 -0
  26. data/lib/relaxdb/validators.rb +11 -0
  27. data/lib/relaxdb/view_object.rb +34 -0
  28. data/lib/relaxdb/view_result.rb +18 -0
  29. data/lib/relaxdb/view_uploader.rb +49 -0
  30. data/lib/relaxdb/views.rb +114 -0
  31. data/readme.rb +80 -0
  32. data/spec/belongs_to_spec.rb +124 -0
  33. data/spec/callbacks_spec.rb +80 -0
  34. data/spec/derived_properties_spec.rb +112 -0
  35. data/spec/design_doc_spec.rb +34 -0
  36. data/spec/doc_inheritable_spec.rb +100 -0
  37. data/spec/document_spec.rb +545 -0
  38. data/spec/has_many_spec.rb +202 -0
  39. data/spec/has_one_spec.rb +123 -0
  40. data/spec/migration_spec.rb +97 -0
  41. data/spec/migration_version_spec.rb +28 -0
  42. data/spec/paginate_params_spec.rb +15 -0
  43. data/spec/paginate_spec.rb +360 -0
  44. data/spec/query_spec.rb +90 -0
  45. data/spec/references_many_spec.rb +173 -0
  46. data/spec/relaxdb_spec.rb +364 -0
  47. data/spec/server_spec.rb +32 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +65 -0
  50. data/spec/spec_models.rb +199 -0
  51. data/spec/view_by_spec.rb +76 -0
  52. data/spec/view_object_spec.rb +47 -0
  53. data/spec/view_spec.rb +23 -0
  54. metadata +137 -0
@@ -0,0 +1,202 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB::HasManyProxy do
5
+
6
+ before(:all) do
7
+ setup_test_db
8
+ end
9
+
10
+ describe "has_many" do
11
+
12
+
13
+ describe "target_class in the generated view" do
14
+ it "should infer the class name from the relationship if not supplied" do
15
+ view = mock(:view).as_null_object
16
+ RelaxDB::ViewCreator.should_receive(:has_n).with(
17
+ "", # client_class
18
+ :foo_bars, # relationship
19
+ "FooBar", # target_class
20
+ "" # relationship_to_client
21
+ ).and_return view
22
+ klass = Class.new(RelaxDB::Document) do
23
+ has_many :foo_bars
24
+ end
25
+ end
26
+
27
+ it "should use the class name if supplied" do
28
+ view = mock(:view).as_null_object
29
+ RelaxDB::ViewCreator.should_receive(:has_n).with(
30
+ "", # client_class
31
+ :foo_bars, # relationship
32
+ "Bar", # target_class
33
+ "" # relationship_to_client
34
+ ).and_return view
35
+ klass = Class.new(RelaxDB::Document) do
36
+ has_many :foo_bars, :class => "Bar"
37
+ end
38
+ end
39
+ end
40
+
41
+ it "should be considered enumerable" do
42
+ u = User.new.save
43
+ u.items.should be_a_kind_of(Enumerable)
44
+ end
45
+
46
+ it "should actually be enumerable" do
47
+ u = User.new.save
48
+ u.items << Item.new(:name => "a")
49
+ u.items << Item.new(:name => "b")
50
+ names = u.items.inject("") { |memo, i| memo << i.name }
51
+ names.should == "ab"
52
+ end
53
+
54
+ it "should preserve the collection across the load / save boundary" do
55
+ u = User.new.save
56
+ u.items << Item.new
57
+ u = RelaxDB.load u._id
58
+ u.items.size.should == 1
59
+ end
60
+
61
+ it "should work with MultiWordClassNames" do
62
+ c = MultiWordChild.new
63
+ m = MultiWordClass.new.save
64
+ m.multi_word_children << c
65
+ m = RelaxDB.load m._id
66
+ m.multi_word_children[0].should == c
67
+ end
68
+
69
+ describe "#<<" do
70
+
71
+ it "should link the added item to the parent" do
72
+ u = User.new
73
+ u.items << Item.new
74
+ u.items[0].user.should == u
75
+ end
76
+
77
+ it "should return self" do
78
+ u = User.new.save
79
+ u.items << Item.new << Item.new
80
+ u.items[0].user.should == u
81
+ u.items[1].user.should == u
82
+ end
83
+
84
+ it "should not created duplicates when invoked with same object more than once" do
85
+ u = User.new.save
86
+ i = Item.new
87
+ u.items << i << i
88
+ u.items.size.should == 1
89
+ end
90
+
91
+ it "should return false when the child fails validation" do
92
+ d = Dysfunctional.new
93
+ r = (d.failures << Failure.new)
94
+ r.should be_false
95
+ d.failures.should be_empty
96
+ end
97
+
98
+ end
99
+
100
+ describe "#=" do
101
+
102
+ before(:each) do
103
+ # Create the underlying views
104
+ User.new(:items => [], :invites_received => [], :invites_sent => [])
105
+ end
106
+
107
+ it "should not attempt to save the child objects when the relationship is established" do
108
+ RelaxDB.db.put_count = 0
109
+ i1, i2 = Item.new(:name => "i1"), Item.new(:name => "i2")
110
+ User.new(:items => [i1, i2])
111
+ RelaxDB.db.put_count.should == 0
112
+ end
113
+
114
+ it "should preserve given relationships across save/load boundary" do
115
+ i1, i2 = Item.new(:name => "i1"), Item.new(:name => "i2")
116
+ u = User.new(:items => [i1, i2])
117
+ RelaxDB.bulk_save u, *u.items
118
+ u = RelaxDB.load u._id
119
+ u.items.map { |i| i.name }.sort.join.should == "i1i2"
120
+ end
121
+
122
+ it "should invoke the derived properties writer" do
123
+ class HmsdParent < RelaxDB::Document
124
+ property :foo, :derived => [:zongs, lambda {|f, o| o.zongs.first.z / 2 }]
125
+ has_many :zongs, :class => "HmsdChild"
126
+ end
127
+ class HmsdChild < RelaxDB::Document
128
+ property :z
129
+ belongs_to :hmsd_parent
130
+ end
131
+ oz = HmsdChild.new(:z => 10)
132
+ op = HmsdParent.new(:zongs => [oz])
133
+ op.foo.should == 5
134
+ end
135
+
136
+ end
137
+
138
+ describe "#delete" do
139
+
140
+ it "should nullify the belongs_to relationship" do
141
+ u = User.new.save
142
+ i = Item.new
143
+ u.items << i
144
+ u.items.delete i
145
+ i.user.should be_nil
146
+ RelaxDB.load(i._id).user.should be_nil
147
+ end
148
+
149
+ end
150
+
151
+ describe "#clear" do
152
+
153
+ it "should result in an empty collection" do
154
+ u = User.new.save
155
+ u.items << Item.new << Item.new
156
+ u.items.clear
157
+ u.items.should be_empty
158
+ end
159
+
160
+ it "should nullify all child relationships" do
161
+ u = User.new.save
162
+ i1, i2 = Item.new, Item.new
163
+ u.items << i1
164
+ u.items << i2
165
+ u.items.clear
166
+
167
+ i1.user.should be_nil
168
+ i2.user.should be_nil
169
+ RelaxDB.load(i1._id).user.should be_nil
170
+ RelaxDB.load(i2._id).user.should be_nil
171
+ end
172
+
173
+ end
174
+
175
+ describe "owner" do
176
+
177
+ it "should be able to form multiple relationships with the same class of child" do
178
+ u1, u2 = User.new.save, User.new.save
179
+ i = Invite.new(:recipient => u2)
180
+ u1.invites_sent << Invite.new
181
+ RelaxDB.load(u1._id).invites_sent[0] == i
182
+ RelaxDB.load(u2._id).invites_received[0] == i
183
+ end
184
+
185
+ describe "#destroy" do
186
+
187
+ it "should nullify its child relationships" do
188
+ Item.view_by :user_id
189
+
190
+ u = User.new.save
191
+ u.items << Item.new << Item.new
192
+ u.destroy!
193
+ Item.by_user_id(:key => u._id).should be_empty
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+
200
+ end
201
+
202
+ end
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB::HasOneProxy do
5
+
6
+ before(:each) do
7
+ setup_test_db
8
+ end
9
+
10
+ describe "has_one" do
11
+
12
+ it "should return nil when accessed before assignment" do
13
+ p = Photo.new
14
+ p.rating.should == nil
15
+ end
16
+
17
+ it "should be establishable via a constructor attribute" do
18
+ r = Rating.new
19
+ p = Photo.new :rating => r
20
+ p.rating.should == r
21
+ end
22
+
23
+ it "should be establishable via assignment" do
24
+ p = Photo.new
25
+ r = Rating.new
26
+ p.rating = r
27
+ p.rating.should == r
28
+ end
29
+
30
+ it "should return the same object on repeated invocations" do
31
+ p = Photo.new.save
32
+ p.rating = Rating.new
33
+ p = RelaxDB.load(p._id)
34
+ p.rating.object_id.should == p.rating.object_id
35
+ end
36
+
37
+ it "should be preserved across load / save boundary" do
38
+ r = Rating.new
39
+ p = Photo.new(:rating => r).save
40
+ p = RelaxDB.load p._id
41
+ p.rating.should == r
42
+ end
43
+
44
+ it "should be able reference itself via its child" do
45
+ r = Rating.new
46
+ p = Photo.new(:rating => r).save
47
+ p = RelaxDB.load p._id
48
+ p.rating.photo.should == p
49
+ end
50
+
51
+ it "should work with MultiWordClassNames" do
52
+ c = MultiWordChild.new
53
+ m = MultiWordClass.new(:multi_word_child => c).save
54
+ m = RelaxDB.load m._id
55
+ m.multi_word_child.should == c
56
+ end
57
+
58
+ describe "#=" do
59
+
60
+ it "should create a reference from the child to the parent" do
61
+ p = Photo.new
62
+ r = Rating.new
63
+ p.rating = r
64
+ r.photo.should == p
65
+ end
66
+
67
+ it "should save the assigned object" do
68
+ p = Photo.new
69
+ r = Rating.new
70
+ p.rating = r
71
+ r.should_not be_unsaved
72
+ end
73
+
74
+ it "will not save the parent" do
75
+ p = Photo.new
76
+ r = Rating.new
77
+ p.rating = r
78
+ p.should be_unsaved
79
+ end
80
+
81
+ it "should set the target to nil when nil is assigned" do
82
+ p = Photo.new
83
+ p.rating = nil
84
+ p.rating.should be_nil
85
+ end
86
+
87
+ it "should nullify any existing relationship in the database" do
88
+ p = Photo.new
89
+ r = Rating.new
90
+ p.rating = r
91
+ p.rating = nil
92
+ RelaxDB.load(r._id).photo.should be_nil
93
+ end
94
+
95
+ it "should nullify any existing relationship on a known in-memory object" do
96
+ p = Photo.new
97
+ r = Rating.new
98
+ p.rating = r
99
+ p.rating = nil
100
+ r.photo.should be_nil
101
+ end
102
+
103
+ it "will not nullify any existing relationship on unknown in-memory objects" do
104
+ p = Photo.new.save
105
+ r = Rating.new
106
+ p.rating = r
107
+ r_copy = RelaxDB.load(r._id)
108
+ p.rating = nil
109
+ r_copy.photo.should_not be_nil
110
+ end
111
+
112
+ it "will not throw an error when the rhs fails validation" do
113
+ d = Dysfunctional.new.save
114
+ f = Failure.new
115
+ d.failure = f
116
+ d.failure.should == f
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,97 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+ require File.join(File.dirname(__FILE__), "spec_models")
3
+
4
+ describe RelaxDB::Migration do
5
+
6
+ before(:each) do
7
+ @mig = RelaxDB::Migration
8
+ setup_test_db
9
+ end
10
+
11
+ it "should yield each obj to the block and save the result" do
12
+ Primitives.new(:num => 5).save!
13
+ r = @mig.run Primitives do |p|
14
+ pn = Primitives.new(:num => p.num * 2)
15
+ [p, pn]
16
+ end
17
+ Primitives.by_num.map { |p| p.num}.should == [5, 10]
18
+ end
19
+
20
+ it "should raise an exception if a save results in a conflict" do
21
+ op = Primitives.new.save!
22
+ lambda do
23
+ @mig.run Primitives do |p|
24
+ op.save!
25
+ p
26
+ end
27
+ end.should raise_error(RelaxDB::UpdateConflict)
28
+ end
29
+
30
+ it "should not save docs for blocks that return nil" do
31
+ Primitives.new.save!
32
+ @mig.run Primitives do |p|
33
+ nil
34
+ end
35
+ end
36
+
37
+ describe "multiple docs" do
38
+
39
+ before(:each) do
40
+ ps = (1..5).map { |i| Primitives.new :num => i }
41
+ RelaxDB.bulk_save *ps
42
+ RelaxDB.db.reset_req_count
43
+ end
44
+
45
+ # Note: two extra requests per paginate_view request are required
46
+ it "should operate on a doc set of the given size aka limit" do
47
+ @mig.run(Primitives, 1) { |p| p.num *= p.num; p }
48
+ RelaxDB.db.req_count.should == 10 + 5 * 2
49
+ Primitives.by_num.map { |p| p.num }.should == [1, 4, 9, 16, 25]
50
+ end
51
+
52
+ it "should operate on a doc set of default size" do
53
+ @mig.run(Primitives) { |p| p.num *= p.num; p }
54
+ RelaxDB.db.req_count.should == 2 + 1 * 2
55
+ Primitives.by_num.map { |p| p.num }.should == [1, 4, 9, 16, 25]
56
+ end
57
+
58
+ end
59
+
60
+ describe "#fv" do
61
+ it "should return valid numbers" do
62
+ @mig.fv("foo/bar/001_foo.rb").should == 1
63
+ end
64
+ end
65
+
66
+ describe ".run_all" do
67
+
68
+ it "should save the version after each successful migration" do
69
+ @mig.run_all "a/b/1_", lambda {}
70
+ RelaxDB::MigrationVersion.version.should == 1
71
+ end
72
+
73
+ it "should not run those migrations whose version is less than the current version" do
74
+ v = RelaxDB::MigrationVersion.retrieve
75
+ v.version = 2
76
+ v.save!
77
+ @mig.run_all "3_", lambda {}
78
+ RelaxDB::MigrationVersion.version.should == 3
79
+ end
80
+
81
+ it "should run those migrations whose version is greater than the current version" do
82
+ v = RelaxDB::MigrationVersion.retrieve
83
+ v.version = 2
84
+ v.save!
85
+ @mig.run_all "1_foo", lambda {}
86
+ RelaxDB::MigrationVersion.version.should == 2
87
+ end
88
+
89
+ it "should raise an exception on failure" do
90
+ lambda do
91
+ @mig.run_all "1_foo", lambda { raise "Expected" }
92
+ end.should raise_error(RuntimeError, "Expected")
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,28 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+ require File.join(File.dirname(__FILE__), "spec_models")
3
+
4
+ describe RelaxDB::MigrationVersion do
5
+
6
+ before(:each) do
7
+ setup_test_db
8
+ end
9
+
10
+ it "should not exist in a clean db" do
11
+ RelaxDB.load(RelaxDB::MigrationVersion::DOC_ID).should be_nil
12
+ end
13
+
14
+ it "should return zero when it doesnt exist" do
15
+ RelaxDB::MigrationVersion.version.should == 0
16
+ end
17
+
18
+ it "should autosave on retrieval when when it doesnt exist" do
19
+ RelaxDB::MigrationVersion.version
20
+ RelaxDB.load(RelaxDB::MigrationVersion::DOC_ID).should be
21
+ end
22
+
23
+ it "should return the saved version" do
24
+ RelaxDB::MigrationVersion.update 10
25
+ RelaxDB::MigrationVersion.version.should == 10
26
+ end
27
+
28
+ end