paulcarey-relaxdb 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,5 +1,7 @@
1
1
  h3. What's New?
2
2
 
3
+ * 2009-05-27
4
+ ** Added minimal support for data migrations. Although CouchDB's nature removes the necessity for migrations, certain knowledge that all objects possess a particular property can simplify client logic. This desire for simplification is the rationale behind this change.
3
5
  * 2009-04-19
4
6
  ** Defaults to taf2-curb, falling back to Net/HTTP if it taf2-curb can't be loaded. Thanks to "Fred Cheung":http://www.spacevatican.org/2009/4/13/fun-with-ruby-http-clients.
5
7
  ** For those interested in using RelaxDB with an ETag based cache, "look here":http://github.com/fcheung/relaxdb/commit/1d9acfd5f6b3c23da0d275252b6a6e064865440e
@@ -171,6 +173,20 @@ h3. Creating views by hand
171
173
  </code>
172
174
  </pre>
173
175
 
176
+ h3. Migrations
177
+
178
+ <pre>
179
+ <code>
180
+ $ cat 001_double.rb
181
+ RelaxDB::Migration.run Primitives do |p|
182
+ p.num *= 2
183
+ p
184
+ end
185
+
186
+ $ ruby -e 'RelaxDB::Migration.run_all Dir["./*.rb"]'
187
+ </code>
188
+ </pre>
189
+
174
190
  h3. Visualise
175
191
 
176
192
  "Fuschia":http://github.com/paulcarey/fuschia/tree/master offers a web front end for visualising inter-document relationships.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'spec/rake/spectask'
4
4
 
5
5
  PLUGIN = "relaxdb"
6
6
  NAME = "relaxdb"
7
- GEM_VERSION = "0.3.2"
7
+ GEM_VERSION = "0.3.3"
8
8
  AUTHOR = "Paul Carey"
9
9
  EMAIL = "paul.p.carey@gmail.com"
10
10
  HOMEPAGE = "http://github.com/paulcarey/relaxdb/"
@@ -0,0 +1,40 @@
1
+ module RelaxDB
2
+
3
+ class Migration
4
+
5
+ def self.run klass, limit = 1000
6
+ query = lambda do |page_params|
7
+ RelaxDB.paginate_view "#{klass}_all", :startkey => nil, :endkey => {}, :attributes => [:_id],
8
+ :page_params => page_params, :limit => limit
9
+ end
10
+
11
+ objs = query.call({})
12
+ until objs.empty?
13
+ migrated = objs.map { |o| yield o }.flatten.reject { |o| o.nil? }
14
+ RelaxDB.bulk_save! *migrated
15
+ objs = objs.next_params ? query.call(objs.next_params) : []
16
+ end
17
+ end
18
+
19
+ #
20
+ # Runs all outstanding migrations in a given directory
21
+ #
22
+ # ==== Example
23
+ # RelaxDB::Migration.run_all Dir["couchdb/migrations/**/*.rb"]
24
+ #
25
+ def self.run_all file_names, action = lambda { |fn| require fn }
26
+ v = RelaxDB::MigrationVersion.version
27
+ file_names.select { |fn| fv(fn) > v }.each do |fn|
28
+ RelaxDB.logger.info "Applying #{fn}"
29
+ action.call fn
30
+ RelaxDB::MigrationVersion.update fv(fn)
31
+ end
32
+ end
33
+
34
+ def self.fv file_name
35
+ File.basename(file_name).split("_")[0].to_i
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,21 @@
1
+ class RelaxDB::MigrationVersion < RelaxDB::Document
2
+
3
+ DOC_ID = "relaxdb_migration_version"
4
+
5
+ property :version, :default => 0
6
+
7
+ def self.version
8
+ retrieve.version
9
+ end
10
+
11
+ def self.update v
12
+ mv = retrieve
13
+ mv.version = v
14
+ mv.save!
15
+ end
16
+
17
+ def self.retrieve
18
+ (v = RelaxDB.load(DOC_ID)) ? v : new(:_id => DOC_ID).save!
19
+ end
20
+
21
+ end
@@ -73,7 +73,7 @@ module RelaxDB
73
73
  end
74
74
 
75
75
  pre_save_success = objs.inject(true) { |s, o| s &= o.pre_save }
76
- raise ValidationFailure, objs unless pre_save_success
76
+ raise ValidationFailure, objs.inspect unless pre_save_success
77
77
 
78
78
  docs = {}
79
79
  objs.each { |o| docs[o._id] = o }
