relaxo 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +77 -3
- data/bin/relaxo +15 -7
- data/lib/relaxo/client.rb +118 -0
- data/lib/relaxo/database.rb +182 -0
- data/lib/relaxo/server.rb +48 -0
- data/lib/relaxo/session.rb +116 -0
- data/lib/relaxo/version.rb +1 -1
- data/lib/relaxo.rb +37 -0
- metadata +27 -7
data/README.md
CHANGED
@@ -2,14 +2,88 @@ Relaxo
|
|
2
2
|
======
|
3
3
|
|
4
4
|
* Author: Samuel G. D. Williams (<http://www.oriontransfer.co.nz>)
|
5
|
-
* Copyright (C)
|
5
|
+
* Copyright (C) 2012 Samuel G. D. Williams.
|
6
6
|
* Released under the MIT license.
|
7
7
|
|
8
|
-
Relaxo
|
8
|
+
Relaxo provides a set of tools and interfaces for interacting with CouchDB. It aims to be as simple and efficient as possible while still improving the usability of various CouchDB features.
|
9
|
+
|
10
|
+
Installation
|
11
|
+
------------
|
12
|
+
|
13
|
+
Install the ruby gem as follows:
|
14
|
+
|
15
|
+
sudo gem install relaxo
|
16
|
+
|
17
|
+
To build and install the gem from source:
|
18
|
+
|
19
|
+
cd build/
|
20
|
+
sudo GEM=gem1.9 rake1.9 install_gem
|
21
|
+
|
22
|
+
Basic Usage
|
23
|
+
-----------
|
24
|
+
|
25
|
+
Connect to a local database and manipulate some documents.
|
26
|
+
|
27
|
+
require 'relaxo'
|
28
|
+
|
29
|
+
$database = Relaxo.connect("http://localhost:5984/test")
|
30
|
+
|
31
|
+
doc1 = {:bob => 'dole'}
|
32
|
+
$database.save(doc1)
|
33
|
+
|
34
|
+
doc2 = $database.get(doc1['_id'])
|
35
|
+
doc2[:foo] = 'bar'
|
36
|
+
$database.save(doc2)
|
37
|
+
|
38
|
+
Bulk Changes/Sessions
|
39
|
+
---------------------
|
40
|
+
|
41
|
+
Sessions support a very similar interface to the main database class and can for many cases be used interchangeably, but with added efficiency.
|
42
|
+
|
43
|
+
require 'relaxo'
|
44
|
+
require 'relaxo/session'
|
45
|
+
|
46
|
+
$database = Relaxo.connect("http://localhost:5984/test")
|
47
|
+
|
48
|
+
$animals = ['Neko-san', 'Wan-chan', 'Nezu-chan', 'Chicken-san']
|
49
|
+
|
50
|
+
$database.session do |session|
|
51
|
+
$animals.each do |animal|
|
52
|
+
session.save({:name => animal})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
# => [
|
56
|
+
# {:name=>"Neko-san", "_id"=>"...", "_rev"=>"..."},
|
57
|
+
# {:name=>"Wan-chan", "_id"=>"...", "_rev"=>"..."},
|
58
|
+
# {:name=>"Nezu-chan", "_id"=>"...", "_rev"=>"..."},
|
59
|
+
# {:name=>"Chicken-san", "_id"=>"...", "_rev"=>"..."}
|
60
|
+
#]
|
61
|
+
|
62
|
+
All documents will allocated uuids appropriately and at the end of the session block they will be updated (saved or deleted)
|
63
|
+
using CouchDB `_bulk_save`.
|
64
|
+
|
65
|
+
To abort the session, either raise an exception or call `session.abort!` which is equivalent to `throw :abort`.
|
66
|
+
|
67
|
+
Loading Data
|
68
|
+
------------
|
69
|
+
|
70
|
+
Relaxo includes a command line script to import documents into a CouchDB database:
|
9
71
|
|
10
72
|
relaxo http://localhost:5984/test design.yaml sample.yaml
|
11
73
|
|
12
|
-
Where `design.yaml` and `sample.yaml` contain lists of valid documents.
|
74
|
+
Where `design.yaml` and `sample.yaml` contain lists of valid documents, e.g.:
|
75
|
+
|
76
|
+
# design.yaml
|
77
|
+
- _id: "_design/services"
|
78
|
+
language: javascript
|
79
|
+
views:
|
80
|
+
service:
|
81
|
+
map: |
|
82
|
+
function(doc) {
|
83
|
+
if (doc.type == 'service') {
|
84
|
+
emit(doc._id, doc._rev);
|
85
|
+
}
|
86
|
+
}
|
13
87
|
|
14
88
|
License
|
15
89
|
-------
|
data/bin/relaxo
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'relaxo'
|
4
4
|
require 'yaml'
|
5
5
|
|
6
6
|
OPTIONS = {
|
7
7
|
:existing => :merge
|
8
8
|
}
|
9
9
|
|
10
|
-
|
10
|
+
if ARGV.delete('--merge')
|
11
|
+
OPTIONS[:existing] = :merge
|
12
|
+
elsif ARGV.delete('--replace')
|
13
|
+
OPTIONS[:existing] = :replace
|
14
|
+
elsif ARGV.delete('--update')
|
15
|
+
OPTIONS[:existing] = :update
|
16
|
+
end
|
17
|
+
|
18
|
+
$database = Relaxo.connect(ARGV.shift)
|
11
19
|
$documents = YAML::load(ARGF)
|
12
20
|
|
13
21
|
unless Array === $documents
|
@@ -25,15 +33,15 @@ $documents.each do |document|
|
|
25
33
|
$stderr.puts "Loading #{document.inspect}"
|
26
34
|
existing_document = nil
|
27
35
|
|
28
|
-
if document && document[
|
29
|
-
existing_document = $
|
36
|
+
if document && document[Relaxo::ID]
|
37
|
+
existing_document = $database.get(document[Relaxo::ID]) rescue nil
|
30
38
|
end
|
31
39
|
|
32
40
|
if existing_document
|
33
41
|
if OPTIONS[:existing] == :replace
|
34
42
|
$stderr.puts "Replacing existing document..."
|
35
43
|
# The document is replaced entirely with the incoming data.
|
36
|
-
document[
|
44
|
+
document[Relaxo::REV] = existing_document[Relaxo::REV]
|
37
45
|
elsif OPTIONS[:existing] == :update
|
38
46
|
$stderr.puts "Updating existing document..."
|
39
47
|
# Values in `existing_document` take priority
|
@@ -42,13 +50,13 @@ $documents.each do |document|
|
|
42
50
|
$stderr.puts "Merging existing document..."
|
43
51
|
# Values in `document` take priority, except for `_rev`.
|
44
52
|
document.update(existing_document) do |key, oldval, newval|
|
45
|
-
key ==
|
53
|
+
key == Relaxo::REV ? newval : oldval
|
46
54
|
end
|
47
55
|
end
|
48
56
|
end
|
49
57
|
|
50
58
|
$stderr.puts "Saving #{document.inspect}"
|
51
|
-
$result = $
|
59
|
+
$result = $database.save(document)
|
52
60
|
|
53
61
|
$stats[:saved] += 1
|
54
62
|
rescue RestClient::BadRequest => ex
|
@@ -0,0 +1,118 @@
|
|
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 'json'
|
22
|
+
require 'rest_client'
|
23
|
+
require 'cgi'
|
24
|
+
|
25
|
+
module Relaxo
|
26
|
+
module Client
|
27
|
+
@@debug = false
|
28
|
+
|
29
|
+
def self.debug= flag
|
30
|
+
@@debug = flag
|
31
|
+
end
|
32
|
+
|
33
|
+
DEFAULT_GET_HEADERS = {:accept => :json}
|
34
|
+
DEFAULT_PUT_HEADERS = {:accept => :json, :content_type => :json}
|
35
|
+
|
36
|
+
def self.execute(request)
|
37
|
+
# Poor mans debugging:
|
38
|
+
$stderr.puts "Client: #{request[:method]} #{request[:url]}" if @@debug
|
39
|
+
|
40
|
+
response = RestClient::Request.execute(request)
|
41
|
+
return JSON.parse(response)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.get(url)
|
45
|
+
execute({
|
46
|
+
:method => :get,
|
47
|
+
:url => url,
|
48
|
+
:headers => DEFAULT_GET_HEADERS
|
49
|
+
})
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.head(url)
|
53
|
+
execute({
|
54
|
+
:method => :head,
|
55
|
+
:url => url,
|
56
|
+
:headers => DEFAULT_GET_HEADERS
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.put(url, document)
|
61
|
+
execute({
|
62
|
+
:method => :put,
|
63
|
+
:url => url,
|
64
|
+
:headers => DEFAULT_PUT_HEADERS,
|
65
|
+
:payload => JSON.generate(document)
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.post(url, document)
|
70
|
+
execute({
|
71
|
+
:method => :post,
|
72
|
+
:url => url,
|
73
|
+
:headers => DEFAULT_PUT_HEADERS,
|
74
|
+
:payload => JSON.generate(document)
|
75
|
+
})
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.delete(url)
|
79
|
+
execute({
|
80
|
+
:method => :delete,
|
81
|
+
:url => url,
|
82
|
+
:headers => DEFAULT_PUT_HEADERS
|
83
|
+
})
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.escape(component)
|
87
|
+
return CGI.escape(component)
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.encode_parameters(parameters)
|
91
|
+
query = []
|
92
|
+
|
93
|
+
parameters.each do |key, value|
|
94
|
+
key_string = key.to_s
|
95
|
+
|
96
|
+
if Symbol === value || key_string.end_with?("docid")
|
97
|
+
query << escape(key_string) + '=' + escape(value.to_s)
|
98
|
+
else
|
99
|
+
query << escape(key_string) + '=' + escape(value.to_json)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
return '?' + query.join('&')
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.encode_url(url, parameters = {})
|
107
|
+
if parameters.empty?
|
108
|
+
url
|
109
|
+
else
|
110
|
+
url + encode_parameters(parameters)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.escape_id(id)
|
115
|
+
/^_design\/(.*)/ =~ id ? "_design/#{escape($1)}" : escape(id)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,182 @@
|
|
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/client'
|
22
|
+
require 'relaxo/server'
|
23
|
+
|
24
|
+
module Relaxo
|
25
|
+
|
26
|
+
ID = '_id'
|
27
|
+
REV = '_rev'
|
28
|
+
ATTACHMENTS = '_attachments'
|
29
|
+
|
30
|
+
def self.encode_attachments!(document)
|
31
|
+
return unless document[ATTACHMENTS]
|
32
|
+
|
33
|
+
document[ATTACHMENTS].each do |name,contents|
|
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
|
43
|
+
|
44
|
+
@documents = []
|
45
|
+
@uuids = []
|
46
|
+
end
|
47
|
+
|
48
|
+
def get(*args)
|
49
|
+
@database.get(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def delete(document)
|
53
|
+
@documents << {:_deleted => true}.merge(document)
|
54
|
+
end
|
55
|
+
|
56
|
+
def save(document)
|
57
|
+
Relaxo::encode_attachments!(document)
|
58
|
+
|
59
|
+
@documents << document
|
60
|
+
|
61
|
+
# We assume the save operation will be successful:
|
62
|
+
unless document.key? ID
|
63
|
+
@uuids << (document[ID] = @database.server.next_uuid)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def session(klass)
|
68
|
+
yield self
|
69
|
+
|
70
|
+
klass.new(self, @documents.last)
|
71
|
+
end
|
72
|
+
|
73
|
+
def view(*args)
|
74
|
+
@database.view(*args)
|
75
|
+
end
|
76
|
+
|
77
|
+
def commit!
|
78
|
+
#puts "Commiting session:"
|
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
|
101
|
+
end
|
102
|
+
|
103
|
+
#def rollback!
|
104
|
+
# Restore all documents based on @uuids
|
105
|
+
#end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Database
|
109
|
+
def initialize(server, name)
|
110
|
+
@server = server
|
111
|
+
@name = name
|
112
|
+
|
113
|
+
@root = server.url + "/" + CGI.escape(name)
|
114
|
+
end
|
115
|
+
|
116
|
+
attr :server
|
117
|
+
attr :name
|
118
|
+
attr :root
|
119
|
+
|
120
|
+
def get(id, parameters = {})
|
121
|
+
Client.get document_url(id, parameters)
|
122
|
+
end
|
123
|
+
|
124
|
+
def put(document)
|
125
|
+
Client.put document_url(document[ID] || @server.next_uuid), document
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete(document)
|
129
|
+
Client.delete document_url(document[ID]) + "?rev=#{document[REV]}"
|
130
|
+
end
|
131
|
+
|
132
|
+
def save(document)
|
133
|
+
Relaxo::encode_attachments!(document)
|
134
|
+
|
135
|
+
status = put(document)
|
136
|
+
|
137
|
+
if status['ok']
|
138
|
+
document[ID] = status['id']
|
139
|
+
document[REV] = status['rev']
|
140
|
+
end
|
141
|
+
|
142
|
+
return status
|
143
|
+
end
|
144
|
+
|
145
|
+
def bulk_save(documents)
|
146
|
+
Client.post command_url("_bulk_docs"), {
|
147
|
+
:docs => documents,
|
148
|
+
:all_or_nothing => true
|
149
|
+
}
|
150
|
+
end
|
151
|
+
|
152
|
+
# Accepts paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
153
|
+
def view(name, parameters = {})
|
154
|
+
Client.get view_url(name, parameters)
|
155
|
+
end
|
156
|
+
|
157
|
+
def info
|
158
|
+
Client.get @root
|
159
|
+
end
|
160
|
+
|
161
|
+
def documents(parameters = {})
|
162
|
+
view("_all_docs", parameters)
|
163
|
+
end
|
164
|
+
|
165
|
+
private
|
166
|
+
|
167
|
+
# Convert a simplified view name into a complete view path. If the name already starts with a "_" no alterations will be made.
|
168
|
+
def view_url(name, parameters = {})
|
169
|
+
path = (name =~ /^([^_].+?)\/(.*)$/ ? "_design/#{$1}/_view/#{$2}" : name)
|
170
|
+
|
171
|
+
Client.encode_url("#{@root}/#{path}", parameters)
|
172
|
+
end
|
173
|
+
|
174
|
+
def document_url(id, parameters = {})
|
175
|
+
Client.encode_url("#{@root}/#{Client.escape_id(id)}", parameters)
|
176
|
+
end
|
177
|
+
|
178
|
+
def command_url(command, parameters = {})
|
179
|
+
Client.encode_url("#{@root}/#{command}", parameters)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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/client'
|
22
|
+
|
23
|
+
module Relaxo
|
24
|
+
class Server
|
25
|
+
DEFAULT_UUID_FETCH_COUNT = 10
|
26
|
+
|
27
|
+
def initialize(url)
|
28
|
+
@url = url
|
29
|
+
@uuids = []
|
30
|
+
end
|
31
|
+
|
32
|
+
attr :url
|
33
|
+
|
34
|
+
def fetch_uuids(count)
|
35
|
+
@uuids += Client.get("#{@url}/_uuids?count=#{count}")["uuids"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def next_uuid
|
39
|
+
fetch_uuids(DEFAULT_UUID_FETCH_COUNT) if @uuids.size == 0
|
40
|
+
|
41
|
+
@uuids.pop
|
42
|
+
end
|
43
|
+
|
44
|
+
def info
|
45
|
+
Client.get @url
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,116 @@
|
|
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/client'
|
22
|
+
require 'relaxo/server'
|
23
|
+
|
24
|
+
module Relaxo
|
25
|
+
|
26
|
+
# We monkey-patch this in as Session is basically an optional feature for doing bulk_saves.
|
27
|
+
class Database
|
28
|
+
def session(klass = nil)
|
29
|
+
session = Session.new(self)
|
30
|
+
|
31
|
+
catch(:abort) do
|
32
|
+
yield session
|
33
|
+
|
34
|
+
changed = session.commit!
|
35
|
+
|
36
|
+
if klass
|
37
|
+
klass.new(self, changed.last)
|
38
|
+
else
|
39
|
+
changed
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Session
|
46
|
+
def initialize(database)
|
47
|
+
@database = database
|
48
|
+
|
49
|
+
@documents = []
|
50
|
+
@uuids = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def get(*args)
|
54
|
+
@database.get(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete(document)
|
58
|
+
@documents << {:_deleted => true}.merge(document)
|
59
|
+
end
|
60
|
+
|
61
|
+
def save(document)
|
62
|
+
Relaxo::encode_attachments!(document)
|
63
|
+
|
64
|
+
@documents << document
|
65
|
+
|
66
|
+
# We assume the save operation will be successful:
|
67
|
+
unless document.key? ID
|
68
|
+
@uuids << (document[ID] = @database.server.next_uuid)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def session(klass)
|
73
|
+
yield self
|
74
|
+
|
75
|
+
klass.new(self, @documents.last)
|
76
|
+
end
|
77
|
+
|
78
|
+
def view(*args)
|
79
|
+
@database.view(*args)
|
80
|
+
end
|
81
|
+
|
82
|
+
def commit!
|
83
|
+
#puts "Commiting session:"
|
84
|
+
#puts YAML::dump(@documents)
|
85
|
+
|
86
|
+
changed = []
|
87
|
+
|
88
|
+
unless @documents.empty?
|
89
|
+
results = @database.bulk_save @documents
|
90
|
+
|
91
|
+
# Update the documents with revision information:
|
92
|
+
@documents.each_with_index do |document, index|
|
93
|
+
status = results[index]
|
94
|
+
|
95
|
+
if status['ok']
|
96
|
+
document[ID] = status['id']
|
97
|
+
document[REV] = status['rev']
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
changed = @documents
|
102
|
+
@documents = []
|
103
|
+
end
|
104
|
+
|
105
|
+
return changed
|
106
|
+
end
|
107
|
+
|
108
|
+
def abort!
|
109
|
+
throw :abort
|
110
|
+
end
|
111
|
+
|
112
|
+
#def rollback!
|
113
|
+
# Restore all documents based on @uuids
|
114
|
+
#end
|
115
|
+
end
|
116
|
+
end
|
data/lib/relaxo/version.rb
CHANGED
data/lib/relaxo.rb
CHANGED
@@ -0,0 +1,37 @@
|
|
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
|
+
module Relaxo
|
24
|
+
def self.connect(url)
|
25
|
+
host = "http://localhost:5984"
|
26
|
+
|
27
|
+
if url =~ /^(https?:\/\/.+?)\/(.+)$/
|
28
|
+
host = $1
|
29
|
+
name = $2
|
30
|
+
else
|
31
|
+
name = url
|
32
|
+
end
|
33
|
+
|
34
|
+
server = Server.new(host)
|
35
|
+
database = Database.new(server, name)
|
36
|
+
end
|
37
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: relaxo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,24 +9,40 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
12
|
+
date: 2012-07-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: json
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 1.7.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
29
|
+
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
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.6.7
|
30
46
|
description:
|
31
47
|
email: samuel.williams@oriontransfer.co.nz
|
32
48
|
executables:
|
@@ -35,6 +51,10 @@ extensions: []
|
|
35
51
|
extra_rdoc_files: []
|
36
52
|
files:
|
37
53
|
- bin/relaxo
|
54
|
+
- lib/relaxo/client.rb
|
55
|
+
- lib/relaxo/database.rb
|
56
|
+
- lib/relaxo/server.rb
|
57
|
+
- lib/relaxo/session.rb
|
38
58
|
- lib/relaxo/version.rb
|
39
59
|
- lib/relaxo.rb
|
40
60
|
- README.md
|