norr-couchrest 0.30.4 → 0.33.01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/README.md +58 -10
  2. data/history.txt +45 -1
  3. data/lib/couchrest.rb +9 -49
  4. data/lib/couchrest/core/adapters/restclient.rb +35 -0
  5. data/lib/couchrest/core/database.rb +18 -10
  6. data/lib/couchrest/core/document.rb +0 -4
  7. data/lib/couchrest/core/http_abstraction.rb +48 -0
  8. data/lib/couchrest/core/rest_api.rb +49 -0
  9. data/lib/couchrest/middlewares/logger.rb +263 -0
  10. data/lib/couchrest/mixins/attachments.rb +2 -2
  11. data/lib/couchrest/mixins/class_proxy.rb +5 -1
  12. data/lib/couchrest/mixins/collection.rb +23 -6
  13. data/lib/couchrest/mixins/design_doc.rb +5 -0
  14. data/lib/couchrest/mixins/document_queries.rb +33 -4
  15. data/lib/couchrest/mixins/properties.rb +30 -4
  16. data/lib/couchrest/mixins/views.rb +5 -13
  17. data/lib/couchrest/monkeypatches.rb +59 -59
  18. data/lib/couchrest/more/casted_model.rb +3 -2
  19. data/lib/couchrest/more/extended_document.rb +18 -1
  20. data/lib/couchrest/validation/validation_errors.rb +7 -0
  21. data/spec/couchrest/core/couchrest_spec.rb +2 -2
  22. data/spec/couchrest/core/database_spec.rb +19 -5
  23. data/spec/couchrest/core/design_spec.rb +1 -1
  24. data/spec/couchrest/core/document_spec.rb +1 -1
  25. data/spec/couchrest/core/server_spec.rb +1 -1
  26. data/spec/couchrest/helpers/pager_spec.rb +1 -1
  27. data/spec/couchrest/helpers/streamer_spec.rb +1 -1
  28. data/spec/couchrest/more/casted_extended_doc_spec.rb +1 -1
  29. data/spec/couchrest/more/casted_model_spec.rb +1 -1
  30. data/spec/couchrest/more/extended_doc_attachment_spec.rb +1 -1
  31. data/spec/couchrest/more/extended_doc_spec.rb +27 -2
  32. data/spec/couchrest/more/extended_doc_subclass_spec.rb +1 -1
  33. data/spec/couchrest/more/extended_doc_view_spec.rb +21 -9
  34. data/spec/couchrest/more/property_spec.rb +50 -1
  35. data/spec/spec_helper.rb +1 -1
  36. metadata +9 -2
@@ -72,7 +72,7 @@ module CouchRest
72
72
  #
73
73
  # To understand the capabilities of this view system more completely,
74
74
  # it is recommended that you read the RSpec file at
75
- # <tt>spec/core/model_spec.rb</tt>.
75
+ # <tt>spec/couchrest/more/extended_doc_spec.rb</tt>.
76
76
 
77
77
  def view_by(*keys)
78
78
  opts = keys.pop if keys.last.is_a?(Hash)
@@ -95,11 +95,11 @@ module CouchRest
95
95
 
96
96
  # Dispatches to any named view.
97
97
  def view(name, query={}, &block)
98
- unless design_doc_fresh
99
- refresh_design_doc
98
+ db = query.delete(:database) || database
99
+ unless design_doc_fresh
100
+ refresh_design_doc_on(db)
100
101
  end
101
102
  query[:raw] = true if query[:reduce]
102
- db = query.delete(:database) || database
103
103
  raw = query.delete(:raw)
104
104
  fetch_view_with_docs(db, name, query, raw, &block)
105
105
  end
@@ -124,14 +124,6 @@ module CouchRest
124
124
  # potentially large indexes.
125
125
  def cleanup_design_docs!(db = database)
126
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
135
127
  end
136
128
 
137
129
  private
@@ -162,7 +154,7 @@ module CouchRest
162
154
  begin
163
155
  design_doc.view_on(db, view_name, opts, &block)
164
156
  # the design doc may not have been saved yet on this database
165
- rescue RestClient::ResourceNotFound => e
157
+ rescue HttpAbstraction::ResourceNotFound => e
166
158
  if retryable
167
159
  save_design_doc_on(db)
168
160
  retryable = false
@@ -51,63 +51,63 @@ if RUBY_VERSION.to_f < 1.9
51
51
  end
52
52
  end
53
53
 
54
- module RestClient
55
- def self.copy(url, headers={})
56
- Request.execute(:method => :copy,
57
- :url => url,
58
- :headers => headers)
59
- end
60
-
61
- # class Request
62
- #
63
- # def establish_connection(uri)
64
- # Thread.current[:connection].finish if (Thread.current[:connection] && Thread.current[:connection].started?)
65
- # p net_http_class
66
- # net = net_http_class.new(uri.host, uri.port)
67
- # net.use_ssl = uri.is_a?(URI::HTTPS)
68
- # net.verify_mode = OpenSSL::SSL::VERIFY_NONE
69
- # Thread.current[:connection] = net
70
- # Thread.current[:connection].start
71
- # Thread.current[:connection]
72
- # end
73
- #
74
- # def transmit(uri, req, payload)
75
- # setup_credentials(req)
76
- #
77
- # Thread.current[:host] ||= uri.host
78
- # Thread.current[:port] ||= uri.port
79
- #
80
- # if (Thread.current[:connection].nil? || (Thread.current[:host] != uri.host))
81
- # p "establishing a connection"
82
- # establish_connection(uri)
83
- # end
54
+ # module RestClient
55
+ # # def self.copy(url, headers={})
56
+ # # Request.execute(:method => :copy,
57
+ # # :url => url,
58
+ # # :headers => headers)
59
+ # # end
84
60
  #
85
- # display_log request_log
86
- # http = Thread.current[:connection]
87
- # http.read_timeout = @timeout if @timeout
88
- #
89
- # begin
90
- # res = http.request(req, payload)
91
- # rescue
92
- # p "Net::HTTP connection failed, reconnecting"
93
- # establish_connection(uri)
94
- # http = Thread.current[:connection]
95
- # require 'ruby-debug'
96
- # req.body_stream = nil
97
- #
98
- # res = http.request(req, payload)
99
- # display_log response_log(res)
100
- # result res
101
- # else
102
- # display_log response_log(res)
103
- # process_result res
104
- # end
105
- #
106
- # rescue EOFError
107
- # raise RestClient::ServerBrokeConnection
108
- # rescue Timeout::Error
109
- # raise RestClient::RequestTimeout
110
- # end
111
- # end
112
-
113
- end
61
+ # # class Request
62
+ # #
63
+ # # def establish_connection(uri)
64
+ # # Thread.current[:connection].finish if (Thread.current[:connection] && Thread.current[:connection].started?)
65
+ # # p net_http_class
66
+ # # net = net_http_class.new(uri.host, uri.port)
67
+ # # net.use_ssl = uri.is_a?(URI::HTTPS)
68
+ # # net.verify_mode = OpenSSL::SSL::VERIFY_NONE
69
+ # # Thread.current[:connection] = net
70
+ # # Thread.current[:connection].start
71
+ # # Thread.current[:connection]
72
+ # # end
73
+ # #
74
+ # # def transmit(uri, req, payload)
75
+ # # setup_credentials(req)
76
+ # #
77
+ # # Thread.current[:host] ||= uri.host
78
+ # # Thread.current[:port] ||= uri.port
79
+ # #
80
+ # # if (Thread.current[:connection].nil? || (Thread.current[:host] != uri.host))
81
+ # # p "establishing a connection"
82
+ # # establish_connection(uri)
83
+ # # end
84
+ # #
85
+ # # display_log request_log
86
+ # # http = Thread.current[:connection]
87
+ # # http.read_timeout = @timeout if @timeout
88
+ # #
89
+ # # begin
90
+ # # res = http.request(req, payload)
91
+ # # rescue
92
+ # # p "Net::HTTP connection failed, reconnecting"
93
+ # # establish_connection(uri)
94
+ # # http = Thread.current[:connection]
95
+ # # require 'ruby-debug'
96
+ # # req.body_stream = nil
97
+ # #
98
+ # # res = http.request(req, payload)
99
+ # # display_log response_log(res)
100
+ # # result res
101
+ # # else
102
+ # # display_log response_log(res)
103
+ # # process_result res
104
+ # # end
105
+ # #
106
+ # # rescue EOFError
107
+ # # raise RestClient::ServerBrokeConnection
108
+ # # rescue Timeout::Error
109
+ # # raise RestClient::RequestTimeout
110
+ # # end
111
+ # # end
112
+ #
113
+ # end
@@ -1,10 +1,11 @@
1
- require File.join(File.dirname(__FILE__), '..', 'mixins', 'properties')
1
+ require File.expand_path('../../mixins/properties', __FILE__)
2
+
2
3
 