data/lib/relaxdb/views.rb CHANGED
@@ -8,7 +8,7 @@ module RelaxDB
8
8
  function(doc) {
9
9
  var class_match = #{kls_check kls}
10
10
  if (class_match) {
11
- emit(null, doc);
11
+ emit(doc._id, doc);
12
12
  }
13
13
  }
14
14
  QUERY
data/lib/relaxdb.rb CHANGED
@@ -30,6 +30,7 @@ require 'relaxdb/document'
30
30
  require 'relaxdb/extlib'
31
31
  require 'relaxdb/has_many_proxy'
32
32
  require 'relaxdb/has_one_proxy'
33
+ require 'relaxdb/migration'
33
34
  require 'relaxdb/paginate_params'
34
35
  require 'relaxdb/paginator'
35
36
  require 'relaxdb/query'
@@ -43,5 +44,7 @@ require 'relaxdb/view_uploader'
43
44
  require 'relaxdb/views'
44
45
  require 'more/grapher.rb'
45
46
 
47
+ require 'relaxdb/migration_version'
48
+
46
49
  module RelaxDB
47
50
  end
@@ -0,0 +1,100 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe "Inheritance" do
5
+
6
+ before(:each) do
7
+ setup_test_db
8
+ end
9
+
10
+ describe "properties" do
11
+
12
+ it "should by inherited from a parent document" do
13
+ d = SubDescendant.new(:x => 1).save!
14
+ RelaxDB.reload(d).x.should == 1
15
+ end
16
+
17
+ it "should store its own properties" do
18
+ r = RichDescendant.new(:x => 1, :foo => :bar).save!
19
+ RelaxDB.reload(r).x.should == 1
20
+ RelaxDB.reload(r).foo.should == "bar"
21
+ end
22
+
23
+ it "validators should behave as normal" do
24
+ d = SubDescendant.new(:y => false)
25
+ d.save.should be_false
26
+ d.errors[:y].should == "Uh oh"
27
+ end
28
+
29
+ end
30
+
31
+ describe "_all views" do
32
+
33
+ it "should be rewritten" do
34
+ a = Ancestor.new(:x => 0).save!
35
+ d = Descendant.new(:x => 1).save!
36
+
37
+ Ancestor.all.should == [a, d]
38
+ Descendant.all.should == [d]
39
+ end
40
+
41
+ it "should function with inheritance trees" do
42
+ Inh::X.new.save!
43
+
44
+ Inh::Y.new.save!
45
+ Inh::Y1.new.save!
46
+
47
+ Inh::Z.new.save!
48
+ Inh::Z1.new.save!
49
+ Inh::Z2.new.save!
50
+
51
+ Inh::X.all.size.should == 6
52
+ Inh::Y.all.size.should == 2
53
+ Inh::Y1.all.size.should == 1
54
+ Inh::Z.all.size.should == 3
55
+ Inh::Z1.all.size.should == 1
56
+ Inh::Z2.all.size.should == 1
57
+ end
58
+
59
+ end
60
+
61
+ describe "_by views" do
62
+
63
+ it "should be rewritten for ancestors and generated for descendants" do
64
+ a = Ancestor.new(:x => 0).save!
65
+ d = Descendant.new(:x => 1).save!
66
+
67
+ Ancestor.by_x.should == [a, d]
68
+ Descendant.by_x.should == [d]
69
+ end
70
+
71
+ end
72
+
73
+ describe "derived properties" do
74
+
75
+ it "should be stored" do
76
+ u = User.new(:_id => "foo", :name => "u").save!
77
+ s = SubDescendant.new(:user => u).save!
78
+ r = RichDescendant.new(:user => u, :ukulele => u).save!
79
+
80
+ RelaxDB.reload(s).user_name.should == "u"
81
+ RelaxDB.reload(r).user_name.should == "u"
82
+ RelaxDB.reload(r).ukulele_name.should == "u"
83
+ end
84
+
85
+ end
86
+
87
+ describe "references" do
88
+
89
+ it "should function as normal" do
90
+ u = User.new(:name => "u").save!
91
+ s = SubDescendant.new(:user => u).save!
92
+ r = RichDescendant.new(:user => u).save!
93
+
94
+ RelaxDB.reload(s).user.name.should == "u"
95
+ RelaxDB.reload(r).user.name.should == "u"
96
+ end
97
+
98
+ end
99
+
100
+ 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
@@ -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,351 @@
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
+ end
350
+
351
+ end
data/spec/relaxdb_spec.rb CHANGED
@@ -39,11 +39,7 @@ describe RelaxDB do
39
39
  ta.should == t1
