akdubya-cushion 0.5.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/LICENSE +176 -0
- data/README.rdoc +226 -0
- data/Rakefile +65 -0
- data/lib/cushion.rb +97 -0
- data/lib/cushion/core_ext.rb +27 -0
- data/lib/cushion/database.rb +310 -0
- data/lib/cushion/design.rb +33 -0
- data/lib/cushion/document.rb +117 -0
- data/lib/cushion/server.rb +208 -0
- data/spec/cushion_spec.rb +9 -0
- data/spec/database_spec.rb +223 -0
- data/spec/helpers.rb +2 -0
- data/spec/server_spec.rb +119 -0
- metadata +75 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module Cushion
|
|
2
|
+
class Response < Hash
|
|
3
|
+
def initialize(keys = {})
|
|
4
|
+
keys.each do |k,v|
|
|
5
|
+
self[k.to_s] = v
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def []=(key, value)
|
|
10
|
+
super(key.to_s, value)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def [](key)
|
|
14
|
+
super(key.to_s)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class Document < Response
|
|
19
|
+
attr_accessor :database
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def use_database(db)
|
|
23
|
+
@database = db
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def database
|
|
27
|
+
@database
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def id
|
|
32
|
+
self[:_id]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def rev
|
|
36
|
+
self[:_rev]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns true if this document has never been saved
|
|
40
|
+
def new_document?
|
|
41
|
+
!rev
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Saves this document to the database.
|
|
45
|
+
def save
|
|
46
|
+
result = database.save_doc(self)
|
|
47
|
+
if result['ok']
|
|
48
|
+
self[:_rev] = result['rev']
|
|
49
|
+
self[:_id] = result['id']
|
|
50
|
+
end
|
|
51
|
+
result['ok']
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Deletes this document from the database.
|
|
55
|
+
def destroy
|
|
56
|
+
result = database.delete_doc(id, rev)
|
|
57
|
+
if result['ok']
|
|
58
|
+
self[:_rev] = nil
|
|
59
|
+
self[:_id] = nil
|
|
60
|
+
end
|
|
61
|
+
result['ok']
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Reloads this document from the database.
|
|
65
|
+
def reload
|
|
66
|
+
result = database.open_doc(id)
|
|
67
|
+
initialize(result)
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Copies the document to a new id. If +dest_id+ currently exists then
|
|
72
|
+
# +dest_rev+ must be provided.
|
|
73
|
+
def copy(dest_id, dest_rev = nil)
|
|
74
|
+
result = database.copy_doc(id, dest_id, :dest_rev => dest_rev)
|
|
75
|
+
result['ok']
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Moves the document to a new id. If +dest_id+ currently exists then
|
|
79
|
+
# +dest_rev+ must be provided.
|
|
80
|
+
def move(dest_id, dest_rev = nil)
|
|
81
|
+
result = database.move_doc(id, dest_id, rev, :dest_rev => dest_rev)
|
|
82
|
+
result['ok']
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns this document's database.
|
|
86
|
+
def database
|
|
87
|
+
@database || self.class.database
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Opens the attachment identified by +filename+. Returns an IO object.
|
|
91
|
+
def open_attachment(filename)
|
|
92
|
+
database.open_attachment(id, filename)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Attaches a file to this document under +filename+.
|
|
96
|
+
def save_attachment(filename, data, options={})
|
|
97
|
+
result = database.save_attachment(id, rev, filename, data, options)
|
|
98
|
+
self[:_rev] = result['rev']
|
|
99
|
+
result['ok']
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Deletes the attachment identified by +filename+.
|
|
103
|
+
def delete_attachment(filename)
|
|
104
|
+
result = database.delete_attachment(id, rev, filename)
|
|
105
|
+
self[:_rev] = result['rev']
|
|
106
|
+
result['ok']
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Renames an attachment. +oldname+ is the name of the existing attachment
|
|
110
|
+
# and +newname+ is the desired name.
|
|
111
|
+
def rename_attachment(oldname, newname)
|
|
112
|
+
result = database.rename_attachment(id, rev, oldname, newname)
|
|
113
|
+
self[:_rev] = result['rev']
|
|
114
|
+
result['ok']
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
|
|
3
|
+
module Cushion
|
|
4
|
+
class Server
|
|
5
|
+
attr_accessor :uri, :uuid_batch_count
|
|
6
|
+
|
|
7
|
+
# Initialize a Cushion::Server to the uri at +server+.
|
|
8
|
+
def initialize(server = DEFAULT_COUCH_HOST, uuid_batch_count = 1000)
|
|
9
|
+
@uri = server
|
|
10
|
+
@uuid_batch_count = uuid_batch_count
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Retrieves the server's welcome message.
|
|
14
|
+
def info(headers = {})
|
|
15
|
+
get('', headers)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Retrieves a list of running tasks on the server.
|
|
19
|
+
def active_tasks(headers = {})
|
|
20
|
+
get("_active_tasks", headers)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Retrieves a list of all databases on the server.
|
|
24
|
+
def all_dbs(headers = {})
|
|
25
|
+
get("_all_dbs", headers)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Fetches the configuration information for this server.
|
|
29
|
+
def config(headers = {})
|
|
30
|
+
get("_config", headers)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Sets a configuration option identified by +section+ and +option+.
|
|
34
|
+
def set_config(section, option, value)
|
|
35
|
+
put("_config/#{section}/#{option}", value, :accept => "text/plain")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Replicates +source+ database to +target+ database. +source+ and +target+
|
|
39
|
+
# may be either local database names (for local replication) or fully
|
|
40
|
+
# qualified urls (for remote replication).
|
|
41
|
+
def replicate(source, target, headers = {})
|
|
42
|
+
post("_replicate", {:source => source.to_s, :target => target.to_s}, headers)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Restarts the server.
|
|
46
|
+
def restart(headers = {})
|
|
47
|
+
post("_restart", nil, headers)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Fetches stats information for this server.
|
|
51
|
+
def stats(headers = {})
|
|
52
|
+
get("_stats", headers)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Creates a database on this server with the provided +name+.
|
|
56
|
+
def create(name, headers = {})
|
|
57
|
+
db(name).create(headers)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Deletes the database identified by +name+ from this server.
|
|
61
|
+
def delete(name, headers = {})
|
|
62
|
+
db(name).delete(headers)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Deletes and re-creates the database identified by +name+.
|
|
66
|
+
# Returns a Cushion::Database.
|
|
67
|
+
def recreate(name)
|
|
68
|
+
rdb = db(name)
|
|
69
|
+
begin
|
|
70
|
+
rdb.delete
|
|
71
|
+
rescue RestClient::ResourceNotFound
|
|
72
|
+
nil
|
|
73
|
+
end
|
|
74
|
+
rdb.create
|
|
75
|
+
rdb
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Returns a Cushion::Database identified by +name+. This method does
|
|
79
|
+
# not attempt to create the database if it does not already exist on the
|
|
80
|
+
# server.
|
|
81
|
+
def [](name)
|
|
82
|
+
db(name)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns a Cushion::Database identified by +name+. This method does
|
|
86
|
+
# not attempt to create the database if it does not already exist on the
|
|
87
|
+
# server.
|
|
88
|
+
def db(name)
|
|
89
|
+
Cushion::Database.new(self, name)
|
|
90
|
+
end
|
|
91
|
+
alias_method :database, :db
|
|
92
|
+
|
|
93
|
+
# Creates a database on this server with the provided +name+ if it doesn't
|
|
94
|
+
# already exist. Returns a Cushion::Database.
|
|
95
|
+
def db!(name)
|
|
96
|
+
ndb = db(name)
|
|
97
|
+
ndb.create rescue nil
|
|
98
|
+
ndb
|
|
99
|
+
end
|
|
100
|
+
alias_method :database!, :db!
|
|
101
|
+
|
|
102
|
+
# Issues a HEAD request to the CouchDB server.
|
|
103
|
+
def head(path, headers = {})
|
|
104
|
+
RestClient.head("#{@uri}/#{path}", headers).headers
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Issues a GET request to the CouchDB server. Returns a parsed response body
|
|
108
|
+
# if the +accept+ options is set to 'application/json' (the default), otherwise
|
|
109
|
+
# returns the raw RestClient response body.
|
|
110
|
+
def get(path, headers = {})
|
|
111
|
+
defaults = { :accept => "application/json" }
|
|
112
|
+
parse_response(RestClient.get("#{@uri}/#{path}", defaults.merge(headers)))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Issues a POST request to the CouchDB server. Parses the request body if
|
|
116
|
+
# the +content_type+ option is set to 'application/json' (the default).
|
|
117
|
+
# Returns a parsed response body if the +accept+ options is set to
|
|
118
|
+
# 'application/json' (the default), otherwise returns the raw
|
|
119
|
+
# RestClient response body.
|
|
120
|
+
def post(path, body, headers = {})
|
|
121
|
+
defaults = { :accept => "application/json", :content_type => "application/json" }
|
|
122
|
+
opts = defaults.merge(headers)
|
|
123
|
+
parse_response(RestClient.post("#{@uri}/#{path}", construct_payload(body, opts), opts))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Issues a PUT request to the CouchDB server. Parses the request body if
|
|
127
|
+
# the +content_type+ option is set to 'application/json' (the default).
|
|
128
|
+
# Returns a parsed response body if the +accept+ option is set to
|
|
129
|
+
# 'application/json' (the default), otherwise returns the raw
|
|
130
|
+
# RestClient response body.
|
|
131
|
+
def put(path, body, headers = {})
|
|
132
|
+
defaults = { :accept => "application/json", :content_type => "application/json" }
|
|
133
|
+
opts = defaults.merge(headers)
|
|
134
|
+
parse_response(RestClient.put("#{@uri}/#{path}", construct_payload(body, opts), opts))
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Issues a DELETE request to the CouchDB server. Returns a parsed response body
|
|
138
|
+
# if the +accept+ options is set to 'application/json' (the default), otherwise
|
|
139
|
+
# returns the raw RestClient response body.
|
|
140
|
+
def delete(path, headers = {})
|
|
141
|
+
defaults = { :accept => "application/json" }
|
|
142
|
+
parse_response(RestClient.delete("#{@uri}/#{path}", defaults.merge(headers)))
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Issues a COPY request to the CouchDB server, copying a document from +source+
|
|
146
|
+
# to +destination+. Returns a parsed response body if the +accept+ options
|
|
147
|
+
# is set to 'application/json' (the default), otherwise returns the raw
|
|
148
|
+
# RestClient response body.
|
|
149
|
+
def copy(source, destination, headers = {})
|
|
150
|
+
defaults = { :accept => "application/json", 'Destination' => destination }
|
|
151
|
+
parse_response(RestClient.copy("#{@uri}/#{source}", defaults.merge(headers)))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Issues a MOVE request to the CouchDB server, moving a document from +source+
|
|
155
|
+
# to +destination+. Returns a parsed response body if the +accept+ options
|
|
156
|
+
# is set to 'application/json' (the default), otherwise returns the raw
|
|
157
|
+
# RestClient response body.
|
|
158
|
+
def move(source, destination, headers = {})
|
|
159
|
+
defaults = { :accept => "application/json", 'Destination' => destination }
|
|
160
|
+
parse_response(RestClient.move("#{@uri}/#{source}", defaults.merge(headers)))
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def request(verb, path, params)
|
|
164
|
+
RestClient::Request.execute(
|
|
165
|
+
:method => verb,
|
|
166
|
+
:url => "#{@uri}/#{path}",
|
|
167
|
+
:payload => params[:body],
|
|
168
|
+
:headers => params[:headers]
|
|
169
|
+
)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Opens the attachment located at +path+. Returns a Tempfile.
|
|
173
|
+
def open_attachment(path)
|
|
174
|
+
open("#{@uri}/#{path}")
|
|
175
|
+
rescue OpenURI::HTTPError
|
|
176
|
+
raise RestClient::ResourceNotFound
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Retrives the next unused UUID from CouchDB. Provide a +count+ to set the number
|
|
180
|
+
# of UUIDs cached by this server instance.
|
|
181
|
+
def next_uuid(count = @uuid_batch_count)
|
|
182
|
+
@uuids ||= []
|
|
183
|
+
if @uuids.empty?
|
|
184
|
+
@uuids = get("_uuids?count=#{count}")["uuids"]
|
|
185
|
+
end
|
|
186
|
+
@uuids.pop
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
private
|
|
190
|
+
|
|
191
|
+
def parse_response(result)
|
|
192
|
+
if result.headers[:content_type] == "application/json"
|
|
193
|
+
JSON.parse(result)
|
|
194
|
+
else
|
|
195
|
+
result
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def construct_payload(body, opts)
|
|
200
|
+
return nil unless body
|
|
201
|
+
if opts[:content_type] == "application/json"
|
|
202
|
+
body.to_json
|
|
203
|
+
else
|
|
204
|
+
body
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/helpers'
|
|
2
|
+
|
|
3
|
+
describe "Cushion::Database" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@db = Cushion.db!('http://127.0.0.1:5984/cushion_test')
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
after do
|
|
10
|
+
@db.delete rescue nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "Operations" do
|
|
14
|
+
|
|
15
|
+
it "should properly initialize a database instance" do
|
|
16
|
+
badname = Cushion::Database.new(Cushion.new, "my/database")
|
|
17
|
+
badname.name.should == "my%2Fdatabase"
|
|
18
|
+
lambda { Cushion::Database.new( :foo, "mydb" ) }.should.raise ArgumentError
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should create and delete a database" do
|
|
22
|
+
newdb = Cushion.db('http://127.0.0.1:5984/foo_test')
|
|
23
|
+
newdb.create["ok"].should.be.true
|
|
24
|
+
newdb.delete["ok"].should.be.true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should retrieve database info" do
|
|
28
|
+
@db.info["db_name"].should == "cushion_test"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should compact a database" do
|
|
32
|
+
@db.save_doc("foo" => "bar")
|
|
33
|
+
@db.compact["ok"].should.be.true
|
|
34
|
+
# Finish compaction before moving on
|
|
35
|
+
while @db.server.active_tasks != [] do
|
|
36
|
+
sleep(0.5)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should pass requests to external handlers" do
|
|
41
|
+
lambda { @db.external(:get, "stats") }.should.not.raise
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "Saving" do
|
|
47
|
+
|
|
48
|
+
it "should save a document" do
|
|
49
|
+
@db.save_doc("_id" => "123")["ok"].should.be.true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should automatically generate an id if none provided on save" do
|
|
53
|
+
saved = @db.save_doc("foo" => "bar")
|
|
54
|
+
saved["ok"].should.be.true
|
|
55
|
+
saved["rev"].should.not.be.nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should bulk save documents" do
|
|
59
|
+
count = @db.info["doc_count"]
|
|
60
|
+
@db.bulk_docs([{"_id" => "456"},{"_id" => "789"}])["ok"].should.be.true
|
|
61
|
+
@db.info["doc_count"].should == count + 2
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "Deleting" do
|
|
67
|
+
|
|
68
|
+
before do
|
|
69
|
+
@db.save_doc("_id" => "123")
|
|
70
|
+
@db.save_doc("_id" => "456")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should delete a document" do
|
|
74
|
+
doc = @db.open_doc("123")
|
|
75
|
+
@db.delete_doc("123", doc['_rev'])["ok"].should.be.true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should bulk delete documents" do
|
|
79
|
+
count = @db.info["doc_count"]
|
|
80
|
+
docs = @db.all_docs(:keys => ["123", "456"], :include_docs => true)
|
|
81
|
+
@db.bulk_delete(docs["rows"].map{ |row| row["doc"] })["ok"].should.be.true
|
|
82
|
+
@db.info["doc_count"].should == count - 2
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "Copying" do
|
|
88
|
+
|
|
89
|
+
before do
|
|
90
|
+
@abc = @db.save_doc("_id" => "abc")
|
|
91
|
+
@ghi = @db.save_doc("_id" => "ghi")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should copy an existing doc to a new/existing doc" do
|
|
95
|
+
res = @db.copy_doc("abc", "def")
|
|
96
|
+
res["id"].should == "def"
|
|
97
|
+
@db.copy_doc("abc", "def", :dest_rev => res["rev"])["ok"].should.be.true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should move an existing doc to a new/existing doc" do
|
|
101
|
+
@db.move_doc("abc", "def", @abc["rev"])["ok"].should.be.true
|
|
102
|
+
lambda { @db.open_doc("abc") }.should.raise RestClient::ResourceNotFound
|
|
103
|
+
doc = @db.open_doc("def")
|
|
104
|
+
@db.move_doc("def", "ghi", doc["_rev"], :dest_rev => @ghi["rev"])["ok"].should.be.true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe "Reading" do
|
|
110
|
+
|
|
111
|
+
before do
|
|
112
|
+
@db.save_doc("_id" => "123")
|
|
113
|
+
@db.save_doc("_id" => "456")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "should open a document" do
|
|
117
|
+
@db.open_doc("123")["_id"].should == "123"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "should load a Cushion::Document" do
|
|
121
|
+
@db.doc("123").should.be.kind_of Cushion::Document
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "should retrieve all documents" do
|
|
125
|
+
@db.all_docs["total_rows"].should == 2
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "should retrieve all documents by keys" do
|
|
129
|
+
@db.all_docs(:keys => ["123"])["rows"].length.should == 1
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "Views" do
|
|
135
|
+
|
|
136
|
+
before do
|
|
137
|
+
@db.save_doc("_id" => "gomer", "name" => "gomer pyle")
|
|
138
|
+
@db.save_doc("_id" => "vince", "name" => "vince carter")
|
|
139
|
+
@view = {:map => "function(doc){emit(doc.name,null)}"}
|
|
140
|
+
@db.save_doc("_id" => "_design/foo", "views" => { "bar" => @view })
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "should retrieve docs from temp views" do
|
|
144
|
+
@db.temp_view(@view, :key => "gomer pyle")["rows"].length.should == 1
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should retrieve docs from temp views by keys" do
|
|
148
|
+
@db.temp_view(@view, :keys => ["vince carter"])["rows"].length.should == 1
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "should retrieve docs from regular views" do
|
|
152
|
+
@db.view("foo/bar", :key => "gomer pyle")["rows"].length.should == 1
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should retrieve docs from regular views by keys" do
|
|
156
|
+
@db.view("foo/bar", :keys => ["vince carter"])["rows"].length.should == 1
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "should retrieve a doc from a show function" do
|
|
160
|
+
design = @db.open_doc("_design/foo")
|
|
161
|
+
design["shows"] = { "people" => "function(doc, req) { var response = {'code':200, 'headers':{}, 'body':'Hello World'}; return response; }" }
|
|
162
|
+
@db.save_doc(design)
|
|
163
|
+
@db.show("foo", "people", "gomer").should == "Hello World"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "should retrieve docs from a list function" do
|
|
167
|
+
design = @db.open_doc("_design/foo")
|
|
168
|
+
design["lists"] = { "people" => "function(head, row, req, row_info) { var response = {'code':200, 'headers':{}, 'body':'x'}; return response; }" }
|
|
169
|
+
@db.save_doc(design)
|
|
170
|
+
@db.list("foo", "people", "bar").should == "xxxx"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
describe "Attachments" do
|
|
176
|
+
|
|
177
|
+
it "should save and open inline attachments" do
|
|
178
|
+
@db.save_doc("_id" => "inline", "_attachments" => {
|
|
179
|
+
"foo.txt" => {
|
|
180
|
+
"content_type" => "text/plain",
|
|
181
|
+
"data" => "Hello World!"
|
|
182
|
+
}
|
|
183
|
+
})["ok"].should.be.true
|
|
184
|
+
|
|
185
|
+
@db.open_attachment("inline", "foo.txt").read.should == "Hello World!"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "should save and open standalone attachments" do
|
|
189
|
+
res = @db.save_doc("_id" => "attachable")
|
|
190
|
+
@db.save_attachment(res['id'], res['rev'],
|
|
191
|
+
"foo.txt", "Hello World!",
|
|
192
|
+
:content_type => "text/plain"
|
|
193
|
+
)["ok"].should.be.true
|
|
194
|
+
|
|
195
|
+
@db.open_attachment("attachable", "foo.txt").read.should == "Hello World!"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "should delete attachments" do
|
|
199
|
+
res = @db.save_doc("_id" => "deleteme", "_attachments" => {
|
|
200
|
+
"foo.txt" => {
|
|
201
|
+
"content_type" => "text/plain",
|
|
202
|
+
"data" => "Hello World!"
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
@db.delete_attachment("deleteme", res["rev"], "foo.txt")["ok"].should.be.true
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "should rename attachments" do
|
|
210
|
+
res = @db.save_doc("_id" => "rename", "_attachments" => {
|
|
211
|
+
"foo.txt" => {
|
|
212
|
+
"content_type" => "text/plain",
|
|
213
|
+
"data" => "Hello World!"
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
@db.rename_attachment("rename", res["rev"], "foo.txt", "bar.txt")["ok"].should.be.true
|
|
218
|
+
@db.open_doc("rename")["_attachments"]["bar.txt"].should.not.be.nil
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
end
|