3
4
  module CouchRest
4
5
  module CastedModel
5
6
 
6
7
  def self.included(base)
7
- base.send(:include, CouchRest::Mixins::Properties)
8
+ base.send(:include, ::CouchRest::Mixins::Properties)
8
9
  base.send(:attr_accessor, :casted_by)
9
10
  end
10
11
 
@@ -52,8 +52,25 @@ module CouchRest
52
52
  end
53
53
  end
54
54
 
55
-
55
+ # Defines an instance and save it directly to the database
56
+ #
57
+ # ==== Returns
58
+ # returns the reloaded document
59
+ def self.create(options)
60
+ instance = new(options)
61
+ instance.create
62
+ instance
63
+ end
56
64
 
65
+ # Defines an instance and save it directly to the database
66
+ #
67
+ # ==== Returns
68
+ # returns the reloaded document or raises an exception
69
+ def self.create!(options)
70
+ instance = new(options)
71
+ instance.create!
72
+ instance
73
+ end
57
74
 
58
75
  # Automatically set <tt>updated_at</tt> and <tt>created_at</tt> fields
59
76
  # on the document whenever saving occurs. CouchRest uses a pretty
@@ -104,6 +104,13 @@ module CouchRest
104
104
  entries.empty?
105
105
  end
106
106
 
107
+ # Return size of errors hash
108
+ #
109
+ # Allows us to play nicely with Rails' helpers
110
+ def count
111
+ errors.size
112
+ end
113
+
107
114
  def method_missing(meth, *args, &block)
108
115
  errors.send(meth, *args, &block)
109
116
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest do
4
4
 
@@ -191,7 +191,7 @@ describe CouchRest do
191
191
  describe "using a proxy for RestClient connections" do
192
192
  it "should set proxy url for RestClient" do
193
193
  CouchRest.proxy 'http://localhost:8888/'
194
- proxy_uri = URI.parse(RestClient.proxy)
194
+ proxy_uri = URI.parse(HttpAbstraction.proxy)
195
195
  proxy_uri.host.should eql( 'localhost' )
196
196
  proxy_uri.port.should eql( 8888 )
197
197
  CouchRest.proxy nil
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Database do
4
4
  before(:each) do
@@ -263,7 +263,11 @@ describe CouchRest::Database do
263
263
  r['ok'].should == true
264
264
  doc = @db.get("attach-this")
265
265
  attachment = @db.fetch_attachment(doc,"couchdb.png")
266
- attachment.should == image
266
+ if attachment.respond_to?(:net_http_res)
267
+ attachment.net_http_res.body.should == image
268
+ else
269
+ attachment.should == image
270
+ end
267
271
  end
268
272
  end
269
273
 
@@ -368,8 +372,18 @@ describe CouchRest::Database do
368
372
  end
369
373
  it "should delete the attachment" do
