relaxdb 0.3.5

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 (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