Merge commit 'mattetti/master'
This commit is contained in:
commit
1938270d65
|
@ -17,7 +17,7 @@ Note: CouchRest only support CouchDB 0.9.0 or newer.
|
||||||
Alternatively, you can install from Github:
|
Alternatively, you can install from Github:
|
||||||
|
|
||||||
$ gem sources -a http://gems.github.com (you only have to do this once)
|
$ gem sources -a http://gems.github.com (you only have to do this once)
|
||||||
$ sudo gem install mattetti-couchrest
|
$ sudo gem install couchrest-couchrest
|
||||||
|
|
||||||
### Relax, it's RESTful
|
### Relax, it's RESTful
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = %q{couchrest}
|
s.name = %q{couchrest}
|
||||||
s.version = "0.31"
|
s.version = "0.33"
|
||||||
|
|
||||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
s.authors = ["J. Chris Anderson", "Matt Aimonetti"]
|
s.authors = ["J. Chris Anderson", "Matt Aimonetti"]
|
||||||
|
@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
||||||
s.description = %q{CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.}
|
s.description = %q{CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments.}
|
||||||
s.email = %q{jchris@apache.org}
|
s.email = %q{jchris@apache.org}
|
||||||
s.extra_rdoc_files = ["README.md", "LICENSE", "THANKS.md"]
|
s.extra_rdoc_files = ["README.md", "LICENSE", "THANKS.md"]
|
||||||
s.files = ["LICENSE", "README.md", "Rakefile", "THANKS.md", "history.txt", "examples/model", "examples/model/example.rb", "examples/word_count", "examples/word_count/markov", "examples/word_count/views", "examples/word_count/views/books", "examples/word_count/views/books/chunked-map.js", "examples/word_count/views/books/united-map.js", "examples/word_count/views/markov", "examples/word_count/views/markov/chain-map.js", "examples/word_count/views/markov/chain-reduce.js", "examples/word_count/views/word_count", "examples/word_count/views/word_count/count-map.js", "examples/word_count/views/word_count/count-reduce.js", "examples/word_count/word_count.rb", "examples/word_count/word_count_query.rb", "examples/word_count/word_count_views.rb", "lib/couchrest", "lib/couchrest/commands", "lib/couchrest/commands/generate.rb", "lib/couchrest/commands/push.rb", "lib/couchrest/core", "lib/couchrest/core/adapters", "lib/couchrest/core/adapters/restclient.rb", "lib/couchrest/core/database.rb", "lib/couchrest/core/design.rb", "lib/couchrest/core/document.rb", "lib/couchrest/core/http_abstraction.rb", "lib/couchrest/core/response.rb", "lib/couchrest/core/server.rb", "lib/couchrest/core/view.rb", "lib/couchrest/helper", "lib/couchrest/helper/pager.rb", "lib/couchrest/helper/streamer.rb", "lib/couchrest/helper/upgrade.rb", "lib/couchrest/mixins", "lib/couchrest/mixins/attachments.rb", "lib/couchrest/mixins/callbacks.rb", "lib/couchrest/mixins/class_proxy.rb", "lib/couchrest/mixins/collection.rb", "lib/couchrest/mixins/design_doc.rb", "lib/couchrest/mixins/document_queries.rb", "lib/couchrest/mixins/extended_attachments.rb", "lib/couchrest/mixins/extended_document_mixins.rb", "lib/couchrest/mixins/properties.rb", "lib/couchrest/mixins/validation.rb", "lib/couchrest/mixins/views.rb", "lib/couchrest/mixins.rb", "lib/couchrest/monkeypatches.rb", "lib/couchrest/more", "lib/couchrest/more/casted_model.rb", "lib/couchrest/more/extended_document.rb", "lib/couchrest/more/property.rb", "lib/couchrest/support", "lib/couchrest/support/blank.rb", "lib/couchrest/support/class.rb", "lib/couchrest/support/rails.rb", "lib/couchrest/validation", "lib/couchrest/validation/auto_validate.rb", "lib/couchrest/validation/contextual_validators.rb", "lib/couchrest/validation/validation_errors.rb", "lib/couchrest/validation/validators", "lib/couchrest/validation/validators/absent_field_validator.rb", "lib/couchrest/validation/validators/confirmation_validator.rb", "lib/couchrest/validation/validators/format_validator.rb", "lib/couchrest/validation/validators/formats", "lib/couchrest/validation/validators/formats/email.rb", "lib/couchrest/validation/validators/formats/url.rb", "lib/couchrest/validation/validators/generic_validator.rb", "lib/couchrest/validation/validators/length_validator.rb", "lib/couchrest/validation/validators/method_validator.rb", "lib/couchrest/validation/validators/numeric_validator.rb", "lib/couchrest/validation/validators/required_field_validator.rb", "lib/couchrest.rb", "spec/couchrest", "spec/couchrest/core", "spec/couchrest/core/couchrest_spec.rb", "spec/couchrest/core/database_spec.rb", "spec/couchrest/core/design_spec.rb", "spec/couchrest/core/document_spec.rb", "spec/couchrest/core/server_spec.rb", "spec/couchrest/helpers", "spec/couchrest/helpers/pager_spec.rb", "spec/couchrest/helpers/streamer_spec.rb", "spec/couchrest/more", "spec/couchrest/more/casted_extended_doc_spec.rb", "spec/couchrest/more/casted_model_spec.rb", "spec/couchrest/more/extended_doc_attachment_spec.rb", "spec/couchrest/more/extended_doc_spec.rb", "spec/couchrest/more/extended_doc_subclass_spec.rb", "spec/couchrest/more/extended_doc_view_spec.rb", "spec/couchrest/more/property_spec.rb", "spec/fixtures", "spec/fixtures/attachments", "spec/fixtures/attachments/couchdb.png", "spec/fixtures/attachments/README", "spec/fixtures/attachments/test.html", "spec/fixtures/more", "spec/fixtures/more/article.rb", "spec/fixtures/more/card.rb", "spec/fixtures/more/cat.rb", "spec/fixtures/more/course.rb", "spec/fixtures/more/event.rb", "spec/fixtures/more/invoice.rb", "spec/fixtures/more/person.rb", "spec/fixtures/more/question.rb", "spec/fixtures/more/service.rb", "spec/fixtures/views", "spec/fixtures/views/lib.js", "spec/fixtures/views/test_view", "spec/fixtures/views/test_view/lib.js", "spec/fixtures/views/test_view/only-map.js", "spec/fixtures/views/test_view/test-map.js", "spec/fixtures/views/test_view/test-reduce.js", "spec/spec.opts", "spec/spec_helper.rb", "utils/remap.rb", "utils/subset.rb"]
|
s.files = ["LICENSE", "README.md", "Rakefile", "THANKS.md", "history.txt", "examples/model", "examples/model/example.rb", "examples/word_count", "examples/word_count/markov", "examples/word_count/views", "examples/word_count/views/books", "examples/word_count/views/books/chunked-map.js", "examples/word_count/views/books/united-map.js", "examples/word_count/views/markov", "examples/word_count/views/markov/chain-map.js", "examples/word_count/views/markov/chain-reduce.js", "examples/word_count/views/word_count", "examples/word_count/views/word_count/count-map.js", "examples/word_count/views/word_count/count-reduce.js", "examples/word_count/word_count.rb", "examples/word_count/word_count_query.rb", "examples/word_count/word_count_views.rb", "lib/couchrest", "lib/couchrest/commands", "lib/couchrest/commands/generate.rb", "lib/couchrest/commands/push.rb", "lib/couchrest/core", "lib/couchrest/core/adapters", "lib/couchrest/core/adapters/restclient.rb", "lib/couchrest/core/database.rb", "lib/couchrest/core/design.rb", "lib/couchrest/core/document.rb", "lib/couchrest/core/http_abstraction.rb", "lib/couchrest/core/response.rb", "lib/couchrest/core/rest_api.rb", "lib/couchrest/core/server.rb", "lib/couchrest/core/view.rb", "lib/couchrest/helper", "lib/couchrest/helper/pager.rb", "lib/couchrest/helper/streamer.rb", "lib/couchrest/helper/upgrade.rb", "lib/couchrest/middlewares", "lib/couchrest/middlewares/logger.rb", "lib/couchrest/mixins", "lib/couchrest/mixins/attachments.rb", "lib/couchrest/mixins/callbacks.rb", "lib/couchrest/mixins/class_proxy.rb", "lib/couchrest/mixins/collection.rb", "lib/couchrest/mixins/design_doc.rb", "lib/couchrest/mixins/document_queries.rb", "lib/couchrest/mixins/extended_attachments.rb", "lib/couchrest/mixins/extended_document_mixins.rb", "lib/couchrest/mixins/properties.rb", "lib/couchrest/mixins/validation.rb", "lib/couchrest/mixins/views.rb", "lib/couchrest/mixins.rb", "lib/couchrest/monkeypatches.rb", "lib/couchrest/more", "lib/couchrest/more/casted_model.rb", "lib/couchrest/more/extended_document.rb", "lib/couchrest/more/property.rb", "lib/couchrest/support", "lib/couchrest/support/blank.rb", "lib/couchrest/support/class.rb", "lib/couchrest/support/rails.rb", "lib/couchrest/validation", "lib/couchrest/validation/auto_validate.rb", "lib/couchrest/validation/contextual_validators.rb", "lib/couchrest/validation/validation_errors.rb", "lib/couchrest/validation/validators", "lib/couchrest/validation/validators/absent_field_validator.rb", "lib/couchrest/validation/validators/confirmation_validator.rb", "lib/couchrest/validation/validators/format_validator.rb", "lib/couchrest/validation/validators/formats", "lib/couchrest/validation/validators/formats/email.rb", "lib/couchrest/validation/validators/formats/url.rb", "lib/couchrest/validation/validators/generic_validator.rb", "lib/couchrest/validation/validators/length_validator.rb", "lib/couchrest/validation/validators/method_validator.rb", "lib/couchrest/validation/validators/numeric_validator.rb", "lib/couchrest/validation/validators/required_field_validator.rb", "lib/couchrest.rb", "spec/couchrest", "spec/couchrest/core", "spec/couchrest/core/couchrest_spec.rb", "spec/couchrest/core/database_spec.rb", "spec/couchrest/core/design_spec.rb", "spec/couchrest/core/document_spec.rb", "spec/couchrest/core/server_spec.rb", "spec/couchrest/helpers", "spec/couchrest/helpers/pager_spec.rb", "spec/couchrest/helpers/streamer_spec.rb", "spec/couchrest/more", "spec/couchrest/more/casted_extended_doc_spec.rb", "spec/couchrest/more/casted_model_spec.rb", "spec/couchrest/more/extended_doc_attachment_spec.rb", "spec/couchrest/more/extended_doc_spec.rb", "spec/couchrest/more/extended_doc_subclass_spec.rb", "spec/couchrest/more/extended_doc_view_spec.rb", "spec/couchrest/more/property_spec.rb", "spec/fixtures", "spec/fixtures/attachments", "spec/fixtures/attachments/couchdb.png", "spec/fixtures/attachments/README", "spec/fixtures/attachments/test.html", "spec/fixtures/more", "spec/fixtures/more/article.rb", "spec/fixtures/more/card.rb", "spec/fixtures/more/cat.rb", "spec/fixtures/more/course.rb", "spec/fixtures/more/event.rb", "spec/fixtures/more/invoice.rb", "spec/fixtures/more/person.rb", "spec/fixtures/more/question.rb", "spec/fixtures/more/service.rb", "spec/fixtures/views", "spec/fixtures/views/lib.js", "spec/fixtures/views/test_view", "spec/fixtures/views/test_view/lib.js", "spec/fixtures/views/test_view/only-map.js", "spec/fixtures/views/test_view/test-map.js", "spec/fixtures/views/test_view/test-reduce.js", "spec/spec.opts", "spec/spec_helper.rb", "utils/remap.rb", "utils/subset.rb"]
|
||||||
s.homepage = %q{http://github.com/jchris/couchrest}
|
s.homepage = %q{http://github.com/jchris/couchrest}
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
s.rubygems_version = %q{1.3.4}
|
s.rubygems_version = %q{1.3.4}
|
||||||
|
|
35
history.txt
35
history.txt
|
@ -1,18 +1,31 @@
|
||||||
== 0.40
|
== 0.33
|
||||||
|
|
||||||
=== Notes
|
|
||||||
|
|
||||||
This release slightly modifies the API and if you were using a previous version of CouchRest,
|
|
||||||
you will need to make the following modifications.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* Major enhancements
|
* Major enhancements
|
||||||
|
|
||||||
*
|
* Added a new Rack logger middleware letting you log/save requests/queries (Matt Aimonetti)
|
||||||
|
|
||||||
|
* Minor enhancements
|
||||||
|
|
||||||
|
* Added #amount_pages to a paginated result array (Matt Aimonetti)
|
||||||
|
* Ruby 1.9.2 compatible (Matt Aimonetti)
|
||||||
|
* Added a property? method for property cast as :boolean (John Wood)
|
||||||
|
* Added an option to force the deletion of a attachments (bypass 409s) (Matt Aimonetti)
|
||||||
|
* Created a new abstraction layer for the REST API (Matt Aimonetti)
|
||||||
|
* Bug fix: made ExtendedDocument#all compatible with Couch 0.10 (tc)
|
||||||
|
|
||||||
|
== 0.32
|
||||||
|
|
||||||
|
* Major enhancements
|
||||||
|
|
||||||
|
* ExtendedDocument.get doesn't raise an exception anymore. If no documents are found nil is returned.
|
||||||
|
* ExtendedDocument.get! works the say #get used to work and will raise an exception if a document isn't found.
|
||||||
|
|
||||||
* Minor enhancements
|
* Minor enhancements
|
||||||
|
|
||||||
|
* Bug fix: Model.all(:keys => [1,2]) was not working (Matt Aimonetti)
|
||||||
|
* Added ValidationErrors#count in order to play nicely with Rails (Peter Wagenet)
|
||||||
|
* Bug fix: class proxy design doc refresh (Daniel Kirsh)
|
||||||
|
* Bug fix: the count method on the proxy collection was missing (Daniel Kirsch)
|
||||||
* Added #amount_pages to a paginated collection. (Matt Aimonetti)
|
* Added #amount_pages to a paginated collection. (Matt Aimonetti)
|
||||||
|
|
||||||
== 0.31
|
== 0.31
|
||||||
|
@ -47,4 +60,4 @@ you will need to make the following modifications.
|
||||||
---
|
---
|
||||||
|
|
||||||
Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
|
Unfortunately, before 0.30 we did not keep a track of the modifications made to CouchRest.
|
||||||
You can see the full commit history on GitHub: http://github.com/mattetti/couchrest/commits/master/
|
You can see the full commit history on GitHub: http://github.com/couchrest/couchrest/commits/master/
|
|
@ -28,7 +28,7 @@ require 'couchrest/monkeypatches'
|
||||||
|
|
||||||
# = CouchDB, close to the metal
|
# = CouchDB, close to the metal
|
||||||
module CouchRest
|
module CouchRest
|
||||||
VERSION = '0.31' unless self.const_defined?("VERSION")
|
VERSION = '0.33' unless self.const_defined?("VERSION")
|
||||||
|
|
||||||
autoload :Server, 'couchrest/core/server'
|
autoload :Server, 'couchrest/core/server'
|
||||||
autoload :Database, 'couchrest/core/database'
|
autoload :Database, 'couchrest/core/database'
|
||||||
|
@ -45,9 +45,14 @@ module CouchRest
|
||||||
autoload :ExtendedDocument, 'couchrest/more/extended_document'
|
autoload :ExtendedDocument, 'couchrest/more/extended_document'
|
||||||
autoload :CastedModel, 'couchrest/more/casted_model'
|
autoload :CastedModel, 'couchrest/more/casted_model'
|
||||||
|
|
||||||
|
require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'rest_api')
|
||||||
require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'http_abstraction')
|
require File.join(File.dirname(__FILE__), 'couchrest', 'core', 'http_abstraction')
|
||||||
require File.join(File.dirname(__FILE__), 'couchrest', 'mixins')
|
require File.join(File.dirname(__FILE__), 'couchrest', 'mixins')
|
||||||
require File.join(File.dirname(__FILE__), 'couchrest', 'support', 'rails') if defined?(Rails)
|
require File.join(File.dirname(__FILE__), 'couchrest', 'support', 'rails') if defined?(Rails)
|
||||||
|
|
||||||
|
# we extend CouchRest with the RestAPI module which gives us acess to
|
||||||
|
# the get, post, put, delete and copy
|
||||||
|
CouchRest.extend(::RestAPI)
|
||||||
|
|
||||||
# The CouchRest module methods handle the basic JSON serialization
|
# The CouchRest module methods handle the basic JSON serialization
|
||||||
# and deserialization, as well as query parameters. The module also includes
|
# and deserialization, as well as query parameters. The module also includes
|
||||||
|
@ -140,52 +145,6 @@ module CouchRest
|
||||||
cr.database(parsed[:database])
|
cr.database(parsed[:database])
|
||||||
end
|
end
|
||||||
|
|
||||||
def put(uri, doc = nil)
|
|
||||||
payload = doc.to_json if doc
|
|
||||||
begin
|
|
||||||
JSON.parse(HttpAbstraction.put(uri, payload))
|
|
||||||
rescue Exception => e
|
|
||||||
if $DEBUG
|
|
||||||
raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
|
||||||
else
|
|
||||||
raise e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def get(uri)
|
|
||||||
begin
|
|
||||||
JSON.parse(HttpAbstraction.get(uri), :max_nesting => false)
|
|
||||||
rescue => e
|
|
||||||
if $DEBUG
|
|
||||||
raise "Error while sending a GET request #{uri}\n: #{e}"
|
|
||||||
else
|
|
||||||
raise e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def post uri, doc = nil
|
|
||||||
payload = doc.to_json if doc
|
|
||||||
begin
|
|
||||||
JSON.parse(HttpAbstraction.post(uri, payload))
|
|
||||||
rescue Exception => e
|
|
||||||
if $DEBUG
|
|
||||||
raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
|
||||||
else
|
|
||||||
raise e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete uri
|
|
||||||
JSON.parse(HttpAbstraction.delete(uri))
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy uri, destination
|
|
||||||
JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination}))
|
|
||||||
end
|
|
||||||
|
|
||||||
def paramify_url url, params = {}
|
def paramify_url url, params = {}
|
||||||
if params && !params.empty?
|
if params && !params.empty?
|
||||||
query = params.collect do |k,v|
|
query = params.collect do |k,v|
|
||||||
|
|
|
@ -113,10 +113,21 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE an attachment directly from CouchDB
|
# DELETE an attachment directly from CouchDB
|
||||||
def delete_attachment doc, name
|
def delete_attachment(doc, name, force=false)
|
||||||
uri = url_for_attachment(doc, name)
|
uri = url_for_attachment(doc, name)
|
||||||
# this needs a rev
|
# this needs a rev
|
||||||
JSON.parse(HttpAbstraction.delete(uri))
|
begin
|
||||||
|
JSON.parse(HttpAbstraction.delete(uri))
|
||||||
|
rescue Exception => error
|
||||||
|
if force
|
||||||
|
# get over a 409
|
||||||
|
doc = get(doc['_id'])
|
||||||
|
uri = url_for_attachment(doc, name)
|
||||||
|
JSON.parse(HttpAbstraction.delete(uri))
|
||||||
|
else
|
||||||
|
error
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Save a document to CouchDB. This will use the <tt>_id</tt> field from
|
# Save a document to CouchDB. This will use the <tt>_id</tt> field from
|
||||||
|
|
49
lib/couchrest/core/rest_api.rb
Normal file
49
lib/couchrest/core/rest_api.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
module RestAPI
|
||||||
|
|
||||||
|
def put(uri, doc = nil)
|
||||||
|
payload = doc.to_json if doc
|
||||||
|
begin
|
||||||
|
JSON.parse(HttpAbstraction.put(uri, payload))
|
||||||
|
rescue Exception => e
|
||||||
|
if $DEBUG
|
||||||
|
raise "Error while sending a PUT request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get(uri)
|
||||||
|
begin
|
||||||
|
JSON.parse(HttpAbstraction.get(uri), :max_nesting => false)
|
||||||
|
rescue => e
|
||||||
|
if $DEBUG
|
||||||
|
raise "Error while sending a GET request #{uri}\n: #{e}"
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def post(uri, doc = nil)
|
||||||
|
payload = doc.to_json if doc
|
||||||
|
begin
|
||||||
|
JSON.parse(HttpAbstraction.post(uri, payload))
|
||||||
|
rescue Exception => e
|
||||||
|
if $DEBUG
|
||||||
|
raise "Error while sending a POST request #{uri}\npayload: #{payload.inspect}\n#{e}"
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(uri)
|
||||||
|
JSON.parse(HttpAbstraction.delete(uri))
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy(uri, destination)
|
||||||
|
JSON.parse(HttpAbstraction.copy(uri, {'Destination' => destination}))
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
263
lib/couchrest/middlewares/logger.rb
Normal file
263
lib/couchrest/middlewares/logger.rb
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
####################################
|
||||||
|
# USAGE
|
||||||
|
#
|
||||||
|
# in your rack.rb file
|
||||||
|
# require this file and then:
|
||||||
|
#
|
||||||
|
# couch = CouchRest.new
|
||||||
|
# LOG_DB = couch.database!('couchrest-logger')
|
||||||
|
# use CouchRest::Logger, LOG_DB
|
||||||
|
#
|
||||||
|
# Note:
|
||||||
|
# to require just this middleware, if you have the gem installed do:
|
||||||
|
# require 'couchrest/middlewares/logger'
|
||||||
|
#
|
||||||
|
# For log processing examples, see examples at the bottom of this file
|
||||||
|
|
||||||
|
module CouchRest
|
||||||
|
class Logger
|
||||||
|
|
||||||
|
def self.log
|
||||||
|
Thread.current["couchrest.logger"] ||= {:queries => []}
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(app, db=nil)
|
||||||
|
@app = app
|
||||||
|
@db = db
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.record(log_info)
|
||||||
|
log[:queries] << log_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def log
|
||||||
|
Thread.current["couchrest.logger"] ||= {:queries => []}
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_log
|
||||||
|
Thread.current["couchrest.logger"] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
reset_log
|
||||||
|
log['started_at'] = Time.now
|
||||||
|
log['env'] = env
|
||||||
|
log['url'] = 'http://' + env['HTTP_HOST'] + env['REQUEST_URI']
|
||||||
|
response = @app.call(env)
|
||||||
|
log['ended_at'] = Time.now
|
||||||
|
log['duration'] = log['ended_at'] - log['started_at']
|
||||||
|
# let's report the log in a different thread so we don't slow down the app
|
||||||
|
@db ? Thread.new(@db, log){|db, rlog| db.save_doc(rlog);} : p(log.inspect)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# inject our logger into CouchRest HTTP abstraction layer
|
||||||
|
module HttpAbstraction
|
||||||
|
|
||||||
|
def self.get(uri, headers=nil)
|
||||||
|
start_query = Time.now
|
||||||
|
log = {:method => :get, :uri => uri, :headers => headers}
|
||||||
|
response = super(uri, headers=nil)
|
||||||
|
end_query = Time.now
|
||||||
|
log[:duration] = (end_query - start_query)
|
||||||
|
CouchRest::Logger.record(log)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.post(uri, payload, headers=nil)
|
||||||
|
start_query = Time.now
|
||||||
|
log = {:method => :post, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
|
||||||
|
response = super(uri, payload, headers=nil)
|
||||||
|
end_query = Time.now
|
||||||
|
log[:duration] = (end_query - start_query)
|
||||||
|
CouchRest::Logger.record(log)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.put(uri, payload, headers=nil)
|
||||||
|
start_query = Time.now
|
||||||
|
log = {:method => :put, :uri => uri, :payload => (payload ? (JSON.load(payload) rescue 'parsing error') : nil), :headers => headers}
|
||||||
|
response = super(uri, payload, headers=nil)
|
||||||
|
end_query = Time.now
|
||||||
|
log[:duration] = (end_query - start_query)
|
||||||
|
CouchRest::Logger.record(log)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.delete(uri, headers=nil)
|
||||||
|
start_query = Time.now
|
||||||
|
log = {:method => :delete, :uri => uri, :headers => headers}
|
||||||
|
response = super(uri, headers=nil)
|
||||||
|
end_query = Time.now
|
||||||
|
log[:duration] = (end_query - start_query)
|
||||||
|
CouchRest::Logger.record(log)
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# Advanced usage example
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# # DB VIEWS
|
||||||
|
# by_url = {
|
||||||
|
# :map =>
|
||||||
|
# "function(doc) {
|
||||||
|
# if(doc['url']){ emit(doc['url'], 1) };
|
||||||
|
# }",
|
||||||
|
# :reduce =>
|
||||||
|
# 'function (key, values, rereduce) {
|
||||||
|
# return(sum(values));
|
||||||
|
# };'
|
||||||
|
# }
|
||||||
|
# req_duration = {
|
||||||
|
# :map =>
|
||||||
|
# "function(doc) {
|
||||||
|
# if(doc['duration']){ emit(doc['url'], doc['duration']) };
|
||||||
|
# }",
|
||||||
|
# :reduce =>
|
||||||
|
# 'function (key, values, rereduce) {
|
||||||
|
# return(sum(values)/values.length);
|
||||||
|
# };'
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# query_duration = {
|
||||||
|
# :map =>
|
||||||
|
# "function(doc) {
|
||||||
|
# if(doc['queries']){
|
||||||
|
# doc.queries.forEach(function(query){
|
||||||
|
# if(query['duration'] && query['method']){
|
||||||
|
# emit(query['method'], query['duration'])
|
||||||
|
# }
|
||||||
|
# });
|
||||||
|
# };
|
||||||
|
# }" ,
|
||||||
|
# :reduce =>
|
||||||
|
# 'function (key, values, rereduce) {
|
||||||
|
# return(sum(values)/values.length);
|
||||||
|
# };'
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# action_queries = {
|
||||||
|
# :map =>
|
||||||
|
# "function(doc) {
|
||||||
|
# if(doc['queries']){
|
||||||
|
# emit(doc['url'], doc['queries'].length)
|
||||||
|
# };
|
||||||
|
# }",
|
||||||
|
# :reduce =>
|
||||||
|
# 'function (key, values, rereduce) {
|
||||||
|
# return(sum(values)/values.length);
|
||||||
|
# };'
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# action_time_spent_in_db = {
|
||||||
|
# :map =>
|
||||||
|
# "function(doc) {
|
||||||
|
# if(doc['queries']){
|
||||||
|
# var totalDuration = 0;
|
||||||
|
# doc.queries.forEach(function(query){
|
||||||
|
# totalDuration += query['duration']
|
||||||
|
# })
|
||||||
|
# emit(doc['url'], totalDuration)
|
||||||
|
# };
|
||||||
|
# }",
|
||||||
|
# :reduce =>
|
||||||
|
# 'function (key, values, rereduce) {
|
||||||
|
# return(sum(values)/values.length);
|
||||||
|
# };'
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# show_queries = %Q~function(doc, req) {
|
||||||
|
# var body = ""
|
||||||
|
# body += "<h1>" + doc['url'] + "</h1>"
|
||||||
|
# body += "<h2>Request duration in seconds: " + doc['duration'] + "</h2>"
|
||||||
|
# body += "<h3>" + doc['queries'].length + " queries</h3><ul>"
|
||||||
|
# if (doc.queries){
|
||||||
|
# doc.queries.forEach(function(query){
|
||||||
|
# body += "<li>"+ query['uri'] +"</li>"
|
||||||
|
# });
|
||||||
|
# };
|
||||||
|
# body += "</ul>"
|
||||||
|
# if(doc){ return { body: body} }
|
||||||
|
# }~
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# couch = CouchRest.new
|
||||||
|
# LOG_DB = couch.database!('couchrest-logger')
|
||||||
|
# design_doc = LOG_DB.get("_design/stats") rescue nil
|
||||||
|
# LOG_DB.delete_doc design_doc rescue nil
|
||||||
|
# LOG_DB.save_doc({
|
||||||
|
# "_id" => "_design/stats",
|
||||||
|
# :views => {
|
||||||
|
# :by_url => by_url,
|
||||||
|
# :request_duration => req_duration,
|
||||||
|
# :query_duration => query_duration,
|
||||||
|
# :action_queries => action_queries,
|
||||||
|
# :action_time_spent_in_db => action_time_spent_in_db
|
||||||
|
# },
|
||||||
|
# :shows => {
|
||||||
|
# :queries => show_queries
|
||||||
|
# }
|
||||||
|
# })
|
||||||
|
#
|
||||||
|
# module CouchRest
|
||||||
|
# class Logger
|
||||||
|
#
|
||||||
|
# def self.roundup(value)
|
||||||
|
# begin
|
||||||
|
# value = Float(value)
|
||||||
|
# (value * 100).round.to_f / 100
|
||||||
|
# rescue
|
||||||
|
# value
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# # Usage example:
|
||||||
|
# # CouchRest::Logger.average_request_duration(LOG_DB)['rows'].first['value']
|
||||||
|
# def self.average_request_duration(db)
|
||||||
|
# raw = db.view('stats/request_duration', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.average_query_duration(db)
|
||||||
|
# raw = db.view('stats/query_duration', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.average_get_query_duration(db)
|
||||||
|
# raw = db.view('stats/query_duration', :key => 'get', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.average_post_query_duration(db)
|
||||||
|
# raw = db.view('stats/query_duration', :key => 'post', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.average_queries_per_action(db)
|
||||||
|
# raw = db.view('stats/action_queries', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.average_db_time_per_action(db)
|
||||||
|
# raw = db.view('stats/action_time_spent_in_db', :reduce => true)
|
||||||
|
# (raw.has_key?('rows') && !raw['rows'].empty?) ? roundup(raw['rows'].first['value']) : 'not available yet'
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.stats(db)
|
||||||
|
# Thread.new(db){|db|
|
||||||
|
# puts "=== STATS ===\n"
|
||||||
|
# puts "average request duration: #{average_request_duration(db)}\n"
|
||||||
|
# puts "average query duration: #{average_query_duration(db)}\n"
|
||||||
|
# puts "average queries per action : #{average_queries_per_action(db)}\n"
|
||||||
|
# puts "average time spent in DB (per action): #{average_db_time_per_action(db)}\n"
|
||||||
|
# puts "===============\n"
|
||||||
|
# }
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# end
|
||||||
|
# end
|
|
@ -19,9 +19,9 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# deletes an attachment directly from couchdb
|
# deletes an attachment directly from couchdb
|
||||||
def delete_attachment(name)
|
def delete_attachment(name, force=false)
|
||||||
raise ArgumentError, "doc.database required to delete_attachment" unless database
|
raise ArgumentError, "doc.database required to delete_attachment" unless database
|
||||||
result = database.delete_attachment(self, name)
|
result = database.delete_attachment(self, name, force)
|
||||||
self['_rev'] = result['rev']
|
self['_rev'] = result['rev']
|
||||||
result['ok']
|
result['ok']
|
||||||
end
|
end
|
||||||
|
|
|
@ -59,6 +59,10 @@ module CouchRest
|
||||||
@klass.all({:database => @database}.merge(opts), &block)
|
@klass.all({:database => @database}.merge(opts), &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def count(opts = {}, &block)
|
||||||
|
@klass.all({:database => @database, :raw => true, :limit => 0}.merge(opts), &block)['total_rows']
|
||||||
|
end
|
||||||
|
|
||||||
def first(opts = {})
|
def first(opts = {})
|
||||||
@klass.first({:database => @database}.merge(opts))
|
@klass.first({:database => @database}.merge(opts))
|
||||||
end
|
end
|
||||||
|
@ -100,7 +104,7 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh_design_doc
|
def refresh_design_doc
|
||||||
@klass.refresh_design_doc
|
@klass.refresh_design_doc_on(@database)
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_design_doc
|
def save_design_doc
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
module CouchRest
|
module CouchRest
|
||||||
module Mixins
|
module Mixins
|
||||||
|
module PaginatedResults
|
||||||
|
def amount_pages
|
||||||
|
@amount_pages ||= 0
|
||||||
|
end
|
||||||
|
def amount_pages=(value)
|
||||||
|
@amount_pages = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
module Collection
|
module Collection
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
|
@ -115,7 +124,10 @@ module CouchRest
|
||||||
results = @database.view(@view_name, pagination_options(page, per_page))
|
results = @database.view(@view_name, pagination_options(page, per_page))
|
||||||
@amount_pages ||= (results['total_rows'].to_f / per_page.to_f).ceil
|
@amount_pages ||= (results['total_rows'].to_f / per_page.to_f).ceil
|
||||||
remember_where_we_left_off(results, page)
|
remember_where_we_left_off(results, page)
|
||||||
convert_to_container_array(results)
|
results = convert_to_container_array(results)
|
||||||
|
results.extend(PaginatedResults)
|
||||||
|
results.amount_pages = @amount_pages
|
||||||
|
results
|
||||||
end
|
end
|
||||||
|
|
||||||
# See Collection.paginated_each
|
# See Collection.paginated_each
|
||||||
|
@ -181,7 +193,7 @@ module CouchRest
|
||||||
@target.inspect
|
@target.inspect
|
||||||
end
|
end
|
||||||
|
|
||||||
def convert_to_container_array(results)
|
def convert_to_container_array(results)
|
||||||
if @container_class.nil?
|
if @container_class.nil?
|
||||||
results
|
results
|
||||||
else
|
else
|
||||||
|
|
|
@ -35,7 +35,7 @@ module CouchRest
|
||||||
'all' => {
|
'all' => {
|
||||||
'map' => "function(doc) {
|
'map' => "function(doc) {
|
||||||
if (doc['couchrest-type'] == '#{self.to_s}') {
|
if (doc['couchrest-type'] == '#{self.to_s}') {
|
||||||
emit(null,1);
|
emit(doc['_id'],1);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,11 @@ module CouchRest
|
||||||
save_design_doc
|
save_design_doc
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def refresh_design_doc_on(db)
|
||||||
|
reset_design_doc
|
||||||
|
save_design_doc_on(db)
|
||||||
|
end
|
||||||
|
|
||||||
# Save the design doc onto the default database, and update the
|
# Save the design doc onto the default database, and update the
|
||||||
# design_doc attribute
|
# design_doc attribute
|
||||||
def save_design_doc
|
def save_design_doc
|
||||||
|
|
|
@ -12,7 +12,7 @@ module CouchRest
|
||||||
# name of the current class. Take the standard set of
|
# name of the current class. Take the standard set of
|
||||||
# CouchRest::Database#view options.
|
# CouchRest::Database#view options.
|
||||||
def all(opts = {}, &block)
|
def all(opts = {}, &block)
|
||||||
view(:all, {:reduce => false}.merge(opts), &block)
|
view(:all, opts, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the number of documents that have the "couchrest-type" field
|
# Returns the number of documents that have the "couchrest-type" field
|
||||||
|
@ -39,7 +39,38 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Load a document from the database by id
|
# Load a document from the database by id
|
||||||
|
# No exceptions will be raised if the document isn't found
|
||||||
|
#
|
||||||
|
# ==== Returns
|
||||||
|
# Object:: if the document was found
|
||||||
|
# or
|
||||||
|
# Nil::
|
||||||
|
#
|
||||||
|
# === Parameters
|
||||||
|
# id<String, Integer>:: Document ID
|
||||||
|
# db<Database>:: optional option to pass a custom database to use
|
||||||
def get(id, db = database)
|
def get(id, db = database)
|
||||||
|
begin
|
||||||
|
doc = db.get id
|
||||||
|
rescue
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
new(doc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Load a document from the database by id
|
||||||
|
# An exception will be raised if the document isn't found
|
||||||
|
#
|
||||||
|
# ==== Returns
|
||||||
|
# Object:: if the document was found
|
||||||
|
# or
|
||||||
|
# Exception
|
||||||
|
#
|
||||||
|
# === Parameters
|
||||||
|
# id<String, Integer>:: Document ID
|
||||||
|
# db<Database>:: optional option to pass a custom database to use
|
||||||
|
def get!(id, db = database)
|
||||||
doc = db.get id
|
doc = db.get id
|
||||||
new(doc)
|
new(doc)
|
||||||
end
|
end
|
||||||
|
|
|
@ -65,9 +65,8 @@ module CouchRest
|
||||||
key = self.has_key?(property.name) ? property.name : property.name.to_sym
|
key = self.has_key?(property.name) ? property.name : property.name.to_sym
|
||||||
# Don't cast the property unless it has a value
|
# Don't cast the property unless it has a value
|
||||||
return unless self[key]
|
return unless self[key]
|
||||||
target = property.type
|
if property.type.is_a?(Array)
|
||||||
if target.is_a?(Array)
|
klass = ::CouchRest.constantize(property.type[0])
|
||||||
klass = ::CouchRest.constantize(target[0])
|
|
||||||
arr = self[key].dup.collect do |value|
|
arr = self[key].dup.collect do |value|
|
||||||
unless value.instance_of?(klass)
|
unless value.instance_of?(klass)
|
||||||
value = convert_property_value(property, klass, value)
|
value = convert_property_value(property, klass, value)
|
||||||
|
@ -78,7 +77,12 @@ module CouchRest
|
||||||
self[key] = klass != String ? CastedArray.new(arr) : arr
|
self[key] = klass != String ? CastedArray.new(arr) : arr
|
||||||
self[key].casted_by = self if self[key].respond_to?(:casted_by)
|
self[key].casted_by = self if self[key].respond_to?(:casted_by)
|
||||||
else
|
else
|
||||||
klass = ::CouchRest.constantize(target)
|
if property.type == 'boolean'
|
||||||
|
klass = TrueClass
|
||||||
|
else
|
||||||
|
klass = ::CouchRest.constantize(property.type)
|
||||||
|
end
|
||||||
|
|
||||||
unless self[key].instance_of?(klass)
|
unless self[key].instance_of?(klass)
|
||||||
self[key] = convert_property_value(property, klass, self[property.name])
|
self[key] = convert_property_value(property, klass, self[property.name])
|
||||||
end
|
end
|
||||||
|
@ -93,12 +97,15 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
def convert_property_value(property, klass, value)
|
def convert_property_value(property, klass, value)
|
||||||
if ((property.init_method == 'new') && klass.to_s == 'Time')
|
if ((property.init_method == 'new') && klass == Time)
|
||||||
# Using custom time parsing method because Ruby's default method is toooo slow
|
# Using custom time parsing method because Ruby's default method is toooo slow
|
||||||
value.is_a?(String) ? Time.mktime_with_offset(value.dup) : value
|
value.is_a?(String) ? Time.mktime_with_offset(value.dup) : value
|
||||||
# Float instances don't get initialized with #new
|
# Float instances don't get initialized with #new
|
||||||
elsif ((property.init_method == 'new') && klass.to_s == 'Float')
|
elsif ((property.init_method == 'new') && klass == Float)
|
||||||
cast_float(value)
|
cast_float(value)
|
||||||
|
# 'boolean' type is simply used to generate a property? accessor method
|
||||||
|
elsif ((property.init_method == 'new') && klass == TrueClass)
|
||||||
|
value
|
||||||
else
|
else
|
||||||
klass.send(property.init_method, value.dup)
|
klass.send(property.init_method, value.dup)
|
||||||
end
|
end
|
||||||
|
@ -150,6 +157,18 @@ module CouchRest
|
||||||
end
|
end
|
||||||
EOS
|
EOS
|
||||||
|
|
||||||
|
if property.type == 'boolean'
|
||||||
|
class_eval <<-EOS, __FILE__, __LINE__
|
||||||
|
def #{property.name}?
|
||||||
|
if self['#{property.name}'].nil? || self['#{property.name}'] == false || self['#{property.name}'].to_s.downcase == 'false'
|
||||||
|
false
|
||||||
|
else
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
EOS
|
||||||
|
end
|
||||||
|
|
||||||
if property.alias
|
if property.alias
|
||||||
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
||||||
alias #{property.alias.to_sym} #{property.name.to_sym}
|
alias #{property.alias.to_sym} #{property.name.to_sym}
|
||||||
|
|
|
@ -95,11 +95,11 @@ module CouchRest
|
||||||
|
|
||||||
# Dispatches to any named view.
|
# Dispatches to any named view.
|
||||||
def view(name, query={}, &block)
|
def view(name, query={}, &block)
|
||||||
unless design_doc_fresh
|
db = query.delete(:database) || database
|
||||||
refresh_design_doc
|
unless design_doc_fresh
|
||||||
|
refresh_design_doc_on(db)
|
||||||
end
|
end
|
||||||
query[:raw] = true if query[:reduce]
|
query[:raw] = true if query[:reduce]
|
||||||
db = query.delete(:database) || database
|
|
||||||
raw = query.delete(:raw)
|
raw = query.delete(:raw)
|
||||||
fetch_view_with_docs(db, name, query, raw, &block)
|
fetch_view_with_docs(db, name, query, raw, &block)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
require File.join(File.dirname(__FILE__), '..', 'mixins', 'properties')
|
require File.expand_path('../../mixins/properties', __FILE__)
|
||||||
|
|
||||||
|
|
||||||
module CouchRest
|
module CouchRest
|
||||||
module CastedModel
|
module CastedModel
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.send(:include, CouchRest::Callbacks)
|
base.send(:include, ::CouchRest::Callbacks)
|
||||||
base.send(:include, CouchRest::Mixins::Properties)
|
base.send(:include, ::CouchRest::Mixins::Properties)
|
||||||
base.send(:attr_accessor, :casted_by)
|
base.send(:attr_accessor, :casted_by)
|
||||||
base.send(:attr_accessor, :document_saved)
|
base.send(:attr_accessor, :document_saved)
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,13 @@ module CouchRest
|
||||||
entries.empty?
|
entries.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return size of errors hash
|
||||||
|
#
|
||||||
|
# Allows us to play nicely with Rails' helpers
|
||||||
|
def count
|
||||||
|
errors.size
|
||||||
|
end
|
||||||
|
|
||||||
def method_missing(meth, *args, &block)
|
def method_missing(meth, *args, &block)
|
||||||
errors.send(meth, *args, &block)
|
errors.send(meth, *args, &block)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest do
|
describe CouchRest do
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest::Database do
|
describe CouchRest::Database do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
|
@ -263,7 +263,11 @@ describe CouchRest::Database do
|
||||||
r['ok'].should == true
|
r['ok'].should == true
|
||||||
doc = @db.get("attach-this")
|
doc = @db.get("attach-this")
|
||||||
attachment = @db.fetch_attachment(doc,"couchdb.png")
|
attachment = @db.fetch_attachment(doc,"couchdb.png")
|
||||||
attachment.should == image
|
if attachment.respond_to?(:net_http_res)
|
||||||
|
attachment.net_http_res.body.should == image
|
||||||
|
else
|
||||||
|
attachment.should == image
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -368,8 +372,18 @@ describe CouchRest::Database do
|
||||||
end
|
end
|
||||||
it "should delete the attachment" do
|
it "should delete the attachment" do
|
||||||
lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
|
lambda { @db.fetch_attachment(@doc,'test.html') }.should_not raise_error
|
||||||
@db.delete_attachment(@doc, "test.html")
|
@db.delete_attachment(@doc, "test.html")
|
||||||
lambda { @db.fetch_attachment(@doc,'test.html') }.should raise_error(RestClient::ResourceNotFound)
|
@doc = @db.get('mydocwithattachment') # avoid getting a 409
|
||||||
|
lambda{ @db.fetch_attachment(@doc,'test.html')}.should raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should force a delete even if we get a 409" do
|
||||||
|
@doc['new_attribute'] = 'something new'
|
||||||
|
@db.put_attachment(@doc, 'test', File.open(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'attachments', 'test.html')).read)
|
||||||
|
# at this point the revision number changed, if we try to save doc one more time
|
||||||
|
# we would get a 409.
|
||||||
|
lambda{ @db.save_doc(@doc) }.should raise_error
|
||||||
|
lambda{ @db.delete_attachment(@doc, "test", true) }.should_not raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest::Design do
|
describe CouchRest::Design do
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
class Video < CouchRest::Document; end
|
class Video < CouchRest::Document; end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest::Server do
|
describe CouchRest::Server do
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest::Pager do
|
describe CouchRest::Pager do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
|
|
||||||
describe CouchRest::Streamer do
|
describe CouchRest::Streamer do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||||
|
|
||||||
class Car < CouchRest::ExtendedDocument
|
class Car < CouchRest::ExtendedDocument
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
|
|
||||||
describe "ExtendedDocument attachments" do
|
describe "ExtendedDocument attachments" do
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'cat')
|
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||||
|
@ -270,6 +270,15 @@ describe "ExtendedDocument" do
|
||||||
foundart = Article.get @art.id
|
foundart = Article.get @art.id
|
||||||
foundart.title.should == "All About Getting"
|
foundart.title.should == "All About Getting"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should return nil if `get` is used and the document doesn't exist" do
|
||||||
|
foundart = Article.get 'matt aimonetti'
|
||||||
|
foundart.should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should raise an error if `get!` is used and the document doesn't exist" do
|
||||||
|
lambda{foundart = Article.get!('matt aimonetti')}.should raise_error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "getting a model with a subobjects array" do
|
describe "getting a model with a subobjects array" do
|
||||||
|
@ -561,7 +570,7 @@ describe "ExtendedDocument" do
|
||||||
end
|
end
|
||||||
it "should make it go away" do
|
it "should make it go away" do
|
||||||
@dobj.destroy
|
@dobj.destroy
|
||||||
lambda{Basic.get(@dobj.id)}.should raise_error
|
lambda{Basic.get!(@dobj.id)}.should raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.expand_path("../../../spec_helper", __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'article')
|
require File.join(FIXTURE_PATH, 'more', 'article')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'course')
|
require File.join(FIXTURE_PATH, 'more', 'course')
|
||||||
|
|
||||||
|
@ -168,8 +168,11 @@ describe "ExtendedDocument views" do
|
||||||
end
|
end
|
||||||
things[0]["doc"]["title"].should =='aaa'
|
things[0]["doc"]["title"].should =='aaa'
|
||||||
end
|
end
|
||||||
it "should barf on get if no database given" do
|
it "should return nil on get if no database given" do
|
||||||
lambda{Unattached.get("aaa")}.should raise_error
|
Unattached.get("aaa").should be_nil
|
||||||
|
end
|
||||||
|
it "should barf on get! if no database given" do
|
||||||
|
lambda{Unattached.get!("aaa")}.should raise_error
|
||||||
end
|
end
|
||||||
it "should get from specific database" do
|
it "should get from specific database" do
|
||||||
u = Unattached.get(@first_id, @db)
|
u = Unattached.get(@first_id, @db)
|
||||||
|
@ -200,7 +203,7 @@ describe "ExtendedDocument views" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
reset_test_db!
|
reset_test_db!
|
||||||
# setup the class default doc to save the design doc
|
# setup the class default doc to save the design doc
|
||||||
Unattached.use_database DB
|
Unattached.use_database nil # just to be sure it is really unattached
|
||||||
@us = Unattached.on(DB)
|
@us = Unattached.on(DB)
|
||||||
%w{aaa bbb ddd eee}.each do |title|
|
%w{aaa bbb ddd eee}.each do |title|
|
||||||
u = @us.new(:title => title)
|
u = @us.new(:title => title)
|
||||||
|
@ -212,6 +215,9 @@ describe "ExtendedDocument views" do
|
||||||
rs = @us.all
|
rs = @us.all
|
||||||
rs.length.should == 4
|
rs.length.should == 4
|
||||||
end
|
end
|
||||||
|
it "should count" do
|
||||||
|
@us.count.should == 4
|
||||||
|
end
|
||||||
it "should make the design doc upon first query" do
|
it "should make the design doc upon first query" do
|
||||||
@us.by_title
|
@us.by_title
|
||||||
doc = @us.design_doc
|
doc = @us.design_doc
|
||||||
|
@ -348,7 +354,8 @@ describe "ExtendedDocument views" do
|
||||||
a = Article.new(:title => title, :date => Date.today)
|
a = Article.new(:title => title, :date => Date.today)
|
||||||
a.save
|
a.save
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
require 'date'
|
||||||
it "should return a proxy that looks like an array of 7 Article objects" do
|
it "should return a proxy that looks like an array of 7 Article objects" do
|
||||||
articles = Article.by_date :key => Date.today
|
articles = Article.by_date :key => Date.today
|
||||||
articles.class.should == Array
|
articles.class.should == Array
|
||||||
|
@ -368,8 +375,7 @@ describe "ExtendedDocument views" do
|
||||||
end
|
end
|
||||||
it "should have the amount of paginated pages" do
|
it "should have the amount of paginated pages" do
|
||||||
articles = Article.by_date :key => Date.today
|
articles = Article.by_date :key => Date.today
|
||||||
articles.paginate(:per_page => 3)
|
articles.paginate(:per_page => 3).amount_pages.should == 3
|
||||||
articles.amount_pages.should == 3
|
|
||||||
end
|
end
|
||||||
it "should provide a class method to access the collection directly" do
|
it "should provide a class method to access the collection directly" do
|
||||||
articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
|
articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
|
require File.expand_path('../../../spec_helper', __FILE__)
|
||||||
require File.join(FIXTURE_PATH, 'more', 'person')
|
require File.join(FIXTURE_PATH, 'more', 'person')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'card')
|
require File.join(FIXTURE_PATH, 'more', 'card')
|
||||||
require File.join(FIXTURE_PATH, 'more', 'invoice')
|
require File.join(FIXTURE_PATH, 'more', 'invoice')
|
||||||
|
@ -164,6 +164,33 @@ describe "ExtendedDocument properties" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "casting to a boolean value" do
|
||||||
|
class RootBeerFloat < CouchRest::ExtendedDocument
|
||||||
|
use_database DB
|
||||||
|
property :tasty, :cast_as => :boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should add an accessor with a '?' for boolean attributes that returns true or false" do
|
||||||
|
RootBeerFloat.new(:tasty => true).tasty?.should == true
|
||||||
|
RootBeerFloat.new(:tasty => 'you bet').tasty?.should == true
|
||||||
|
RootBeerFloat.new(:tasty => 123).tasty?.should == true
|
||||||
|
|
||||||
|
RootBeerFloat.new(:tasty => false).tasty?.should == false
|
||||||
|
RootBeerFloat.new(:tasty => 'false').tasty?.should == false
|
||||||
|
RootBeerFloat.new(:tasty => 'FaLsE').tasty?.should == false
|
||||||
|
RootBeerFloat.new(:tasty => nil).tasty?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return the real value when the default accessor is used" do
|
||||||
|
RootBeerFloat.new(:tasty => true).tasty.should == true
|
||||||
|
RootBeerFloat.new(:tasty => 'you bet').tasty.should == 'you bet'
|
||||||
|
RootBeerFloat.new(:tasty => 123).tasty.should == 123
|
||||||
|
RootBeerFloat.new(:tasty => 'false').tasty.should == 'false'
|
||||||
|
RootBeerFloat.new(:tasty => false).tasty.should == false
|
||||||
|
RootBeerFloat.new(:tasty => nil).tasty.should == nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue