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,15 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB::PaginateParams do
5
+
6
+ it "should be invalid if hasn't been initialized with both a startkey and endkey" do
7
+ RelaxDB::PaginateParams.new({}).should be_invalid
8
+ end
9
+
10
+ it "should be valid if initialized with both a startkey and endkey" do
11
+ pp = RelaxDB::PaginateParams.new :startkey => nil, :endkey => nil
12
+ pp.should_not be_invalid
13
+ end
14
+
15
+ end
@@ -0,0 +1,360 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe "RelaxDB Pagination" do
5
+
6
+ before(:each) do
7
+ setup_test_db
8
+
9
+ letters = [
10
+ ["a", 1], ["a", 2], ["a", 3],
11
+ ["b", 1], ["b", 2], ["b", 3], ["b", 4], ["b", 5],
12
+ ["c", 1], ["c", 2]
13
+ ].map { |o| Letter.new :letter => o[0], :number => o[1], :_id => "#{o[0]}#{o[1]}" }
14
+
15
+ RelaxDB.bulk_save *letters
16
+ end
17
+
18
+ # helper function
19
+ def s(letters)
20
+ letters.map { |l| "#{l.letter}#{l.number}"}.join(", ")
21
+ end
22
+
23
+ def n(letters)
24
+ letters.map { |l| "#{l.number}"}.join(", ")
25
+ end
26
+
27
+ describe "functional tests" do
28
+
29
+ it "should navigate through a series" do
30
+ query = lambda do |page_params|
31
+ Letter.paginate_by_letter_and_number :page_params => page_params,
32
+ :startkey => ["a"], :endkey => ["a",{}], :limit => 2
33
+ end
34
+
35
+ letters = query.call({})
36
+ s(letters).should == "a1, a2"
37
+ letters.prev_params.should be_false
38
+
39
+ letters = query.call(letters.next_params)
40
+ s(letters).should == "a3"
41
+ letters.next_params.should be_false
42
+
43
+ letters = query.call(letters.prev_params)
44
+ s(letters).should == "a1, a2"
45
+ letters.prev_params.should be_false
46
+ letters.next_params.should be
47
+ end
48
+
49
+ it "should navigate through b series with descending false" do
50
+ query = lambda do |page_params|
51
+ Letter.paginate_by_letter_and_number :page_params => page_params,
52
+ :startkey => ["b"], :endkey => ["b",{}], :limit => 2
53
+ end
54
+
55
+ letters = query.call({})
56
+ s(letters).should == "b1, b2"
57
+ letters.prev_params.should be_false
58
+
59
+ letters = query.call(letters.next_params)
60
+ s(letters).should == "b3, b4"
61
+ letters.next_params.should be
62
+
63
+ letters = query.call(letters.prev_params)
64
+ s(letters).should == "b1, b2"
65
+ letters.prev_params.should be_false
66
+
67
+ letters = query.call(letters.next_params)
68
+ s(letters).should == "b3, b4"
69
+ letters.prev_params.should be
70
+
71
+ letters = query.call(letters.next_params)
72
+ s(letters).should == "b5"
73
+ letters.next_params.should be_false
74
+
75
+ letters = query.call(letters.prev_params)
76
+ s(letters).should == "b3, b4"
77
+ letters.next_params.should be
78
+
79
+ letters = query.call(letters.prev_params)
80
+ s(letters).should == "b1, b2"
81
+ letters.prev_params.should be_false
82
+ letters.next_params.should be
83
+ end
84
+
85
+ it "should navigate through b series with descending true" do
86
+ query = lambda do |page_params|
87
+ Letter.paginate_by_letter_and_number :page_params => page_params,
88
+ :startkey => ["b", {}], :endkey => ["b"], :descending => true, :limit => 2
89
+ end
90
+
91
+ letters = query.call({})
92
+ s(letters).should == "b5, b4"
93
+ letters.prev_params.should be_false
94
+
95
+ letters = query.call(letters.next_params)
96
+ s(letters).should == "b3, b2"
97
+ letters.prev_params.should be
98
+
99
+ letters = query.call(letters.next_params)
100
+ s(letters).should == "b1"
101
+ letters.next_params.should be_false
102
+
103
+ letters = query.call(letters.prev_params)
104
+ s(letters).should == "b3, b2"
105
+ letters.next_params.should be
106
+
107
+ letters = query.call(letters.prev_params)
108
+ s(letters).should == "b5, b4"
109
+ letters.prev_params.should be_false
110
+ letters.next_params.should be
111
+ end
112
+
113
+ it "should not display pagination options for c series" do
114
+ letters = Letter.paginate_by_letter_and_number :page_params => {},
115
+ :startkey => ["c"], :endkey => ["c", {}], :limit => 2
116
+
117
+ letters.next_params.should be_false
118
+ letters.prev_params.should be_false
119
+ end
120
+
121
+ end
122
+
123
+ describe "next_query" do
124
+
125
+ it "should emit a url encoded and json encoded string with query name page_params" do
126
+ letters = Letter.paginate_by_letter_and_number :page_params => {:startkey => ["b", 2]},
127
+ :startkey => ["b"], :endkey => ["b",{}],:limit => 2
128
+
129
+ # unescape and parse required as param order is implementation dependent
130
+ hash = JSON.parse(CGI.unescape(letters.next_query.split("=")[1]))
131
+
132
+ hash["descending"].should be_false
133
+ hash["startkey"].should == ["b", 4]
134
+ end
135
+
136
+ it "should be treated as next_param by the paginator" do
137
+ page_params = {}
138
+ query = lambda do
139
+ Letter.paginate_by_letter_and_number :page_params => page_params,
140
+ :startkey => ["b"], :endkey => ["b",{}], :limit => 2
141
+ end
142
+
143
+ letters = query.call
144
+ page_params = CGI::unescape(letters.next_query.split("=")[1])
145
+ letters = query.call
146
+ s(letters).should == "b3, b4"
147
+ end
148
+
149
+ end
150
+
151
+ describe "prev_query" do
152
+
153
+ it "should be treated as prev_query by the paginator" do
154
+ page_params = {}
155
+ query = lambda do
156
+ Letter.paginate_by_letter_and_number :page_params => page_params,
157
+ :startkey => ["b", {}], :endkey => ["b"], :descending => true, :limit => 2
158
+ end
159
+
160
+ letters = query.call
161
+ page_params = CGI::unescape(letters.next_query.split("=")[1])
162
+ letters = query.call
163
+ s(letters).should == "b3, b2"
164
+ end
165
+
166
+ it "should emit a url encoded and json encoded string with query name page_params" do
167
+ letters = Letter.paginate_by_letter_and_number :page_params => {:startkey => ["b", 2]},
168
+ :startkey => ["b"], :endkey => ["b",{}],:limit => 2
169
+
170
+ hash = JSON.parse(CGI.unescape(letters.prev_query.split("=")[1]))
171
+
172
+ hash["descending"].should be_true
173
+ hash["startkey"].should == ["b", 3]
174
+ end
175
+
176
+ end
177
+
178
+ describe "multiple keys per document, simple (non array) keys" do
179
+
180
+ it "should work when descending is false" do
181
+ query = lambda do |page_params|
182
+ Letter.paginate_by_number :page_params => page_params,
183
+ :startkey => 1, :endkey => {}, :limit => 4
184
+ end
185
+
186
+ numbers = query.call({})
187
+ n(numbers).should == "1, 1, 1, 2"
188
+ numbers.prev_params.should be_false
189
+
190
+ numbers = query.call(numbers.next_params)
191
+ n(numbers).should == "2, 2, 3, 3"
192
+ numbers.next_params.should be
193
+
194
+ numbers = query.call(numbers.prev_params)
195
+ n(numbers).should == "1, 1, 1, 2"
196
+ numbers.prev_params.should be_false
197
+
198
+ numbers = query.call(numbers.next_params)
199
+ n(numbers) == "2, 2, 3, 3"
200
+ numbers.prev_params.should be
201
+
202
+ numbers = query.call(numbers.next_params)
203
+ n(numbers) == "4, 5"
204
+ numbers.next_params.should be_false
205
+
206
+ numbers = query.call(numbers.prev_params)
207
+ n(numbers) == "2, 2, 3, 3"
208
+ numbers.next_params.should be
209
+
210
+ numbers = query.call(numbers.prev_params)
211
+ n(numbers) == "1, 1, 1, 2"
212
+ numbers.next_params.should be
213
+ numbers.prev_params.should be_false
214
+ end
215
+
216
+ it "should work when descending is true" do
217
+ query = lambda do |page_params|
218
+ Letter.paginate_by_number :page_params => page_params,
219
+ :startkey => 5, :endkey => nil, :descending => true, :limit => 4
220
+ end
221
+
222
+ numbers = query.call({})
223
+ n(numbers).should == "5, 4, 3, 3"
224
+ numbers.prev_params.should be_false
225
+
226
+ numbers = query.call(numbers.next_params)
227
+ n(numbers).should == "2, 2, 2, 1"
228
+ numbers.next_params.should be
229
+
230
+ numbers = query.call(numbers.prev_params)
231
+ n(numbers).should == "5, 4, 3, 3"
232
+ numbers.prev_params.should be_false
233
+
234
+ numbers = query.call(numbers.next_params)
235
+ n(numbers).should == "2, 2, 2, 1"
236
+ numbers.prev_params.should be
237
+
238
+ numbers = query.call(numbers.next_params)
239
+ n(numbers).should == "1, 1"
240
+ numbers.next_params.should be_false
241
+
242
+ numbers = query.call(numbers.prev_params)
243
+ n(numbers).should == "2, 2, 2, 1"
244
+ numbers.next_params.should be
245
+
246
+ numbers = query.call(numbers.prev_params)
247
+ n(numbers).should == "5, 4, 3, 3"
248
+ numbers.prev_params.should be_false
249
+ numbers.next_params.should be
250
+ end
251
+
252
+ it "should not get stuck when the number of keys exceeds the limit" do
253
+ query = lambda do |page_params|
254
+ Letter.paginate_by_number :page_params => page_params,
255
+ :startkey => 1, :endkey => {}, :limit => 2
256
+ end
257
+
258
+ numbers = query.call({})
259
+ n(numbers).should == "1, 1"
260
+ numbers = query.call(numbers.next_params)
261
+ n(numbers).should == "1, 2"
262
+ end
263
+
264
+ end
265
+
266
+ describe ".paginate_by" do
267
+
268
+ it "should throw an error unless both startkey and endkey are specified" do
269
+ lambda do
270
+ Letter.paginate_by_number :page_params => page_params, :startkey => 1, :limit => 2
271
+ end.should raise_error
272
+ end
273
+
274
+ it "should return an empty array when no documents exist" do
275
+ Letter.all.destroy!
276
+ letters = Letter.paginate_by_number :page_params => {}, :startkey => 1, :endkey => 3
277
+ letters.should be_empty
278
+ end
279
+
280
+ it "should return an array that responds negatively to next_query and prev_query when no documents exist" do
281
+ Letter.all.destroy!
282
+ letters = Letter.paginate_by_number :page_params => {}, :startkey => 1, :endkey => 3
283
+ letters.prev_query.should be_false
284
+ letters.next_query.should be_false
285
+ end
286
+
287
+ end
288
+
289
+ describe ".paginate_view functional tests" do
290
+
291
+ def navigate_b_series(query)
292
+ letters = query.call({})
293
+ s(letters).should == "b1, b2"
294
+ letters.prev_params.should be_false
295
+
296
+ letters = query.call(letters.next_params)
297
+ s(letters).should == "b3, b4"
298
+ letters.prev_params.should be
299
+
300
+ letters = query.call(letters.next_params)
301
+ s(letters).should == "b5"
302
+ letters.next_params.should be_false
303
+
304
+ letters = query.call(letters.prev_params)
305
+ s(letters).should == "b3, b4"
306
+ letters.next_params.should be
307
+
308
+ letters = query.call(letters.prev_params)
309
+ s(letters).should == "b1, b2"
310
+ letters.next_params.should be
311
+ letters.prev_params.should be_false
312
+ end
313
+
314
+ before(:each) do
315
+ map = <<-FUNC
316
+ function (doc) {
317
+ if (doc.relaxdb_class === "Letter") {
318
+ emit([doc.letter, doc.number], doc);
319
+ }
320
+ }
321
+ FUNC
322
+
323
+ reduce = <<-FUNC
324
+ function (keys, values, combine) {
325
+ return values.length;
326
+ }
327
+ FUNC
328
+
329
+ view_name = "Letter_by_letter_and_number"
330
+ RelaxDB::DesignDocument.get(RelaxDB.dd).add_map_view(view_name, map).add_reduce_view(view_name, reduce).save
331
+ end
332
+
333
+ it "should pass using symbols as view_keys" do
334
+ query = lambda do |page_params|
335
+ RelaxDB.paginate_view "Letter_by_letter_and_number", :page_params => page_params,
336
+ :startkey => ["b"], :endkey => ["b", {}], :limit => 2, :attributes => [:letter, :number]
337
+ end
338
+ navigate_b_series query
339
+ end
340
+
341
+ it "should pass using symbols and values as view_keys" do
342
+ query = lambda do |page_params|
343
+ RelaxDB.paginate_view "Letter_by_letter_and_number", :page_params => page_params,
344
+ :startkey => ["b"], :endkey => ["b", {}], :limit => 2, :attributes => ["b", :number]
345
+ end
346
+ navigate_b_series query
347
+ end
348
+
349
+ it "should pass using lambdas as view_keys" do
350
+ query = lambda do |page_params|
351
+ RelaxDB.paginate_view "Letter_by_letter_and_number", :page_params => page_params,
352
+ :startkey => ["b"], :endkey => ["b", {}], :limit => 2,
353
+ :attributes => ["b", lambda { |l| l.number } ]
354
+ end
355
+ navigate_b_series query
356
+ end
357
+
358
+ end
359
+
360
+ end
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB::Query do
5
+
6
+ before(:all) do
7
+ RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => ""
8
+ end
9
+
10
+ describe "#view_name" do
11
+
12
+ it "should match a single key attribute" do
13
+ q = RelaxDB::ViewCreator.by_att_list ["bar"], :foo
14
+ q.view_name.should == "bar_by_foo"
15
+ end
16
+
17
+ it "should match key attributes" do
18
+ q = RelaxDB::ViewCreator.by_att_list ["bar"], :foo, :bar
19
+ q.view_name.should == "bar_by_foo_and_bar"
20
+ end
21
+ end
22
+
23
+ describe "#view_path" do
24
+
25
+ it "should list design document and view name and default reduce to false" do
26
+ q = RelaxDB::Query.new("mount")
27
+ q.view_path.should == "_design//_view/mount"
28
+ end
29
+
30
+ it "should contain URL and JSON encoded key when the key has been set" do
31
+ q = RelaxDB::Query.new("")
32
+ q.key("olympus")
33
+ q.view_path.should == "_design//_view/?key=%22olympus%22"
34
+ end
35
+
36
+ it "should honour startkey, endkey and limit" do
37
+ q = RelaxDB::Query.new("")
38
+ q.startkey(["olympus"]).endkey(["vesuvius", 3600]).limit(100)
39
+ q.view_path.should == "_design//_view/?startkey=%5B%22olympus%22%5D&endkey=%5B%22vesuvius%22%2C3600%5D&limit=100"
40
+ end
41
+
42
+ it "should specify a null key if key was set to nil" do
43
+ q = RelaxDB::Query.new("")
44
+ q.key(nil)
45
+ q.view_path.should == "_design//_view/?key=null"
46
+ end
47
+
48
+ it "should specify a null startkey if startkey was set to nil" do
49
+ q = RelaxDB::Query.new("")
50
+ q.startkey(nil)
51
+ q.view_path.should == "_design//_view/?startkey=null"
52
+ end
53
+
54
+ it "should specify a null endkey if endkey was set to nil" do
55
+ q = RelaxDB::Query.new("")
56
+ q.endkey(nil)
57
+ q.view_path.should == "_design//_view/?endkey=null"
58
+ end
59
+
60
+ it "should not JSON encode the startkey_docid" do
61
+ q = RelaxDB::Query.new("")
62
+ q.startkey_docid("foo")
63
+ q.view_path.should == "_design//_view/?startkey_docid=foo"
64
+ end
65
+
66
+ it "should not JSON encode the endkey_docid" do
67
+ q = RelaxDB::Query.new("")
68
+ q.endkey_docid("foo")
69
+ q.view_path.should == "_design//_view/?endkey_docid=foo"
70
+ end
71
+
72
+ it "should not include design or view if it starts with a _" do
73
+ q = RelaxDB::Query.new "_"
74
+ # q.view_path.should == "_"
75
+ q.view_path.should == "_"
76
+ end
77
+
78
+ end
79
+
80
+ describe "#keys" do
81
+
82
+ it "should return a JSON encoded hash" do
83
+ q = RelaxDB::Query.new("")
84
+ q.keys(["a", "b"])
85
+ q.keys.should == '{"keys":["a","b"]}'
86
+ end
87
+
88
+ end
89
+
90
+ end