40
40
  tb.should == t2
41
41
  end
42
-
43
- it "should succeed when passed no args" do
44
- RelaxDB.bulk_save
45
- end
46
-
42
+
47
43
  it "should return false on failure" do
48
44
  c = Class.new(RelaxDB::Document) do
49
45
  property :foo, :validator => lambda { false }
@@ -128,6 +124,16 @@ describe RelaxDB do
128
124
 
129
125
  describe ".bulk_save!" do
130
126
 
127
+ it "should succeed when passed no args" do
128
+ RelaxDB.bulk_save!
129
+ end
130
+
131
+ it "should raise when passed a nil value" do
132
+ lambda do
133
+ RelaxDB.bulk_save! *[nil]
134
+ end.should raise_error
135
+ end
136
+
131
137
  it "should raise an exception if a obj fails validation" do
132
138
  c = Class.new(RelaxDB::Document) do
133
139
  property :foo, :validator => lambda { false }
@@ -207,6 +213,16 @@ describe RelaxDB do
207
213
  ar2.should == a2
208
214
  end
209
215
 
216
+ it "should load multiple documents in order" do
217
+ ns = (0...100).map { rand(1_000_000_000).to_s }
218
+ objs = ns.map { |n| Primitives.new :_id => n }
219
+ RelaxDB.bulk_save! *objs
220
+ objs = RelaxDB.load! ns
221
+ (0...100).each do |i|
222
+ ns[i].should == objs[i]._id
223
+ end
224
+ end
225
+
210
226
  it "should throw an exception if given a single id for a non-existant doc" do
211
227
  lambda do
212
228
  RelaxDB.load! "nothere"
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB do
5
+
6
+ before(:all) do
7
+ RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => "spec_doc"
8
+ @server = RelaxDB::Server.new("localhost", 5984)
9
+ end
10
+
11
+ before(:each) do
12
+ RelaxDB.delete_db "relaxdb_spec" rescue "ok"
13
+ RelaxDB.use_db "relaxdb_spec"
14
+ end
15
+
16
+ describe "GET" do
17
+
18
+ it "should raise a HTTP_404 for a non existant doc" do
19
+ lambda do
20
+ @server.get "/relaxdb_spec/foo"
21
+ end.should raise_error(RelaxDB::HTTP_404)
22
+ end
23
+
24
+ it "should raise a RuntimeError for non specific errors" do
25
+ lambda do
26
+ @server.get "/relaxdb_spec/_design/spec_doc/_view?fail=true"
27
+ end.should raise_error(RuntimeError)
28
+ end
29
+
30
+ end
31
+
32
+ end
data/spec/spec_helper.rb CHANGED
@@ -9,8 +9,12 @@ end
9
9
  $:.unshift(File.dirname(__FILE__) + '/../lib')
10
10
  require 'relaxdb'
11
11
 
12
+ class RdbFormatter; def call(sv, time, progname, msg); puts msg; end; end
13
+
12
14
  def setup_test_db
13
15
  # RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => "spec_doc", :logger => Logger.new(STDOUT)
16
+ # RelaxDB.logger.formatter = RdbFormatter.new
17
+
14
18
  RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => "spec_doc"
15
19
 
16
20
  RelaxDB.delete_db "relaxdb_spec" rescue "ok"
