relaxo 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -14
- data/bin/relaxo +73 -20
- data/lib/relaxo/attachments.rb +69 -0
- data/lib/relaxo/base64-1.8.rb +8 -0
- data/lib/relaxo/client.rb +31 -15
- data/lib/relaxo/connection.rb +5 -0
- data/lib/relaxo/database.rb +34 -83
- data/lib/relaxo/json.rb +33 -0
- data/lib/relaxo/{session.rb → transaction.rb} +12 -17
- data/lib/relaxo/version.rb +2 -2
- data/test/README.md +5 -0
- data/test/attachments_test.rb +32 -0
- data/test/connection_test.rb +29 -0
- data/test/database_test.rb +34 -0
- data/test/helper.rb +19 -0
- data/test/transaction_test.rb +63 -0
- metadata +68 -49
data/README.md
CHANGED
@@ -26,30 +26,28 @@ Connect to a local database and manipulate some documents.
|
|
26
26
|
|
27
27
|
require 'relaxo'
|
28
28
|
|
29
|
-
|
29
|
+
database = Relaxo.connect("http://localhost:5984/test")
|
30
30
|
|
31
31
|
doc1 = {:bob => 'dole'}
|
32
|
-
|
32
|
+
database.save(doc1)
|
33
33
|
|
34
|
-
doc2 =
|
34
|
+
doc2 = database.get(doc1['_id'])
|
35
35
|
doc2[:foo] = 'bar'
|
36
|
-
|
36
|
+
database.save(doc2)
|
37
37
|
|
38
|
-
Bulk Changes/Sessions
|
39
|
-
---------------------
|
38
|
+
### Bulk Changes/Sessions ###
|
40
39
|
|
41
40
|
Sessions support a very similar interface to the main database class and can for many cases be used interchangeably, but with added efficiency.
|
42
41
|
|
43
42
|
require 'relaxo'
|
44
43
|
require 'relaxo/session'
|
45
44
|
|
46
|
-
|
45
|
+
database = Relaxo.connect("http://localhost:5984/test")
|
46
|
+
animals = ['Neko-san', 'Wan-chan', 'Nezu-chan', 'Chicken-san']
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
$animals.each do |animal|
|
52
|
-
session.save({:name => animal})
|
48
|
+
database.transaction do |transaction|
|
49
|
+
animals.each do |animal|
|
50
|
+
transaction.save({:name => animal})
|
53
51
|
end
|
54
52
|
end
|
55
53
|
# => [
|
@@ -64,8 +62,7 @@ using CouchDB `_bulk_save`.
|
|
64
62
|
|
65
63
|
To abort the session, either raise an exception or call `session.abort!` which is equivalent to `throw :abort`.
|
66
64
|
|
67
|
-
Loading Data
|
68
|
-
------------
|
65
|
+
### Loading Data ###
|
69
66
|
|
70
67
|
Relaxo includes a command line script to import documents into a CouchDB database:
|
71
68
|
|
data/bin/relaxo
CHANGED
@@ -1,29 +1,76 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'relaxo'
|
4
|
+
require 'relaxo/version'
|
5
|
+
require 'optparse'
|
4
6
|
require 'yaml'
|
7
|
+
require 'csv'
|
5
8
|
|
6
9
|
OPTIONS = {
|
7
|
-
:existing => :merge
|
10
|
+
:existing => :update, # :merge, :replace
|
11
|
+
:format => :yaml,
|
12
|
+
:transaction => true,
|
8
13
|
}
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
module Formats
|
16
|
+
def self.yaml(io, &block)
|
17
|
+
documents = YAML::load(io)
|
18
|
+
|
19
|
+
unless Array === documents
|
20
|
+
documents = [documents]
|
21
|
+
end
|
22
|
+
|
23
|
+
documents.each &block
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.csv(io, &block)
|
27
|
+
csv = CSV.new(io, :headers => :first_row)
|
28
|
+
|
29
|
+
csv.each do |row|
|
30
|
+
yield row.to_hash
|
31
|
+
end
|
32
|
+
end
|
16
33
|
end
|
17
34
|
|
35
|
+
ARGV.options do |o|
|
36
|
+
script_name = File.basename($0)
|
37
|
+
|
38
|
+
o.banner = "Usage: #{script_name} [options] [server-url] [files]"
|
39
|
+
o.define_head "This script can be used to import data to CouchDB."
|
40
|
+
|
41
|
+
o.separator ""
|
42
|
+
o.separator "Document creation:"
|
43
|
+
|
44
|
+
o.on("--existing [mode]", "Control whether to 'update (new document attributes takes priority), 'merge' (existing document attributes takes priority) or replace (old document attributes discarded) existing documents.") do |mode|
|
45
|
+
OPTIONS[:existing] = mode.to_sym
|
46
|
+
end
|
47
|
+
|
48
|
+
o.on("--format [type]", "Control the input format. 'yaml' files are imported as a single document or array of documents. 'csv' files are imported as records using the first row as attribute keys.") do |format|
|
49
|
+
OPTIONS[:format] = format.to_sym
|
50
|
+
end
|
51
|
+
|
52
|
+
o.on("--[no-]transaction", "Controls whether data is saved using the batch save operation. Not suitable for huge amounts of data.")
|
53
|
+
|
54
|
+
o.separator ""
|
55
|
+
o.separator "Help and Copyright information:"
|
56
|
+
|
57
|
+
o.on_tail("--copy", "Display copyright and warranty information") do
|
58
|
+
$stderr.puts "#{script_name} v#{Relaxo::VERSION::STRING}. Copyright (c) 2012 Samuel Williams."
|
59
|
+
$stderr.puts "This software is released under the MIT license and comes with ABSOLUTELY NO WARRANTY."
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
o.on_tail("-h", "--help", "Show this help message.") do
|
64
|
+
$stderr.puts o
|
65
|
+
exit
|
66
|
+
end
|
67
|
+
end.parse!
|
68
|
+
|
18
69
|
$url = ARGV.shift
|
19
|
-
$database = Relaxo.connect($url)
|
20
70
|
$stderr.puts "Connecting to #{$url}..."
|
71
|
+
$database = Relaxo.connect($url)
|
21
72
|
|
22
|
-
$
|
23
|
-
|
24
|
-
unless Array === $documents
|
25
|
-
$documents = [$documents]
|
26
|
-
end
|
73
|
+
$format = Formats.method(OPTIONS[:format])
|
27
74
|
|
28
75
|
$stats = {
|
29
76
|
:saved => 0,
|
@@ -31,13 +78,13 @@ $stats = {
|
|
31
78
|
:total => 0
|
32
79
|
}
|
33
80
|
|
34
|
-
|
81
|
+
def process_document(database)
|
35
82
|
begin
|
36
|
-
$stderr.puts "Loading #{document[Relaxo::ID]}"
|
37
83
|
existing_document = nil
|
38
84
|
|
39
85
|
if document && document[Relaxo::ID]
|
40
|
-
|
86
|
+
$stderr.puts "Loading #{document[Relaxo::ID]}"
|
87
|
+
existing_document = database.get(document[Relaxo::ID]) rescue nil
|
41
88
|
end
|
42
89
|
|
43
90
|
if existing_document
|
@@ -59,7 +106,7 @@ $documents.each do |document|
|
|
59
106
|
end
|
60
107
|
|
61
108
|
$stderr.puts "Saving #{document.inspect}"
|
62
|
-
$result =
|
109
|
+
$result = database.save(document)
|
63
110
|
|
64
111
|
$stats[:saved] += 1
|
65
112
|
rescue RestClient::BadRequest => ex
|
@@ -71,7 +118,13 @@ $documents.each do |document|
|
|
71
118
|
$stats[:total] += 1
|
72
119
|
end
|
73
120
|
|
74
|
-
|
75
|
-
|
76
|
-
|
121
|
+
begin
|
122
|
+
$format.call(ARGF) do |document|
|
123
|
+
process_document(document)
|
124
|
+
end
|
125
|
+
ensure
|
126
|
+
$stderr.puts "#{$stats[:saved]} document(s) saved out of #{$stats[:total]}."
|
127
|
+
if $stats[:errors] > 0
|
128
|
+
$stderr.puts "#{$stats[:errors]} errors occurred!"
|
129
|
+
end
|
77
130
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Copyright (c) 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require 'relaxo/database'
|
22
|
+
|
23
|
+
if RUBY_VERSION < "1.9"
|
24
|
+
require 'relaxo/base64-1.8'
|
25
|
+
else
|
26
|
+
require 'base64'
|
27
|
+
end
|
28
|
+
|
29
|
+
module Relaxo
|
30
|
+
ATTACHMENTS = '_attachments'
|
31
|
+
|
32
|
+
def self.encode_attachments!(document)
|
33
|
+
return unless document[ATTACHMENTS]
|
34
|
+
|
35
|
+
document[ATTACHMENTS].each do |name,contents|
|
36
|
+
next if contents.include? 'stub'
|
37
|
+
|
38
|
+
contents['data'] = Base64.strict_encode64(contents['data'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Database
|
43
|
+
def attach(document, name, data, options = {})
|
44
|
+
parameters = {
|
45
|
+
:rev => document[REV]
|
46
|
+
}.merge(options[:parameters] || {})
|
47
|
+
|
48
|
+
headers = {}
|
49
|
+
|
50
|
+
if options[:headers]
|
51
|
+
headers = options[:headers].dup
|
52
|
+
else
|
53
|
+
headers = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
if options[:content_type]
|
57
|
+
headers[:content_type] = options[:content_type]
|
58
|
+
end
|
59
|
+
|
60
|
+
Client.attach attachment_url(document[ID], name, parameters), data, headers
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def attachment_url(id, name, parameters = {})
|
66
|
+
Client.encode_url("#{@root}/#{Client.escape_id(id)}/#{Client.escape(name)}", parameters)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/relaxo/client.rb
CHANGED
@@ -18,27 +18,30 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
-
require 'json'
|
21
|
+
require 'relaxo/json'
|
22
22
|
require 'rest_client'
|
23
23
|
require 'cgi'
|
24
24
|
|
25
25
|
module Relaxo
|
26
|
+
# Typically returned from CouchDB when the request was successful:
|
27
|
+
SUCCESS = {'ok' => true}
|
28
|
+
|
26
29
|
module Client
|
27
|
-
@@debug = false
|
28
|
-
|
29
|
-
def self.debug= flag
|
30
|
-
@@debug = flag
|
31
|
-
end
|
32
|
-
|
33
30
|
DEFAULT_GET_HEADERS = {:accept => :json}
|
34
31
|
DEFAULT_PUT_HEADERS = {:accept => :json, :content_type => :json}
|
35
32
|
|
36
33
|
def self.execute(request)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
if request[:method] == :head
|
35
|
+
begin
|
36
|
+
response = RestClient::Request.execute(request)
|
37
|
+
return response.code == 200
|
38
|
+
rescue RestClient::ResourceNotFound
|
39
|
+
return false
|
40
|
+
end
|
41
|
+
else
|
42
|
+
response = RestClient::Request.execute(request)
|
43
|
+
return JSON.parse(response)
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
def self.get(url)
|
@@ -57,12 +60,25 @@ module Relaxo
|
|
57
60
|
})
|
58
61
|
end
|
59
62
|
|
60
|
-
def self.
|
63
|
+
def self.attach(url, data, headers = {})
|
64
|
+
headers = {
|
65
|
+
:accept => :json
|
66
|
+
}.merge(headers)
|
67
|
+
|
68
|
+
execute({
|
69
|
+
:method => :put,
|
70
|
+
:url => url,
|
71
|
+
:headers => headers,
|
72
|
+
:payload => data
|
73
|
+
})
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.put(url, document = nil)
|
61
77
|
execute({
|
62
78
|
:method => :put,
|
63
79
|
:url => url,
|
64
80
|
:headers => DEFAULT_PUT_HEADERS,
|
65
|
-
:payload => JSON.generate(document)
|
81
|
+
:payload => document ? JSON.generate(document) : nil
|
66
82
|
})
|
67
83
|
end
|
68
84
|
|
@@ -115,4 +131,4 @@ module Relaxo
|
|
115
131
|
/^_design\/(.*)/ =~ id ? "_design/#{escape($1)}" : escape(id)
|
116
132
|
end
|
117
133
|
end
|
118
|
-
end
|
134
|
+
end
|
data/lib/relaxo/connection.rb
CHANGED
data/lib/relaxo/database.rb
CHANGED
@@ -21,102 +21,53 @@
|
|
21
21
|
require 'relaxo/client'
|
22
22
|
require 'relaxo/connection'
|
23
23
|
|
24
|
+
if RUBY_VERSION < "1.9"
|
25
|
+
require 'relaxo/base64-1.8'
|
26
|
+
else
|
27
|
+
require 'base64'
|
28
|
+
end
|
29
|
+
|
24
30
|
module Relaxo
|
25
|
-
|
26
31
|
ID = '_id'
|
27
32
|
REV = '_rev'
|
28
|
-
|
33
|
+
DELETED = '_deleted'
|
29
34
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
next if contents['stub']
|
35
|
-
|
36
|
-
contents['data'] = Base64.encode64(contents['data'])
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class Session
|
41
|
-
def initialize(database)
|
42
|
-
@database = database
|
35
|
+
class Database
|
36
|
+
def initialize(connection, name)
|
37
|
+
@connection = connection
|
38
|
+
@name = name
|
43
39
|
|
44
|
-
@
|
45
|
-
@uuids = []
|
40
|
+
@root = connection.url + "/" + CGI.escape(name)
|
46
41
|
end
|
47
42
|
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
attr :connection
|
44
|
+
attr :name
|
45
|
+
attr :root
|
51
46
|
|
52
|
-
|
53
|
-
|
47
|
+
# Create the database, will potentially throw an exception if it already exists.
|
48
|
+
def create!
|
49
|
+
Client.put @root
|
54
50
|
end
|
55
51
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
@documents << document
|
60
|
-
|
61
|
-
# We assume the save operation will be successful:
|
62
|
-
unless document.key? ID
|
63
|
-
@uuids << (document[ID] = @database.connection.next_uuid)
|
64
|
-
end
|
52
|
+
# Return true if the database already exists.
|
53
|
+
def exist?
|
54
|
+
Client.head @root
|
65
55
|
end
|
66
56
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
klass.new(self, @documents.last)
|
57
|
+
# Delete the database and all data.
|
58
|
+
def delete!
|
59
|
+
Client.delete @root
|
71
60
|
end
|
72
61
|
|
73
|
-
|
74
|
-
|
62
|
+
# Compact the database, removing old document revisions and optimizing space use.
|
63
|
+
def compact!
|
64
|
+
Client.post "#{@root}/_compact"
|
75
65
|
end
|
76
66
|
|
77
|
-
def
|
78
|
-
|
79
|
-
#puts YAML::dump(@documents)
|
80
|
-
|
81
|
-
changed = []
|
82
|
-
|
83
|
-
unless @documents.empty?
|
84
|
-
results = @database.bulk_save @documents
|
85
|
-
|
86
|
-
# Update the documents with revision information:
|
87
|
-
@documents.each_with_index do |document, index|
|
88
|
-
status = results[index]
|
89
|
-
|
90
|
-
if status['ok']
|
91
|
-
document[ID] = status['id']
|
92
|
-
document[REV] = status['rev']
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
changed = @documents
|
97
|
-
@documents = []
|
98
|
-
end
|
99
|
-
|
100
|
-
return changed
|
67
|
+
def id?(id, parameters = {})
|
68
|
+
Client.head document_url(id, parameters)
|
101
69
|
end
|
102
70
|
|
103
|
-
#def rollback!
|
104
|
-
# Restore all documents based on @uuids
|
105
|
-
#end
|
106
|
-
end
|
107
|
-
|
108
|
-
class Database
|
109
|
-
def initialize(connection, name)
|
110
|
-
@connection = connection
|
111
|
-
@name = name
|
112
|
-
|
113
|
-
@root = connection.url + "/" + CGI.escape(name)
|
114
|
-
end
|
115
|
-
|
116
|
-
attr :connection
|
117
|
-
attr :name
|
118
|
-
attr :root
|
119
|
-
|
120
71
|
def get(id, parameters = {})
|
121
72
|
Client.get document_url(id, parameters)
|
122
73
|
end
|
@@ -130,8 +81,6 @@ module Relaxo
|
|
130
81
|
end
|
131
82
|
|
132
83
|
def save(document)
|
133
|
-
Relaxo::encode_attachments!(document)
|
134
|
-
|
135
84
|
status = put(document)
|
136
85
|
|
137
86
|
if status['ok']
|
@@ -142,11 +91,13 @@ module Relaxo
|
|
142
91
|
return status
|
143
92
|
end
|
144
93
|
|
145
|
-
def bulk_save(documents)
|
146
|
-
|
94
|
+
def bulk_save(documents, options = {})
|
95
|
+
options = {
|
147
96
|
:docs => documents,
|
148
97
|
:all_or_nothing => true
|
149
|
-
}
|
98
|
+
}.merge(options)
|
99
|
+
|
100
|
+
Client.post command_url("_bulk_docs"), options
|
150
101
|
end
|
151
102
|
|
152
103
|
# Accepts paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
data/lib/relaxo/json.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Copyright (c) 2012 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
# You can define `Relaxo::JSON` before loading Relaxo, and it will use this implementation without trying to load the default JSON implementation.
|
22
|
+
|
23
|
+
module Relaxo
|
24
|
+
end
|
25
|
+
|
26
|
+
unless defined? Relaxo::JSON
|
27
|
+
unless defined? JSON
|
28
|
+
# Try to load a JSON implementation if it doesn't already exist:
|
29
|
+
require 'json'
|
30
|
+
end
|
31
|
+
|
32
|
+
Relaxo::JSON = JSON
|
33
|
+
end
|
@@ -23,15 +23,15 @@ require 'relaxo/connection'
|
|
23
23
|
|
24
24
|
module Relaxo
|
25
25
|
|
26
|
-
# We monkey-patch this in as
|
26
|
+
# We monkey-patch this in as Transaction is basically an optional feature for doing bulk_saves.
|
27
27
|
class Database
|
28
|
-
def
|
29
|
-
|
28
|
+
def transaction(klass = nil)
|
29
|
+
transaction = Transaction.new(self)
|
30
30
|
|
31
31
|
catch(:abort) do
|
32
|
-
yield
|
32
|
+
yield transaction
|
33
33
|
|
34
|
-
changed =
|
34
|
+
changed = transaction.commit!
|
35
35
|
|
36
36
|
if klass
|
37
37
|
klass.new(self, changed.last)
|
@@ -42,7 +42,7 @@ module Relaxo
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
class
|
45
|
+
class Transaction
|
46
46
|
def initialize(database)
|
47
47
|
@database = database
|
48
48
|
|
@@ -55,12 +55,14 @@ module Relaxo
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def delete(document)
|
58
|
-
@documents << {
|
58
|
+
@documents << {
|
59
|
+
ID => document[ID],
|
60
|
+
REV => document[REV],
|
61
|
+
DELETED => true
|
62
|
+
}
|
59
63
|
end
|
60
64
|
|
61
65
|
def save(document)
|
62
|
-
Relaxo::encode_attachments!(document)
|
63
|
-
|
64
66
|
@documents << document
|
65
67
|
|
66
68
|
# We assume the save operation will be successful:
|
@@ -69,7 +71,7 @@ module Relaxo
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
|
-
def
|
74
|
+
def transaction(klass)
|
73
75
|
yield self
|
74
76
|
|
75
77
|
klass.new(self, @documents.last)
|
@@ -80,9 +82,6 @@ module Relaxo
|
|
80
82
|
end
|
81
83
|
|
82
84
|
def commit!
|
83
|
-
#puts "Commiting session:"
|
84
|
-
#puts YAML::dump(@documents)
|
85
|
-
|
86
85
|
changed = []
|
87
86
|
|
88
87
|
unless @documents.empty?
|
@@ -108,9 +107,5 @@ module Relaxo
|
|
108
107
|
def abort!
|
109
108
|
throw :abort
|
110
109
|
end
|
111
|
-
|
112
|
-
#def rollback!
|
113
|
-
# Restore all documents based on @uuids
|
114
|
-
#end
|
115
110
|
end
|
116
111
|
end
|
data/lib/relaxo/version.rb
CHANGED
data/test/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
require 'relaxo'
|
6
|
+
require 'relaxo/attachments'
|
7
|
+
|
8
|
+
class DatabaseTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@connection = Relaxo::Connection.new(TEST_DATABASE_HOST)
|
11
|
+
@database = Relaxo::Database.new(@connection, TEST_DATABASE_NAME)
|
12
|
+
|
13
|
+
if @database.exist?
|
14
|
+
@database.delete!
|
15
|
+
end
|
16
|
+
|
17
|
+
@database.create!
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_attachments
|
21
|
+
document = {
|
22
|
+
Relaxo::ATTACHMENTS => {
|
23
|
+
"foo.txt" => {
|
24
|
+
"content_type" => "text\/plain",
|
25
|
+
"data" => "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
puts @database.save(document).inspect
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
require 'relaxo'
|
6
|
+
|
7
|
+
class ConnectionTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@connection = Relaxo::Connection.new(TEST_DATABASE_HOST)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_info
|
13
|
+
assert_equal Hash, @connection.info.class
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_create_database
|
17
|
+
database = Relaxo::Database.new(@connection, TEST_DATABASE_NAME)
|
18
|
+
|
19
|
+
if database.exist?
|
20
|
+
assert_equal Relaxo::SUCCESS, database.delete!
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_equal Relaxo::SUCCESS, database.create!
|
24
|
+
|
25
|
+
assert_includes TEST_DATABASE_NAME, @connection.databases
|
26
|
+
|
27
|
+
assert_equal Relaxo::SUCCESS, database.delete!
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
require 'relaxo'
|
6
|
+
|
7
|
+
class DatabaseTest < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@connection = Relaxo::Connection.new(TEST_DATABASE_HOST)
|
10
|
+
@database = Relaxo::Database.new(@connection, TEST_DATABASE_NAME)
|
11
|
+
|
12
|
+
if @database.exist?
|
13
|
+
@database.delete!
|
14
|
+
end
|
15
|
+
|
16
|
+
@database.create!
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_adding_document
|
20
|
+
assert_equal false, @database.id?('foobar')
|
21
|
+
|
22
|
+
document = {'animal' => 'Cat', 'name' => 'Seifa'}
|
23
|
+
|
24
|
+
@database.save(document)
|
25
|
+
|
26
|
+
id = document[Relaxo::ID]
|
27
|
+
assert_equal true, @database.id?(id)
|
28
|
+
|
29
|
+
copy = @database.get(id)
|
30
|
+
document.each do |key, value|
|
31
|
+
assert_equal value, copy[key]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../../lib/", __FILE__)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
TEST_DATABASE_NAME = 'relaxo-test-database'
|
8
|
+
TEST_DATABASE_HOST = 'localhost:5984'
|
9
|
+
|
10
|
+
class Test::Unit::TestCase
|
11
|
+
# Why isn't this in rails?
|
12
|
+
def assert_includes(elem, array, message = nil)
|
13
|
+
message = build_message message, '<?> is not found in <?>.', elem, array
|
14
|
+
|
15
|
+
assert_block message do
|
16
|
+
array.include? elem
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'helper'
|
4
|
+
|
5
|
+
require 'relaxo'
|
6
|
+
require 'relaxo/transaction'
|
7
|
+
|
8
|
+
class TransactionTest < Test::Unit::TestCase
|
9
|
+
def setup
|
10
|
+
@connection = Relaxo::Connection.new(TEST_DATABASE_HOST)
|
11
|
+
@database = Relaxo::Database.new(@connection, TEST_DATABASE_NAME)
|
12
|
+
|
13
|
+
if @database.exist?
|
14
|
+
@database.delete!
|
15
|
+
end
|
16
|
+
|
17
|
+
@database.create!
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_adding_documents
|
21
|
+
documents = @database.transaction do |txn|
|
22
|
+
10.times do |i|
|
23
|
+
txn.save({:i => i})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# We got 10 document IDs back
|
28
|
+
assert_equal 10, documents.size
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_abortion
|
32
|
+
all_documents = @database.documents
|
33
|
+
|
34
|
+
documents = @database.transaction do |txn|
|
35
|
+
10.times do |i|
|
36
|
+
txn.save({:i => i})
|
37
|
+
|
38
|
+
txn.abort! if i == 5
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
assert_equal nil, documents
|
43
|
+
assert_equal all_documents, @database.documents
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_deletion
|
47
|
+
documents = @database.transaction do |txn|
|
48
|
+
3.times do |i|
|
49
|
+
txn.save({:i => i})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@database.transaction do |txn|
|
54
|
+
documents.each do |document|
|
55
|
+
txn.delete(document)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
documents.each do |document|
|
60
|
+
assert_equal false, @database.id?(document[Relaxo::ID])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
metadata
CHANGED
@@ -1,86 +1,105 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: relaxo
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 4
|
8
|
+
- 0
|
9
|
+
version: 0.4.0
|
6
10
|
platform: ruby
|
7
|
-
authors:
|
11
|
+
authors:
|
8
12
|
- Samuel Williams
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
15
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
|
17
|
+
date: 2012-10-14 00:00:00 +13:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
15
21
|
name: json
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 1.7.3
|
22
|
-
type: :runtime
|
23
22
|
prerelease: false
|
24
|
-
|
25
|
-
|
26
|
-
requirements:
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
27
25
|
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 7
|
30
|
+
- 3
|
29
31
|
version: 1.7.3
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: rest-client
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 1.6.7
|
38
32
|
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rest-client
|
39
36
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
requirements:
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
43
39
|
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 1
|
43
|
+
- 6
|
44
|
+
- 7
|
45
45
|
version: 1.6.7
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
46
48
|
description:
|
47
49
|
email: samuel.williams@oriontransfer.co.nz
|
48
|
-
executables:
|
50
|
+
executables:
|
49
51
|
- relaxo
|
50
52
|
extensions: []
|
53
|
+
|
51
54
|
extra_rdoc_files: []
|
52
|
-
|
55
|
+
|
56
|
+
files:
|
53
57
|
- bin/relaxo
|
58
|
+
- lib/relaxo/attachments.rb
|
59
|
+
- lib/relaxo/base64-1.8.rb
|
54
60
|
- lib/relaxo/client.rb
|
55
61
|
- lib/relaxo/connection.rb
|
56
62
|
- lib/relaxo/database.rb
|
57
|
-
- lib/relaxo/
|
63
|
+
- lib/relaxo/json.rb
|
64
|
+
- lib/relaxo/transaction.rb
|
58
65
|
- lib/relaxo/version.rb
|
59
66
|
- lib/relaxo.rb
|
67
|
+
- test/README.md
|
68
|
+
- test/attachments_test.rb
|
69
|
+
- test/connection_test.rb
|
70
|
+
- test/database_test.rb
|
71
|
+
- test/helper.rb
|
72
|
+
- test/transaction_test.rb
|
60
73
|
- README.md
|
74
|
+
has_rdoc: true
|
61
75
|
homepage: http://www.oriontransfer.co.nz/gems/relaxo
|
62
76
|
licenses: []
|
77
|
+
|
63
78
|
post_install_message:
|
64
79
|
rdoc_options: []
|
65
|
-
|
80
|
+
|
81
|
+
require_paths:
|
66
82
|
- lib
|
67
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
79
97
|
requirements: []
|
98
|
+
|
80
99
|
rubyforge_project:
|
81
|
-
rubygems_version: 1.
|
100
|
+
rubygems_version: 1.3.6
|
82
101
|
signing_key:
|
83
102
|
specification_version: 3
|
84
103
|
summary: Relaxo is a helper for loading and working with CouchDB.
|
85
104
|
test_files: []
|
86
|
-
|
105
|
+
|