couch-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ module CouchClient
2
+ # The Row is an extended Hash that provides additional state to
3
+ # get status codes and connect documents to the server.
4
+ class Row < ConsistentHash
5
+ def initialize(code, row, connection)
6
+ self.merge!(row)
7
+ self["doc"] &&= Document.new(code, row["doc"], connection)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe CouchClient::AttachmentList do
4
+ it 'should exist inherent from ConsistentHash' do
5
+ CouchClient::AttachmentList.ancestors[1].should eql(CouchClient::ConsistentHash)
6
+ end
7
+ end
@@ -0,0 +1,57 @@
1
+ require 'digest/sha1'
2
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
3
+
4
+ describe CouchClient::Attachment do
5
+ before(:all) do
6
+ @couch = CouchClient.connect(COUCHDB_TEST_SETTINGS)
7
+ @couch.database.create
8
+
9
+ @alice = @couch.build({"name" => "alice", "city" => "nyc"})
10
+ @alice.save
11
+
12
+ @read = lambda do |file|
13
+ File.read(File.join(File.dirname(__FILE__), "files", file))
14
+ end
15
+
16
+ @digest = lambda do |file|
17
+ Digest::SHA1.hexdigest(file)
18
+ end
19
+
20
+ @plain = @read.call("plain.txt")
21
+ @image = @read.call("image.png")
22
+
23
+ @plain_digest = @digest.call(@plain)
24
+ @image_digest = @digest.call(@image)
25
+
26
+ @alice.attach("plain.txt", @plain, "text/plain")
27
+ @alice.attach("image.png", @image, "image/png")
28
+
29
+ @attachment_plain = @alice.saved_doc.attachments["plain.txt"]
30
+ @attachment_image = @alice.saved_doc.attachments["image.png"]
31
+ end
32
+
33
+ after(:all) do
34
+ @couch.database.delete!
35
+ end
36
+
37
+ describe '#uri' do
38
+ it 'should yield the uri for the attachment' do
39
+ @attachment_plain.uri.should eql([@couch.hookup.handler.uri, @alice.id, "plain.txt"].join("/"))
40
+ @attachment_image.uri.should eql([@couch.hookup.handler.uri, @alice.id, "image.png"].join("/"))
41
+ end
42
+ end
43
+
44
+ describe '#path' do
45
+ it 'should yield the uri for the attachment' do
46
+ @attachment_plain.path.should eql([@couch.hookup.handler.path, @alice.id, "plain.txt"].join("/"))
47
+ @attachment_image.path.should eql([@couch.hookup.handler.path, @alice.id, "image.png"].join("/"))
48
+ end
49
+ end
50
+
51
+ describe '#file' do
52
+ it 'should yield the file for the attachment as a string' do
53
+ @digest.call(@attachment_plain.data).should eql(@plain_digest)
54
+ @digest.call(@attachment_image.data).should eql(@image_digest)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe CouchClient::Collection do
4
+ before(:all) do
5
+ @couch = CouchClient.connect(COUCHDB_TEST_SETTINGS)
6
+ @couch.database.create
7
+
8
+ factory = lambda do |hash|
9
+ doc = @couch.build(hash)
10
+ doc.save
11
+ doc
12
+ end
13
+
14
+ @alice = factory.call({"_id" => "123", "name" => "alice", "city" => "nyc"})
15
+ @bob = factory.call({"_id" => "456", "name" => "bob", "city" => "chicago"})
16
+ @design = factory.call({"_id" => "_design/people",
17
+ "views" => {
18
+ "all" => {"map" => "function(doc){emit(doc._id, doc)}"}
19
+ }
20
+ })
21
+
22
+ @people = @couch.design("people").view("all", "include_docs" => true)
23
+ end
24
+
25
+ after(:all) do
26
+ @couch.database.delete!
27
+ end
28
+
29
+ it 'should be an CouchClient::Collection object' do
30
+ @people.should be_a_kind_of(CouchClient::Collection)
31
+ end
32
+
33
+ it 'should have a collection of rows' do
34
+ @people.size.should eql(2)
35
+ @people.first["doc"].should eql(@alice)
36
+ @people.last["doc"].should eql(@bob)
37
+ end
38
+
39
+ it 'should have `code` and `info` methods' do
40
+ @people.should respond_to(:code)
41
+ @people.should respond_to(:info)
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe CouchClient::ConnectionHandler do
4
+ before(:all) do
5
+ @ch = CouchClient::ConnectionHandler.new
6
+ end
7
+
8
+ it 'should have sensible defaults' do
9
+ @ch.scheme.should eql("http")
10
+ @ch.host.should eql("localhost")
11
+ @ch.port.should eql(5984)
12
+ end
13
+
14
+ it 'should set parameters' do
15
+ @ch.scheme = "https"
16
+ @ch.username = "admin"
17
+ @ch.password = "nimda"
18
+ @ch.host = "couchone.com"
19
+ @ch.port = 8080
20
+ @ch.database = "sandbox"
21
+ end
22
+
23
+ it 'should get parameters' do
24
+ @ch.scheme.should eql("https")
25
+ @ch.username.should eql("admin")
26
+ @ch.password.should eql("nimda")
27
+ @ch.host.should eql("couchone.com")
28
+ @ch.port.should eql(8080)
29
+ @ch.database.should eql("sandbox")
30
+ end
31
+
32
+ it 'shoudl output a path string' do
33
+ @ch.path.should eql("/sandbox")
34
+ end
35
+
36
+ it 'should output a uri string' do
37
+ @ch.uri.should eql("https://couchone.com:8080/sandbox")
38
+ end
39
+
40
+ it 'should output a uri string with a path if passed a path' do
41
+ @ch.uri(["path"]).should eql("https://couchone.com:8080/sandbox/path")
42
+ @ch.uri(["path"], nil).should eql("https://couchone.com:8080/sandbox/path")
43
+ @ch.uri(["_$,+-/"]).should eql("https://couchone.com:8080/sandbox/_%24%2C%2B-%2F")
44
+ @ch.uri(["?=&; #"]).should eql("https://couchone.com:8080/sandbox/%3F%3D%26%3B+%23")
45
+ @ch.uri(["_design/test", "spaces & special/chars"]).should eql("https://couchone.com:8080/sandbox/_design/test/spaces+%26+special%2Fchars")
46
+ end
47
+
48
+ it 'should output a uri string with a query if a query is given' do
49
+ @ch.uri(nil, {"a" => "apple"}).should eql("https://couchone.com:8080/sandbox?a=apple")
50
+ @ch.uri(nil, {"a" => "apple", "b" => "banana"}).should eql("https://couchone.com:8080/sandbox?a=apple&b=banana")
51
+ @ch.uri(nil, {"a" => "_$,+-/", "b" => "?=&; #"}).should eql("https://couchone.com:8080/sandbox?a=_%24%2C%2B-%2F&b=%3F%3D%26%3B+%23")
52
+ end
53
+
54
+ it 'should output a uri string with path and query if both are given' do
55
+ @ch.uri(["path", "one", "two"], {"a" => "apple", "b" => "banana"}).should eql("https://couchone.com:8080/sandbox/path/one/two?a=apple&b=banana")
56
+ end
57
+
58
+ it 'should properly escape database urls' do
59
+ @ch.database = "abc123/_$()+-"
60
+ @ch.uri(["path"]).should eql("https://couchone.com:8080/abc123%2F_%24%28%29%2B-/path")
61
+ end
62
+
63
+ it 'should raise an error if an invalid name is given' do
64
+ lambda{@ch.database = "ABC!@#"}.should raise_error(CouchClient::InvalidDatabaseName)
65
+ end
66
+ end
@@ -0,0 +1,93 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe CouchClient::Connection do
4
+ before(:all) do
5
+ @couch = CouchClient.connect(COUCHDB_TEST_SETTINGS)
6
+ @couch.database.create
7
+
8
+ factory = lambda do |hash|
9
+ doc = @couch.build(hash)
10
+ doc.save
11
+ doc
12
+ end
13
+
14
+ @alice = factory.call({"name" => "alice", "city" => "nyc"})
15
+ @bob = factory.call({"name" => "bob", "city" => "chicago"})
16
+ @deleted = factory.call({"name" => "deleted", "city" => "unknown"})
17
+ @deleted.delete! # used to test if deleted documents raise an error when fetched
18
+ @design = factory.call({"_id" => "_design/people", "views" => {"all" => {"map" => "function(doc){emit(doc._id, doc)}"}}})
19
+ end
20
+
21
+ after(:all) do
22
+ @couch.database.delete!
23
+ end
24
+
25
+ it 'should have a Hookup' do
26
+ @couch.hookup.should be_a(CouchClient::Hookup)
27
+ end
28
+
29
+ it 'should have a Database' do
30
+ @couch.database.should be_a(CouchClient::Database)
31
+ end
32
+
33
+ describe '#[]' do
34
+ it 'should get the document associated if it exists' do
35
+ @couch[@alice["_id"]].should eql(@alice)
36
+ @couch[@bob["_id"]].should eql(@bob)
37
+ @couch[@design["_id"]].should eql(@design)
38
+ end
39
+
40
+ it 'should raise an error if the document was deleted' do
41
+ lambda{@couch[@deleted["_id"]].should}.should raise_error(CouchClient::DocumentNotFound)
42
+ end
43
+
44
+ it 'should raise an error if the document does not exist' do
45
+ lambda{@couch['missing'].should}.should raise_error(CouchClient::DocumentNotFound)
46
+ end
47
+
48
+ it 'should raise an error if the response was not a valid document' do
49
+ lambda{@couch["_design/people/_view/all"]}.should raise_error(CouchClient::DocumentNotValid)
50
+ end
51
+ end
52
+
53
+ describe '#design' do
54
+ it 'should return a design object when a valid design id is given' do
55
+ @couch.design("people").should be_a(CouchClient::Design)
56
+ end
57
+
58
+ it 'should allow access to design views' do
59
+ @couch.design("people").view("all").should be_a(CouchClient::Collection)
60
+ end
61
+ end
62
+
63
+ describe '#all_docs' do
64
+ it 'should return a list of all documents stored' do
65
+ all_docs = @couch.all_docs("include_docs" => true)
66
+ all_docs.should be_a(CouchClient::Collection)
67
+ docs = all_docs.map{|doc| doc["doc"].id}
68
+ docs.should include(@alice.id)
69
+ docs.should include(@bob.id)
70
+ docs.should include(@design.id)
71
+ end
72
+ end
73
+
74
+ describe '#build' do
75
+ before(:all) do
76
+ @charlie = @couch.build({"name" => "charlie", "city" => "san fran"})
77
+ end
78
+
79
+ it 'should create a new Document' do
80
+ @charlie.should be_a(CouchClient::Document)
81
+ end
82
+
83
+ it 'should have the hash keys and values provided' do
84
+ @charlie.should eql({"name" => "charlie", "city" => "san fran"})
85
+ end
86
+ end
87
+
88
+ describe '#inspect' do
89
+ it 'should yield an inspect string with valid settings' do
90
+ @couch.inspect.should eql("#<CouchClient::Connection: uri: http://localhost:5984/couch-client_test>")
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,171 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe CouchClient::ConsistentHash do
4
+ describe '#initialize' do
5
+ describe 'when given a hash' do
6
+ before do
7
+ @ch = CouchClient::ConsistentHash.new({:a => "apple", "b" => :banana})
8
+ end
9
+
10
+ it 'should construct a new ConsistentHash' do
11
+ @ch[:a].should eql("apple")
12
+ @ch["a"].should eql("apple")
13
+ @ch[:b].should eql("banana")
14
+ @ch["b"].should eql("banana")
15
+ @ch[:c].should be_nil
16
+ end
17
+ end
18
+
19
+ describe 'when given a default value' do
20
+ before do
21
+ @ch = CouchClient::ConsistentHash.new("default")
22
+ @ch[:a] = "apple"
23
+ end
24
+
25
+ it 'should construct a new ConsistentHash with a default' do
26
+
27
+ @ch[:a].should eql("apple")
28
+ @ch[:b].should eql("default")
29
+ end
30
+ end
31
+
32
+ describe 'when given a hash with a default value' do
33
+ before do
34
+ h = Hash.new("default")
35
+ h[:a] = "apple"
36
+ @ch = CouchClient::ConsistentHash.new(h)
37
+ @ch[:b] = "banana"
38
+ end
39
+
40
+ it 'should construct a new ConsistentHash with a default' do
41
+ @ch[:a].should eql("apple")
42
+ @ch[:b].should eql("banana")
43
+ @ch[:z].should eql("default")
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#default' do
49
+ before do
50
+ @ch = CouchClient::ConsistentHash.new("default")
51
+ @ch[:a] = "apple"
52
+ end
53
+
54
+ it 'should give the default value if it does not exists' do
55
+ @ch.default.should eql("default")
56
+ end
57
+ end
58
+
59
+ describe '#[]=' do
60
+ before do
61
+ @ch = CouchClient::ConsistentHash.new()
62
+ end
63
+
64
+ it 'should set a field' do
65
+ @ch[:a] = "apple"
66
+ @ch[:a].should eql("apple")
67
+ @ch["a"].should eql("apple")
68
+ end
69
+ end
70
+
71
+ describe '#update, #merge!' do
72
+ before do
73
+ @ch = CouchClient::ConsistentHash.new({:a => "apple", :b => "banana"})
74
+ end
75
+
76
+ it 'should update an existing hash with fields from a new hash' do
77
+ @ch.update({:b => "blueberry", :c => "cherry"})
78
+ @ch.should eql({"a"=>"apple", "b"=>"blueberry", "c"=>"cherry"})
79
+ end
80
+ end
81
+
82
+ describe '#key?' do
83
+ before do
84
+ @ch = CouchClient::ConsistentHash.new({:a => "apple"})
85
+ end
86
+
87
+ it 'should identify if a hash has a key' do
88
+ @ch.key?(:a).should be_true
89
+ @ch.key?(:b).should be_false
90
+ end
91
+ end
92
+
93
+ describe '#fetch' do
94
+ before do
95
+ @ch = CouchClient::ConsistentHash.new({:a => "apple"})
96
+ end
97
+
98
+ it 'should return the value if the key given exists' do
99
+ @ch.fetch(:a).should eql("apple")
100
+ end
101
+
102
+ it 'should raise an error if the key given does not exist' do
103
+ lambda{@ch.fetch(:b)}.should raise_error(KeyError)
104
+ end
105
+
106
+ it 'should return a default if one is given' do
107
+ @ch.fetch(:b, "default").should eql("default")
108
+ end
109
+ end
110
+
111
+ describe '#values_at' do
112
+ before do
113
+ @ch = CouchClient::ConsistentHash.new({:a => "apple", :b => "banana", :c => "cherry"})
114
+ end
115
+
116
+ it 'should return an array of values for the keys given' do
117
+ @ch.values_at(:a, :c).should eql(["apple", "cherry"])
118
+ end
119
+ end
120
+
121
+ describe '#dup' do
122
+ before do
123
+ @ch = CouchClient::ConsistentHash.new({:a => "apple"})
124
+ end
125
+
126
+ it 'should return a new hash' do
127
+ @ch2 = @ch.dup
128
+ @ch2.object_id.should_not eql(@ch.object_id)
129
+ end
130
+ end
131
+
132
+ describe '#merge' do
133
+ before do
134
+ @ch = CouchClient::ConsistentHash.new({:a => "apple", :b => "banana"})
135
+ end
136
+
137
+ it 'should return an new hash with fields from both hashs' do
138
+ @ch2 = @ch.merge({:b => "blueberry", :c => "cherry"})
139
+
140
+ @ch.should eql({"a" => "apple", "b" => "banana"})
141
+ @ch2.should eql({"a"=>"apple", "b"=>"blueberry", "c"=>"cherry"})
142
+ end
143
+ end
144
+
145
+ describe '#delete' do
146
+ before do
147
+ @ch = CouchClient::ConsistentHash.new({:a => "apple"})
148
+ end
149
+
150
+ it 'should delete the specified field' do
151
+ @ch.delete(:b)
152
+ @ch.should eql({"a" => "apple"})
153
+ end
154
+ end
155
+
156
+ describe '#to_hash' do
157
+ before do
158
+ @ch = CouchClient::ConsistentHash.new({:a => "apple"})
159
+ end
160
+
161
+ it 'should return a regular hash' do
162
+ @h = @ch.to_hash
163
+
164
+ @ch[:a].should eql("apple")
165
+ @h[:a].should be_nil
166
+
167
+ @ch.should be_an_instance_of(CouchClient::ConsistentHash)
168
+ @h.should be_an_instance_of(Hash)
169
+ end
170
+ end
171
+ end