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.
@@ -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
- # Inline
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
- # Standalone
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
- # Fetch attachment data
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 and attachments may also be copied or moved within the same database.
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.move("mydoc", "existing_doc", :rev => ..., :dest_rev => ...)
88
+ db.copy("mydoc", "existing_doc", :dest_rev => ...)
88
89
  # => overwrites the existing doc
89
90
 
90
- # Attachments
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.move_attachment("mydoc", "foo.txt", "bar.txt")
94
- # => renames an attachment; aliased at #rename_attachment
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
- See the database specs for more copy and move examples.
100
+ == Querying Views
97
101
 
98
- == Views
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
- - creating (design docs)
101
- - querying
102
- - temp views
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)
@@ -21,7 +21,7 @@ def Cushion!(dbname, opts = {})
21
21
  end
22
22
 
23
23
  module Cushion
24
- VERSION = '0.6.2'
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
 
@@ -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, options = {})
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
- if name == :all
279
+
280
+ case name
281
+ when :all
306
282
  slug = "_all_docs"
307
- elsif name == :temp
283
+ when :temp
308
284
  slug = "_temp_view"
309
285
  body.merge!(options.delete(:funcs))
310
286
  else
311
- slug = "_view/#{name}"
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("_show/#{design}/#{show_template}/#{slug}", options)
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("_list/#{design}/#{list_template}/#{view}", options)
341
+ path = Cushion.paramify_url("_design/#{design}/_list/#{list_template}/#{view}", options)
356
342
  get(path, defaults.merge(headers))
357
343
  end
358
344
 
@@ -125,17 +125,29 @@ module Cushion
125
125
  database.fetch(id, filename)
126
126
  end
127
127
 
128
- # Renames an attachment. +oldname+ is the name of the existing attachment
128
+ # Copies an attachment. +oldname+ is the name of the existing attachment
129
129
  # and +newname+ is the desired name.
130
- def rename(oldname, newname)
131
- result = database.move_attachment(id, oldname, newname)
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] = attachments.delete(oldname)
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['ok']
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
@@ -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 = {})
@@ -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)["_revs"].should.not.be.nil
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"}])["ok"].should.be.true
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)["ok"].should.be.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 and moving documents" do
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")["ok"].should.be.true
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"])["ok"].should.be.true
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
@@ -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.true
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.true
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.6.2
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-14 00:00:00 -07:00
12
+ date: 2009-03-20 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency