simply_couch 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +182 -0
- data/LICENSE.txt +15 -0
- data/README.md +294 -0
- data/lib/core_ext/date.rb +15 -0
- data/lib/core_ext/time.rb +23 -0
- data/lib/simply_couch/class_methods_base.rb +72 -0
- data/lib/simply_couch/has_attachment.rb +225 -0
- data/lib/simply_couch/include_relation.rb +160 -0
- data/lib/simply_couch/instance_methods.rb +356 -0
- data/lib/simply_couch/locale/en.yml +5 -0
- data/lib/simply_couch/model/ancestry.rb +307 -0
- data/lib/simply_couch/model/association_property.rb +26 -0
- data/lib/simply_couch/model/attachments.rb +90 -0
- data/lib/simply_couch/model/belongs_to.rb +140 -0
- data/lib/simply_couch/model/database.rb +209 -0
- data/lib/simply_couch/model/embedded_in.rb +196 -0
- data/lib/simply_couch/model/find_by.rb +202 -0
- data/lib/simply_couch/model/finders.rb +77 -0
- data/lib/simply_couch/model/has_and_belongs_to_many.rb +223 -0
- data/lib/simply_couch/model/has_many.rb +177 -0
- data/lib/simply_couch/model/has_many_embedded.rb +187 -0
- data/lib/simply_couch/model/has_one.rb +75 -0
- data/lib/simply_couch/model/pagination.rb +25 -0
- data/lib/simply_couch/model/pagination_options.rb +55 -0
- data/lib/simply_couch/model/persistence.rb +411 -0
- data/lib/simply_couch/model/properties.rb +11 -0
- data/lib/simply_couch/model/validations.rb +28 -0
- data/lib/simply_couch/model/view/base_view_spec.rb +115 -0
- data/lib/simply_couch/model/view/custom_view_spec.rb +49 -0
- data/lib/simply_couch/model/view/custom_views.rb +50 -0
- data/lib/simply_couch/model/view/lists.rb +25 -0
- data/lib/simply_couch/model/view/model_view_spec.rb +106 -0
- data/lib/simply_couch/model/view/properties_view_spec.rb +53 -0
- data/lib/simply_couch/model/view/raw_view_spec.rb +30 -0
- data/lib/simply_couch/model/view/view_query.rb +98 -0
- data/lib/simply_couch/model/view.rb +8 -0
- data/lib/simply_couch/model/views/array_property_view_spec.rb +26 -0
- data/lib/simply_couch/model/views/deleted_model_view_spec.rb +43 -0
- data/lib/simply_couch/model/views.rb +2 -0
- data/lib/simply_couch/model.rb +195 -0
- data/lib/simply_couch/rake.rb +23 -0
- data/lib/simply_couch/storage.rb +147 -0
- data/lib/simply_couch.rb +26 -0
- metadata +144 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module View
|
|
4
|
+
# A view to return model instances by searching its properties.
|
|
5
|
+
# If you pass reduce => true will count instead
|
|
6
|
+
#
|
|
7
|
+
# example:
|
|
8
|
+
# view :my_view, :key => :name
|
|
9
|
+
#
|
|
10
|
+
# in addition you can pass in conditions as a javascript string
|
|
11
|
+
# view :my_view_only_completed, :key => :name, :conditions => 'doc.completed = true'
|
|
12
|
+
# and also a results filter (the results will be run through the given proc):
|
|
13
|
+
# view :my_view, :key => :name, :results_filter => lambda{|results| results.size}
|
|
14
|
+
class ModelViewSpec < BaseViewSpec
|
|
15
|
+
# The key simply_couch uses for class identification in CouchDB documents
|
|
16
|
+
RUBY_CLASS_KEY = 'ruby_class'
|
|
17
|
+
|
|
18
|
+
class JavascriptGenerator
|
|
19
|
+
def initialize(options, klass)
|
|
20
|
+
@options = options
|
|
21
|
+
@klass = klass
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def map_body(&block)
|
|
25
|
+
<<-JS
|
|
26
|
+
function(doc) {
|
|
27
|
+
if(doc.#{RUBY_CLASS_KEY} && doc.#{RUBY_CLASS_KEY} == '#{@klass.name}'#{conditions}) {
|
|
28
|
+
#{yield}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
JS
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def map_function
|
|
35
|
+
map_body do
|
|
36
|
+
"emit(#{formatted_key}, #{emit_value});"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def formatted_key(_key = nil)
|
|
41
|
+
_key ||= @options[:key]
|
|
42
|
+
if _key.is_a? Array
|
|
43
|
+
'[' + _key.map{|key_part| formatted_key(key_part)}.join(', ') + ']'
|
|
44
|
+
else
|
|
45
|
+
"doc['#{_key}']"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# Allow custom emit values. Raise when the specified argument is not recognized
|
|
52
|
+
def emit_value
|
|
53
|
+
case @options[:emit_value]
|
|
54
|
+
when Symbol then "doc['#{@options[:emit_value]}']"
|
|
55
|
+
when String then @options[:emit_value]
|
|
56
|
+
when Numeric then @options[:emit_value]
|
|
57
|
+
when NilClass then 1
|
|
58
|
+
else
|
|
59
|
+
raise "The emit value specified is not recognized"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def conditions
|
|
64
|
+
" && (#{@options[:conditions]})" if @options[:conditions]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
delegate :map_function, :map_body, :formatted_key, :to => :generator
|
|
69
|
+
|
|
70
|
+
def view_parameters
|
|
71
|
+
_super = super
|
|
72
|
+
if _super[:reduce]
|
|
73
|
+
_super
|
|
74
|
+
else
|
|
75
|
+
{:include_docs => true, :reduce => false}.merge(_super)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def reduce_function
|
|
80
|
+
"_sum"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def process_results(results)
|
|
84
|
+
processed = if count?
|
|
85
|
+
results['rows'].first.try(:[], 'value') || 0
|
|
86
|
+
else
|
|
87
|
+
results['rows'].map {|row|
|
|
88
|
+
row['doc'] || (row['id'] unless view_parameters[:include_docs])
|
|
89
|
+
}.compact
|
|
90
|
+
end
|
|
91
|
+
super processed
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def generator
|
|
97
|
+
@generator ||= JavascriptGenerator.new(@options, @klass)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def count?
|
|
101
|
+
view_parameters[:reduce]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module View
|
|
4
|
+
# A view to return model instances with only some properties populated by searching its properties, e.g. for very large documents where you are only interested in some of their data
|
|
5
|
+
#
|
|
6
|
+
# example:
|
|
7
|
+
# view :my_view, :key => :name, :properties => [:name, :author], :type => :properties
|
|
8
|
+
class PropertiesViewSpec < ModelViewSpec
|
|
9
|
+
def map_function
|
|
10
|
+
map_body do
|
|
11
|
+
"emit(#{formatted_key}, #{properties_for_map(properties)});"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def reduce_function
|
|
16
|
+
<<-JS
|
|
17
|
+
function(key, values, rereduce) {
|
|
18
|
+
if(rereduce) {
|
|
19
|
+
return sum(values);
|
|
20
|
+
} else {
|
|
21
|
+
return values.length;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
JS
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def process_results(results)
|
|
28
|
+
results['rows'].map do |row|
|
|
29
|
+
klass.json_create row['value'].merge(:_id => row['id'])
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def view_parameters
|
|
34
|
+
{:include_docs => false}.merge(super)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def language
|
|
38
|
+
:javascript
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def properties
|
|
44
|
+
options[:properties]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def properties_for_map(properties)
|
|
48
|
+
'{' + properties.map{|p| "#{p}: doc.#{p}"}.join(', ') + '}'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module View
|
|
4
|
+
# A view for custom map/reduce functions that returns the raw data from couchdb
|
|
5
|
+
#
|
|
6
|
+
# example:
|
|
7
|
+
# view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :reduce => nil
|
|
8
|
+
# optionally you can pass in a results filter which you can use to process the raw couchdb results before returning them
|
|
9
|
+
#
|
|
10
|
+
# example:
|
|
11
|
+
# view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :results_filter => lambda{|results| results['rows'].map{|row| row['value']}}
|
|
12
|
+
#
|
|
13
|
+
# example:
|
|
14
|
+
# view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :lib => {:module => "exports.name = 'module';"}
|
|
15
|
+
class RawViewSpec < BaseViewSpec
|
|
16
|
+
def map_function
|
|
17
|
+
options[:map]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reduce_function
|
|
21
|
+
options[:reduce]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def lib
|
|
25
|
+
options[:lib]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module View
|
|
4
|
+
# Used to query views (and create them if they don't exist). Usually you won't have to use this class directly.
|
|
5
|
+
class ViewQuery
|
|
6
|
+
def initialize(couchrest_database, design_document_name, view, list = nil, lib = nil, language = :javascript)
|
|
7
|
+
@database = couchrest_database
|
|
8
|
+
@design_document_name = design_document_name
|
|
9
|
+
@view_name = view.keys[0]
|
|
10
|
+
@map_function = view.values[0][:map]
|
|
11
|
+
@reduce_function = view.values[0][:reduce]
|
|
12
|
+
@lib = lib
|
|
13
|
+
@language = language
|
|
14
|
+
if list
|
|
15
|
+
@list_function = list.values[0]
|
|
16
|
+
@list_name = list.keys[0]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def query_view!(parameters = {})
|
|
21
|
+
update_view unless view_has_been_updated?
|
|
22
|
+
begin
|
|
23
|
+
query_view parameters
|
|
24
|
+
rescue CouchRest::NotFound => e
|
|
25
|
+
update_view
|
|
26
|
+
retry
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# mainly useful for testing where you drop the database between tests.
|
|
31
|
+
# only after clearing the cache design docs will be updated/re-created.
|
|
32
|
+
def self.clear_cache
|
|
33
|
+
__updated_views.clear
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.__updated_views
|
|
37
|
+
@updated_views ||= {}
|
|
38
|
+
@updated_views
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def update_view
|
|
44
|
+
design_doc = @database.get "_design/#{@design_document_name}" rescue nil
|
|
45
|
+
original_views = design_doc && design_doc['views'].dup
|
|
46
|
+
original_lists = design_doc && design_doc['lists'] && design_doc['lists'].dup
|
|
47
|
+
view_updated unless design_doc.nil?
|
|
48
|
+
design_doc ||= empty_design_document
|
|
49
|
+
design_doc['views'][@view_name.to_s] = view_functions
|
|
50
|
+
if @lib
|
|
51
|
+
design_doc['views']['lib'] = (design_doc['views']['lib'] || {}).merge(@lib)
|
|
52
|
+
end
|
|
53
|
+
if @list_function
|
|
54
|
+
design_doc['lists'] ||= {}
|
|
55
|
+
design_doc['lists'][@list_name.to_s] = @list_function
|
|
56
|
+
end
|
|
57
|
+
@database.save_doc(design_doc) if original_views != design_doc['views'] || original_lists != design_doc['lists']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def view_functions
|
|
61
|
+
if @reduce_function
|
|
62
|
+
{'map' => @map_function, 'reduce' => @reduce_function}
|
|
63
|
+
else
|
|
64
|
+
{'map' => @map_function}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def empty_design_document
|
|
69
|
+
{'views' => {}, 'lists' => {}, "_id" => "_design/#{@design_document_name}", "language" => @language.to_s}
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def view_has_been_updated?
|
|
73
|
+
updated_views[[@design_document_name, @view_name]]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def view_updated
|
|
77
|
+
updated_views[[@design_document_name, @view_name]] = true
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def updated_views
|
|
81
|
+
self.class.__updated_views
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def query_view(parameters)
|
|
85
|
+
if @list_name
|
|
86
|
+
@database.connection.get CouchRest.paramify_url("/#{@database.name}/_design/#{@design_document_name}/_list/#{@list_name}/#{@view_name}", parameters)
|
|
87
|
+
else
|
|
88
|
+
@database.view view_url, parameters
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def view_url
|
|
93
|
+
"#{@design_document_name}/#{@view_name}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
require 'simply_couch/model/view/base_view_spec'
|
|
2
|
+
require 'simply_couch/model/view/model_view_spec'
|
|
3
|
+
require 'simply_couch/model/view/properties_view_spec'
|
|
4
|
+
require 'simply_couch/model/view/custom_view_spec'
|
|
5
|
+
require 'simply_couch/model/view/raw_view_spec'
|
|
6
|
+
require 'simply_couch/model/view/view_query'
|
|
7
|
+
require 'simply_couch/model/view/custom_views'
|
|
8
|
+
require 'simply_couch/model/view/lists'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module Views
|
|
4
|
+
class ArrayPropertyViewSpec < SimplyCouch::Model::View::ModelViewSpec
|
|
5
|
+
def map_function
|
|
6
|
+
"function(doc) {
|
|
7
|
+
if(doc.ruby_class && doc.ruby_class == '#{@klass.name}') {
|
|
8
|
+
if (#{formatted_key(key)}.constructor.toString().match(/function Array()/)) {
|
|
9
|
+
for (var i in #{formatted_key(key)}) {
|
|
10
|
+
emit(#{formatted_key(key)}[i], 1);
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
emit(#{formatted_key(key)}, 1);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def key
|
|
20
|
+
@options[:key]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module SimplyCouch
|
|
2
|
+
module Model
|
|
3
|
+
module Views
|
|
4
|
+
class DeletedModelViewSpec < SimplyCouch::Model::View::ModelViewSpec
|
|
5
|
+
def map_function
|
|
6
|
+
<<-eos
|
|
7
|
+
function(doc) {
|
|
8
|
+
if (doc.ruby_class && doc.ruby_class == '#{@klass.name}') {
|
|
9
|
+
if (doc['#{@klass.soft_delete_attribute}'] && doc['#{@klass.soft_delete_attribute}'] != null){
|
|
10
|
+
// "soft" deleted
|
|
11
|
+
}else{
|
|
12
|
+
emit(doc.created_at, 1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
eos
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def reduce_function
|
|
20
|
+
'_sum'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def view_parameters
|
|
24
|
+
_super = super
|
|
25
|
+
if _super[:reduce]
|
|
26
|
+
_super
|
|
27
|
+
else
|
|
28
|
+
{:include_docs => true, :reduce => false}.merge(_super)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def process_results(results)
|
|
33
|
+
if count?
|
|
34
|
+
results['rows'].first.try(:[], 'value') || 0
|
|
35
|
+
else
|
|
36
|
+
results['rows'].map { |row| row['doc'] || row['id'] }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
require 'active_model'
|
|
2
|
+
|
|
3
|
+
CouchRest.decode_json_objects = true
|
|
4
|
+
require 'json'
|
|
5
|
+
JSON.create_id = 'ruby_class'
|
|
6
|
+
|
|
7
|
+
require 'active_support'
|
|
8
|
+
unless {}.respond_to?(:assert_valid_keys)
|
|
9
|
+
require 'active_support/core_ext'
|
|
10
|
+
end
|
|
11
|
+
I18n.load_path << File.join(File.expand_path(File.dirname(__FILE__)), 'locale', 'en.yml')
|
|
12
|
+
require File.expand_path(File.dirname(__FILE__) + '/../simply_couch')
|
|
13
|
+
require 'simply_couch/model/database'
|
|
14
|
+
require 'simply_couch/model/validations'
|
|
15
|
+
require 'simply_couch/model/pagination_options'
|
|
16
|
+
require 'simply_couch/model/association_property'
|
|
17
|
+
require 'simply_couch/model/properties'
|
|
18
|
+
require 'simply_couch/model/ancestry'
|
|
19
|
+
require 'simply_couch/model/finders'
|
|
20
|
+
require 'simply_couch/model/find_by'
|
|
21
|
+
require 'simply_couch/model/belongs_to'
|
|
22
|
+
require 'simply_couch/model/embedded_in'
|
|
23
|
+
require 'simply_couch/model/has_many'
|
|
24
|
+
require 'simply_couch/model/has_many_embedded'
|
|
25
|
+
require 'simply_couch/model/has_and_belongs_to_many'
|
|
26
|
+
require 'simply_couch/model/has_one'
|
|
27
|
+
require 'simply_couch/model/attachments'
|
|
28
|
+
require 'simply_couch/model/pagination'
|
|
29
|
+
require 'simply_couch/model/persistence'
|
|
30
|
+
require 'simply_couch/model/view'
|
|
31
|
+
require 'simply_couch/model/views'
|
|
32
|
+
require 'simply_couch/include_relation'
|
|
33
|
+
|
|
34
|
+
module SimplyCouch
|
|
35
|
+
module Model
|
|
36
|
+
def self.included(clazz)
|
|
37
|
+
clazz.send(:include, Persistence)
|
|
38
|
+
clazz.send(:include, InstanceMethods)
|
|
39
|
+
clazz.send(:extend, ClassMethods)
|
|
40
|
+
|
|
41
|
+
clazz.instance_eval do
|
|
42
|
+
attr_accessor :_accessible_attributes, :_protected_attributes
|
|
43
|
+
|
|
44
|
+
view :all_documents, :key => :created_at
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
module ClassMethods
|
|
49
|
+
include SimplyCouch::ClassMethods::Base
|
|
50
|
+
include SimplyCouch::Model::Database
|
|
51
|
+
include SimplyCouch::Model::Validations
|
|
52
|
+
include SimplyCouch::Model::BelongsTo
|
|
53
|
+
include SimplyCouch::Model::EmbeddedIn
|
|
54
|
+
include SimplyCouch::Model::HasMany
|
|
55
|
+
include SimplyCouch::Model::HasManyEmbedded
|
|
56
|
+
include SimplyCouch::Model::HasAndBelongsToMany
|
|
57
|
+
include SimplyCouch::Model::HasOne
|
|
58
|
+
include SimplyCouch::Model::Finders
|
|
59
|
+
include SimplyCouch::Model::FindBy
|
|
60
|
+
include SimplyCouch::Model::Pagination
|
|
61
|
+
include SimplyCouch::Model::PaginationOptions
|
|
62
|
+
include SimplyCouch::Storage::ClassMethods
|
|
63
|
+
include SimplyCouch::Model::Ancestry
|
|
64
|
+
|
|
65
|
+
def create(attributes = {}, &blk)
|
|
66
|
+
instance = new(attributes, &blk)
|
|
67
|
+
instance.save
|
|
68
|
+
instance
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def create!(attributes = {}, &blk)
|
|
72
|
+
instance = new(attributes, &blk)
|
|
73
|
+
instance.save!
|
|
74
|
+
instance
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def enable_soft_delete(property_name = :deleted_at)
|
|
78
|
+
@_soft_delete_attribute = property_name.to_sym
|
|
79
|
+
property property_name, :type => Time
|
|
80
|
+
_define_hard_delete_methods
|
|
81
|
+
_define_soft_delete_views
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def soft_delete_attribute
|
|
85
|
+
@_soft_delete_attribute
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def soft_deleting_enabled?
|
|
89
|
+
!soft_delete_attribute.nil?
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def split_design_documents_per_view(enabled = true)
|
|
93
|
+
@_split_design_documents = enabled
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def split_design_documents?
|
|
97
|
+
@_split_design_documents || false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def auto_conflict_resolution_on_save
|
|
101
|
+
@auto_conflict_resolution_on_save.nil? ? true : @auto_conflict_resolution_on_save
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def auto_conflict_resolution_on_save=(val)
|
|
105
|
+
@auto_conflict_resolution_on_save = val
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def method_missing(name, *args)
|
|
109
|
+
if name.to_s =~ /^find_by/
|
|
110
|
+
_define_find_by(name, *args)
|
|
111
|
+
elsif name.to_s =~ /^find_all_by/
|
|
112
|
+
_define_find_all_by(name, *args)
|
|
113
|
+
elsif name.to_s =~ /^count_by/
|
|
114
|
+
_define_count_by(name, *args)
|
|
115
|
+
else
|
|
116
|
+
super
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def _define_hard_delete_methods
|
|
121
|
+
define_method("destroy!") do
|
|
122
|
+
destroy(true)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
define_method("delete!") do
|
|
126
|
+
destroy(true)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def _define_soft_delete_views
|
|
131
|
+
view :all_documents_without_deleted, :type => SimplyCouch::Model::Views::DeletedModelViewSpec
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def _define_cache_accessors(name, options)
|
|
135
|
+
define_method "_get_cached_#{name}" do
|
|
136
|
+
instance_variable_get("@#{name}") || {}
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
define_method "_set_cached_#{name}" do |value, cache_key|
|
|
140
|
+
cached = send("_get_cached_#{name}")
|
|
141
|
+
cached[cache_key] = value
|
|
142
|
+
instance_variable_set("@#{name}", cached)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
define_method "_cache_key_for" do |opt|
|
|
146
|
+
opt.blank? ? :all : opt.to_s
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def extract_association_options(local_options = nil)
|
|
152
|
+
forced_reload = false
|
|
153
|
+
with_deleted = false
|
|
154
|
+
limit = nil
|
|
155
|
+
descending = false
|
|
156
|
+
skip = nil
|
|
157
|
+
|
|
158
|
+
if local_options
|
|
159
|
+
local_options.assert_valid_keys(:force_reload, :with_deleted, :limit, :order)
|
|
160
|
+
forced_reload = local_options.delete(:force_reload)
|
|
161
|
+
with_deleted = local_options[:with_deleted]
|
|
162
|
+
limit = local_options[:limit]
|
|
163
|
+
descending = (local_options[:order] == :desc) ? true : false
|
|
164
|
+
skip = local_options[:skip]
|
|
165
|
+
end
|
|
166
|
+
return [forced_reload, with_deleted, limit, descending, skip]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def self.delete_all_design_documents(database)
|
|
170
|
+
db = CouchRest.database(database)
|
|
171
|
+
db.info # ensure DB exists
|
|
172
|
+
design_docs = CouchRest.get("#{database}/_all_docs?startkey=%22_design%22&endkey=%22_design0%22")['rows'].map do |row|
|
|
173
|
+
[row['id'], row['value']['rev']]
|
|
174
|
+
end
|
|
175
|
+
design_docs.each do |doc_id, rev|
|
|
176
|
+
db.delete_doc({'_id' => doc_id, '_rev' => rev})
|
|
177
|
+
end
|
|
178
|
+
design_docs.size
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def self.compact_all_design_documents(database)
|
|
182
|
+
db = CouchRest.database(database)
|
|
183
|
+
db.info # ensure DB exists
|
|
184
|
+
design_docs = CouchRest.get("#{database}/_all_docs?startkey=%22_design%22&endkey=%22_design0%22")['rows'].map do |row|
|
|
185
|
+
[row['id'], row['value']['rev']]
|
|
186
|
+
end
|
|
187
|
+
design_docs.each do |doc_id, rev|
|
|
188
|
+
puts "#{database}/_compact/#{doc_id.gsub("_design/",'')}"
|
|
189
|
+
CouchRest.post("#{database}/_compact/#{doc_id.gsub("_design/",'')}")
|
|
190
|
+
end
|
|
191
|
+
design_docs.size
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
namespace :simply_couch do
|
|
2
|
+
desc "delete all design documents"
|
|
3
|
+
task :delete_design_documents do
|
|
4
|
+
require File.dirname(__FILE__) + "/couch"
|
|
5
|
+
if database = ENV['DATABASE']
|
|
6
|
+
deleted = SimplyCouch::Model.delete_all_design_documents(database)
|
|
7
|
+
puts "deleted #{deleted} design documents in #{database}"
|
|
8
|
+
else
|
|
9
|
+
puts "please specify which database to clear: DATABASE=http://localhost:5984/simply_couch rake simply_couch:delete_design_documents"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "compact all design documents"
|
|
14
|
+
task :compact_design_documents do
|
|
15
|
+
require File.dirname(__FILE__) + "/couch"
|
|
16
|
+
if database = ENV['DATABASE']
|
|
17
|
+
compacted = SimplyCouch::Model.compact_all_design_documents(database)
|
|
18
|
+
puts "triggered compaction of #{compacted} design documents in #{database}"
|
|
19
|
+
else
|
|
20
|
+
puts "please specify which database to clear: DATABASE=http://localhost:5984/simply_couch rake simply_couch:delete_design_documents"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|