samflores-couchrest 0.2.1 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +10 -34
- data/Rakefile +5 -2
- data/bin/couchdir +20 -0
- data/examples/model/example.rb +13 -19
- data/examples/word_count/word_count.rb +24 -3
- data/examples/word_count/word_count_query.rb +6 -7
- data/lib/couchrest/core/database.rb +49 -126
- data/lib/couchrest/core/document.rb +25 -58
- data/lib/couchrest/core/model.rb +612 -0
- data/lib/couchrest/core/server.rb +10 -47
- data/lib/couchrest/core/validations.rb +328 -0
- data/lib/couchrest/monkeypatches.rb +0 -95
- data/lib/couchrest.rb +10 -57
- data/spec/couchrest/core/database_spec.rb +68 -183
- data/spec/couchrest/core/design_spec.rb +1 -1
- data/spec/couchrest/core/document_spec.rb +104 -285
- data/spec/couchrest/core/model_spec.rb +855 -0
- data/spec/couchrest/helpers/pager_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -13
- metadata +17 -83
- data/examples/word_count/word_count_views.rb +0 -26
- data/lib/couchrest/core/response.rb +0 -16
- data/lib/couchrest/mixins/attachments.rb +0 -31
- data/lib/couchrest/mixins/callbacks.rb +0 -483
- data/lib/couchrest/mixins/design_doc.rb +0 -64
- data/lib/couchrest/mixins/document_queries.rb +0 -48
- data/lib/couchrest/mixins/extended_attachments.rb +0 -68
- data/lib/couchrest/mixins/extended_document_mixins.rb +0 -6
- data/lib/couchrest/mixins/properties.rb +0 -125
- data/lib/couchrest/mixins/validation.rb +0 -234
- data/lib/couchrest/mixins/views.rb +0 -168
- data/lib/couchrest/mixins.rb +0 -4
- data/lib/couchrest/more/casted_model.rb +0 -28
- data/lib/couchrest/more/extended_document.rb +0 -217
- data/lib/couchrest/more/property.rb +0 -40
- data/lib/couchrest/support/blank.rb +0 -42
- data/lib/couchrest/support/class.rb +0 -191
- data/lib/couchrest/validation/auto_validate.rb +0 -163
- data/lib/couchrest/validation/contextual_validators.rb +0 -78
- data/lib/couchrest/validation/validation_errors.rb +0 -118
- data/lib/couchrest/validation/validators/absent_field_validator.rb +0 -74
- data/lib/couchrest/validation/validators/confirmation_validator.rb +0 -99
- data/lib/couchrest/validation/validators/format_validator.rb +0 -117
- data/lib/couchrest/validation/validators/formats/email.rb +0 -66
- data/lib/couchrest/validation/validators/formats/url.rb +0 -43
- data/lib/couchrest/validation/validators/generic_validator.rb +0 -120
- data/lib/couchrest/validation/validators/length_validator.rb +0 -134
- data/lib/couchrest/validation/validators/method_validator.rb +0 -89
- data/lib/couchrest/validation/validators/numeric_validator.rb +0 -104
- data/lib/couchrest/validation/validators/required_field_validator.rb +0 -109
- data/spec/couchrest/core/server_spec.rb +0 -35
- data/spec/couchrest/more/casted_extended_doc_spec.rb +0 -40
- data/spec/couchrest/more/casted_model_spec.rb +0 -98
- data/spec/couchrest/more/extended_doc_attachment_spec.rb +0 -130
- data/spec/couchrest/more/extended_doc_spec.rb +0 -509
- data/spec/couchrest/more/extended_doc_view_spec.rb +0 -207
- data/spec/couchrest/more/property_spec.rb +0 -130
- data/spec/couchrest/support/class_spec.rb +0 -59
- data/spec/fixtures/more/article.rb +0 -34
- data/spec/fixtures/more/card.rb +0 -20
- data/spec/fixtures/more/course.rb +0 -14
- data/spec/fixtures/more/event.rb +0 -6
- data/spec/fixtures/more/invoice.rb +0 -17
- data/spec/fixtures/more/person.rb +0 -8
- data/spec/fixtures/more/question.rb +0 -6
- data/spec/fixtures/more/service.rb +0 -12
data/README.md
CHANGED
@@ -6,7 +6,8 @@ which I find to be concise, clear, and well designed. CouchRest lightly wraps
|
|
6
6
|
CouchDB's HTTP API, managing JSON serialization, and remembering the URI-paths
|
7
7
|
to CouchDB's API endpoints so you don't have to.
|
8
8
|
|
9
|
-
CouchRest is designed to make a simple base for application and
|
9
|
+
CouchRest's lighweight is designed to make a simple base for application and
|
10
|
+
framework-specific object oriented APIs.
|
10
11
|
|
11
12
|
## Easy Install
|
12
13
|
|
@@ -31,7 +32,7 @@ Quick Start:
|
|
31
32
|
|
32
33
|
# with !, it creates the database if it doesn't already exist
|
33
34
|
@db = CouchRest.database!("http://127.0.0.1:5984/couchrest-test")
|
34
|
-
response = @db.
|
35
|
+
response = @db.save({:key => 'value', 'another key' => 'another value'})
|
35
36
|
doc = @db.get(response['id'])
|
36
37
|
puts doc.inspect
|
37
38
|
|
@@ -47,7 +48,7 @@ Bulk Save:
|
|
47
48
|
|
48
49
|
Creating and Querying Views:
|
49
50
|
|
50
|
-
@db.
|
51
|
+
@db.save({
|
51
52
|
"_id" => "_design/first",
|
52
53
|
:views => {
|
53
54
|
:test => {
|
@@ -59,35 +60,10 @@ Creating and Querying Views:
|
|
59
60
|
|
60
61
|
## CouchRest::Model
|
61
62
|
|
62
|
-
CouchRest::Model
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
### Callbacks
|
68
|
-
|
69
|
-
`CouchRest::ExtendedDocuments` instances have 2 callbacks already defined for you:
|
70
|
-
`create_callback`, `save_callback`, `update_callback` and `destroy_callback`
|
71
|
-
|
72
|
-
In your document inherits from `CouchRest::ExtendedDocument`, define your callback as follows:
|
73
|
-
|
74
|
-
save_callback :before, :generate_slug_from_name
|
75
|
-
|
76
|
-
CouchRest uses a mixin you can find in lib/mixins/callbacks which is extracted from Rails 3, here are some simple usage examples:
|
77
|
-
|
78
|
-
save_callback :before, :before_method
|
79
|
-
save_callback :after, :after_method, :if => :condition
|
80
|
-
save_callback :around {|r| stuff; yield; stuff }
|
81
|
-
|
82
|
-
Check the mixin or the ExtendedDocument class to see how to implement your own callbacks.
|
83
|
-
|
84
|
-
### Casting
|
85
|
-
|
86
|
-
Often, you will want to store multiple objects within a document, to be able to retrieve your objects when you load the document,
|
87
|
-
you can define some casting rules.
|
88
|
-
|
89
|
-
property :casted_attribute, :cast_as => 'WithCastedModelMixin'
|
90
|
-
property :keywords, :cast_as => ["String"]
|
91
|
-
|
92
|
-
If you want to cast an array of instances from a specific Class, use the trick shown above ["ClassName"]
|
63
|
+
CouchRest::Model is a module designed along the lines of DataMapper::Resource.
|
64
|
+
By subclassing, suddenly you get all sorts of powerful sugar, so that working
|
65
|
+
with CouchDB in your Rails or Merb app is no harder than working with the
|
66
|
+
standard SQL alternatives. See the CouchRest::Model documentation for an
|
67
|
+
example article class that illustrates usage.
|
93
68
|
|
69
|
+
CouchRest::Model will be removed from this package.
|
data/Rakefile
CHANGED
@@ -23,15 +23,18 @@ spec = Gem::Specification.new do |s|
|
|
23
23
|
s.homepage = "http://github.com/jchris/couchrest"
|
24
24
|
s.description = "CouchRest provides a simple interface on top of CouchDB's RESTful HTTP API, as well as including some utility scripts for managing views and attachments."
|
25
25
|
s.has_rdoc = true
|
26
|
-
s.authors = ["J. Chris Anderson"
|
26
|
+
s.authors = ["J. Chris Anderson"]
|
27
27
|
s.files = %w( LICENSE README.md Rakefile THANKS.md ) +
|
28
|
-
Dir["{examples,lib,spec,utils}/**/*"] -
|
28
|
+
Dir["{bin,examples,lib,spec,utils}/**/*"] -
|
29
29
|
Dir["spec/tmp"]
|
30
30
|
s.extra_rdoc_files = %w( README.md LICENSE THANKS.md )
|
31
31
|
s.require_path = "lib"
|
32
|
+
s.bindir = 'bin'
|
33
|
+
s.executables << 'couchdir'
|
32
34
|
s.add_dependency("json", ">= 1.1.2")
|
33
35
|
s.add_dependency("rest-client", ">= 0.5")
|
34
36
|
s.add_dependency("mime-types", ">= 1.15")
|
37
|
+
s.add_dependency("extlib", ">= 0.9.6")
|
35
38
|
end
|
36
39
|
|
37
40
|
|
data/bin/couchdir
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
unless ARGV.length >= 2
|
4
|
+
puts "usage: couchdir path/to/directory db-name [docid]"
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'couchrest'
|
10
|
+
|
11
|
+
dirname = ARGV[0]
|
12
|
+
dbname = ARGV[1]
|
13
|
+
docid = ARGV[2]
|
14
|
+
|
15
|
+
puts "Create attachments for the files in #{dirname} in database #{dbname}."
|
16
|
+
|
17
|
+
fm = CouchRest::FileManager.new(dbname)
|
18
|
+
fm.loud = true
|
19
|
+
puts "Pushing views from directory #{dirname} to database #{fm.db}"
|
20
|
+
fm.push_directory(dirname, docid)
|
data/examples/model/example.rb
CHANGED
@@ -1,38 +1,31 @@
|
|
1
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'couchrest'
|
2
3
|
|
3
4
|
def show obj
|
4
5
|
puts obj.inspect
|
5
6
|
puts
|
6
7
|
end
|
7
8
|
|
8
|
-
|
9
|
-
SERVER.default_database = 'couchrest-extendeddoc-example'
|
9
|
+
CouchRest::Model.default_database = CouchRest.database!('couchrest-model-example')
|
10
10
|
|
11
|
-
class Author < CouchRest::
|
12
|
-
|
13
|
-
property :name
|
14
|
-
|
11
|
+
class Author < CouchRest::Model
|
12
|
+
key_accessor :name
|
15
13
|
def drink_scotch
|
16
14
|
puts "... glug type glug ... I'm #{name} ... type glug glug ..."
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
|
-
class Post < CouchRest::
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
property :body
|
25
|
-
property :author, :cast_as => 'Author'
|
18
|
+
class Post < CouchRest::Model
|
19
|
+
key_accessor :title, :body, :author
|
20
|
+
|
21
|
+
cast :author, :as => 'Author'
|
26
22
|
|
27
23
|
timestamps!
|
28
24
|
end
|
29
25
|
|
30
|
-
class Comment < CouchRest::
|
31
|
-
|
32
|
-
|
33
|
-
property :commenter, :cast_as => 'Author'
|
34
|
-
timestamps!
|
35
|
-
|
26
|
+
class Comment < CouchRest::Model
|
27
|
+
cast :commenter, :as => 'Author'
|
28
|
+
|
36
29
|
def post= post
|
37
30
|
self["post_id"] = post.id
|
38
31
|
end
|
@@ -40,6 +33,7 @@ class Comment < CouchRest::ExtendedDocument
|
|
40
33
|
Post.get(self['post_id']) if self['post_id']
|
41
34
|
end
|
42
35
|
|
36
|
+
timestamps!
|
43
37
|
end
|
44
38
|
|
45
39
|
puts "Act I: CRUD"
|
@@ -1,5 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'couchrest'
|
1
|
+
require File.dirname(__FILE__) + '/../../couchrest'
|
3
2
|
|
4
3
|
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
4
|
db = couch.database('word-count-example')
|
@@ -40,7 +39,29 @@ books.keys.each do |book|
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
42
|
+
|
43
|
+
# word_count = {
|
44
|
+
# :map => 'function(doc){
|
45
|
+
# var words = doc.text.split(/\W/);
|
46
|
+
# words.forEach(function(word){
|
47
|
+
# if (word.length > 0) emit([word,doc.title],1);
|
48
|
+
# });
|
49
|
+
# }',
|
50
|
+
# :reduce => 'function(key,combine){
|
51
|
+
# return sum(combine);
|
52
|
+
# }'
|
53
|
+
# }
|
54
|
+
#
|
55
|
+
# db.delete db.get("_design/word_count") rescue nil
|
56
|
+
#
|
57
|
+
# db.save({
|
58
|
+
# "_id" => "_design/word_count",
|
59
|
+
# :views => {
|
60
|
+
# :count => word_count,
|
61
|
+
# :words => {:map => word_count[:map]}
|
62
|
+
# }
|
63
|
+
# })
|
43
64
|
|
44
65
|
# puts "The books have been stored in your CouchDB. To initiate the MapReduce process, visit http://127.0.0.1:5984/_utils/ in your browser and click 'word-count-example', then select view 'words' or 'count'. The process could take about 15 minutes on an average MacBook."
|
45
|
-
|
66
|
+
#
|
46
67
|
|
@@ -1,23 +1,22 @@
|
|
1
|
-
require '
|
2
|
-
require 'couchrest'
|
1
|
+
require File.dirname(__FILE__) + '/../../couchrest'
|
3
2
|
|
4
3
|
couch = CouchRest.new("http://127.0.0.1:5984")
|
5
4
|
db = couch.database('word-count-example')
|
6
5
|
|
7
6
|
puts "Now that we've parsed all those books into CouchDB, the queries we can run are incredibly flexible."
|
8
7
|
puts "\nThe simplest query we can run is the total word count for all words in all documents:"
|
9
|
-
|
10
|
-
puts db.view('word_count/
|
8
|
+
|
9
|
+
puts db.view('word_count/count').inspect
|
11
10
|
|
12
11
|
puts "\nWe can also narrow the query down to just one word, across all documents. Here is the count for 'flight' in all three books:"
|
13
12
|
|
14
13
|
word = 'flight'
|
15
14
|
params = {
|
16
15
|
:startkey => [word],
|
17
|
-
:endkey => [word,
|
16
|
+
:endkey => [word,'Z']
|
18
17
|
}
|
19
18
|
|
20
|
-
puts db.view('word_count/
|
19
|
+
puts db.view('word_count/count',params).inspect
|
21
20
|
|
22
21
|
puts "\nWe scope the query using startkey and endkey params to take advantage of CouchDB's collation ordering. Here are the params for the last query:"
|
23
22
|
puts params.inspect
|
@@ -29,7 +28,7 @@ params = {
|
|
29
28
|
:key => [word, title]
|
30
29
|
}
|
31
30
|
|
32
|
-
puts db.view('word_count/
|
31
|
+
puts db.view('word_count/count',params).inspect
|
33
32
|
|
34
33
|
|
35
34
|
puts "\nHere are the params for 'flight' in the da-vinci book:"
|
@@ -3,7 +3,7 @@ require "base64"
|
|
3
3
|
|
4
4
|
module CouchRest
|
5
5
|
class Database
|
6
|
-
attr_reader :server, :host, :name, :root
|
6
|
+
attr_reader :server, :host, :name, :root
|
7
7
|
attr_accessor :bulk_save_cache_limit
|
8
8
|
|
9
9
|
# Create a CouchRest::Database adapter for the supplied CouchRest::Server
|
@@ -13,30 +13,30 @@ module CouchRest
|
|
13
13
|
# server<CouchRest::Server>:: database host
|
14
14
|
# name<String>:: database name
|
15
15
|
#
|
16
|
-
def initialize
|
16
|
+
def initialize server, name
|
17
17
|
@name = name
|
18
18
|
@server = server
|
19
19
|
@host = server.uri
|
20
|
-
@
|
20
|
+
@root = "#{host}/#{name}"
|
21
21
|
@streamer = Streamer.new(self)
|
22
22
|
@bulk_save_cache = []
|
23
|
-
@bulk_save_cache_limit =
|
23
|
+
@bulk_save_cache_limit = 50
|
24
24
|
end
|
25
25
|
|
26
26
|
# returns the database's uri
|
27
27
|
def to_s
|
28
|
-
@
|
28
|
+
@root
|
29
29
|
end
|
30
30
|
|
31
31
|
# GET the database info from CouchDB
|
32
32
|
def info
|
33
|
-
CouchRest.get @
|
33
|
+
CouchRest.get @root
|
34
34
|
end
|
35
35
|
|
36
36
|
# Query the <tt>_all_docs</tt> view. Accepts all the same arguments as view.
|
37
|
-
def documents
|
37
|
+
def documents params = {}
|
38
38
|
keys = params.delete(:keys)
|
39
|
-
url = CouchRest.paramify_url "#{@
|
39
|
+
url = CouchRest.paramify_url "#{@root}/_all_docs", params
|
40
40
|
if keys
|
41
41
|
CouchRest.post(url, {:keys => keys})
|
42
42
|
else
|
@@ -47,10 +47,10 @@ module CouchRest
|
|
47
47
|
# POST a temporary view function to CouchDB for querying. This is not
|
48
48
|
# recommended, as you don't get any performance benefit from CouchDB's
|
49
49
|
# materialized views. Can be quite slow on large databases.
|
50
|
-
def slow_view
|
50
|
+
def slow_view funcs, params = {}
|
51
51
|
keys = params.delete(:keys)
|
52
52
|
funcs = funcs.merge({:keys => keys}) if keys
|
53
|
-
url = CouchRest.paramify_url "#{@
|
53
|
+
url = CouchRest.paramify_url "#{@root}/_slow_view", params
|
54
54
|
JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
|
55
55
|
end
|
56
56
|
|
@@ -59,17 +59,14 @@ module CouchRest
|
|
59
59
|
|
60
60
|
# Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts
|
61
61
|
# paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
62
|
-
def view
|
62
|
+
def view name, params = {}, &block
|
63
63
|
keys = params.delete(:keys)
|
64
|
-
|
65
|
-
dname = name.shift
|
66
|
-
vname = name.join('/')
|
67
|
-
url = CouchRest.paramify_url "#{@uri}/_design/#{dname}/_view/#{vname}", params
|
64
|
+
url = CouchRest.paramify_url "#{@root}/_view/#{name}", params
|
68
65
|
if keys
|
69
66
|
CouchRest.post(url, {:keys => keys})
|
70
67
|
else
|
71
68
|
if block_given?
|
72
|
-
@streamer.view(
|
69
|
+
@streamer.view(name, params, &block)
|
73
70
|
else
|
74
71
|
CouchRest.get url
|
75
72
|
end
|
@@ -77,9 +74,9 @@ module CouchRest
|
|
77
74
|
end
|
78
75
|
|
79
76
|
# GET a document from CouchDB, by id. Returns a Ruby Hash.
|
80
|
-
def get
|
77
|
+
def get id
|
81
78
|
slug = escape_docid(id)
|
82
|
-
hash = CouchRest.get("#{@
|
79
|
+
hash = CouchRest.get("#{@root}/#{slug}")
|
83
80
|
doc = if /^_design/ =~ hash["_id"]
|
84
81
|
Design.new(hash)
|
85
82
|
else
|
@@ -90,29 +87,25 @@ module CouchRest
|
|
90
87
|
end
|
91
88
|
|
92
89
|
# GET an attachment directly from CouchDB
|
93
|
-
def fetch_attachment
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
RestClient.get uri
|
98
|
-
# "#{@uri}/#{slug}/#{name}"
|
90
|
+
def fetch_attachment docid, name
|
91
|
+
slug = escape_docid(docid)
|
92
|
+
name = CGI.escape(name)
|
93
|
+
RestClient.get "#{@root}/#{slug}/#{name}"
|
99
94
|
end
|
100
95
|
|
101
96
|
# PUT an attachment directly to CouchDB
|
102
|
-
def put_attachment
|
97
|
+
def put_attachment doc, name, file, options = {}
|
103
98
|
docid = escape_docid(doc['_id'])
|
104
99
|
name = CGI.escape(name)
|
105
|
-
uri =
|
100
|
+
uri = if doc['_rev']
|
101
|
+
"#{@root}/#{docid}/#{name}?rev=#{doc['_rev']}"
|
102
|
+
else
|
103
|
+
"#{@root}/#{docid}/#{name}"
|
104
|
+
end
|
105
|
+
|
106
106
|
JSON.parse(RestClient.put(uri, file, options))
|
107
107
|
end
|
108
108
|
|
109
|
-
# DELETE an attachment directly from CouchDB
|
110
|
-
def delete_attachment doc, name
|
111
|
-
uri = uri_for_attachment(doc, name)
|
112
|
-
# this needs a rev
|
113
|
-
JSON.parse(RestClient.delete(uri))
|
114
|
-
end
|
115
|
-
|
116
109
|
# Save a document to CouchDB. This will use the <tt>_id</tt> field from
|
117
110
|
# the document as the id for PUT, or request a new UUID from CouchDB, if
|
118
111
|
# no <tt>_id</tt> is present on the document. IDs are attached to
|
@@ -122,7 +115,7 @@ module CouchRest
|
|
122
115
|
#
|
123
116
|
# If <tt>bulk</tt> is true (false by default) the document is cached for bulk-saving later.
|
124
117
|
# Bulk saving happens automatically when #bulk_save_cache limit is exceded, or on the next non bulk save.
|
125
|
-
def
|
118
|
+
def save (doc, bulk = false)
|
126
119
|
if doc['_attachments']
|
127
120
|
doc['_attachments'] = encode_attachments(doc['_attachments'])
|
128
121
|
end
|
@@ -135,13 +128,13 @@ module CouchRest
|
|
135
128
|
end
|
136
129
|
result = if doc['_id']
|
137
130
|
slug = escape_docid(doc['_id'])
|
138
|
-
CouchRest.put "#{@
|
131
|
+
CouchRest.put "#{@root}/#{slug}", doc
|
139
132
|
else
|
140
133
|
begin
|
141
134
|
slug = doc['_id'] = @server.next_uuid
|
142
|
-
CouchRest.put "#{@
|
135
|
+
CouchRest.put "#{@root}/#{slug}", doc
|
143
136
|
rescue #old version of couchdb
|
144
|
-
CouchRest.post @
|
137
|
+
CouchRest.post @root, doc
|
145
138
|
end
|
146
139
|
end
|
147
140
|
if result['ok']
|
@@ -152,40 +145,30 @@ module CouchRest
|
|
152
145
|
result
|
153
146
|
end
|
154
147
|
|
155
|
-
### DEPRECATION NOTICE
|
156
|
-
def save(doc, bulk=false)
|
157
|
-
puts "CouchRest::Database's save method is being deprecated, please use save_doc instead"
|
158
|
-
save_doc(doc, bulk)
|
159
|
-
end
|
160
|
-
|
161
|
-
|
162
148
|
# POST an array of documents to CouchDB. If any of the documents are
|
163
149
|
# missing ids, supply one from the uuid cache.
|
164
150
|
#
|
165
151
|
# If called with no arguments, bulk saves the cache of documents to be bulk saved.
|
166
|
-
def bulk_save(docs = nil
|
152
|
+
def bulk_save (docs = nil)
|
167
153
|
if docs.nil?
|
168
154
|
docs = @bulk_save_cache
|
169
155
|
@bulk_save_cache = []
|
170
156
|
end
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
doc['_id'] = nextid if nextid
|
177
|
-
end
|
157
|
+
ids, noids = docs.partition{|d|d['_id']}
|
158
|
+
uuid_count = [noids.length, @server.uuid_batch_count].max
|
159
|
+
noids.each do |doc|
|
160
|
+
nextid = @server.next_uuid(uuid_count) rescue nil
|
161
|
+
doc['_id'] = nextid if nextid
|
178
162
|
end
|
179
|
-
CouchRest.post "#{@
|
163
|
+
CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
|
180
164
|
end
|
181
|
-
alias :bulk_delete :bulk_save
|
182
165
|
|
183
166
|
# DELETE the document from CouchDB that has the given <tt>_id</tt> and
|
184
167
|
# <tt>_rev</tt>.
|
185
168
|
#
|
186
169
|
# If <tt>bulk</tt> is true (false by default) the deletion is recorded for bulk-saving (bulk-deletion :) later.
|
187
170
|
# Bulk saving happens automatically when #bulk_save_cache limit is exceded, or on the next non bulk save.
|
188
|
-
def
|
171
|
+
def delete (doc, bulk = false)
|
189
172
|
raise ArgumentError, "_id and _rev required for deleting" unless doc['_id'] && doc['_rev']
|
190
173
|
if bulk
|
191
174
|
@bulk_save_cache << { '_id' => doc['_id'], '_rev' => doc['_rev'], '_deleted' => true }
|
@@ -193,19 +176,13 @@ module CouchRest
|
|
193
176
|
return { "ok" => true } # Mimic the non-deferred version
|
194
177
|
end
|
195
178
|
slug = escape_docid(doc['_id'])
|
196
|
-
CouchRest.delete "#{@
|
197
|
-
end
|
198
|
-
|
199
|
-
### DEPRECATION NOTICE
|
200
|
-
def delete(doc, bulk=false)
|
201
|
-
puts "CouchRest::Database's delete method is being deprecated, please use delete_doc instead"
|
202
|
-
delete_doc(doc, bulk)
|
179
|
+
CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
|
203
180
|
end
|
204
181
|
|
205
182
|
# COPY an existing document to a new id. If the destination id currently exists, a rev must be provided.
|
206
183
|
# <tt>dest</tt> can take one of two forms if overwriting: "id_to_overwrite?rev=revision" or the actual doc
|
207
184
|
# hash with a '_rev' key
|
208
|
-
def
|
185
|
+
def copy doc, dest
|
209
186
|
raise ArgumentError, "_id is required for copying" unless doc['_id']
|
210
187
|
slug = escape_docid(doc['_id'])
|
211
188
|
destination = if dest.respond_to?(:has_key?) && dest['_id'] && dest['_rev']
|
@@ -213,19 +190,13 @@ module CouchRest
|
|
213
190
|
else
|
214
191
|
dest
|
215
192
|
end
|
216
|
-
CouchRest.copy "#{@
|
217
|
-
end
|
218
|
-
|
219
|
-
### DEPRECATION NOTICE
|
220
|
-
def copy(doc, dest)
|
221
|
-
puts "CouchRest::Database's copy method is being deprecated, please use copy_doc instead"
|
222
|
-
copy_doc(doc, dest)
|
193
|
+
CouchRest.copy "#{@root}/#{slug}", destination
|
223
194
|
end
|
224
195
|
|
225
196
|
# MOVE an existing document to a new id. If the destination id currently exists, a rev must be provided.
|
226
197
|
# <tt>dest</tt> can take one of two forms if overwriting: "id_to_overwrite?rev=revision" or the actual doc
|
227
198
|
# hash with a '_rev' key
|
228
|
-
def
|
199
|
+
def move doc, dest
|
229
200
|
raise ArgumentError, "_id and _rev are required for moving" unless doc['_id'] && doc['_rev']
|
230
201
|
slug = escape_docid(doc['_id'])
|
231
202
|
destination = if dest.respond_to?(:has_key?) && dest['_id'] && dest['_rev']
|
@@ -233,75 +204,27 @@ module CouchRest
|
|
233
204
|
else
|
234
205
|
dest
|
235
206
|
end
|
236
|
-
CouchRest.move "#{@
|
237
|
-
end
|
238
|
-
|
239
|
-
### DEPRECATION NOTICE
|
240
|
-
def move(doc, dest)
|
241
|
-
puts "CouchRest::Database's move method is being deprecated, please use move_doc instead"
|
242
|
-
move_doc(doc, dest)
|
207
|
+
CouchRest.move "#{@root}/#{slug}?rev=#{doc['_rev']}", destination
|
243
208
|
end
|
244
209
|
|
245
210
|
# Compact the database, removing old document revisions and optimizing space use.
|
246
211
|
def compact!
|
247
|
-
CouchRest.post "#{@
|
248
|
-
end
|
249
|
-
|
250
|
-
# Create the database
|
251
|
-
def create!
|
252
|
-
bool = server.create_db(@name) rescue false
|
253
|
-
bool && true
|
254
|
-
end
|
255
|
-
|
256
|
-
# Delete and re create the database
|
257
|
-
def recreate!
|
258
|
-
delete!
|
259
|
-
create!
|
260
|
-
rescue RestClient::ResourceNotFound
|
261
|
-
ensure
|
262
|
-
create!
|
263
|
-
end
|
264
|
-
|
265
|
-
# Replicates via "pulling" from another database to this database. Makes no attempt to deal with conflicts.
|
266
|
-
def replicate_from other_db
|
267
|
-
raise ArgumentError, "must provide a CouchReset::Database" unless other_db.kind_of?(CouchRest::Database)
|
268
|
-
CouchRest.post "#{@host}/_replicate", :source => other_db.root, :target => name
|
269
|
-
end
|
270
|
-
|
271
|
-
# Replicates via "pushing" to another database. Makes no attempt to deal with conflicts.
|
272
|
-
def replicate_to other_db
|
273
|
-
raise ArgumentError, "must provide a CouchReset::Database" unless other_db.kind_of?(CouchRest::Database)
|
274
|
-
CouchRest.post "#{@host}/_replicate", :target => other_db.root, :source => name
|
212
|
+
CouchRest.post "#{@root}/_compact"
|
275
213
|
end
|
276
|
-
|
214
|
+
|
277
215
|
# DELETE the database itself. This is not undoable and could be rather
|
278
216
|
# catastrophic. Use with care!
|
279
217
|
def delete!
|
280
|
-
CouchRest.delete @
|
218
|
+
CouchRest.delete @root
|
281
219
|
end
|
282
220
|
|
283
221
|
private
|
284
|
-
|
285
|
-
def uri_for_attachment(doc, name)
|
286
|
-
if doc.is_a?(String)
|
287
|
-
puts "CouchRest::Database#fetch_attachment will eventually require a doc as the first argument, not a doc.id"
|
288
|
-
docid = doc
|
289
|
-
rev = nil
|
290
|
-
else
|
291
|
-
docid = doc['_id']
|
292
|
-
rev = doc['_rev']
|
293
|
-
end
|
294
|
-
docid = escape_docid(docid)
|
295
|
-
name = CGI.escape(name)
|
296
|
-
rev = "?rev=#{doc['_rev']}" if rev
|
297
|
-
"#{@root}/#{docid}/#{name}#{rev}"
|
298
|
-
end
|
299
|
-
|
222
|
+
|
300
223
|
def escape_docid id
|
301
224
|
/^_design\/(.*)/ =~ id ? "_design/#{CGI.escape($1)}" : CGI.escape(id)
|
302
225
|
end
|
303
226
|
|
304
|
-
def encode_attachments
|
227
|
+
def encode_attachments attachments
|
305
228
|
attachments.each do |k,v|
|
306
229
|
next if v['stub']
|
307
230
|
v['data'] = base64(v['data'])
|
@@ -309,7 +232,7 @@ module CouchRest
|
|
309
232
|
attachments
|
310
233
|
end
|
311
234
|
|
312
|
-
def base64
|
235
|
+
def base64 data
|
313
236
|
Base64.encode64(data).gsub(/\s/,'')
|
314
237
|
end
|
315
238
|
end
|