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.
- data/README.md +58 -10
- data/history.txt +45 -1
- data/lib/couchrest.rb +9 -49
- data/lib/couchrest/core/adapters/restclient.rb +35 -0
- data/lib/couchrest/core/database.rb +18 -10
- data/lib/couchrest/core/document.rb +0 -4
- data/lib/couchrest/core/http_abstraction.rb +48 -0
- data/lib/couchrest/core/rest_api.rb +49 -0
- data/lib/couchrest/middlewares/logger.rb +263 -0
- data/lib/couchrest/mixins/attachments.rb +2 -2
- data/lib/couchrest/mixins/class_proxy.rb +5 -1
- data/lib/couchrest/mixins/collection.rb +23 -6
- data/lib/couchrest/mixins/design_doc.rb +5 -0
- data/lib/couchrest/mixins/document_queries.rb +33 -4
- data/lib/couchrest/mixins/properties.rb +30 -4
- data/lib/couchrest/mixins/views.rb +5 -13
- data/lib/couchrest/monkeypatches.rb +59 -59
- data/lib/couchrest/more/casted_model.rb +3 -2
- data/lib/couchrest/more/extended_document.rb +18 -1
- data/lib/couchrest/validation/validation_errors.rb +7 -0
- data/spec/couchrest/core/couchrest_spec.rb +2 -2
- data/spec/couchrest/core/database_spec.rb +19 -5
- data/spec/couchrest/core/design_spec.rb +1 -1
- data/spec/couchrest/core/document_spec.rb +1 -1
- data/spec/couchrest/core/server_spec.rb +1 -1
- data/spec/couchrest/helpers/pager_spec.rb +1 -1
- data/spec/couchrest/helpers/streamer_spec.rb +1 -1
- data/spec/couchrest/more/casted_extended_doc_spec.rb +1 -1
- data/spec/couchrest/more/casted_model_spec.rb +1 -1
- data/spec/couchrest/more/extended_doc_attachment_spec.rb +1 -1
- data/spec/couchrest/more/extended_doc_spec.rb +27 -2
- data/spec/couchrest/more/extended_doc_subclass_spec.rb +1 -1
- data/spec/couchrest/more/extended_doc_view_spec.rb +21 -9
- data/spec/couchrest/more/property_spec.rb +50 -1
- data/spec/spec_helper.rb +1 -1
- 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/
|
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
|
-
|
99
|
-
|
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
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
|
113
|
-
|
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.
|
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.
|
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(
|
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.
|
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.
|
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
|
-
|
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,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require File.
|
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.
|
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.
|
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
|
-
|
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
|
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
|
171
|
-
|
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
|
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,
|