akdubya-cushion 0.5.2 → 0.6.0
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/README.rdoc +94 -174
- data/lib/cushion.rb +54 -10
- data/lib/cushion/database.rb +294 -203
- data/lib/cushion/design.rb +4 -5
- data/lib/cushion/document.rb +119 -69
- data/lib/cushion/server.rb +9 -13
- data/spec/cushion_spec.rb +0 -2
- data/spec/database_spec.rb +215 -132
- data/spec/document_spec.rb +172 -0
- data/spec/server_spec.rb +52 -66
- metadata +3 -2
data/README.rdoc
CHANGED
|
@@ -1,226 +1,146 @@
|
|
|
1
1
|
= Cushion: A slim CouchDB client
|
|
2
2
|
|
|
3
|
-
Cushion is a
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Cushion is a Ruby client for accessing CouchDB servers that's light on the
|
|
4
|
+
extras and heavy on the syntatical sugar.
|
|
5
|
+
|
|
6
|
+
Credit goes to CouchRest (http://github.com/jchris/couchrest/tree/master) for
|
|
7
|
+
the inspiration.
|
|
6
8
|
|
|
7
9
|
== Getting Started
|
|
8
10
|
|
|
9
11
|
# myapp.rb
|
|
10
12
|
require 'cushion'
|
|
11
13
|
|
|
12
|
-
db = Cushion
|
|
13
|
-
db.save_doc("_id" => "abc", "foo" => "bar")
|
|
14
|
-
db.open_doc("abc")
|
|
15
|
-
|
|
16
|
-
== Servers
|
|
17
|
-
|
|
18
|
-
The server location defaults to http://127.0.0.1:5984, so you may omit the host
|
|
19
|
-
when initializing a server if you are satisfied with the default.
|
|
20
|
-
|
|
21
|
-
Cushion.server
|
|
22
|
-
Cushion.server('http://myhost:6969')
|
|
23
|
-
|
|
24
|
-
Display the server welcome message:
|
|
25
|
-
|
|
26
|
-
server.info
|
|
27
|
-
|
|
28
|
-
Get a list of all databases on the server:
|
|
14
|
+
db = Cushion!(mydb)
|
|
29
15
|
|
|
30
|
-
|
|
16
|
+
== Document Basics
|
|
31
17
|
|
|
32
|
-
|
|
18
|
+
Storing documents is simple. Just supply a hash of attributes. Leave out the
|
|
19
|
+
<tt>_id</tt> attribute if you want to use an auto-generated UUID. Set the
|
|
20
|
+
<tt>_rev</tt> attribute to update a document:
|
|
33
21
|
|
|
34
|
-
|
|
22
|
+
db.store("baz" => "bat")
|
|
23
|
+
# => {"ok"=>true, "id"=> "bdd39a3f9a1e5894d3d1283aa0d0f53f", "rev"=> "2699240268"}
|
|
35
24
|
|
|
36
|
-
|
|
25
|
+
response = db.store("_id" => "mydoc", "foo" => "bar")
|
|
26
|
+
# => {"ok"=>true, "id"=>"mydoc", "rev"=>"882534292"}
|
|
37
27
|
|
|
38
|
-
|
|
28
|
+
db.store("_id" => "mydoc", "foo" => "baz", "_rev" => response['rev'])
|
|
29
|
+
# => {"ok"=>true, "id"=>"mydoc", "rev"=>"3617508982"}
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
Fetching documents is just as simple.
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
server.restart
|
|
47
|
-
|
|
48
|
-
Obtain server stats:
|
|
49
|
-
|
|
50
|
-
server.stats
|
|
51
|
-
|
|
52
|
-
Replicate from a source database to a target database:
|
|
53
|
-
|
|
54
|
-
server.replicate("db1", "db2")
|
|
55
|
-
server.replicate("db1", "http://host2:5984/bar")
|
|
33
|
+
db.key?("mydoc") # => true
|
|
34
|
+
db.fetch("mydoc") # => {"_id"=>"mydoc", "_rev"=>"3617508982", "foo"=>"baz"}
|
|
35
|
+
db.fetch("bogusid") # => raises RestClient::ResourceNotFound
|
|
56
36
|
|
|
57
|
-
|
|
37
|
+
# Use etags to perform a conditional GET
|
|
38
|
+
db.fetch("mydoc", :etag => cur_rev) # => raises RestClient::NotModified
|
|
58
39
|
|
|
59
|
-
|
|
60
|
-
|
|
40
|
+
Store attachments inline or via CouchDB's standalone attachment API. The standalone
|
|
41
|
+
method accepts both IO objects and strings:
|
|
61
42
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Create a database directly from a url, or just return the database instance if
|
|
69
|
-
it already exists:
|
|
70
|
-
|
|
71
|
-
Cushion.db!('http://127.0.0.1:5984/mydb')
|
|
72
|
-
|
|
73
|
-
Compact a database, eliminating old document revisions:
|
|
74
|
-
|
|
75
|
-
db.compact
|
|
76
|
-
|
|
77
|
-
Create and delete a database from an instance of <tt>Cushion::Database</tt>
|
|
78
|
-
|
|
79
|
-
db.create
|
|
80
|
-
db.delete
|
|
81
|
-
|
|
82
|
-
Open a document:
|
|
83
|
-
|
|
84
|
-
db.open_doc("mydoc")
|
|
43
|
+
# Inline
|
|
44
|
+
db.store("_id" => "hasfiles", ..., "_attachments" => {
|
|
45
|
+
"foo.txt" => {
|
|
46
|
+
"content_type" => "text/plain",
|
|
47
|
+
"data" => "Hello World!"
|
|
48
|
+
}})
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
# Standalone
|
|
51
|
+
res = @db.store("_id" => "savemefirst", ...)
|
|
52
|
+
db.attach("savemefirst", "foo.txt", "Hello World!", :rev => res['rev'],
|
|
53
|
+
:content_type => "text/plain")
|
|
54
|
+
# => Foo now contains an attachment hash similar to the above example
|
|
87
55
|
|
|
88
|
-
|
|
56
|
+
# Fetch attachment data
|
|
57
|
+
db.fetch("savemefirst", "foo.txt") # => "Hello World!"
|
|
89
58
|
|
|
90
|
-
|
|
59
|
+
Cushion returns parsed JSON by default. In those cases where you need the raw
|
|
60
|
+
JSON string, simply set an accept header:
|
|
91
61
|
|
|
92
|
-
db.
|
|
93
|
-
|
|
94
|
-
ab.save_doc("_id" => "exists", "_rev" => "1234", .. attributes ..)
|
|
62
|
+
db.fetch("mydoc", :headers => { :accept => "text/plain" })
|
|
63
|
+
# => "{\"_id\":\"mydoc\",\"_rev\":\"3617508982\",\"foo\":\"baz\"}\n"
|
|
95
64
|
|
|
96
|
-
|
|
65
|
+
The technique above works for nearly every <tt>Cushion</tt> request method.
|
|
97
66
|
|
|
98
|
-
|
|
67
|
+
== Document Macros
|
|
99
68
|
|
|
100
|
-
|
|
69
|
+
You can use CouchDB's bulk docs feature to create, update and delete many
|
|
70
|
+
documents at once:
|
|
101
71
|
|
|
102
72
|
docs = [
|
|
103
|
-
{ "_id" => "0", "_rev" => "123456", "_deleted" => true }, #=> Delete
|
|
104
|
-
{ "_id" => "1", "_rev" => "32486671", "foo" => "bar" }, #=> Update
|
|
105
|
-
{ "_id" => "2", "baz" => "bat" } #=> Create
|
|
73
|
+
{ "_id" => "0", "_rev" => "123456", "_deleted" => true }, #=> Delete
|
|
74
|
+
{ "_id" => "1", "_rev" => "32486671", "foo" => "bar" }, #=> Update
|
|
75
|
+
{ "_id" => "2", "baz" => "bat" } #=> Create
|
|
106
76
|
]
|
|
107
77
|
|
|
108
|
-
db.
|
|
78
|
+
db.bulk(docs) # => returns a hash of updated documents
|
|
79
|
+
db.bulk(docs, :delete => true) # => deletes the selected docs
|
|
109
80
|
|
|
110
|
-
|
|
81
|
+
Documents and attachments may also be copied or moved within the same database.
|
|
82
|
+
Some useful examples:
|
|
111
83
|
|
|
112
|
-
|
|
84
|
+
# Documents
|
|
85
|
+
db.copy("mydoc", "new_doc")
|
|
86
|
+
# => {"ok"=>true, "id"=>"new_doc", "rev"=> ...}
|
|
87
|
+
db.move("mydoc", "existing_doc", :rev => ..., :dest_rev => ...)
|
|
88
|
+
# => overwrites the existing doc
|
|
113
89
|
|
|
114
|
-
|
|
90
|
+
# Attachments
|
|
91
|
+
db.copy_attachment("mydoc", "foo.txt", "bar.txt")
|
|
92
|
+
# => copies an attachment within the same doc
|
|
93
|
+
db.move_attachment("mydoc", "foo.txt", "bar.txt")
|
|
94
|
+
# => renames an attachment; aliased at #rename_attachment
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
"1" => ["12345", "42836"],
|
|
118
|
-
"2" => ["572654"],
|
|
119
|
-
"3" => ["34462"]
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
db.purge(doc_revs)
|
|
123
|
-
|
|
124
|
-
Copy or move a document to a new +id+. Specify a +dest_rev+ to overwrite an existing
|
|
125
|
-
document:
|
|
126
|
-
|
|
127
|
-
db.copy_doc("doc1", "doc2")
|
|
128
|
-
db.copy_doc("doc1", "doc2", :dest_rev => "36452")
|
|
129
|
-
db.move_doc("doc1", "1234", "doc2")
|
|
130
|
-
db.move_doc("doc1", "1234", "doc2", :dest_rev => "37462")
|
|
131
|
-
|
|
132
|
-
CouchDB can attach multiple files directly to documents, either as inline Base64
|
|
133
|
-
encoded data or via a standalone attachment API.
|
|
134
|
-
|
|
135
|
-
Open a document attachment. This will return an <tt>IO</tt> object:
|
|
136
|
-
|
|
137
|
-
temp = db.open_attachment("mydoc", "foo.txt")
|
|
138
|
-
temp.read
|
|
139
|
-
|
|
140
|
-
Save an inline attachment to a document:
|
|
141
|
-
|
|
142
|
-
db.save_doc("_id" => "mydoc", "_attachments" => {
|
|
143
|
-
"foo.txt" => {
|
|
144
|
-
"content_type" => "text/plain",
|
|
145
|
-
"data" => "Hello World!"
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
Save a standalone attachment to a saved document. Content type defaults to
|
|
150
|
-
"application/octet-stream":
|
|
151
|
-
|
|
152
|
-
db.save_attachment("mydoc", "1234", "bar.txt", "somedata", :content_type => "text/plain")
|
|
153
|
-
|
|
154
|
-
Delete a document attachment:
|
|
155
|
-
|
|
156
|
-
db.delete_attachment("mydoc", "1234", "foo.txt")
|
|
157
|
-
|
|
158
|
-
Rename an attachment:
|
|
159
|
-
|
|
160
|
-
db.rename_attachment("mydoc", "1234", "baz.txt", "bat.txt")
|
|
96
|
+
See the database specs for more copy and move examples.
|
|
161
97
|
|
|
162
98
|
== Views
|
|
163
99
|
|
|
164
|
-
|
|
100
|
+
- creating (design docs)
|
|
101
|
+
- querying
|
|
102
|
+
- temp views
|
|
165
103
|
|
|
166
|
-
|
|
167
|
-
db.temp_view(temp_view, :key => "verified")
|
|
104
|
+
== Servers and Databases
|
|
168
105
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
db.view("people/by_first_name", :key => "gomer")
|
|
172
|
-
|
|
173
|
-
Show and list functions:
|
|
174
|
-
|
|
175
|
-
db.show("examples", "people", "mydoc", :format => "xml")
|
|
176
|
-
db.list("examples", "browse-people", "people-by-name", :startkey => ["a"], :limit => 10)
|
|
106
|
+
The server location defaults to http://127.0.0.1:5984, so you may omit the host
|
|
107
|
+
when initializing a server if you are satisfied with the default.
|
|
177
108
|
|
|
178
|
-
|
|
109
|
+
NOTE: Some cruft needs cleaning up. Use <tt>Cushion!(dbname, opts)</tt> for
|
|
110
|
+
now.
|
|
179
111
|
|
|
180
|
-
|
|
112
|
+
Display various bits of server metadata as follows:
|
|
181
113
|
|
|
182
|
-
|
|
183
|
-
|
|
114
|
+
server.info #=> welcome message
|
|
115
|
+
server.all_dbs #=> all dbs available
|
|
116
|
+
server.active_tasks #=> running tasks (e.g., replication or compaction)
|
|
117
|
+
server.config #=> server config
|
|
118
|
+
server.restart #=> restart the server
|
|
119
|
+
server.stats #=> detailed runtime stats
|
|
184
120
|
|
|
185
|
-
|
|
121
|
+
<tt>Cushion::Server</tt> can also replicate local and remote databases:
|
|
186
122
|
|
|
187
|
-
|
|
123
|
+
server.replicate("db1", "db2")
|
|
124
|
+
server.replicate("db1", "http://host2:5984/bar")
|
|
188
125
|
|
|
189
|
-
|
|
190
|
-
cases it is useful to return the raw response from CouchDB. Simply set the correct
|
|
191
|
-
HTTP headers to request an alternate format:
|
|
126
|
+
Creating database instances:
|
|
192
127
|
|
|
193
|
-
|
|
128
|
+
- top level methods
|
|
129
|
+
- options
|
|
194
130
|
|
|
195
|
-
|
|
196
|
-
the explicit headers key like so:
|
|
131
|
+
DB Operations:
|
|
197
132
|
|
|
198
|
-
db.
|
|
133
|
+
db.create
|
|
134
|
+
db.delete
|
|
135
|
+
db.compact
|
|
199
136
|
|
|
200
137
|
== Cushion::Document
|
|
201
138
|
|
|
202
|
-
|
|
203
|
-
individual documents.
|
|
204
|
-
|
|
205
|
-
Create a document:
|
|
206
|
-
|
|
207
|
-
Cushion::Document.use_database(db)
|
|
208
|
-
doc = Cushion::Document.new("foo" => "bar")
|
|
209
|
-
doc.save
|
|
210
|
-
|
|
211
|
-
Open a document and return an instance of <tt>Cushion::Document</tt>:
|
|
212
|
-
|
|
213
|
-
db.doc("mydoc")
|
|
214
|
-
doc["_foo"] = "bar"
|
|
215
|
-
doc.save
|
|
216
|
-
|
|
217
|
-
Copy a document:
|
|
218
|
-
|
|
219
|
-
doc.copy("mydoc2")
|
|
139
|
+
== Tricks
|
|
220
140
|
|
|
221
|
-
|
|
141
|
+
Use the #headers method to obtain response headers on any request:
|
|
222
142
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
143
|
+
db.fetch("mydoc").headers
|
|
144
|
+
# => {:server=>"CouchDB/0.9.0a (Erlang OTP/R12B)", :etag=>"\"3617508982\"",
|
|
145
|
+
:date=>"Fri, 06 Mar 2009 10:21:59 GMT", :content_type=>"application/json",
|
|
146
|
+
:content_length=>"48", :cache_control=>"must-revalidate"}
|
data/lib/cushion.rb
CHANGED
|
@@ -12,14 +12,22 @@ require dir + 'design'
|
|
|
12
12
|
|
|
13
13
|
DEFAULT_COUCH_HOST = "http://127.0.0.1:5984"
|
|
14
14
|
|
|
15
|
+
def Cushion(dbname, opts = {})
|
|
16
|
+
Cushion.server(opts).db(dbname)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def Cushion!(dbname, opts = {})
|
|
20
|
+
Cushion.server(opts).db!(dbname)
|
|
21
|
+
end
|
|
22
|
+
|
|
15
23
|
module Cushion
|
|
16
|
-
VERSION = '0.
|
|
24
|
+
VERSION = '0.6.0'
|
|
17
25
|
|
|
18
26
|
class << self
|
|
19
27
|
|
|
20
28
|
# Returns a Cushion::Server instance.
|
|
21
|
-
def server(
|
|
22
|
-
Server.new(
|
|
29
|
+
def server(options = {})
|
|
30
|
+
Server.new(options)
|
|
23
31
|
end
|
|
24
32
|
alias_method :new, :server
|
|
25
33
|
|
|
@@ -27,7 +35,7 @@ module Cushion
|
|
|
27
35
|
# to create the database on the server.
|
|
28
36
|
def db(url)
|
|
29
37
|
parsed = parse(url)
|
|
30
|
-
server = Cushion.new(parsed[:host])
|
|
38
|
+
server = Cushion.new(:uri => parsed[:host])
|
|
31
39
|
server.db(parsed[:db])
|
|
32
40
|
end
|
|
33
41
|
alias_method :database, :db
|
|
@@ -36,7 +44,7 @@ module Cushion
|
|
|
36
44
|
# instance.
|
|
37
45
|
def db!(url)
|
|
38
46
|
parsed = parse(url)
|
|
39
|
-
server = Cushion.new(parsed[:host])
|
|
47
|
+
server = Cushion.new(:uri => parsed[:host])
|
|
40
48
|
server.db!(parsed[:db])
|
|
41
49
|
end
|
|
42
50
|
alias_method :database!, :db!
|
|
@@ -45,7 +53,7 @@ module Cushion
|
|
|
45
53
|
# instance.
|
|
46
54
|
def recreate(url)
|
|
47
55
|
parsed = parse(url)
|
|
48
|
-
server = Cushion.new(parsed[:host])
|
|
56
|
+
server = Cushion.new(:uri => parsed[:host])
|
|
49
57
|
server.recreate(parsed[:db])
|
|
50
58
|
end
|
|
51
59
|
|
|
@@ -61,9 +69,13 @@ module Cushion
|
|
|
61
69
|
url
|
|
62
70
|
end
|
|
63
71
|
|
|
64
|
-
# Handles
|
|
65
|
-
def
|
|
66
|
-
|
|
72
|
+
# Handles key escaping.
|
|
73
|
+
def escape_key(id, filename = nil)
|
|
74
|
+
if filename
|
|
75
|
+
"#{escape_docid(id)}/#{CGI.escape(filename)}"
|
|
76
|
+
else
|
|
77
|
+
escape_docid(id)
|
|
78
|
+
end
|
|
67
79
|
end
|
|
68
80
|
|
|
69
81
|
# Base64 encodes inline attachments.
|
|
@@ -78,7 +90,7 @@ module Cushion
|
|
|
78
90
|
def base64(data)
|
|
79
91
|
Base64.encode64(data).gsub(/\s/,'')
|
|
80
92
|
end
|
|
81
|
-
|
|
93
|
+
|
|
82
94
|
# Sets the RestClient proxy.
|
|
83
95
|
def proxy(url)
|
|
84
96
|
RestClient.proxy = url
|
|
@@ -86,6 +98,10 @@ module Cushion
|
|
|
86
98
|
|
|
87
99
|
private
|
|
88
100
|
|
|
101
|
+
def escape_docid(id)
|
|
102
|
+
/^_design\/(.*)/ =~ id ? "_design/#{CGI.escape($1)}" : CGI.escape(id)
|
|
103
|
+
end
|
|
104
|
+
|
|
89
105
|
def parse(url)
|
|
90
106
|
parsed = URI.parse(url)
|
|
91
107
|
{
|
|
@@ -94,4 +110,32 @@ module Cushion
|
|
|
94
110
|
}
|
|
95
111
|
end
|
|
96
112
|
end # class << self
|
|
113
|
+
|
|
114
|
+
# Provides a clean method of adding metadata (e.g., headers) to JSON parsed
|
|
115
|
+
# responses. Inspired by <tt>OpenURI::Meta</tt>.
|
|
116
|
+
module Meta
|
|
117
|
+
def Meta.init(obj, src=nil)
|
|
118
|
+
obj.extend Meta
|
|
119
|
+
obj.instance_eval {
|
|
120
|
+
@headers = {}
|
|
121
|
+
}
|
|
122
|
+
if src
|
|
123
|
+
src.headers.each {|name, value|
|
|
124
|
+
obj.add_header_field(name, value)
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
obj
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
attr_accessor :headers
|
|
131
|
+
|
|
132
|
+
def add_header_field(name, value)
|
|
133
|
+
#value.gsub!('"', '') if name == :etag ==> CouchDB seems to require the xtra "'s
|
|
134
|
+
@headers[name] = value
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def etag
|
|
138
|
+
@headers[:etag]
|
|
139
|
+
end
|
|
140
|
+
end
|
|
97
141
|
end
|
data/lib/cushion/database.rb
CHANGED
|
@@ -4,92 +4,157 @@ require 'base64'
|
|
|
4
4
|
module Cushion
|
|
5
5
|
class Database
|
|
6
6
|
attr_reader :server, :name
|
|
7
|
+
attr_accessor :use_tempfiles
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
# Initializes a Cushion::Database instance.
|
|
10
|
+
def initialize(name, options = {})
|
|
11
|
+
unless options[:server]
|
|
12
|
+
raise ArgumentError, "server option must be provided"
|
|
13
|
+
end
|
|
14
|
+
unless name
|
|
15
|
+
raise ArgumentError, "name must be provided"
|
|
16
|
+
end
|
|
10
17
|
# TODO: CouchDB has strict db naming requirements. Should validate.
|
|
11
18
|
@name = CGI.escape(name.to_s)
|
|
12
|
-
@server = server
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
# Retrieves information about this database.
|
|
16
|
-
def info(headers = {})
|
|
17
|
-
server.get(@name, headers)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# Compacts this database.
|
|
21
|
-
def compact(headers = {})
|
|
22
|
-
post("_compact", nil, headers)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Creates this database on the server.
|
|
26
|
-
def create(headers = {})
|
|
27
|
-
server.put(@name, nil, headers)
|
|
19
|
+
@server = options[:server]
|
|
20
|
+
@use_tempfiles = options[:use_tempfiles]
|
|
28
21
|
end
|
|
29
22
|
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Query the default +all_docs+ view. Set the +keys+ option to perform a
|
|
36
|
-
# key-based multi-document fetch. Set the +headers+ option to pass
|
|
37
|
-
# custom request headers.
|
|
23
|
+
# Retrieves a single document or attachment by key. Returns attachments as
|
|
24
|
+
# an <tt>OpenURI</tt> <tt>IO</tt> object if the +use_tempfiles+ database
|
|
25
|
+
# option has been set. Set the +headers+ option to pass custom request headers.
|
|
26
|
+
# Examples:
|
|
38
27
|
#
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
28
|
+
# db.fetch("mydoc")
|
|
29
|
+
# db.fetch("my/doc") # Forward slashes are automatically escaped...
|
|
30
|
+
# db.fetch("_design/foo") # ...except in the case of design docs
|
|
31
|
+
#
|
|
32
|
+
# Attachments can be fetched by supplying the id and filename as follows:
|
|
33
|
+
#
|
|
34
|
+
# db.fetch("mydoc", "foo.txt")
|
|
35
|
+
# db.fetch("mydoc", "path/to/foo.txt") # Virtual file path
|
|
36
|
+
#
|
|
37
|
+
# Cushion requests "application/json" by default, and response bodies will
|
|
38
|
+
# automatically be parsed as such. To request data from CouchDB in another
|
|
39
|
+
# (unparsed) format, simply set the +accept+ header:
|
|
40
|
+
#
|
|
41
|
+
# db.fetch("mydoc", :headers => { :accept => "text/plain" })
|
|
42
|
+
#
|
|
43
|
+
# Set <code>:head => true</code> to return the headers rather than the
|
|
44
|
+
# content body. Set <code>:etag => some_value</code> to perform a
|
|
45
|
+
# simple if-none-match conditional GET.
|
|
46
|
+
#
|
|
47
|
+
def fetch(*args)
|
|
48
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
49
|
+
id, file = args
|
|
50
|
+
slug = Cushion.escape_key(id, file)
|
|
51
|
+
headers = options.delete(:headers) || {}
|
|
52
|
+
if etag = options.delete(:etag)
|
|
53
|
+
headers.merge!(:if_none_match => "\"#{etag}\"")
|
|
47
54
|
end
|
|
55
|
+
head = options.delete(:head)
|
|
56
|
+
path = Cushion.paramify_url("#{slug}", options)
|
|
57
|
+
if head
|
|
58
|
+
return head(path, headers)
|
|
59
|
+
elsif file && @use_tempfiles
|
|
60
|
+
return server.open_attachment("#{@name}/#{path}")
|
|
61
|
+
end
|
|
62
|
+
get(path, headers)
|
|
48
63
|
end
|
|
49
64
|
|
|
50
|
-
#
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
# Returns true if a document key exists in this database. See #fetch.
|
|
66
|
+
def key?(*args)
|
|
67
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
68
|
+
id, file = args
|
|
69
|
+
!!fetch(id, file, options.merge(:head => true))
|
|
70
|
+
rescue RestClient::ResourceNotFound
|
|
71
|
+
false
|
|
57
72
|
end
|
|
73
|
+
alias_method :has_key?, :key?
|
|
58
74
|
|
|
59
75
|
# Retrieves a single document by +id+ and returns a <tt>Cushion::Document</tt>
|
|
60
76
|
# linked to this database.
|
|
61
77
|
#
|
|
62
|
-
def doc(id,
|
|
63
|
-
result =
|
|
64
|
-
|
|
78
|
+
def doc(id, options = {})
|
|
79
|
+
result = fetch(id.to_s, options)
|
|
80
|
+
|
|
81
|
+
ndoc = if /^_design/ =~ result["_id"]
|
|
82
|
+
Design.new(result)
|
|
83
|
+
else
|
|
84
|
+
Document.new(result)
|
|
85
|
+
end
|
|
86
|
+
|
|
65
87
|
ndoc.database = self
|
|
66
88
|
ndoc
|
|
67
89
|
end
|
|
68
90
|
alias_method :document, :doc
|
|
69
91
|
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
92
|
+
# Stores a document to the database. Pass a hash with the desired attributes.
|
|
93
|
+
# If an +_id+ attribute is not provided one will be generated automatically
|
|
94
|
+
# from the server UUID cache. Examples:
|
|
95
|
+
#
|
|
96
|
+
# db.store("foo" => "bar") #=> Creates a doc with an auto-generated key
|
|
97
|
+
# db.store("_id" => "def") #=> Creates a doc with key "def"
|
|
98
|
+
#
|
|
99
|
+
# To update a document, set the +_rev+ attribute on the document hash:
|
|
74
100
|
#
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
101
|
+
# db.store("_id" => "ghi", "_rev" => "1234")
|
|
102
|
+
#
|
|
103
|
+
# Inline attachments are automatically encoded within the document.
|
|
104
|
+
#
|
|
105
|
+
def store(doc, options = {})
|
|
106
|
+
headers = options.delete(:headers) || {}
|
|
107
|
+
if doc['_attachments']
|
|
108
|
+
doc['_attachments'] = Cushion.encode_attachments(doc['_attachments'])
|
|
79
109
|
end
|
|
80
|
-
if
|
|
81
|
-
slug = Cushion.
|
|
82
|
-
put("#{slug}",
|
|
110
|
+
res = if doc['_id']
|
|
111
|
+
slug = Cushion.escape_key(doc['_id'])
|
|
112
|
+
put("#{slug}", doc, headers)
|
|
83
113
|
else
|
|
84
|
-
slug =
|
|
85
|
-
put("#{slug}",
|
|
114
|
+
slug = doc['_id'] = server.next_uuid
|
|
115
|
+
put("#{slug}", doc, headers)
|
|
86
116
|
end
|
|
117
|
+
if res['ok']
|
|
118
|
+
doc['_id'] = res['id']
|
|
119
|
+
doc['_rev'] = res['rev']
|
|
120
|
+
end
|
|
121
|
+
res
|
|
87
122
|
end
|
|
88
123
|
|
|
89
|
-
#
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
124
|
+
# Save a file attachment under an existing document, or create a new document
|
|
125
|
+
# containing an attachment. +id+ is the document id. +filename+ is the name
|
|
126
|
+
# of the attachment (extensions may be omitted). Set the +rev+ option to store
|
|
127
|
+
# the attachment under an existing document. Example:
|
|
128
|
+
#
|
|
129
|
+
# db.attach("docid", "foo.txt", somedata, :rev => "1234")
|
|
130
|
+
# #=> Stores an attachment under docid
|
|
131
|
+
#
|
|
132
|
+
# db.attach("anotherid", "bar.jpg", :content_type => "image/jpeg")
|
|
133
|
+
# #=> Creates a new document containing the attachment. Also sets the
|
|
134
|
+
# content type.
|
|
135
|
+
#
|
|
136
|
+
# +data+ may be a <tt>String</tt>, or any object that responds to read.
|
|
137
|
+
#
|
|
138
|
+
# Content type defaults to 'application/octet-stream'.
|
|
139
|
+
#
|
|
140
|
+
def attach(id, filename, data, options = {})
|
|
141
|
+
headers = options.delete(:headers) || {}
|
|
142
|
+
headers[:content_type] = options.delete(:content_type) || "application/octet-stream"
|
|
143
|
+
rev = options.delete(:rev)
|
|
144
|
+
slug = Cushion.escape_key(id, filename)
|
|
145
|
+
rev_slug = "?rev=#{rev}" if rev
|
|
146
|
+
data = data.respond_to?(:read) ? data.read : data
|
|
147
|
+
put("#{slug}#{rev_slug}", data, headers)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Deletes a single document or attachment by key. The +rev+ option must be
|
|
151
|
+
# provided.
|
|
152
|
+
def destroy(*args)
|
|
153
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
154
|
+
headers = options.delete(:headers) || {}
|
|
155
|
+
id, file = args
|
|
156
|
+
slug = Cushion.escape_key(id, file)
|
|
157
|
+
delete("#{slug}?rev=#{options[:rev]}", headers)
|
|
93
158
|
end
|
|
94
159
|
|
|
95
160
|
# Creates, updates and deletes multiple documents in this database according
|
|
@@ -102,10 +167,10 @@ module Cushion
|
|
|
102
167
|
# { "_id" => "1", "_rev" => "32486671", "foo" => "bar" }, #=> Update this doc
|
|
103
168
|
# { "_id" => "2", "baz" => "bat" } #=> Create this doc
|
|
104
169
|
# ]
|
|
105
|
-
#
|
|
106
|
-
# db.bulk_docs(docs)
|
|
107
170
|
#
|
|
108
|
-
#
|
|
171
|
+
# db.bulk(docs)
|
|
172
|
+
#
|
|
173
|
+
# <tt>bulk</tt> returns a hash of updated doc ids and revs, as follows:
|
|
109
174
|
#
|
|
110
175
|
# {
|
|
111
176
|
# "ok" => true,
|
|
@@ -117,12 +182,19 @@ module Cushion
|
|
|
117
182
|
# }
|
|
118
183
|
#
|
|
119
184
|
# Set the +use_uuids+ option to generate UUIDs from the server cache before
|
|
120
|
-
#
|
|
185
|
+
# saving. Set the +headers+ option to pass custom request headers.
|
|
121
186
|
#
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
187
|
+
def bulk(docs, options = {})
|
|
188
|
+
delete_all = options.delete(:delete)
|
|
189
|
+
headers = options.delete(:headers) || {}
|
|
190
|
+
use_uuids = options.delete(:use_uuids) || true
|
|
191
|
+
if delete_all
|
|
192
|
+
updates = docs.map { |doc|
|
|
193
|
+
{ '_id' => doc['_id'], '_rev' => doc['_rev'], '_deleted' => true } }
|
|
194
|
+
else
|
|
195
|
+
updates = docs
|
|
196
|
+
end
|
|
197
|
+
if (use_uuids)
|
|
126
198
|
ids, noids = docs.partition{|d|d['_id']}
|
|
127
199
|
uuid_count = [noids.length, server.uuid_batch_count].max
|
|
128
200
|
noids.each do |doc|
|
|
@@ -130,114 +202,144 @@ module Cushion
|
|
|
130
202
|
doc['_id'] = nextid if nextid
|
|
131
203
|
end
|
|
132
204
|
end
|
|
133
|
-
post("_bulk_docs", {:docs =>
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# A convenience method for deleting multiple documents at once. Just pass in
|
|
137
|
-
# an array of saved +docs+ and the correct deletion params are
|
|
138
|
-
# automatically set. (See #bulk_docs)
|
|
139
|
-
#
|
|
140
|
-
def bulk_delete(docs, params = {})
|
|
141
|
-
deletions = docs.map { |doc| { '_id' => doc['_id'], '_rev' => doc['_rev'], '_deleted' => true } }
|
|
142
|
-
bulk_docs(deletions, params.merge(:use_uuids => false))
|
|
205
|
+
post("_bulk_docs", {:docs => updates}, headers)
|
|
143
206
|
end
|
|
144
207
|
|
|
145
|
-
#
|
|
146
|
-
# +
|
|
147
|
-
# to
|
|
148
|
-
#
|
|
149
|
-
# doc_revs = {
|
|
150
|
-
# "1" => ["12345", "42836"],
|
|
151
|
-
# "2" => ["572654"],
|
|
152
|
-
# "3" => ["34462"]
|
|
153
|
-
# }
|
|
208
|
+
# Copies the document at +source+ to a new or existing location at +destination+.
|
|
209
|
+
# Set the +dest_rev+ option to overwrite an existing document. Set the
|
|
210
|
+
# +headers+ option to pass custom request headers. Example:
|
|
154
211
|
#
|
|
155
|
-
#
|
|
212
|
+
# db.copy("doc1", "doc2")
|
|
213
|
+
# #=> Copies to a new location
|
|
214
|
+
# db.copy("doc1", "doc3", :dest_rev => "4567")
|
|
215
|
+
# #=> Overwrites an existing doc
|
|
156
216
|
#
|
|
157
|
-
def
|
|
158
|
-
|
|
217
|
+
def copy(source, destination, options = {})
|
|
218
|
+
headers = options.delete(:headers) || {}
|
|
219
|
+
dest_rev = options.delete(:dest_rev)
|
|
220
|
+
slug = Cushion.escape_key(source)
|
|
221
|
+
dest = if dest_rev
|
|
222
|
+
"#{destination}?rev=#{dest_rev}"
|
|
223
|
+
else
|
|
224
|
+
destination
|
|
225
|
+
end
|
|
226
|
+
server.copy("#{@name}/#{slug}", dest, headers)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Copies an attachment to a new location. This is presently experimental.
|
|
230
|
+
def copy_attachment(id, old_filename, new_filename, options = {})
|
|
231
|
+
headers = options.delete(:headers) || {}
|
|
232
|
+
src = fetch(id, old_filename)
|
|
233
|
+
headers[:content_type] = src.headers[:content_type]
|
|
234
|
+
dest_id = options[:dest_id] || id
|
|
235
|
+
opts = options[:dest_rev] ? { :rev => options[:dest_rev] } : {}
|
|
236
|
+
if opts.empty? && (id == dest_id)
|
|
237
|
+
opts = { :rev => src.headers[:etag] }
|
|
238
|
+
end
|
|
239
|
+
res = attach(dest_id, new_filename, src, { :headers => headers }.merge(opts))
|
|
240
|
+
if id == dest_id
|
|
241
|
+
res.merge("src_rev" => res["rev"])
|
|
242
|
+
else
|
|
243
|
+
res.merge("src_rev" => src.headers[:etag])
|
|
244
|
+
end
|
|
159
245
|
end
|
|
160
246
|
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
#
|
|
247
|
+
# Moves the document at +source+ to a new or existing location at +destination+.
|
|
248
|
+
# Set the +dest_rev+ option to overwrite an existing document. Set the
|
|
249
|
+
# +headers+ option to pass custom request headers. Example:
|
|
164
250
|
#
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
251
|
+
# db.move("doc1", "doc2", :rev => "1234")
|
|
252
|
+
# #=> Moves to a new location
|
|
253
|
+
# db.copy("doc1", "doc3", :rev => "1234", :dest_rev => "4567")
|
|
254
|
+
# #=> Overwrites an existing doc
|
|
255
|
+
#
|
|
256
|
+
def move(source, destination, options = {})
|
|
257
|
+
headers = options.delete(:headers) || {}
|
|
258
|
+
dest_rev = options.delete(:dest_rev)
|
|
259
|
+
slug = Cushion.escape_key(source)
|
|
260
|
+
path = Cushion.paramify_url("#{slug}", options)
|
|
261
|
+
dest = if dest_rev
|
|
262
|
+
"#{destination}?rev=#{dest_rev}"
|
|
171
263
|
else
|
|
172
|
-
|
|
264
|
+
destination
|
|
173
265
|
end
|
|
174
|
-
|
|
266
|
+
server.move("#{@name}/#{path}", dest, headers)
|
|
175
267
|
end
|
|
176
268
|
|
|
177
|
-
# Moves
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
def move_doc(source_id, dest_id, src_rev, params = {})
|
|
183
|
-
headers = params.delete(:headers) || {}
|
|
184
|
-
dest_rev = params[:dest_rev]
|
|
185
|
-
slug = Cushion.escape_docid(source_id)
|
|
186
|
-
destination = if dest_rev
|
|
187
|
-
"#{dest_id}?rev=#{dest_rev}"
|
|
269
|
+
# Moves an attachment to a new location. This is presently experimental.
|
|
270
|
+
def move_attachment(id, old_filename, new_filename, options = {})
|
|
271
|
+
res = copy_attachment(id, old_filename, new_filename, options)
|
|
272
|
+
if res["ok"]
|
|
273
|
+
destroy(id, old_filename, :rev => res["src_rev"])
|
|
188
274
|
else
|
|
189
|
-
|
|
275
|
+
res
|
|
190
276
|
end
|
|
191
|
-
move("#{slug}?rev=#{src_rev}", destination, headers)
|
|
192
277
|
end
|
|
278
|
+
alias_method :rename_attachment, :move_attachment
|
|
193
279
|
|
|
194
|
-
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
280
|
+
# Query a named view. Set +name+ to :all to query CouchDB's all_docs view.
|
|
281
|
+
# Set +name+ to :temp to query a temp_view. Set the +keys+ option to perform
|
|
282
|
+
# a key-based multi-document fetch against any view. Examples
|
|
197
283
|
#
|
|
198
284
|
# temp_view = { :map => "function(doc){emit(doc.status,null)}" }
|
|
199
|
-
# db.
|
|
285
|
+
# db.view(:temp, :funcs => temp_view, :key => "verified")
|
|
286
|
+
# db.view("people/by_first_name", :key => "gomer")
|
|
287
|
+
# db.view("foo/bar", :keys => ["a", "b", "c"])
|
|
288
|
+
# db.view(:all)
|
|
200
289
|
#
|
|
201
|
-
# Set the +headers+ option to pass custom request headers.
|
|
290
|
+
# Set the +headers+ option to pass custom request headers. Set
|
|
291
|
+
# <code>:etag => some_value</code> to perform a simple if-none-match
|
|
292
|
+
# conditional GET.
|
|
202
293
|
#
|
|
203
294
|
# Temp view queries are slow, so they should only be used as a convenience
|
|
204
|
-
# during development.
|
|
205
|
-
#
|
|
206
|
-
def temp_view(funcs, params = {})
|
|
207
|
-
keys = params.delete(:keys)
|
|
208
|
-
headers = params.delete(:headers) || {}
|
|
209
|
-
funcs = funcs.merge({:keys => keys}) if keys
|
|
210
|
-
path = Cushion.paramify_url("_temp_view", params)
|
|
211
|
-
post(path, funcs, headers)
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
# Query a saved view identified by +view+. Set the +keys+ param to perform a
|
|
215
|
-
# key-based multi-document fetch. Example:
|
|
295
|
+
# during development. Whenever possible you should query against saved
|
|
296
|
+
# views.
|
|
216
297
|
#
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
298
|
+
def view(name, options = {})
|
|
299
|
+
keys = options.delete(:keys)
|
|
300
|
+
headers = options.delete(:headers) || {}
|
|
301
|
+
if etag = options.delete(:etag)
|
|
302
|
+
headers.merge!(:if_none_match => "\"#{etag}\"".squeeze("\""))
|
|
303
|
+
end
|
|
304
|
+
body = keys ? {:keys => keys} : {}
|
|
305
|
+
if name == :all
|
|
306
|
+
slug = "_all_docs"
|
|
307
|
+
elsif name == :temp
|
|
308
|
+
slug = "_temp_view"
|
|
309
|
+
body.merge!(options.delete(:funcs))
|
|
310
|
+
else
|
|
311
|
+
slug = "_view/#{name}"
|
|
312
|
+
end
|
|
313
|
+
path = Cushion.paramify_url(slug, options)
|
|
314
|
+
|
|
315
|
+
if body.any?
|
|
316
|
+
post(path, body, headers)
|
|
227
317
|
else
|
|
228
318
|
get(path, headers)
|
|
229
319
|
end
|
|
230
320
|
end
|
|
231
321
|
|
|
322
|
+
# Convenience method for querying the all_docs view. See #view for more
|
|
323
|
+
# information.
|
|
324
|
+
def all(options = {})
|
|
325
|
+
view(:all, options)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Convenience method for querying temporary views. See #view for more
|
|
329
|
+
# information.
|
|
330
|
+
def temp(funcs, options = {})
|
|
331
|
+
view(:temp, options.merge(:funcs => funcs))
|
|
332
|
+
end
|
|
333
|
+
|
|
232
334
|
# Query the show template identified by +design+, +show_template+ and +id+.
|
|
233
335
|
# The results are not parsed by default. Set the +headers+ option to pass
|
|
234
336
|
# custom request headers.
|
|
235
337
|
#
|
|
236
|
-
def show(design, show_template, id,
|
|
338
|
+
def show(design, show_template, id, options = {})
|
|
237
339
|
defaults = { :accept => "text/html;text/plain;*/*" }
|
|
238
|
-
headers =
|
|
239
|
-
slug = Cushion.
|
|
240
|
-
path = Cushion.paramify_url("_show/#{design}/#{show_template}/#{slug}",
|
|
340
|
+
headers = options.delete(:headers) || {}
|
|
341
|
+
slug = Cushion.escape_key(id)
|
|
342
|
+
path = Cushion.paramify_url("_show/#{design}/#{show_template}/#{slug}", options)
|
|
241
343
|
get(path, defaults.merge(headers))
|
|
242
344
|
end
|
|
243
345
|
|
|
@@ -245,65 +347,66 @@ module Cushion
|
|
|
245
347
|
# The results are not parsed by default. Set the +headers+ option to pass
|
|
246
348
|
# custom request headers.
|
|
247
349
|
#
|
|
248
|
-
def list(design, list_template, view,
|
|
350
|
+
def list(design, list_template, view, options = {})
|
|
249
351
|
defaults = { :accept => "text/html;text/plain;*/*" }
|
|
250
|
-
headers =
|
|
251
|
-
path = Cushion.paramify_url("_list/#{design}/#{list_template}/#{view}",
|
|
352
|
+
headers = options.delete(:headers) || {}
|
|
353
|
+
path = Cushion.paramify_url("_list/#{design}/#{list_template}/#{view}", options)
|
|
252
354
|
get(path, defaults.merge(headers))
|
|
253
355
|
end
|
|
254
356
|
|
|
255
|
-
#
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
#
|
|
259
|
-
def external(verb, process_path, params = {})
|
|
260
|
-
path = Cushion.paramify_url("_#{process_path}", params[:query])
|
|
261
|
-
request(verb, path, :body => params[:body], :headers => params[:headers])
|
|
357
|
+
# Retrieves information about this database.
|
|
358
|
+
def info(headers = {})
|
|
359
|
+
server.get(@name, headers)
|
|
262
360
|
end
|
|
263
361
|
|
|
264
|
-
#
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def open_attachment(id, filename, params = {})
|
|
268
|
-
slug = Cushion.escape_docid(id)
|
|
269
|
-
fname = CGI.escape(filename)
|
|
270
|
-
path = Cushion.paramify_url("#{@name}/#{slug}/#{fname}", params)
|
|
271
|
-
server.open_attachment(path)
|
|
362
|
+
# Compacts this database.
|
|
363
|
+
def compact(headers = {})
|
|
364
|
+
post("_compact", nil, headers)
|
|
272
365
|
end
|
|
273
366
|
|
|
274
|
-
#
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
# as the last param.
|
|
278
|
-
#
|
|
279
|
-
def save_attachment(id, rev, filename, data, headers = {})
|
|
280
|
-
defaults = { :content_type => "application/octet-stream" }
|
|
281
|
-
slug = Cushion.escape_docid(id)
|
|
282
|
-
fname = CGI.escape(filename)
|
|
283
|
-
put("#{slug}/#{fname}?rev=#{rev}", data, defaults.merge(headers))
|
|
367
|
+
# Creates this database on the server.
|
|
368
|
+
def create(headers = {})
|
|
369
|
+
server.put(@name, nil, headers)
|
|
284
370
|
end
|
|
285
371
|
|
|
286
|
-
# Deletes
|
|
287
|
-
|
|
372
|
+
# Deletes this database from the server.
|
|
373
|
+
def drop(headers = {})
|
|
374
|
+
server.delete(@name, headers)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Deletes and recreates this database.
|
|
378
|
+
def recreate
|
|
379
|
+
begin
|
|
380
|
+
drop
|
|
381
|
+
rescue RestClient::ResourceNotFound
|
|
382
|
+
nil
|
|
383
|
+
end
|
|
384
|
+
create
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Completely purges the supplied document revisions from the database.
|
|
388
|
+
# +doc_revs+ is a hash of document ids, each containing an array of revisions
|
|
389
|
+
# to be deleted. Example:
|
|
390
|
+
#
|
|
391
|
+
# doc_revs = {
|
|
392
|
+
# "1" => ["12345", "42836"],
|
|
393
|
+
# "2" => ["572654"],
|
|
394
|
+
# "3" => ["34462"]
|
|
395
|
+
# }
|
|
288
396
|
#
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
397
|
+
# db.purge(doc_revs)
|
|
398
|
+
#
|
|
399
|
+
def purge(doc_revs, options = {})
|
|
400
|
+
post("_purge", doc_revs, options)
|
|
293
401
|
end
|
|
294
402
|
|
|
295
|
-
#
|
|
296
|
-
#
|
|
297
|
-
#
|
|
403
|
+
# Issues a request to the CouchDB external server identified by +process+.
|
|
404
|
+
# Calls to external must include a request +verb+. Set the +headers+ option
|
|
405
|
+
# to pass custom request headers.
|
|
298
406
|
#
|
|
299
|
-
def
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if res["ok"] == true
|
|
303
|
-
res = delete_attachment(id, res["rev"], oldname)
|
|
304
|
-
else
|
|
305
|
-
res
|
|
306
|
-
end
|
|
407
|
+
def external(verb, process_path, params = {})
|
|
408
|
+
path = Cushion.paramify_url("_#{process_path}", params[:query])
|
|
409
|
+
request(verb, path, :body => params[:body], :headers => params[:headers])
|
|
307
410
|
end
|
|
308
411
|
|
|
309
412
|
# Issues a HEAD request to this database. See Cushion::Server#head.
|
|
@@ -331,22 +434,10 @@ module Cushion
|
|
|
331
434
|
server.delete("#{@name}/#{path}", headers)
|
|
332
435
|
end
|
|
333
436
|
|
|
334
|
-
# Issues a COPY request to this database. See Cushion::Server#copy.
|
|
335
|
-
def copy(source, destination, headers = {})
|
|
336
|
-
server.copy("#{@name}/#{source}", destination, headers)
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
# Issues a MOVE request to this database. See Cushion::Server#move.
|
|
340
|
-
def move(source, destination, headers = {})
|
|
341
|
-
server.move("#{@name}/#{source}", destination, headers)
|
|
342
|
-
end
|
|
343
|
-
|
|
344
437
|
# Issues a generic request to this database. See Cushion::Server#request.
|
|
345
438
|
def request(verb, path, params)
|
|
346
439
|
server.request(verb, "#{@name}/#{path}", params)
|
|
347
440
|
end
|
|
348
441
|
|
|
349
|
-
## EXPERIMENTAL ##
|
|
350
|
-
|
|
351
442
|
end
|
|
352
443
|
end
|