akdubya-cushion 0.6.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +30 -18
- data/lib/cushion.rb +1 -2
- data/lib/cushion/database.rb +27 -41
- data/lib/cushion/document.rb +17 -16
- data/lib/cushion/server.rb +0 -9
- data/spec/database_spec.rb +10 -30
- data/spec/document_spec.rb +8 -19
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -40,20 +40,23 @@ Fetching documents is just as simple.
|
|
40
40
|
Store attachments inline or via CouchDB's standalone attachment API. The standalone
|
41
41
|
method accepts both IO objects and strings:
|
42
42
|
|
43
|
-
|
43
|
+
Inline:
|
44
|
+
|
44
45
|
db.store("_id" => "hasfiles", ..., "_attachments" => {
|
45
46
|
"foo.txt" => {
|
46
47
|
"content_type" => "text/plain",
|
47
48
|
"data" => "Hello World!"
|
48
49
|
}})
|
49
50
|
|
50
|
-
|
51
|
+
Standalone:
|
52
|
+
|
51
53
|
res = @db.store("_id" => "savemefirst", ...)
|
52
54
|
db.attach("savemefirst", "foo.txt", "Hello World!", :rev => res['rev'],
|
53
55
|
:content_type => "text/plain")
|
54
56
|
# => Foo now contains an attachment hash similar to the above example
|
55
57
|
|
56
|
-
|
58
|
+
Fetch attachment data:
|
59
|
+
|
57
60
|
db.fetch("savemefirst", "foo.txt") # => "Hello World!"
|
58
61
|
|
59
62
|
Cushion returns parsed JSON by default. In those cases where you need the raw
|
@@ -78,39 +81,48 @@ documents at once:
|
|
78
81
|
db.bulk(docs) # => returns a hash of updated documents
|
79
82
|
db.bulk(docs, :delete => true) # => deletes the selected docs
|
80
83
|
|
81
|
-
Documents
|
82
|
-
Some useful examples:
|
84
|
+
Documents may be copied within the same database.
|
83
85
|
|
84
|
-
# Documents
|
85
86
|
db.copy("mydoc", "new_doc")
|
86
87
|
# => {"ok"=>true, "id"=>"new_doc", "rev"=> ...}
|
87
|
-
db.
|
88
|
+
db.copy("mydoc", "existing_doc", :dest_rev => ...)
|
88
89
|
# => overwrites the existing doc
|
89
90
|
|
90
|
-
|
91
|
+
Attachments may also be copied.
|
92
|
+
|
91
93
|
db.copy_attachment("mydoc", "foo.txt", "bar.txt")
|
92
94
|
# => copies an attachment within the same doc
|
93
|
-
db.
|
94
|
-
# =>
|
95
|
+
db.copy_attachment("mydoc", "foo.txt", "bar.txt", :dest_id => 'existing_doc', :dest_rev => ...)
|
96
|
+
# => copies an attachment to an existing doc
|
97
|
+
|
98
|
+
== Creating Views
|
95
99
|
|
96
|
-
|
100
|
+
== Querying Views
|
97
101
|
|
98
|
-
|
102
|
+
Query regular views by passing in the design doc name and view name along with
|
103
|
+
an optional hash of parameters.
|
99
104
|
|
100
|
-
|
101
|
-
|
102
|
-
|
105
|
+
db.view("people/by_first_name", :key => "gomer")
|
106
|
+
db.view("foo/bar", :keys => ["a", "b", "c"])
|
107
|
+
db.view(:all)
|
108
|
+
|
109
|
+
You may also query the database using temporary views.
|
110
|
+
|
111
|
+
temp_view = { :map => "function(doc){emit(doc.status,null)}" }
|
112
|
+
db.view(:temp, :funcs => temp_view, :key => "verified")
|
113
|
+
|
114
|
+
Temp view queries are slow, so they should only be used as a convenience during
|
115
|
+
development. Whenever possible you should query against saved views.
|
103
116
|
|
104
117
|
== Servers and Databases
|
105
118
|
|
106
119
|
The server location defaults to http://127.0.0.1:5984, so you may omit the host
|
107
120
|
when initializing a server if you are satisfied with the default.
|
108
121
|
|
109
|
-
NOTE: Some cruft needs cleaning up. Use <tt>Cushion!(dbname, opts)</tt> for
|
110
|
-
now.
|
111
|
-
|
112
122
|
Display various bits of server metadata as follows:
|
113
123
|
|
124
|
+
server = Cushion.server :uri => 'http://myhost:5984'
|
125
|
+
|
114
126
|
server.info #=> welcome message
|
115
127
|
server.all_dbs #=> all dbs available
|
116
128
|
server.active_tasks #=> running tasks (e.g., replication or compaction)
|
data/lib/cushion.rb
CHANGED
@@ -21,7 +21,7 @@ def Cushion!(dbname, opts = {})
|
|
21
21
|
end
|
22
22
|
|
23
23
|
module Cushion
|
24
|
-
VERSION = '0.
|
24
|
+
VERSION = '0.9.0'
|
25
25
|
|
26
26
|
class << self
|
27
27
|
|
@@ -130,7 +130,6 @@ module Cushion
|
|
130
130
|
attr_accessor :headers
|
131
131
|
|
132
132
|
def add_header_field(name, value)
|
133
|
-
#value.gsub!('"', '') if name == :etag ==> CouchDB seems to require the xtra "'s
|
134
133
|
@headers[name] = value
|
135
134
|
end
|
136
135
|
|
data/lib/cushion/database.rb
CHANGED
@@ -234,7 +234,7 @@ module Cushion
|
|
234
234
|
dest_id = options[:dest_id] || id
|
235
235
|
opts = options[:dest_rev] ? { :rev => options[:dest_rev] } : {}
|
236
236
|
if opts.empty? && (id == dest_id)
|
237
|
-
opts = { :rev => src.headers[:etag] }
|
237
|
+
opts = { :rev => src.headers[:etag].gsub('"', '') }
|
238
238
|
end
|
239
239
|
res = attach(dest_id, new_filename, src, headers.merge(opts))
|
240
240
|
if id == dest_id
|
@@ -244,42 +244,9 @@ module Cushion
|
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
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:
|
250
|
-
#
|
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}"
|
263
|
-
else
|
264
|
-
destination
|
265
|
-
end
|
266
|
-
server.move("#{@name}/#{path}", dest, headers)
|
267
|
-
end
|
268
|
-
|
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"])
|
274
|
-
else
|
275
|
-
res
|
276
|
-
end
|
277
|
-
end
|
278
|
-
alias_method :rename_attachment, :move_attachment
|
279
|
-
|
280
247
|
# Query a named view. Set +name+ to :all to query CouchDB's all_docs view.
|
281
248
|
# 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
|
249
|
+
# a key-based multi-document fetch against any view. Examples:
|
283
250
|
#
|
284
251
|
# temp_view = { :map => "function(doc){emit(doc.status,null)}" }
|
285
252
|
# db.view(:temp, :funcs => temp_view, :key => "verified")
|
@@ -287,6 +254,11 @@ module Cushion
|
|
287
254
|
# db.view("foo/bar", :keys => ["a", "b", "c"])
|
288
255
|
# db.view(:all)
|
289
256
|
#
|
257
|
+
# You should pass the design doc name and view name as two separate
|
258
|
+
# parameters if the design doc name contains slashes:
|
259
|
+
#
|
260
|
+
# db.view("foo/bar", "baz", :limit => 1)
|
261
|
+
#
|
290
262
|
# Set the +headers+ option to pass custom request headers. Set
|
291
263
|
# <code>:etag => some_value</code> to perform a simple if-none-match
|
292
264
|
# conditional GET.
|
@@ -295,21 +267,32 @@ module Cushion
|
|
295
267
|
# during development. Whenever possible you should query against saved
|
296
268
|
# views.
|
297
269
|
#
|
298
|
-
def view(name,
|
270
|
+
def view(name, *args)
|
271
|
+
options = args.last.respond_to?(:merge) ? args.pop : {}
|
272
|
+
|
299
273
|
keys = options.delete(:keys)
|
300
274
|
headers = options.delete(:headers) || {}
|
301
275
|
if etag = options.delete(:etag)
|
302
276
|
headers.merge!(:if_none_match => "\"#{etag}\"".squeeze("\""))
|
303
277
|
end
|
304
278
|
body = keys ? {:keys => keys} : {}
|
305
|
-
|
279
|
+
|
280
|
+
case name
|
281
|
+
when :all
|
306
282
|
slug = "_all_docs"
|
307
|
-
|
283
|
+
when :temp
|
308
284
|
slug = "_temp_view"
|
309
285
|
body.merge!(options.delete(:funcs))
|
310
286
|
else
|
311
|
-
|
287
|
+
if args.any?
|
288
|
+
dname = Cushion.escape_key(name)
|
289
|
+
vname = args.first
|
290
|
+
else
|
291
|
+
dname, vname = name.split('/', 2)
|
292
|
+
end
|
293
|
+
slug = "_design/#{dname}/_view/#{Cushion.escape_key(vname)}"
|
312
294
|
end
|
295
|
+
|
313
296
|
path = Cushion.paramify_url(slug, options)
|
314
297
|
|
315
298
|
if body.any?
|
@@ -335,11 +318,13 @@ module Cushion
|
|
335
318
|
# The results are not parsed by default. Set the +headers+ option to pass
|
336
319
|
# custom request headers.
|
337
320
|
#
|
321
|
+
# TODO: Need to escape names
|
322
|
+
#
|
338
323
|
def show(design, show_template, id, options = {})
|
339
324
|
defaults = { :accept => "text/html;text/plain;*/*" }
|
340
325
|
headers = options.delete(:headers) || {}
|
341
326
|
slug = Cushion.escape_key(id)
|
342
|
-
path = Cushion.paramify_url("
|
327
|
+
path = Cushion.paramify_url("_design/#{design}/_show/#{show_template}/#{slug}", options)
|
343
328
|
get(path, defaults.merge(headers))
|
344
329
|
end
|
345
330
|
|
@@ -347,12 +332,13 @@ module Cushion
|
|
347
332
|
# The results are not parsed by default. Set the +headers+ option to pass
|
348
333
|
# custom request headers.
|
349
334
|
#
|
335
|
+
# TODO: Need to escape names
|
350
336
|
# TODO: Update for multi-key fetch (CouchDB r750565)
|
351
337
|
#
|
352
338
|
def list(design, list_template, view, options = {})
|
353
339
|
defaults = { :accept => "text/html;text/plain;*/*" }
|
354
340
|
headers = options.delete(:headers) || {}
|
355
|
-
path = Cushion.paramify_url("
|
341
|
+
path = Cushion.paramify_url("_design/#{design}/_list/#{list_template}/#{view}", options)
|
356
342
|
get(path, defaults.merge(headers))
|
357
343
|
end
|
358
344
|
|
data/lib/cushion/document.rb
CHANGED
@@ -125,17 +125,29 @@ module Cushion
|
|
125
125
|
database.fetch(id, filename)
|
126
126
|
end
|
127
127
|
|
128
|
-
#
|
128
|
+
# Copies an attachment. +oldname+ is the name of the existing attachment
|
129
129
|
# and +newname+ is the desired name.
|
130
|
-
def
|
131
|
-
result = database.
|
130
|
+
def copy(oldname, newname)
|
131
|
+
result = database.copy_attachment(id, oldname, newname)
|
132
132
|
if result['ok']
|
133
133
|
self[:_rev] = result['rev']
|
134
|
-
attachments[newname] =
|
134
|
+
attachments[newname] = {
|
135
|
+
"stub" => true,
|
136
|
+
"content_type" => attachments[oldname]['content_type'],
|
137
|
+
"length" => attachments[oldname]['length']
|
138
|
+
}
|
135
139
|
end
|
136
140
|
result['ok']
|
137
141
|
end
|
138
142
|
|
143
|
+
# Renames an attachment. +oldname+ is the name of the existing attachment
|
144
|
+
# and +newname+ is the desired name.
|
145
|
+
def rename(oldname, newname)
|
146
|
+
if copy(oldname, newname)
|
147
|
+
detach(oldname)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
139
151
|
# Reloads this document.
|
140
152
|
def reload
|
141
153
|
initialize(database.fetch(id))
|
@@ -146,18 +158,7 @@ module Cushion
|
|
146
158
|
# the +dest_rev+ option must be provided.
|
147
159
|
def copy_to(dest_id, opts = {})
|
148
160
|
result = database.copy(id, dest_id, :dest_rev => opts[:rev])
|
149
|
-
result['
|
150
|
-
end
|
151
|
-
|
152
|
-
# Moves this document to a new id. If +dest_id+ currently exists then
|
153
|
-
# the +dest_rev+ option must be provided.
|
154
|
-
def move_to(dest_id, opts = {})
|
155
|
-
result = database.move(id, dest_id, :rev => rev, :dest_rev => opts[:rev])
|
156
|
-
if result['ok']
|
157
|
-
self[:_rev] = nil
|
158
|
-
self[:_id] = nil
|
159
|
-
end
|
160
|
-
result['ok']
|
161
|
+
result['rev']
|
161
162
|
end
|
162
163
|
|
163
164
|
def to_json
|
data/lib/cushion/server.rb
CHANGED
@@ -146,15 +146,6 @@ module Cushion
|
|
146
146
|
parse_response(RestClient.copy("#{@uri}/#{source}", defaults.merge(headers)))
|
147
147
|
end
|
148
148
|
|
149
|
-
# Issues a MOVE request to the CouchDB server, moving a document from +source+
|
150
|
-
# to +destination+. Returns a parsed response body if the +accept+ option
|
151
|
-
# is set to 'application/json' (the default), otherwise returns the raw
|
152
|
-
# RestClient response body.
|
153
|
-
def move(source, destination, headers = {})
|
154
|
-
defaults = { :accept => "application/json", 'Destination' => destination }
|
155
|
-
parse_response(RestClient.move("#{@uri}/#{source}", defaults.merge(headers)))
|
156
|
-
end
|
157
|
-
|
158
149
|
# Issues a generic request to the server +path+ with the method set to +verb+.
|
159
150
|
# Accepts +body+ and +headers+ options.
|
160
151
|
def request(verb, path, params = {})
|
data/spec/database_spec.rb
CHANGED
@@ -82,7 +82,7 @@ describe "A Cushion database" do
|
|
82
82
|
|
83
83
|
it "should pass extra parameters to CouchDB" do
|
84
84
|
@db.store("_id" => "123")
|
85
|
-
@db.fetch("123", :revs => true)["
|
85
|
+
@db.fetch("123", :revs => true)["_revisions"].should.not.be.nil
|
86
86
|
end
|
87
87
|
|
88
88
|
it "should pass headers to CouchDB" do
|
@@ -176,7 +176,7 @@ describe "A Cushion database" do
|
|
176
176
|
|
177
177
|
it "should bulk save documents with #bulk" do
|
178
178
|
count = @db.info["doc_count"]
|
179
|
-
@db.bulk([{"_id" => "456"},{"_id" => "789"}])
|
179
|
+
@db.bulk([{"_id" => "456"},{"_id" => "789"}]).length.should == 2
|
180
180
|
@db.info["doc_count"].should == count + 2
|
181
181
|
end
|
182
182
|
|
@@ -185,7 +185,7 @@ describe "A Cushion database" do
|
|
185
185
|
@db.store("_id" => "456")
|
186
186
|
count = @db.info["doc_count"]
|
187
187
|
docs = @db.all(:keys => ["123", "456"], :include_docs => true)
|
188
|
-
@db.bulk(docs["rows"].map{ |row| row["doc"] }, :delete => true)
|
188
|
+
@db.bulk(docs["rows"].map{ |row| row["doc"] }, :delete => true).length.should == 2
|
189
189
|
@db.info["doc_count"].should == count - 2
|
190
190
|
end
|
191
191
|
|
@@ -223,6 +223,10 @@ describe "A Cushion database" do
|
|
223
223
|
@db.view("foo/bar", :keys => ["vince carter"])["rows"].length.should == 1
|
224
224
|
end
|
225
225
|
|
226
|
+
it "should retrieve docs from regular views with #view and split params" do
|
227
|
+
@db.view('foo', 'bar', :key => "gomer pyle")["rows"].length.should == 1
|
228
|
+
end
|
229
|
+
|
226
230
|
it "should perform a conditional GET" do
|
227
231
|
etag = @db.view("foo/bar").etag
|
228
232
|
lambda {
|
@@ -245,7 +249,7 @@ describe "A Cushion database" do
|
|
245
249
|
end
|
246
250
|
end
|
247
251
|
|
248
|
-
describe "when copying
|
252
|
+
describe "when copying documents" do
|
249
253
|
before do
|
250
254
|
@source = @db.store("_id" => "source", "_attachments" => {
|
251
255
|
"foo.txt" => {
|
@@ -257,23 +261,12 @@ describe "A Cushion database" do
|
|
257
261
|
end
|
258
262
|
|
259
263
|
it "should copy a doc to a new id with #copy" do
|
260
|
-
@db.copy("source", "source_1")[
|
264
|
+
@db.copy("source", "source_1")['rev'].should.not.be.nil
|
261
265
|
lambda { @db.fetch("source_1") }.should.not.raise
|
262
266
|
end
|
263
267
|
|
264
268
|
it "should copy a doc to an existing doc" do
|
265
|
-
@db.copy("source", "dest", :dest_rev => @dest["rev"])[
|
266
|
-
@db.fetch("dest")["_attachments"].should.not.be.nil
|
267
|
-
end
|
268
|
-
|
269
|
-
it "should move a doc to a new id with #move" do
|
270
|
-
@db.move("source", "source_1", :rev => @source["rev"])["ok"].should.be.true
|
271
|
-
lambda { @db.fetch("source_1") }.should.not.raise
|
272
|
-
lambda { @db.fetch("source") }.should.raise RestClient::ResourceNotFound
|
273
|
-
end
|
274
|
-
|
275
|
-
it "should move a doc to an existing doc" do
|
276
|
-
@db.move("source", "dest", :rev => @source["rev"], :dest_rev => @dest["rev"])["ok"].should.be.true
|
269
|
+
@db.copy("source", "dest", :dest_rev => @dest["rev"])['rev'].should.not.be.nil
|
277
270
|
@db.fetch("dest")["_attachments"].should.not.be.nil
|
278
271
|
end
|
279
272
|
|
@@ -287,18 +280,5 @@ describe "A Cushion database" do
|
|
287
280
|
:dest_rev => @dest["rev"])["ok"].should.be.true
|
288
281
|
@db.fetch("dest", "bar.txt").should == "Hello World!"
|
289
282
|
end
|
290
|
-
|
291
|
-
it "should move a file to a new key under the same doc with #move_attachment" do
|
292
|
-
@db.move_attachment("source", "foo.txt", "bar.txt")["ok"].should.be.true
|
293
|
-
@db.fetch("source", "bar.txt").should == "Hello World!"
|
294
|
-
lambda { @db.fetch("source", "foo.txt") }.should.raise RestClient::ResourceNotFound
|
295
|
-
end
|
296
|
-
|
297
|
-
it "should move a file to a new key in another doc with #move_attachment" do
|
298
|
-
@db.move_attachment("source", "foo.txt", "bar.txt", :dest_id => "dest",
|
299
|
-
:dest_rev => @dest["rev"])["ok"].should.be.true
|
300
|
-
@db.fetch("dest", "bar.txt").should == "Hello World!"
|
301
|
-
lambda { @db.fetch("source", "foo.txt") }.should.raise RestClient::ResourceNotFound
|
302
|
-
end
|
303
283
|
end
|
304
284
|
end
|
data/spec/document_spec.rb
CHANGED
@@ -119,6 +119,12 @@ describe "A Cushion Document" do
|
|
119
119
|
@doc.fetch("foo.txt").should == "hello"
|
120
120
|
end
|
121
121
|
|
122
|
+
it "should copy an attachment with #copy" do
|
123
|
+
@doc.copy('foo.txt', 'bar.txt').should.be.true
|
124
|
+
@doc.attachments['bar.txt'].should.not.be.nil
|
125
|
+
@doc.attachments['bar.txt']['content_type'].should == 'text/plain'
|
126
|
+
end
|
127
|
+
|
122
128
|
it "should rename an attachment with #rename" do
|
123
129
|
@doc.rename("foo.txt", "bar.txt").should.be.true
|
124
130
|
@doc.attachments["foo.txt"].should.be.nil
|
@@ -136,7 +142,7 @@ describe "A Cushion Document" do
|
|
136
142
|
it "should copy itself to a new document with #copy_to" do
|
137
143
|
@doc["foo"] = "bar"
|
138
144
|
@doc.save
|
139
|
-
@doc.copy_to("newdoc").should.be.
|
145
|
+
@doc.copy_to("newdoc").should.not.be.nil
|
140
146
|
@db.fetch("newdoc")["foo"].should == "bar"
|
141
147
|
end
|
142
148
|
|
@@ -144,25 +150,8 @@ describe "A Cushion Document" do
|
|
144
150
|
res = @db.store("_id" => "otherdoc")
|
145
151
|
@doc["foo"] = "bar"
|
146
152
|
@doc.save
|
147
|
-
@doc.copy_to("otherdoc", :rev => res['rev']).should.be.
|
148
|
-
@db.fetch("otherdoc")["foo"].should == "bar"
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should move itself to a new document with #move_to" do
|
152
|
-
@doc.merge!("_id" => "123", "foo" => "bar")
|
153
|
-
@doc.save
|
154
|
-
@doc.move_to("newdoc").should.be.true
|
155
|
-
@db.fetch("newdoc")["foo"].should == "bar"
|
156
|
-
@db.key?("123").should.be.false
|
157
|
-
end
|
158
|
-
|
159
|
-
it "should move itself to an existing doc with #move_to" do
|
160
|
-
@doc.merge!("_id" => "123", "foo" => "bar")
|
161
|
-
res = @db.store("_id" => "otherdoc")
|
162
|
-
@doc.save
|
163
|
-
@doc.move_to("otherdoc", :rev => res['rev']).should.be.true
|
153
|
+
@doc.copy_to("otherdoc", :rev => res['rev']).should.not.be.nil
|
164
154
|
@db.fetch("otherdoc")["foo"].should == "bar"
|
165
|
-
@db.key?("123").should.be.false
|
166
155
|
end
|
167
156
|
|
168
157
|
it "should serialize its attributes with #to_json" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: akdubya-cushion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksander Williams
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|