paulcarey-relaxdb 0.3.2 → 0.3.3

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.
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: