couchrest 0.24 → 0.26

Sign up to get free protection for your applications and to get access to all the features.
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/incubator/couchdb/trunk/share/www/script/couch.js),
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.
@@ -81,6 +81,10 @@ module CouchRest
81
81
  @klass.all_design_doc_versions(@database)
82
82
  end
83
83
 
84
+ def model_design_doc
85
+ @klass.model_design_doc(@database)
86
+ end
87
+
84
88
  def cleanup_design_docs!
85
89
  @klass.cleanup_design_docs!(@database)
86
90
  end
@@ -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
- md5 = Digest::MD5.hexdigest(funcs.sort.join(''))
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 and we can assign the value
27
- if !property.default.nil? && (self.respond_to?("#{key}=") || self.key?(key))
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 any non-current design docs that were created by this class.
113
- # Running this when you're deployed version of your application is steadily
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
- ddocs = all_design_doc_versions(db)
119
- ddocs["rows"].each do |row|
120
- if (row['id'] != design_doc_id)
121
- db.delete_doc({
122
- "_id" => row['id'],
123
- "_rev" => row['value']['rev']
124
- })
125
- end
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 "rubygems"
16
- gem 'json'
17
- require 'json'
18
- gem 'rest-client'
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.24' unless self.const_defined?("VERSION")
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 :false_default, :default => false
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 work with a default value of false" do
161
+
162
+ it "should set default value of read-only property" do
163
163
  obj = WithDefaultValues.new
164
- obj.false_default.should == false
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 clean up design docs left around on specific database" do
187
- Unattached.by_title :database=>@db
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 :database=>@db
191
- Unattached.all_design_doc_versions(@db)["rows"].length.should == 2
189
+ Unattached.by_questions(:database => @db)
190
+ original_revision = Unattached.model_design_doc(@db)['_rev']
192
191
  Unattached.cleanup_design_docs!(@db)
193
- Unattached.all_design_doc_versions(@db)["rows"].length.should == 1
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.all_design_doc_versions["rows"].length.should == 1
248
+ original_id = @us.model_design_doc['_rev']
250
249
  Unattached.view_by :professor
251
250
  @us.by_professor
252
- @us.all_design_doc_versions["rows"].length.should == 2
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.all_design_doc_versions["rows"].length.should == ddocs + 1
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.24"
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