370
374
  lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
371
- @db.delete_attachment(@doc, "test.html")
372
- lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound)
375
+ @db.delete_attachment(@doc, "test.html")
376
+ @doc = @db.get('mydocwithattachment') # avoid getting a 409
377
+ lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error
378
+ end
379
+
380
+ it "should force a delete even if we get a 409" do
381
+ @doc['new_attribute'] = 'something new'
382
+ @db.put_attachment(@doc, 'test', File.open(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'attachments', 'test.html')).read)
383
+ # at this point the revision number changed, if we try to save doc one more time
384
+ # we would get a 409.
385
+ lambda{ @db.save_doc(@doc) }.should raise_error
386
+ lambda{ @db.delete_attachment(@doc, "test", true) }.should_not raise_error
373
387
  end
374
388
  end
375
389
 
@@ -690,7 +704,7 @@ describe CouchRest::Database do
690
704
 
691
705
  it "should recreate a db even tho it doesn't exist" do
692
706
  @cr.databases.should_not include(@db2.name)
693
- @db2.recreate!
707
+ begin @db2.recreate! rescue nil end
694
708
  @cr.databases.should include(@db2.name)
695
709
  end
696
710
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Design do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  class Video < CouchRest::Document; end
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Server do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Pager do
4
4
  before(:all) do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
 
3
3
  describe CouchRest::Streamer do
4
4
  before(:all) do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'card')
3
3
 
4
4
  class Car < CouchRest::ExtendedDocument
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
3
+ require File.expand_path('../../../spec_helper', __FILE__)
4
4
  require File.join(FIXTURE_PATH, 'more', 'card')
5
5
  require File.join(FIXTURE_PATH, 'more', 'cat')
6
6
  require File.join(FIXTURE_PATH, 'more', 'person')
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
2
 
3
3
  describe "ExtendedDocument attachments" do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'article')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -97,6 +97,22 @@ describe "ExtendedDocument" do
97
97
  end
98
98
  end
99
99
 
100
+ describe "creating a new document" do
101
+ it "should instantialize and save a document" do
102
+ article = Article.create(:title => 'my test')
103
+ article.title.should == 'my test'
104
+ article.should_not be_new_document
105
+ end
106
+
107
+ it "should trigger the create callbacks" do
108
+ doc = WithCallBacks.create(:name => 'my other test')
109
+ doc.run_before_create.should be_true
110
+ doc.run_after_create.should be_true
111
+ doc.run_before_save.should be_true
112
+ doc.run_after_save.should be_true
113
+ end
114
+ end
115
+
100
116
  describe "update attributes without saving" do
101
117
  before(:each) do
102
118
  a = Article.get "big-bad-danger" rescue nil
@@ -200,6 +216,15 @@ describe "ExtendedDocument" do
200
216
  foundart = Article.get @art.id
201
217
  foundart.title.should == "All About Getting"
202
218
  end
219
+
220
+ it "should return nil if `get` is used and the document doesn't exist" do
221
+ foundart = Article.get 'matt aimonetti'
222
+ foundart.should be_nil
223
+ end
224
+
225
+ it "should raise an error if `get!` is used and the document doesn't exist" do
226
+ lambda{foundart = Article.get!('matt aimonetti')}.should raise_error
227
+ end
203
228
  end
204
229
 
205
230
  describe "getting a model with a subobjects array" do
@@ -491,7 +516,7 @@ describe "ExtendedDocument" do
491
516
  end
492
517
  it "should make it go away" do
493
518
  @dobj.destroy
494
- lambda{Basic.get(@dobj.id)}.should raise_error
519
+ lambda{Basic.get!(@dobj.id)}.should raise_error
495
520
  end
496
521
  end
497
522
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'card')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require File.expand_path("../../../spec_helper", __FILE__)
2
2
  require File.join(FIXTURE_PATH, 'more', 'article')
3
3
  require File.join(FIXTURE_PATH, 'more', 'course')
