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 CHANGED
@@ -26,30 +26,28 @@ Connect to a local database and manipulate some documents.
26
26
 
27
27
  require 'relaxo'
28
28
 
29
- $database = Relaxo.connect("http://localhost:5984/test")
29
+ database = Relaxo.connect("http://localhost:5984/test")
30
30
 
31
31
  doc1 = {:bob => 'dole'}
32
- $database.save(doc1)
32
+ database.save(doc1)
33
33
 
34
- doc2 = $database.get(doc1['_id'])
34
+ doc2 = database.get(doc1['_id'])
35
35
  doc2[:foo] = 'bar'
36
- $database.save(doc2)
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
- $database = Relaxo.connect("http://localhost:5984/test")
45
+ database = Relaxo.connect("http://localhost:5984/test")
46
+ animals = ['Neko-san', 'Wan-chan', 'Nezu-chan', 'Chicken-san']
47
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})
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
- 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
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
- $documents = YAML::load(ARGF)
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
- $documents.each do |document|
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
- existing_document = $database.get(document[Relaxo::ID]) rescue nil
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 = $database.save(document)
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
- $stderr.puts "#{$stats[:saved]} document(s) saved out of #{$stats[:total]}."
75
- if $stats[:errors] > 0
76
- $stderr.puts "#{$stats[:errors]} errors occurred!"
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
@@ -0,0 +1,8 @@
1
+
2
+ require 'base64'
3
+
4
+ module Base64
5
+ def self.strict_encode64(data)
6
+ encode64(data).gsub(/\s/, '')
7
+ end
8
+ end
@@ -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
- # Poor mans debugging:
38
- $stderr.puts "Relaxo Client: #{request[:method]} #{request[:url]}" if @@debug
39
-
40
- response = RestClient::Request.execute(request)
41
- return JSON.parse(response)
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.put(url, document)
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
@@ -44,5 +44,10 @@ module Relaxo
44
44
  def info
45
45
  Client.get @url
46
46
  end
47
+
48
+ # Returns a list of names, one for each available database.
49
+ def databases
50
+ Client.get("#{@url}/_all_dbs")
51
+ end
47
52
  end
48
53
  end
@@ -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
- ATTACHMENTS = '_attachments'
33
+ DELETED = '_deleted'
29
34
 
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
35
+ class Database
36
+ def initialize(connection, name)
37
+ @connection = connection
38
+ @name = name
43
39
 
44
- @documents = []
45
- @uuids = []
40
+ @root = connection.url + "/" + CGI.escape(name)
46
41
  end
47
42
 
48
- def get(*args)
49
- @database.get(*args)
50
- end
43
+ attr :connection
44
+ attr :name
45
+ attr :root
51
46
 
52
- def delete(document)
53
- @documents << {:_deleted => true}.merge(document)
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
- 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.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
- def session(klass)
68
- yield self
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
- def view(*args)
74
- @database.view(*args)
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 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
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
- Client.post command_url("_bulk_docs"), {
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
@@ -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 Session is basically an optional feature for doing bulk_saves.
26
+ # We monkey-patch this in as Transaction is basically an optional feature for doing bulk_saves.
27
27
  class Database
28
- def session(klass = nil)
29
- session = Session.new(self)
28
+ def transaction(klass = nil)
29
+ transaction = Transaction.new(self)
30
30
 
31
31
  catch(:abort) do
32
- yield session
32
+ yield transaction
33
33
 
34
- changed = session.commit!
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 Session
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 << {:_deleted => true}.merge(document)
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 session(klass)
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
@@ -21,8 +21,8 @@
21
21
  module Relaxo
22
22
  module VERSION
23
23
  MAJOR = 0
24
- MINOR = 3
25
- TINY = 1
24
+ MINOR = 4
25
+ TINY = 0
26
26
 
27
27
  STRING = [MAJOR, MINOR, TINY].join('.')
28
28
  end
@@ -0,0 +1,5 @@
1
+ # Relaxo Unit Tests #
2
+
3
+ Warning: DO NOT RUN THESE UNIT TESTS ON A LIVE SERVER.
4
+
5
+ The unit tests will create and drop databases with the details within `helper.rb`.
@@ -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
@@ -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
- version: 0.3.1
5
- prerelease:
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
- date: 2012-07-22 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
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
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
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
- version_requirements: !ruby/object:Gem::Requirement
41
- none: false
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
- files:
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/session.rb
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
- require_paths:
80
+
81
+ require_paths:
66
82
  - lib
67
- required_ruby_version: !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
70
- - - ! '>='
71
- - !ruby/object:Gem::Version
72
- version: '0'
73
- required_rubygems_version: !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
76
- - - ! '>='
77
- - !ruby/object:Gem::Version
78
- version: '0'
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.8.23
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
- has_rdoc:
105
+