relaxo 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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
+