4
4
 
@@ -121,7 +121,7 @@ describe "ExtendedDocument views" do
121
121
  describe "a model class not tied to a database" do
122
122
  before(:all) do
123
123
  reset_test_db!
124
- @db = DB
124
+ @db = DB
125
125
  %w{aaa bbb ddd eee}.each do |title|
126
126
  u = Unattached.new(:title => title)
127
127
  u.database = @db
@@ -133,14 +133,15 @@ describe "ExtendedDocument views" do
133
133
  lambda{Unattached.all}.should raise_error
134
134
  end
135
135
  it "should query all" do
136
- rs = Unattached.all :database=>@db
136
+ Unattached.cleanup_design_docs!(@db)
137
+ rs = Unattached.all :database => @db
137
138
  rs.length.should == 4
138
139
  end
139
140
  it "should barf on query if no database given" do
140
141
  lambda{Unattached.view :by_title}.should raise_error
141
142
  end
142
143
  it "should make the design doc upon first query" do
143
- Unattached.by_title :database=>@db
144
+ Unattached.by_title :database => @db
144
145
  doc = Unattached.design_doc
145
146
  doc['views']['all']['map'].should include('Unattached')
146
147
  end
@@ -157,7 +158,7 @@ describe "ExtendedDocument views" do
157
158
  things = []
158
159
  Unattached.view(:by_title, :database=>@db) do |thing|
159
160
  things << thing
160
- end
161
+ end
161
162
  things[0]["doc"]["title"].should =='aaa'
162
163
  end
163
164
  it "should yield with by_key method" do
@@ -167,8 +168,11 @@ describe "ExtendedDocument views" do
167
168
  end
168
169
  things[0]["doc"]["title"].should =='aaa'
169
170
  end
170
- it "should barf on get if no database given" do
171
- lambda{Unattached.get("aaa")}.should raise_error
171
+ it "should return nil on get if no database given" do
172
+ Unattached.get("aaa").should be_nil
173
+ end
174
+ it "should barf on get! if no database given" do
175
+ lambda{Unattached.get!("aaa")}.should raise_error
172
176
  end
173
177
  it "should get from specific database" do
174
178
  u = Unattached.get(@first_id, @db)
@@ -199,7 +203,7 @@ describe "ExtendedDocument views" do
199
203
  before(:all) do
200
204
  reset_test_db!
201
205
  # setup the class default doc to save the design doc
202
- Unattached.use_database DB
206
+ Unattached.use_database nil # just to be sure it is really unattached
203
207
  @us = Unattached.on(DB)
204
208
  %w{aaa bbb ddd eee}.each do |title|
205
209
  u = @us.new(:title => title)
@@ -211,6 +215,9 @@ describe "ExtendedDocument views" do
211
215
  rs = @us.all
212
216
  rs.length.should == 4
213
217
  end
218
+ it "should count" do
219
+ @us.count.should == 4
220
+ end
214
221
  it "should make the design doc upon first query" do
215
222
  @us.by_title
216
223
  doc = @us.design_doc
@@ -347,7 +354,8 @@ describe "ExtendedDocument views" do
347
354
  a = Article.new(:title => title, :date => Date.today)
348
355
  a.save
349
356
  end
350
- end
357
+ end
358
+ require 'date'
351
359
  it "should return a proxy that looks like an array of 7 Article objects" do
352
360
  articles = Article.by_date :key => Date.today
353
361
  articles.class.should == Array
@@ -364,6 +372,10 @@ describe "ExtendedDocument views" do
364
372
  articles.paginated_each(:per_page => 3) do |a|
365
373
  a.should_not be_nil
366
374
  end
375
+ end
376
+ it "should have the amount of paginated pages" do
377
+ articles = Article.by_date :key => Date.today
378
+ articles.paginate(:per_page => 3).amount_pages.should == 3
367
379
  end
368
380
  it "should provide a class method to access the collection directly" do
369
381
  articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,