@@ -0,0 +1,76 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe "view_by" do
5
+
6
+ before(:all) do
7
+ RelaxDB.configure :host => "localhost", :port => 5984, :design_doc => "spec_doc"
8
+ end
9
+
10
+ describe "view_by" do
11
+
12
+ before(:each) do
13
+ RelaxDB.delete_db "relaxdb_spec" rescue "ok"
14
+ RelaxDB.use_db "relaxdb_spec"
15
+ RelaxDB.enable_view_creation
16
+
17
+ class ViewByFoo < RelaxDB::Document
18
+ property :foo
19
+ view_by :foo, :descending => true
20
+ end
21
+
22
+ end
23
+
24
+ it "should create corresponding views" do
25
+ dd = RelaxDB::DesignDocument.get "spec_doc"
26
+ dd.data["views"]["ViewByFoo_by_foo"].should be
27
+ end
28
+
29
+ it "should create a by_ att list method" do
30
+ ViewByFoo.new(:foo => :bar).save!
31
+ res = ViewByFoo.by_foo
32
+ res.first.foo.should == "bar"
33
+ end
34
+
35
+ it "should create a paginate_by_ att list method" do
36
+ ViewByFoo.new(:foo => :bar).save!
37
+ res = ViewByFoo.paginate_by_foo :page_params => {}, :startkey => {}, :endkey => nil
38
+ res.first.foo.should == "bar"
39
+ end
40
+
41
+ it "should apply query defaults to by_" do
42
+ ViewByFoo.new(:foo => "a").save!
43
+ ViewByFoo.new(:foo => "b").save!
44
+
45
+ ViewByFoo.by_foo.map{ |o| o.foo }.should == ["b", "a"]
46
+ end
47
+
48
+ it "should allow a single arg to be passed to by_" do
49
+ vbf = ViewByFoo.new(:foo => "a").save!
50
+ ViewByFoo.by_foo("a").should == vbf
51
+ end
52
+
53
+ it "should apply query defaults to paginate_by_" do
54
+ ViewByFoo.new(:foo => "a").save!
55
+ ViewByFoo.new(:foo => "b").save!
56
+
57
+ res = ViewByFoo.paginate_by_foo :page_params => {}, :startkey => {}, :endkey => nil
58
+ res.map{ |o| o.foo }.should == ["b", "a"]
59
+ end
60
+
61
+ it "should allow query defaults to be overridden for paginate_by_" do
62
+ ViewByFoo.new(:foo => :bar).save!
63
+ res = ViewByFoo.paginate_by_foo :page_params => {}, :startkey => nil, :endkey => {}, :descending => false
64
+ res.first.foo.should == "bar"
65
+ end
66
+
67
+ it "should allow query defaults to be overridden for by_" do
68
+ ViewByFoo.new(:foo => "a").save!
69
+ ViewByFoo.new(:foo => "b").save!
70
+
71
+ ViewByFoo.by_foo(:descending => false).map{ |o| o.foo }.should == ["a", "b"]
72
+ end
73
+
74
+ end
75
+
76
+ end
data/spec/view_spec.rb ADDED
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/spec_models.rb'
3
+
4
+ describe RelaxDB::View do
5
+
6
+ describe "exists" do
7
+
8
+ before(:each) do
9
+ create_test_db
10
+ end
11
+
12
+ it "should return nil if a view doesnt exist" do
13
+ RelaxDB::ViewCreator.all([Atom]).should_not be_exists
14
+ end
15
+
16
+ it "should return the view if it exits" do
17
+ RelaxDB::ViewCreator.all([Atom]).save
18
+ RelaxDB::ViewCreator.all([Atom]).should be_exists
19
+ end
20
+
21
+ end
22
+
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paulcarey-relaxdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Carey
@@ -9,7 +9,7 @@ autorequire: relaxdb
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-22 00:00:00 -07:00
12
+ date: 2009-05-27 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -65,6 +65,8 @@ files:
65
65
  - lib/relaxdb/has_many_proxy.rb
66
66
  - lib/relaxdb/has_one_proxy.rb
67
67
  - lib/relaxdb/net_http_server.rb
68
+ - lib/relaxdb/migration.rb
69
+ - lib/relaxdb/migration_version.rb
68
70
  - lib/relaxdb/paginate_params.rb
69
71
  - lib/relaxdb/paginator.rb
70
72
  - lib/relaxdb/query.rb
@@ -83,18 +85,26 @@ files:
83
85
  - lib/more/atomic_bulk_save_support.rb
84
86
  - spec/belongs_to_spec.rb
85
87
  - spec/callbacks_spec.rb
86
- - spec/design_doc_spec.rb
87
88
  - spec/derived_properties_spec.rb
89
+ - spec/design_doc_spec.rb
90
+ - spec/doc_inheritable_spec.rb
88
91
  - spec/document_spec.rb
89
92
  - spec/has_many_spec.rb
90
93
  - spec/has_one_spec.rb
94
+ - spec/migration_spec.rb
95
+ - spec/migration_version_spec.rb
96
+ - spec/paginate_params_spec.rb
97
+ - spec/paginate_spec.rb
91
98
  - spec/query_spec.rb
92
99
  - spec/references_many_spec.rb
93
100
  - spec/relaxdb_spec.rb
101
+ - spec/server_spec.rb
94
102
  - spec/spec.opts
95
103
  - spec/spec_helper.rb
96
104
  - spec/spec_models.rb
105
+ - spec/view_by_spec.rb
97
106
  - spec/view_object_spec.rb
107
+ - spec/view_spec.rb
98
108
  has_rdoc: false
99
109
  homepage: http://github.com/paulcarey/relaxdb/
100
110
  post_install_message: