couchrest 0.24 → 0.26
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.md +3 -1
- data/Rakefile +0 -1
- data/lib/couchrest/core/database.rb +6 -0
- data/lib/couchrest/mixins/class_proxy.rb +4 -0
- data/lib/couchrest/mixins/design_doc.rb +1 -2
- data/lib/couchrest/mixins/properties.rb +2 -2
- data/lib/couchrest/mixins/validation.rb +16 -1
- data/lib/couchrest/mixins/views.rb +22 -14
- data/lib/couchrest.rb +7 -5
- data/spec/couchrest/core/database_spec.rb +5 -0
- data/spec/couchrest/more/casted_model_spec.rb +35 -0
- data/spec/couchrest/more/extended_doc_spec.rb +4 -4
- data/spec/couchrest/more/extended_doc_view_spec.rb +10 -27
- data/spec/fixtures/more/cat.rb +18 -0
- metadata +2 -11
data/README.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# CouchRest: CouchDB, close to the metal
|
2
2
|
|
3
3
|
CouchRest is based on [CouchDB's couch.js test
|
4
|
-
library](http://svn.apache.org/repos/asf/
|
4
|
+
library](http://svn.apache.org/repos/asf/couchdb/trunk/share/www/script/couch.js),
|
5
5
|
which I find to be concise, clear, and well designed. CouchRest lightly wraps
|
6
6
|
CouchDB's HTTP API, managing JSON serialization, and remembering the URI-paths
|
7
7
|
to CouchDB's API endpoints so you don't have to.
|
8
8
|
|
9
9
|
CouchRest is designed to make a simple base for application and framework-specific object oriented APIs. CouchRest is Object-Mapper agnostic, the parsed JSON it returns from CouchDB shows up as subclasses of Ruby's Hash. Naked JSON, just as it was mean to be.
|
10
10
|
|
11
|
+
Note: CouchRest only support CouchDB 0.9.0 or newer.
|
12
|
+
|
11
13
|
## Easy Install
|
12
14
|
|
13
15
|
Easy Install is moving to RubyForge, heads up for the gem.
|
data/Rakefile
CHANGED
@@ -29,7 +29,6 @@ spec = Gem::Specification.new do |s|
|
|
29
29
|
Dir["spec/tmp"]
|
30
30
|
s.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
|
31
31
|
s.require_path = "lib"
|
32
|
-
s.add_dependency("json", ">= 1.1.2")
|
33
32
|
s.add_dependency("rest-client", ">= 0.5")
|
34
33
|
s.add_dependency("mime-types", ">= 1.15")
|
35
34
|
end
|
@@ -44,6 +44,12 @@ module CouchRest
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
# load a set of documents by passing an array of ids
|
48
|
+
def get_bulk(ids)
|
49
|
+
documents(:keys => ids, :include_docs => true)
|
50
|
+
end
|
51
|
+
alias :bulk_load :get_bulk
|
52
|
+
|
47
53
|
# POST a temporary view function to CouchDB for querying. This is not
|
48
54
|
# recommended, as you don't get any performance benefit from CouchDB's
|
49
55
|
# materialized views. Can be quite slow on large databases.
|
@@ -25,8 +25,7 @@ module CouchRest
|
|
25
25
|
design_doc['views'].each do |name, view|
|
26
26
|
funcs << "#{name}/#{view['map']}#{view['reduce']}"
|
27
27
|
end
|
28
|
-
|
29
|
-
self.design_doc_slug_cache = "#{self.to_s}-#{md5}"
|
28
|
+
self.design_doc_slug_cache = self.to_s
|
30
29
|
end
|
31
30
|
|
32
31
|
def default_design_doc
|
@@ -23,8 +23,8 @@ module CouchRest
|
|
23
23
|
# TODO: cache the default object
|
24
24
|
self.class.properties.each do |property|
|
25
25
|
key = property.name.to_s
|
26
|
-
# let's make sure we have a default
|
27
|
-
if
|
26
|
+
# let's make sure we have a default
|
27
|
+
if property.default
|
28
28
|
if property.default.class == Proc
|
29
29
|
self[key] = property.default.call
|
30
30
|
else
|
@@ -115,7 +115,22 @@ module CouchRest
|
|
115
115
|
# Check if a resource is valid in a given context
|
116
116
|
#
|
117
117
|
def valid?(context = :default)
|
118
|
-
self.class.validators.execute(context, self)
|
118
|
+
result = self.class.validators.execute(context, self)
|
119
|
+
result && validate_casted_arrays
|
120
|
+
end
|
121
|
+
|
122
|
+
# checking on casted objects
|
123
|
+
def validate_casted_arrays
|
124
|
+
result = true
|
125
|
+
array_casted_properties = self.class.properties.select { |property| property.casted && property.type.instance_of?(Array) }
|
126
|
+
array_casted_properties.each do |property|
|
127
|
+
casted_values = self.send(property.name)
|
128
|
+
next unless casted_values.respond_to?(:each) && casted_values.first.respond_to?(:valid?)
|
129
|
+
casted_values.each do |value|
|
130
|
+
result = (result && value.valid?) if value.respond_to?(:valid?)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
result
|
119
134
|
end
|
120
135
|
|
121
136
|
# Begin a recursive walk of the model checking validity
|
@@ -104,26 +104,34 @@ module CouchRest
|
|
104
104
|
fetch_view_with_docs(db, name, query, raw, &block)
|
105
105
|
end
|
106
106
|
|
107
|
+
# DEPRECATED
|
108
|
+
# user model_design_doc to retrieve the current design doc
|
107
109
|
def all_design_doc_versions(db = database)
|
108
|
-
db.documents :startkey => "_design/#{self.to_s}
|
110
|
+
db.documents :startkey => "_design/#{self.to_s}",
|
109
111
|
:endkey => "_design/#{self.to_s}-\u9999"
|
110
112
|
end
|
113
|
+
|
114
|
+
def model_design_doc(db = database)
|
115
|
+
begin
|
116
|
+
@model_design_doc = db.get("_design/#{self.to_s}")
|
117
|
+
rescue
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
end
|
111
121
|
|
112
|
-
# Deletes
|
113
|
-
# Running
|
114
|
-
# and consistently using the latest code, is the way to clear out old design
|
115
|
-
# docs. Running it to early could mean that live code has to regenerate
|
122
|
+
# Deletes the current design doc for the current class.
|
123
|
+
# Running it to early could mean that live code has to regenerate
|
116
124
|
# potentially large indexes.
|
117
125
|
def cleanup_design_docs!(db = database)
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
end
|
126
|
+
save_design_doc_on(db)
|
127
|
+
# db.refresh_design_doc
|
128
|
+
# db.save_design_doc
|
129
|
+
# design_doc = model_design_doc(db)
|
130
|
+
# if design_doc
|
131
|
+
# db.delete_doc(design_doc)
|
132
|
+
# else
|
133
|
+
# false
|
134
|
+
# end
|
127
135
|
end
|
128
136
|
|
129
137
|
private
|
data/lib/couchrest.rb
CHANGED
@@ -12,10 +12,12 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
require
|
16
|
-
|
17
|
-
require 'json'
|
18
|
-
|
15
|
+
require 'rubygems'
|
16
|
+
begin
|
17
|
+
require 'json'
|
18
|
+
rescue LoadError
|
19
|
+
raise "You need install and require your own compatible json library since couchrest rest couldn't load the json/json_pure gem" unless Kernel.const_defined?("JSON")
|
20
|
+
end
|
19
21
|
require 'rest_client'
|
20
22
|
|
21
23
|
$:.unshift File.dirname(__FILE__) unless
|
@@ -28,7 +30,7 @@ require 'couchrest/monkeypatches'
|
|
28
30
|
|
29
31
|
# = CouchDB, close to the metal
|
30
32
|
module CouchRest
|
31
|
-
VERSION = '0.
|
33
|
+
VERSION = '0.26' unless self.const_defined?("VERSION")
|
32
34
|
|
33
35
|
autoload :Server, 'couchrest/core/server'
|
34
36
|
autoload :Database, 'couchrest/core/database'
|
@@ -599,6 +599,11 @@ describe CouchRest::Database do
|
|
599
599
|
ds = @db.documents(:startkey => 'doc0', :endkey => 'doc3', :include_docs => true)
|
600
600
|
ds['rows'][0]['doc']['another'].should == "doc"
|
601
601
|
end
|
602
|
+
it "should have the bulk_load macro" do
|
603
|
+
rs = @db.bulk_load ["doc0", "doc7"]
|
604
|
+
rs['rows'].length.should == 2
|
605
|
+
rs['rows'][0]['doc']['another'].should == "doc"
|
606
|
+
end
|
602
607
|
end
|
603
608
|
|
604
609
|
|
@@ -1,5 +1,10 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
2
4
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
5
|
+
require File.join(FIXTURE_PATH, 'more', 'cat')
|
6
|
+
require File.join(FIXTURE_PATH, 'more', 'person')
|
7
|
+
|
3
8
|
|
4
9
|
class WithCastedModelMixin < Hash
|
5
10
|
include CouchRest::CastedModel
|
@@ -103,5 +108,35 @@ describe CouchRest::CastedModel do
|
|
103
108
|
end
|
104
109
|
|
105
110
|
end
|
111
|
+
|
112
|
+
describe "saving document with array of casted models and validation" do
|
113
|
+
before :each do
|
114
|
+
@cat = Cat.new
|
115
|
+
@cat.save
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should save" do
|
119
|
+
toy = CatToy.new :name => "Mouse"
|
120
|
+
@cat.toys.push(toy)
|
121
|
+
@cat.save.should be_true
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should fail because name is not present" do
|
125
|
+
toy = CatToy.new
|
126
|
+
@cat.toys.push(toy)
|
127
|
+
@cat.should_not be_valid
|
128
|
+
@cat.save.should be_false
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should not fail if the casted model doesn't have validation" do
|
132
|
+
Cat.property :masters, :cast_as => ['Person'], :default => []
|
133
|
+
Cat.validates_present :name
|
134
|
+
cat = Cat.new(:name => 'kitty')
|
135
|
+
cat.should be_valid
|
136
|
+
cat.masters.push Person.new
|
137
|
+
cat.should be_valid
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
106
141
|
|
107
142
|
end
|
@@ -10,7 +10,7 @@ describe "ExtendedDocument" do
|
|
10
10
|
property :preset, :default => {:right => 10, :top_align => false}
|
11
11
|
property :set_by_proc, :default => Proc.new{Time.now}, :cast_as => 'Time'
|
12
12
|
property :tags, :default => []
|
13
|
-
property :
|
13
|
+
property :read_only_with_default, :default => 'generic', :read_only => true
|
14
14
|
property :name
|
15
15
|
timestamps!
|
16
16
|
end
|
@@ -158,10 +158,10 @@ describe "ExtendedDocument" do
|
|
158
158
|
obj = WithDefaultValues.new(:tags => ['spec'])
|
159
159
|
obj.tags.should == ['spec']
|
160
160
|
end
|
161
|
-
|
162
|
-
it "should
|
161
|
+
|
162
|
+
it "should set default value of read-only property" do
|
163
163
|
obj = WithDefaultValues.new
|
164
|
-
obj.
|
164
|
+
obj.read_only_with_default.should == 'generic'
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
@@ -183,14 +183,13 @@ describe "ExtendedDocument views" do
|
|
183
183
|
it "should barf on all_design_doc_versions if no database given" do
|
184
184
|
lambda{Unattached.all_design_doc_versions}.should raise_error
|
185
185
|
end
|
186
|
-
it "should
|
187
|
-
|
188
|
-
Unattached.all_design_doc_versions(@db)["rows"].length.should == 1
|
186
|
+
it "should be able to cleanup the db/bump the revision number" do
|
187
|
+
# if the previous specs were not run, the model_design_doc will be blank
|
189
188
|
Unattached.view_by :questions
|
190
|
-
Unattached.by_questions
|
191
|
-
Unattached.
|
189
|
+
Unattached.by_questions(:database => @db)
|
190
|
+
original_revision = Unattached.model_design_doc(@db)['_rev']
|
192
191
|
Unattached.cleanup_design_docs!(@db)
|
193
|
-
Unattached.
|
192
|
+
Unattached.model_design_doc(@db)['_rev'].should_not == original_revision
|
194
193
|
end
|
195
194
|
end
|
196
195
|
|
@@ -246,12 +245,10 @@ describe "ExtendedDocument views" do
|
|
246
245
|
end
|
247
246
|
it "should clean up design docs left around on specific database" do
|
248
247
|
@us.by_title
|
249
|
-
@us.
|
248
|
+
original_id = @us.model_design_doc['_rev']
|
250
249
|
Unattached.view_by :professor
|
251
250
|
@us.by_professor
|
252
|
-
@us.
|
253
|
-
@us.cleanup_design_docs!
|
254
|
-
@us.all_design_doc_versions["rows"].length.should == 1
|
251
|
+
@us.model_design_doc['_rev'].should_not == original_id
|
255
252
|
end
|
256
253
|
end
|
257
254
|
|
@@ -321,6 +318,7 @@ describe "ExtendedDocument views" do
|
|
321
318
|
before(:each) do
|
322
319
|
reset_test_db!
|
323
320
|
Article.by_date
|
321
|
+
@original_doc_rev = Article.model_design_doc['_rev']
|
324
322
|
@design_docs = Article.database.documents :startkey => "_design/", :endkey => "_design/\u9999"
|
325
323
|
end
|
326
324
|
it "should not create a design doc on view definition" do
|
@@ -332,24 +330,9 @@ describe "ExtendedDocument views" do
|
|
332
330
|
ddocs = Article.all_design_doc_versions["rows"].length
|
333
331
|
Article.view_by :updated_at
|
334
332
|
Article.by_updated_at
|
335
|
-
Article.
|
333
|
+
@original_doc_rev.should_not == Article.model_design_doc['_rev']
|
336
334
|
Article.design_doc["views"].keys.should include("by_updated_at")
|
337
335
|
end
|
338
336
|
end
|
339
|
-
|
340
|
-
describe "with a lot of designs left around" do
|
341
|
-
before(:each) do
|
342
|
-
reset_test_db!
|
343
|
-
Article.by_date
|
344
|
-
Article.view_by :field
|
345
|
-
Article.by_field
|
346
|
-
end
|
347
|
-
it "should clean them up" do
|
348
|
-
Article.view_by :stream
|
349
|
-
Article.by_stream
|
350
|
-
Article.all_design_doc_versions["rows"].length.should > 1
|
351
|
-
Article.cleanup_design_docs!
|
352
|
-
Article.all_design_doc_versions["rows"].length.should == 1
|
353
|
-
end
|
354
|
-
end
|
337
|
+
|
355
338
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Cat < CouchRest::ExtendedDocument
|
2
|
+
include ::CouchRest::Validation
|
3
|
+
|
4
|
+
# Set the default database to use
|
5
|
+
use_database TEST_SERVER.default_database
|
6
|
+
|
7
|
+
property :name
|
8
|
+
property :toys, :cast_as => ['CatToy'], :default => []
|
9
|
+
end
|
10
|
+
|
11
|
+
class CatToy < Hash
|
12
|
+
include ::CouchRest::CastedModel
|
13
|
+
include ::CouchRest::Validation
|
14
|
+
|
15
|
+
property :name
|
16
|
+
|
17
|
+
validates_present :name
|
18
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.26"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J. Chris Anderson
|
@@ -13,16 +13,6 @@ cert_chain: []
|
|
13
13
|
date: 2008-11-22 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
17
|
-
name: json
|
18
|
-
type: :runtime
|
19
|
-
version_requirement:
|
20
|
-
version_requirements: !ruby/object:Gem::Requirement
|
21
|
-
requirements:
|
22
|
-
- - ">="
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: 1.1.2
|
25
|
-
version:
|
26
16
|
- !ruby/object:Gem::Dependency
|
27
17
|
name: rest-client
|
28
18
|
type: :runtime
|
@@ -131,6 +121,7 @@ files:
|
|
131
121
|
- spec/fixtures/attachments/test.html
|
132
122
|
- spec/fixtures/more/article.rb
|
133
123
|
- spec/fixtures/more/card.rb
|
124
|
+
- spec/fixtures/more/cat.rb
|
134
125
|
- spec/fixtures/more/course.rb
|
135
126
|
- spec/fixtures/more/event.rb
|
136
127
|
- spec/fixtures/more/invoice.rb
|