Started the refactoring work on couchrest.
* A server can have multiple defined available databases set to be used by documents (think DM repos) * A server can have a default database so documents can easily share the same db connection * Let a document class have a default database to use * Give access to a document uri * extracted some of the document features to a mixin
This commit is contained in:
parent
427122c98a
commit
d9fe6ba374
|
@ -37,6 +37,8 @@ module CouchRest
|
||||||
autoload :FileManager, 'couchrest/helper/file_manager'
|
autoload :FileManager, 'couchrest/helper/file_manager'
|
||||||
autoload :Streamer, 'couchrest/helper/streamer'
|
autoload :Streamer, 'couchrest/helper/streamer'
|
||||||
|
|
||||||
|
require File.join(File.dirname(__FILE__), 'couchrest', 'mixins')
|
||||||
|
|
||||||
# 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
|
||||||
# some helpers for tasks like instantiating a new Database or Server instance.
|
# some helpers for tasks like instantiating a new Database or Server instance.
|
||||||
|
|
|
@ -14,47 +14,20 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
class Document < Response
|
class Document < Response
|
||||||
|
include CouchRest::Mixins::Views
|
||||||
|
|
||||||
attr_accessor :database
|
attr_accessor :database
|
||||||
|
@@database = nil
|
||||||
|
|
||||||
# alias for self['_id']
|
# override the CouchRest::Model-wide default_database
|
||||||
def id
|
# This is not a thread safe operation, do not change the model
|
||||||
self['_id']
|
# database at runtime.
|
||||||
|
def self.use_database(db)
|
||||||
|
@@database = db
|
||||||
end
|
end
|
||||||
|
|
||||||
# alias for self['_rev']
|
def self.database
|
||||||
def rev
|
@@database
|
||||||
self['_rev']
|
|
||||||
end
|
|
||||||
|
|
||||||
# returns true if the document has never been saved
|
|
||||||
def new_document?
|
|
||||||
!rev
|
|
||||||
end
|
|
||||||
|
|
||||||
# Saves the document to the db using create or update. Also runs the :save
|
|
||||||
# callbacks. Sets the <tt>_id</tt> and <tt>_rev</tt> fields based on
|
|
||||||
# CouchDB's response.
|
|
||||||
# If <tt>bulk</tt> is <tt>true</tt> (defaults to false) the document is cached for bulk save.
|
|
||||||
def save(bulk = false)
|
|
||||||
raise ArgumentError, "doc.database required for saving" unless database
|
|
||||||
result = database.save_doc self, bulk
|
|
||||||
result['ok']
|
|
||||||
end
|
|
||||||
|
|
||||||
# Deletes the document from the database. Runs the :delete callbacks.
|
|
||||||
# Removes the <tt>_id</tt> and <tt>_rev</tt> fields, preparing the
|
|
||||||
# document to be saved to a new <tt>_id</tt>.
|
|
||||||
# If <tt>bulk</tt> is <tt>true</tt> (defaults to false) the document won't
|
|
||||||
# actually be deleted from the db until bulk save.
|
|
||||||
def destroy(bulk = false)
|
|
||||||
raise ArgumentError, "doc.database required to destroy" unless database
|
|
||||||
result = database.delete_doc(self, bulk)
|
|
||||||
if result['ok']
|
|
||||||
self['_rev'] = nil
|
|
||||||
self['_id'] = nil
|
|
||||||
end
|
|
||||||
result['ok']
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# copies the document to a new id. If the destination id currently exists, a rev must be provided.
|
# copies the document to a new id. If the destination id currently exists, a rev must be provided.
|
||||||
|
@ -75,6 +48,23 @@ module CouchRest
|
||||||
result['ok']
|
result['ok']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns the CouchDB uri for the document
|
||||||
|
def uri(append_rev = false)
|
||||||
|
return nil if new_document?
|
||||||
|
couch_uri = "http://#{database.uri}/#{CGI.escape(id)}"
|
||||||
|
if append_rev == true
|
||||||
|
couch_uri << "?rev=#{rev}"
|
||||||
|
elsif append_rev.kind_of?(Integer)
|
||||||
|
couch_uri << "?rev=#{append_rev}"
|
||||||
|
end
|
||||||
|
couch_uri
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the document's database
|
||||||
|
def database
|
||||||
|
@database || self.class.database
|
||||||
|
end
|
||||||
|
|
||||||
# saves an attachment directly to couchdb
|
# saves an attachment directly to couchdb
|
||||||
def put_attachment(name, file, options={})
|
def put_attachment(name, file, options={})
|
||||||
raise ArgumentError, "doc.database required to put_attachment" unless database
|
raise ArgumentError, "doc.database required to put_attachment" unless database
|
||||||
|
@ -98,5 +88,4 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,25 +1,62 @@
|
||||||
module CouchRest
|
module CouchRest
|
||||||
class Server
|
class Server
|
||||||
attr_accessor :uri, :uuid_batch_count
|
attr_accessor :uri, :uuid_batch_count, :available_databases
|
||||||
def initialize server = 'http://127.0.0.1:5984', uuid_batch_count = 1000
|
def initialize(server = 'http://127.0.0.1:5984', uuid_batch_count = 1000)
|
||||||
@uri = server
|
@uri = server
|
||||||
@uuid_batch_count = uuid_batch_count
|
@uuid_batch_count = uuid_batch_count
|
||||||
end
|
end
|
||||||
|
|
||||||
# List all databases on the server
|
# Lists all "available" databases.
|
||||||
|
# An available database, is a database that was specified
|
||||||
|
# as avaiable by your code.
|
||||||
|
# It allows to define common databases to use and reuse in your code
|
||||||
|
def available_databases
|
||||||
|
@available_databases ||= {}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a new available database and create it unless it already exists
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# @couch = CouchRest::Server.new
|
||||||
|
# @couch.define_available_database(:default, "tech-blog")
|
||||||
|
#
|
||||||
|
def define_available_database(reference, db_name, create_unless_exists = true)
|
||||||
|
available_databases[reference.to_sym] = create_unless_exists ? database!(db_name) : database(db_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks that a database is set as available
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# @couch.available_database?(:default)
|
||||||
|
#
|
||||||
|
def available_database?(ref_or_name)
|
||||||
|
ref_or_name.is_a?(Symbol) ? available_databases.keys.include?(ref_or_name) : available_databases.values.map{|db| db.name}.include?(ref_or_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_database=(name, create_unless_exists = true)
|
||||||
|
define_available_database(:default, name, create_unless_exists = true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def default_database
|
||||||
|
available_databases[:default]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Lists all databases on the server
|
||||||
def databases
|
def databases
|
||||||
CouchRest.get "#{@uri}/_all_dbs"
|
CouchRest.get "#{@uri}/_all_dbs"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a CouchRest::Database for the given name
|
# Returns a CouchRest::Database for the given name
|
||||||
def database name
|
def database(name)
|
||||||
CouchRest::Database.new(self, name)
|
CouchRest::Database.new(self, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates the database if it doesn't exist
|
# Creates the database if it doesn't exist
|
||||||
def database! name
|
def database!(name)
|
||||||
create_db(name) rescue nil
|
create_db(name) rescue nil
|
||||||
database name
|
database(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET the welcome message
|
# GET the welcome message
|
||||||
|
@ -28,9 +65,9 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a database
|
# Create a database
|
||||||
def create_db name
|
def create_db(name)
|
||||||
CouchRest.put "#{@uri}/#{name}"
|
CouchRest.put "#{@uri}/#{name}"
|
||||||
database name
|
database(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Restart the CouchDB instance
|
# Restart the CouchDB instance
|
||||||
|
@ -39,7 +76,7 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Retrive an unused UUID from CouchDB. Server instances manage caching a list of unused UUIDs.
|
# Retrive an unused UUID from CouchDB. Server instances manage caching a list of unused UUIDs.
|
||||||
def next_uuid count = @uuid_batch_count
|
def next_uuid(count = @uuid_batch_count)
|
||||||
@uuids ||= []
|
@uuids ||= []
|
||||||
if @uuids.empty?
|
if @uuids.empty?
|
||||||
@uuids = CouchRest.post("#{@uri}/_uuids?count=#{count}")["uuids"]
|
@uuids = CouchRest.post("#{@uri}/_uuids?count=#{count}")["uuids"]
|
||||||
|
|
3
lib/couchrest/mixins.rb
Normal file
3
lib/couchrest/mixins.rb
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
mixins_dir = File.join(File.dirname(__FILE__), 'mixins')
|
||||||
|
|
||||||
|
require File.join(mixins_dir, 'views')
|
59
lib/couchrest/mixins/views.rb
Normal file
59
lib/couchrest/mixins/views.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
module CouchRest
|
||||||
|
module Mixins
|
||||||
|
module Views
|
||||||
|
|
||||||
|
# alias for self['_id']
|
||||||
|
def id
|
||||||
|
self['_id']
|
||||||
|
end
|
||||||
|
|
||||||
|
# alias for self['_rev']
|
||||||
|
def rev
|
||||||
|
self['_rev']
|
||||||
|
end
|
||||||
|
|
||||||
|
# returns true if the document has never been saved
|
||||||
|
def new_document?
|
||||||
|
!rev
|
||||||
|
end
|
||||||
|
|
||||||
|
# Saves the document to the db using create or update. Also runs the :save
|
||||||
|
# callbacks. Sets the <tt>_id</tt> and <tt>_rev</tt> fields based on
|
||||||
|
# CouchDB's response.
|
||||||
|
# If <tt>bulk</tt> is <tt>true</tt> (defaults to false) the document is cached for bulk save.
|
||||||
|
def save(bulk = false)
|
||||||
|
raise ArgumentError, "doc.database required for saving" unless database
|
||||||
|
result = database.save_doc self, bulk
|
||||||
|
result['ok']
|
||||||
|
end
|
||||||
|
|
||||||
|
# Deletes the document from the database. Runs the :delete callbacks.
|
||||||
|
# Removes the <tt>_id</tt> and <tt>_rev</tt> fields, preparing the
|
||||||
|
# document to be saved to a new <tt>_id</tt>.
|
||||||
|
# If <tt>bulk</tt> is <tt>true</tt> (defaults to false) the document won't
|
||||||
|
# actually be deleted from the db until bulk save.
|
||||||
|
def destroy(bulk = false)
|
||||||
|
raise ArgumentError, "doc.database required to destroy" unless database
|
||||||
|
result = database.delete_doc(self, bulk)
|
||||||
|
if result['ok']
|
||||||
|
self['_rev'] = nil
|
||||||
|
self['_id'] = nil
|
||||||
|
end
|
||||||
|
result['ok']
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy(dest)
|
||||||
|
raise ArgumentError, "doc.database required to copy" unless database
|
||||||
|
result = database.copy_doc(self, dest)
|
||||||
|
result['ok']
|
||||||
|
end
|
||||||
|
|
||||||
|
def move(dest)
|
||||||
|
raise ArgumentError, "doc.database required to copy" unless database
|
||||||
|
result = database.move_doc(self, dest)
|
||||||
|
result['ok']
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,15 @@
|
||||||
require File.dirname(__FILE__) + '/../../spec_helper'
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
|
|
||||||
describe CouchRest::Document, "[]=" do
|
class Video < CouchRest::Document; end
|
||||||
|
|
||||||
|
describe CouchRest::Document do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
@couch = CouchRest.new
|
||||||
|
@db = @couch.database!(TESTDB)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "[]=" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@doc = CouchRest::Document.new
|
@doc = CouchRest::Document.new
|
||||||
end
|
end
|
||||||
|
@ -18,9 +27,27 @@ describe CouchRest::Document, "[]=" do
|
||||||
@doc[:enamel] = "Strong"
|
@doc[:enamel] = "Strong"
|
||||||
@doc[:enamel].should == "Strong"
|
@doc[:enamel].should == "Strong"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe CouchRest::Document, "new" do
|
describe "default database" do
|
||||||
|
it "should be set using use_database on the model" do
|
||||||
|
Video.new.database.should be_nil
|
||||||
|
Video.use_database @db
|
||||||
|
Video.new.database.should == @db
|
||||||
|
Video.use_database nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be overwritten by instance" do
|
||||||
|
db = @couch.database('test')
|
||||||
|
article = Video.new
|
||||||
|
article.database.should be_nil
|
||||||
|
article.database = db
|
||||||
|
article.database.should_not be_nil
|
||||||
|
article.database.should == db
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "new" do
|
||||||
before(:each) do
|
before(:each) do
|
||||||
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
||||||
end
|
end
|
||||||
|
@ -35,10 +62,10 @@ describe CouchRest::Document, "new" do
|
||||||
it "should freak out when saving without a database" do
|
it "should freak out when saving without a database" do
|
||||||
lambda{@doc.save}.should raise_error(ArgumentError)
|
lambda{@doc.save}.should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# move to database spec
|
# move to database spec
|
||||||
describe CouchRest::Document, "saving using a database" do
|
describe "saving using a database" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
|
@ -51,9 +78,9 @@ describe CouchRest::Document, "saving using a database" do
|
||||||
@doc.id.should == @resp["id"]
|
@doc.id.should == @resp["id"]
|
||||||
@doc.rev.should == @resp["rev"]
|
@doc.rev.should == @resp["rev"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe CouchRest::Document, "bulk saving" do
|
describe "bulk saving" do
|
||||||
before :all do
|
before :all do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
end
|
end
|
||||||
|
@ -66,9 +93,9 @@ describe CouchRest::Document, "bulk saving" do
|
||||||
doc.database.bulk_save
|
doc.database.bulk_save
|
||||||
doc.database.get(doc["_id"])["val"].should == doc["val"]
|
doc.database.get(doc["_id"])["val"].should == doc["val"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "getting from a database" do
|
describe "getting from a database" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
@resp = @db.save_doc({
|
@resp = @db.save_doc({
|
||||||
|
@ -90,9 +117,9 @@ describe "getting from a database" do
|
||||||
@doc.save
|
@doc.save
|
||||||
@db.get(@resp['id'])["more"].should == "these keys"
|
@db.get(@resp['id'])["more"].should == "these keys"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "destroying a document from a db" do
|
describe "destroying a document from a db" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
@resp = @db.save_doc({
|
@resp = @db.save_doc({
|
||||||
|
@ -108,10 +135,10 @@ describe "destroying a document from a db" do
|
||||||
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
@doc = CouchRest::Document.new("key" => [1,2,3], :more => "values")
|
||||||
lambda{@doc.destroy}.should raise_error(ArgumentError)
|
lambda{@doc.destroy}.should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
describe "destroying a document from a db using bulk save" do
|
describe "destroying a document from a db using bulk save" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
@resp = @db.save_doc({
|
@resp = @db.save_doc({
|
||||||
|
@ -127,9 +154,9 @@ describe "destroying a document from a db using bulk save" do
|
||||||
@db.bulk_save
|
@db.bulk_save
|
||||||
lambda{@db.get @resp['id']}.should raise_error
|
lambda{@db.get @resp['id']}.should raise_error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "copying a document" do
|
describe "copying a document" do
|
||||||
before :each do
|
before :each do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
@resp = @db.save_doc({'key' => 'value'})
|
@resp = @db.save_doc({'key' => 'value'})
|
||||||
|
@ -166,9 +193,9 @@ describe "copying a document" do
|
||||||
newdoc['key'].should == 'value'
|
newdoc['key'].should == 'value'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "MOVE existing document" do
|
describe "MOVE existing document" do
|
||||||
before :each do
|
before :each do
|
||||||
@db = reset_test_db!
|
@db = reset_test_db!
|
||||||
@resp = @db.save_doc({'key' => 'value'})
|
@resp = @db.save_doc({'key' => 'value'})
|
||||||
|
@ -210,6 +237,7 @@ describe "MOVE existing document" do
|
||||||
lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
|
lambda {@db.get(@resp['id'])}.should raise_error(RestClient::ResourceNotFound)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "dealing with attachments" do
|
describe "dealing with attachments" do
|
||||||
|
|
34
spec/couchrest/core/server_spec.rb
Normal file
34
spec/couchrest/core/server_spec.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
|
|
||||||
|
describe CouchRest::Server do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
@couch = CouchRest::Server.new
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:all) do
|
||||||
|
@couch.available_databases.each do |ref, db|
|
||||||
|
db.delete!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "available databases" do
|
||||||
|
it "should let you add more databases" do
|
||||||
|
@couch.available_databases.should be_empty
|
||||||
|
@couch.define_available_database(:default, "cr-server-test-db")
|
||||||
|
@couch.available_databases.keys.should include(:default)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should verify that a database is available" do
|
||||||
|
@couch.available_database?(:default).should be_true
|
||||||
|
@couch.available_database?("cr-server-test-db").should be_true
|
||||||
|
@couch.available_database?(:matt).should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should let you set a default database" do
|
||||||
|
@couch.default_database = 'cr-server-test-default-db'
|
||||||
|
@couch.available_database?(:default).should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue