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