couchobject 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +41 -0
- data/README.txt +119 -0
- data/Rakefile +4 -0
- data/TODO +8 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +17 -0
- data/lib/couch_object.rb +27 -0
- data/lib/couch_object/database.rb +115 -0
- data/lib/couch_object/document.rb +106 -0
- data/lib/couch_object/model.rb +5 -0
- data/lib/couch_object/persistable.rb +59 -0
- data/lib/couch_object/response.rb +44 -0
- data/lib/couch_object/server.rb +53 -0
- data/lib/couch_object/utils.rb +13 -0
- data/lib/couch_object/version.rb +9 -0
- data/lib/couch_object/view.rb +23 -0
- data/log/debug.log +0 -0
- data/script/console +17 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/spec/database_spec.rb +143 -0
- data/spec/document_spec.rb +142 -0
- data/spec/integration/database_integration_spec.rb +78 -0
- data/spec/integration/document_integration_spec.rb +41 -0
- data/spec/integration/integration_helper.rb +20 -0
- data/spec/model_spec.rb +5 -0
- data/spec/persistable_spec.rb +91 -0
- data/spec/response_spec.rb +47 -0
- data/spec/rspec_autotest.rb +149 -0
- data/spec/server_spec.rb +74 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/utils_spec.rb +18 -0
- data/spec/view_spec.rb +36 -0
- data/tasks/deployment.rake +27 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +42 -0
- data/tasks/website.rake +9 -0
- metadata +98 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Johan Sørensen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
TODO
|
7
|
+
config/hoe.rb
|
8
|
+
config/requirements.rb
|
9
|
+
lib/couch_object.rb
|
10
|
+
lib/couch_object/database.rb
|
11
|
+
lib/couch_object/document.rb
|
12
|
+
lib/couch_object/model.rb
|
13
|
+
lib/couch_object/persistable.rb
|
14
|
+
lib/couch_object/response.rb
|
15
|
+
lib/couch_object/server.rb
|
16
|
+
lib/couch_object/utils.rb
|
17
|
+
lib/couch_object/version.rb
|
18
|
+
lib/couch_object/view.rb
|
19
|
+
log/debug.log
|
20
|
+
script/console
|
21
|
+
script/destroy
|
22
|
+
script/generate
|
23
|
+
setup.rb
|
24
|
+
spec/database_spec.rb
|
25
|
+
spec/document_spec.rb
|
26
|
+
spec/integration/database_integration_spec.rb
|
27
|
+
spec/integration/document_integration_spec.rb
|
28
|
+
spec/integration/integration_helper.rb
|
29
|
+
spec/model_spec.rb
|
30
|
+
spec/persistable_spec.rb
|
31
|
+
spec/response_spec.rb
|
32
|
+
spec/rspec_autotest.rb
|
33
|
+
spec/server_spec.rb
|
34
|
+
spec/spec.opts
|
35
|
+
spec/spec_helper.rb
|
36
|
+
spec/utils_spec.rb
|
37
|
+
spec/view_spec.rb
|
38
|
+
tasks/deployment.rake
|
39
|
+
tasks/environment.rake
|
40
|
+
tasks/rspec.rake
|
41
|
+
tasks/website.rake
|
data/README.txt
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
= CouchObject
|
2
|
+
|
3
|
+
CouchObject is a set of classes to help you talk to CouchDb (http://couchdbwiki.com/) with Ruby.
|
4
|
+
|
5
|
+
* Author: Johan Sørensen
|
6
|
+
* Contact: johan (at) johansorensen DOT com
|
7
|
+
* Home: http://rubyforge.org/projects/couchobject/
|
8
|
+
* Source (Git): http://repo.or.cz/w/couchobject.git
|
9
|
+
|
10
|
+
== Creating, opening and deleting databases
|
11
|
+
|
12
|
+
CouchObject::Database is the first interaction point to your CouchDb. Creating a CouchDb database:
|
13
|
+
|
14
|
+
>> CouchObject::Database.create!("http://localhost:8888", "mydb")
|
15
|
+
=> {"ok"=>true}
|
16
|
+
>> CouchObject::Database.all_databases("http://localhost:8888")
|
17
|
+
=> ["couchobject", "couchobject_test", "foo", "mydb"]
|
18
|
+
>> db = CouchObject::Database.open("http://localhost:8888/mydb")
|
19
|
+
=> #<CouchObject::Database:0x642fa8 @server=#<CouchObject::Server:0x642ef4 @connection=#<Net::HTTP localhost:8888 open=false>, @port=8888, @uri=#<URI::HTTP:0x321612 URL:http://localhost:8888>, @host="localhost">, @uri="http://localhost:8888", @dbname="mydb">
|
20
|
+
>> db.name
|
21
|
+
=> "mydb"
|
22
|
+
>> CouchObject::Database.delete!("http://localhost:8888", "mydb")
|
23
|
+
=> {"ok"=>true}
|
24
|
+
>> CouchObject::Database.all_databases("http://localhost:8888").include?("mydb")
|
25
|
+
=> false
|
26
|
+
|
27
|
+
=== Interacting with the database
|
28
|
+
|
29
|
+
>> db.get("_all_docs")
|
30
|
+
=> #<CouchObject::Response:0x14ed364 @response=#<Net::HTTPOK 200 OK readbody=true>, @parsed_body={"rows"=>[], "view"=>"_all_docs"}>
|
31
|
+
|
32
|
+
Issueing CouchObject::Database#get, CouchObject::Database#post, CouchObject::Database#put and CouchObject::Database#delete requests will return a CouchObject::Response object
|
33
|
+
|
34
|
+
>> db.get("_all_docs").body
|
35
|
+
=> "{\"view\":\"_all_docs\", \"rows\":[\n\n]}"
|
36
|
+
>> db.get("_all_docs").parsed_body
|
37
|
+
=> {"rows"=>[], "view"=>"_all_docs"}
|
38
|
+
>> db.post("", JSON.unparse({"foo" => "bar"}))
|
39
|
+
=> #<CouchObject::Response:0x14d7780 @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F", "ok"=>true}>
|
40
|
+
>> db.get("_all_docs").parsed_body
|
41
|
+
=> {"rows"=>[{"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F"}], "view"=>"_all_docs"}
|
42
|
+
>> db.get("1206189E4496409DAD3818D241F5478F").parsed_body
|
43
|
+
=> {"_rev"=>-992681820, "_id"=>"1206189E4496409DAD3818D241F5478F", "foo"=>"bar"}
|
44
|
+
>> db.delete("1206189E4496409DAD3818D241F5478F").parsed_body
|
45
|
+
=> {"_rev"=>548318611, "ok"=>true}
|
46
|
+
>> db.get("_all_docs").parsed_body
|
47
|
+
=> {"rows"=>[], "view"=>"_all_docs"}
|
48
|
+
|
49
|
+
== The Document object
|
50
|
+
|
51
|
+
CouchObject::Document wraps a few things in a nice api. In particular you can use it if you don't want to deal with hashes all the time (similar to ActiveRecord and so on):
|
52
|
+
|
53
|
+
>> doc = CouchObject::Document.new({ "foo" => [1,2], "bar" => true })
|
54
|
+
=> #<CouchObject::Document:0x14a7224 @id=nil, @attributes={"foo"=>[1, 2], "bar"=>true}, @revision=nil>
|
55
|
+
>> doc["foo"]
|
56
|
+
=> [1, 2]
|
57
|
+
>> doc.foo
|
58
|
+
=> [1, 2]
|
59
|
+
>> doc.bar
|
60
|
+
=> true
|
61
|
+
>> doc.bar?
|
62
|
+
=> true
|
63
|
+
|
64
|
+
You can also save a document to the database:
|
65
|
+
|
66
|
+
>> doc.new?
|
67
|
+
=> true
|
68
|
+
>> doc.save(db)
|
69
|
+
=> #<CouchObject::Response:0x149f358 @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>2030456697, "_id"=>"CAEADDC895AC4D506542A3796CCA355D", "ok"=>true}>
|
70
|
+
>> doc.id
|
71
|
+
=> "CAEADDC895AC4D506542A3796CCA355D"
|
72
|
+
|
73
|
+
Since CouchObject::Database#get returns a CouchObject::Response object we can convert it into a Document instance easily with CouchObject::Database#to_document:
|
74
|
+
|
75
|
+
>> response = db.get(doc.id)
|
76
|
+
=> #<CouchObject::Response:0x1498b98 @response=#<Net::HTTPOK 200 OK readbody=true>, @parsed_body={"_rev"=>2030456697, "_id"=>"CAEADDC895AC4D506542A3796CCA355D", "foo"=>[1, 2], "bar"=>true}>
|
77
|
+
>> the_doc_we_just_saved = response.to_document
|
78
|
+
=> #<CouchObject::Document:0x148415c @id="CAEADDC895AC4D506542A3796CCA355D", @attributes={"foo"=>[1, 2], "bar"=>true}, @revision=2030456697>
|
79
|
+
>> the_doc_we_just_saved.foo
|
80
|
+
=> [1, 2]
|
81
|
+
>> doc.foo = "quux"
|
82
|
+
=> "quux"
|
83
|
+
>> doc.save(db)
|
84
|
+
=> #<CouchObject::Response:0x4b0adc @response=#<Net::HTTPCreated 201 Created readbody=true>, @parsed_body={"_rev"=>1670064786, "_id"=>"B4077269D2DF8433D145DC0702B9791C", "ok"=>true}>
|
85
|
+
|
86
|
+
|
87
|
+
== CouchObject::Persistable
|
88
|
+
|
89
|
+
It all started with this module, it maps ruby objects to CouchDb documents, using two mapping methods. It's highly experimental and may go away n future releases
|
90
|
+
|
91
|
+
gem "couchobject"
|
92
|
+
require "couch_object"
|
93
|
+
class Bike
|
94
|
+
include CouchObject::Persistable
|
95
|
+
|
96
|
+
def initialize(wheels)
|
97
|
+
@wheels = wheels
|
98
|
+
end
|
99
|
+
attr_accessor :wheels
|
100
|
+
|
101
|
+
def to_couch
|
102
|
+
{:wheels => @wheels}
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.from_couch(attributes)
|
106
|
+
new(attributes["wheels"])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
By including the CouchObject::Persistable and defining two methods on our class we specify how we should serialize and deserialize our object to and from a CouchDb:
|
111
|
+
|
112
|
+
>> bike_4wd = Bike.new(4)
|
113
|
+
=> #<Bike:0x6a0a68 @wheels=4>
|
114
|
+
>> bike_4wd.save("http://localhost:8888/couchobject")
|
115
|
+
=> {"_rev"=>1745167971, "_id"=>"6FA2AFB623A93E0E77DEAAF59BB02565", "ok"=>true}
|
116
|
+
>> bike = Bike.get_by_id("http://localhost:8888/couchobject", bike_4wd.id)
|
117
|
+
=> #<Bike:0x64846c @wheels=4>
|
118
|
+
|
119
|
+
|
data/Rakefile
ADDED
data/TODO
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
- flat namespace for object attributes? (instead of the "attributes" key)
|
2
|
+
- Query/View API
|
3
|
+
- better handling of document id, including setting a custom ones
|
4
|
+
- Database#filter for filtering documents with Ruby (with some ruby2js or RubyToRuby magic)
|
5
|
+
- Expand on View class
|
6
|
+
- A Document object
|
7
|
+
|
8
|
+
- CouchObject::Model for more domain specific/clearer way to model Couch docs in ruby
|
data/config/hoe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'couch_object/version'
|
2
|
+
|
3
|
+
AUTHOR = 'Johan Sørensen' # can also be an array of Authors
|
4
|
+
EMAIL = "johan@johansorensen.com"
|
5
|
+
DESCRIPTION = "CouchObject is a library that maps ruby objects to CouchDb documents"
|
6
|
+
GEM_NAME = 'couchobject' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'couchobject' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
|
11
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
12
|
+
@config = nil
|
13
|
+
RUBYFORGE_USERNAME = "unknown"
|
14
|
+
def rubyforge_username
|
15
|
+
unless @config
|
16
|
+
begin
|
17
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
18
|
+
rescue
|
19
|
+
puts <<-EOS
|
20
|
+
ERROR: No rubyforge config file found: #{@config_file}"
|
21
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
22
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
23
|
+
EOS
|
24
|
+
exit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
REV = nil
|
32
|
+
# UNCOMMENT IF REQUIRED:
|
33
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
34
|
+
VERS = CouchObject::VERSION::STRING + (REV ? ".#{REV}" : "")
|
35
|
+
RDOC_OPTS = ['--quiet', '--title', 'couch_object documentation',
|
36
|
+
"--opname", "index.html",
|
37
|
+
"--line-numbers",
|
38
|
+
"--main", "README",
|
39
|
+
"--inline-source"]
|
40
|
+
|
41
|
+
class Hoe
|
42
|
+
def extra_deps
|
43
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
44
|
+
@extra_deps
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generate all the Rake tasks
|
49
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
50
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
51
|
+
p.author = AUTHOR
|
52
|
+
p.description = DESCRIPTION
|
53
|
+
p.email = EMAIL
|
54
|
+
p.summary = DESCRIPTION
|
55
|
+
p.url = HOMEPATH
|
56
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
57
|
+
p.test_globs = ["spec/**/spec_*.rb"]
|
58
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
59
|
+
|
60
|
+
# == Optional
|
61
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\\n\\n")
|
62
|
+
# An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
63
|
+
p.extra_deps = [
|
64
|
+
["json", ">= 1.1.1"]
|
65
|
+
]
|
66
|
+
|
67
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
72
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
73
|
+
hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
16
|
+
|
17
|
+
require 'couch_object'
|
data/lib/couch_object.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$KCODE = 'u'
|
2
|
+
require 'jcode'
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
gem "json"
|
6
|
+
begin
|
7
|
+
require "json/ext"
|
8
|
+
rescue LoadError
|
9
|
+
$stderr.puts "C version of json (fjson) could not be loaded, using pure ruby one"
|
10
|
+
require "json/pure"
|
11
|
+
end
|
12
|
+
require 'json/add/core'
|
13
|
+
|
14
|
+
$:.unshift File.dirname(__FILE__)
|
15
|
+
|
16
|
+
require "couch_object/utils"
|
17
|
+
require "couch_object/document"
|
18
|
+
require "couch_object/response"
|
19
|
+
require "couch_object/server"
|
20
|
+
require "couch_object/database"
|
21
|
+
require "couch_object/view"
|
22
|
+
require "couch_object/persistable"
|
23
|
+
require "couch_object/model"
|
24
|
+
|
25
|
+
module CouchObject
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module CouchObject
|
2
|
+
# A CouchDb database object
|
3
|
+
class Database
|
4
|
+
# Create a new database at +uri+ with the name if +dbname+
|
5
|
+
def self.create!(uri, dbname)
|
6
|
+
server = Server.new(uri)
|
7
|
+
response = Response.new(server.put("/#{dbname}", "")).parse
|
8
|
+
response.parsed_body
|
9
|
+
end
|
10
|
+
|
11
|
+
# Delete the database at +uri+ with the name if +dbname+
|
12
|
+
def self.delete!(uri, dbname)
|
13
|
+
server = Server.new(uri)
|
14
|
+
response = Response.new(server.delete("/#{dbname}")).parse
|
15
|
+
response.parsed_body
|
16
|
+
end
|
17
|
+
|
18
|
+
# All databases at +uri+
|
19
|
+
def self.all_databases(uri)
|
20
|
+
# FIXME: Move to Server ?
|
21
|
+
server = Server.new(uri)
|
22
|
+
resp = server.get("/_all_dbs")
|
23
|
+
response = Response.new(resp).parse
|
24
|
+
response.parsed_body
|
25
|
+
end
|
26
|
+
|
27
|
+
# Open a connection to the database at +uri+, where +uri+ is a full uri
|
28
|
+
# like: http://localhost:8888/foo
|
29
|
+
def self.open(uri)
|
30
|
+
uri = URI.parse(uri)
|
31
|
+
server_uri = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
32
|
+
new(server_uri, uri.path.tr("/", ""))
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(uri, dbname)
|
36
|
+
@uri = uri
|
37
|
+
@dbname = dbname
|
38
|
+
@server = Server.new(@uri)
|
39
|
+
end
|
40
|
+
attr_accessor :server
|
41
|
+
|
42
|
+
# The full url of this database, eg http://localhost:8888/foo
|
43
|
+
def url
|
44
|
+
Utils.join_url(@uri, @dbname).to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
# Name of this database
|
48
|
+
def name
|
49
|
+
@dbname.dup
|
50
|
+
end
|
51
|
+
|
52
|
+
# Send a GET request to the +path+ which is relative to the database path
|
53
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
54
|
+
# http://host:port/foo_db/bar.
|
55
|
+
# Returns a Response object
|
56
|
+
def get(path)
|
57
|
+
Response.new(@server.get("/#{Utils.join_url(@dbname, path)}")).parse
|
58
|
+
end
|
59
|
+
|
60
|
+
# Send a POST request to the +path+ which is relative to the database path
|
61
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
62
|
+
# http://host:port/foo_db/bar. The post body is the +payload+
|
63
|
+
# Returns a Response object
|
64
|
+
def post(path, payload)
|
65
|
+
Response.new(@server.post("/#{Utils.join_url(@dbname, path)}", payload)).parse
|
66
|
+
end
|
67
|
+
|
68
|
+
# Send a PUT request to the +path+ which is relative to the database path
|
69
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
70
|
+
# http://host:port/foo_db/bar. The put body is the +payload+
|
71
|
+
# Returns a Response object
|
72
|
+
def put(path, payload="")
|
73
|
+
Response.new(@server.put("/#{Utils.join_url(@dbname, path)}", payload)).parse
|
74
|
+
end
|
75
|
+
|
76
|
+
# Send a DELETE request to the +path+ which is relative to the database path
|
77
|
+
# so calling with with "bar" as the path in the "foo_db" database will call
|
78
|
+
# http://host:port/foo_db/bar.
|
79
|
+
# Returns a Response object
|
80
|
+
def delete(path)
|
81
|
+
Response.new(@server.delete("/#{Utils.join_url(@dbname, path)}")).parse
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get a document by id
|
85
|
+
def [](id)
|
86
|
+
get(id.to_s)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Get a document by +id+, optionally a specific +revision+ too
|
90
|
+
def document(id, revision=nil)
|
91
|
+
if revision
|
92
|
+
get("#{id}?rev=#{revision}")
|
93
|
+
else
|
94
|
+
get(id.to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns an Array of all the documents in this db
|
99
|
+
def all_documents
|
100
|
+
resp = Response.new(get("_all_docs")).parse
|
101
|
+
resp.to_document.rows
|
102
|
+
end
|
103
|
+
|
104
|
+
# Queries the database with the block (using a temp. view)
|
105
|
+
def filter(&blk)
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def views(view_name)
|
110
|
+
view = View.new(self, view_name)
|
111
|
+
view.query
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module CouchObject
|
2
|
+
# Represents a CouchDb document
|
3
|
+
class Document
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
# initializes a new document object with +attributes+ as
|
7
|
+
# the document values
|
8
|
+
def initialize(attributes={})
|
9
|
+
@attributes = attributes.dup
|
10
|
+
@id = @attributes.delete("_id")
|
11
|
+
@revision = @attributes.delete("_rev")
|
12
|
+
end
|
13
|
+
attr_accessor :attributes, :id, :revision
|
14
|
+
|
15
|
+
# Sets the id to +new_id+
|
16
|
+
# (Only for internal use really, but public nevertheless)
|
17
|
+
def id=(new_id)
|
18
|
+
if new?
|
19
|
+
attributes["_id"] = @id = new_id
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# is this a new document?
|
26
|
+
def new?
|
27
|
+
@id.nil? && @revision.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
# yields each document attribute
|
31
|
+
def each(&blk)
|
32
|
+
@attributes.each(&blk)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Saves this document to the +database+
|
36
|
+
def save(database)
|
37
|
+
new? ? create(database) : update(database)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Look up an attribute by +key+
|
41
|
+
def [](key)
|
42
|
+
attributes[key]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set an attributes by +key+ to +value+
|
46
|
+
def []=(key, value)
|
47
|
+
attributes[key] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
# is the attribute +key+ in this document?
|
51
|
+
def has_key?(key)
|
52
|
+
attributes.has_key?(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
# is the attribute +key+ in this document?
|
56
|
+
def respond_to?(meth)
|
57
|
+
method_name = meth.to_s
|
58
|
+
|
59
|
+
if has_key?(method_name)
|
60
|
+
return true
|
61
|
+
elsif %w[ ? = ].include?(method_name[-1..-1]) && has_key?(method_name[0..-2])
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts the Document to a JSON representation of its attributes
|
69
|
+
def to_json(extra={})
|
70
|
+
if id.nil?
|
71
|
+
opts = {}.merge(extra)
|
72
|
+
else
|
73
|
+
opts = {"_id" => id}.merge(extra)
|
74
|
+
end
|
75
|
+
attributes.merge(opts).to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
def create(database)
|
80
|
+
response = database.post("", self.to_json)
|
81
|
+
# TODO error handling
|
82
|
+
@id = response.to_document.id
|
83
|
+
@revision = response.to_document.revision
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
87
|
+
def update(database)
|
88
|
+
response = database.put(id, self.to_json("_rev" => revision))
|
89
|
+
# TODO error handling
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def method_missing(method_symbol, *arguments)
|
94
|
+
method_name = method_symbol.to_s
|
95
|
+
|
96
|
+
case method_name[-1..-1]
|
97
|
+
when "="
|
98
|
+
self[method_name[0..-2]] = arguments.first
|
99
|
+
when "?"
|
100
|
+
self[method_name[0..-2]] == true
|
101
|
+
else
|
102
|
+
has_key?(method_name) ? self[method_name] : super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|