samflores-couchrest 0.2.1 → 0.12.3
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 +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
|