langalex-couch_potato 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +260 -0
- data/VERSION.yml +2 -2
- data/init.rb +3 -0
- data/lib/core_ext/date.rb +10 -0
- data/lib/core_ext/string.rb +15 -0
- data/lib/core_ext/time.rb +6 -9
- data/lib/couch_potato/database.rb +90 -0
- data/lib/couch_potato/persistence/belongs_to_property.rb +1 -1
- data/lib/couch_potato/persistence/callbacks.rb +14 -11
- data/lib/couch_potato/persistence/dirty_attributes.rb +13 -6
- data/lib/couch_potato/persistence/json.rb +9 -14
- data/lib/couch_potato/persistence/magic_timestamps.rb +13 -0
- data/lib/couch_potato/persistence/properties.rb +10 -8
- data/lib/couch_potato/persistence/simple_property.rb +14 -11
- data/lib/couch_potato/persistence.rb +11 -165
- data/lib/couch_potato/view/base_view_spec.rb +20 -0
- data/lib/couch_potato/view/custom_view_spec.rb +26 -0
- data/lib/couch_potato/view/custom_views.rb +30 -0
- data/lib/couch_potato/view/model_view_spec.rb +39 -0
- data/lib/couch_potato/view/properties_view_spec.rb +35 -0
- data/lib/couch_potato/view/raw_view_spec.rb +21 -0
- data/lib/couch_potato/view/view_query.rb +45 -0
- data/lib/couch_potato.rb +23 -6
- data/rails/init.rb +7 -0
- data/spec/callbacks_spec.rb +40 -43
- data/spec/create_spec.rb +9 -60
- data/spec/custom_view_spec.rb +93 -19
- data/spec/destroy_spec.rb +5 -4
- data/spec/property_spec.rb +22 -8
- data/spec/spec_helper.rb +12 -14
- data/spec/unit/attributes_spec.rb +26 -0
- data/spec/unit/create_spec.rb +58 -0
- data/spec/{dirty_attributes_spec.rb → unit/dirty_attributes_spec.rb} +31 -13
- data/spec/unit/string_spec.rb +13 -0
- data/spec/unit/view_query_spec.rb +2 -3
- data/spec/update_spec.rb +8 -7
- metadata +54 -32
- data/README.textile +0 -340
- data/lib/couch_potato/active_record/compatibility.rb +0 -9
- data/lib/couch_potato/ordering.rb +0 -84
- data/lib/couch_potato/persistence/bulk_save_queue.rb +0 -47
- data/lib/couch_potato/persistence/collection.rb +0 -51
- data/lib/couch_potato/persistence/custom_view.rb +0 -41
- data/lib/couch_potato/persistence/external_collection.rb +0 -83
- data/lib/couch_potato/persistence/external_has_many_property.rb +0 -72
- data/lib/couch_potato/persistence/find.rb +0 -21
- data/lib/couch_potato/persistence/finder.rb +0 -65
- data/lib/couch_potato/persistence/inline_has_many_property.rb +0 -43
- data/lib/couch_potato/persistence/view_query.rb +0 -81
- data/lib/couch_potato/versioning.rb +0 -46
- data/spec/attributes_spec.rb +0 -42
- data/spec/belongs_to_spec.rb +0 -55
- data/spec/find_spec.rb +0 -96
- data/spec/finder_spec.rb +0 -125
- data/spec/has_many_spec.rb +0 -241
- data/spec/inline_collection_spec.rb +0 -15
- data/spec/ordering_spec.rb +0 -95
- data/spec/reload_spec.rb +0 -50
- data/spec/unit/external_collection_spec.rb +0 -84
- data/spec/unit/finder_spec.rb +0 -10
- data/spec/versioning_spec.rb +0 -150
@@ -1,84 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Ordering
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
property :position
|
6
|
-
cattr_accessor :ordering_scope
|
7
|
-
|
8
|
-
before_create :set_position
|
9
|
-
before_create :update_positions
|
10
|
-
before_destroy :update_lower_positions_after_destroy
|
11
|
-
before_update :update_positions
|
12
|
-
|
13
|
-
def self.set_ordering_scope(scope)
|
14
|
-
self.ordering_scope = scope
|
15
|
-
end
|
16
|
-
|
17
|
-
def position=(new_position)
|
18
|
-
@old_position = position
|
19
|
-
@position = new_position
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
MAX = 9999999
|
27
|
-
|
28
|
-
def set_position
|
29
|
-
self.position ||= self.class.count(scope_conditions) + 1
|
30
|
-
end
|
31
|
-
|
32
|
-
def update_positions
|
33
|
-
@old_position = MAX if new_document?
|
34
|
-
return unless @old_position
|
35
|
-
if position < @old_position
|
36
|
-
new_lower_items = find_in_positions self.position, @old_position - 1
|
37
|
-
move new_lower_items, :down
|
38
|
-
elsif position > @old_position
|
39
|
-
new_higher_items = find_in_positions @old_position + 1, position
|
40
|
-
move new_higher_items, :up
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def update_lower_positions_after_destroy
|
45
|
-
lower_items = find_in_positions self.position + 1, MAX
|
46
|
-
move lower_items, :up
|
47
|
-
end
|
48
|
-
|
49
|
-
def find_in_positions(from, to)
|
50
|
-
self.class.all scope_conditions.merge(:position => from..to)
|
51
|
-
end
|
52
|
-
|
53
|
-
def scope_conditions
|
54
|
-
if ordering_scope
|
55
|
-
{ordering_scope => self.send(ordering_scope)}
|
56
|
-
else
|
57
|
-
{}
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def move(items, direction)
|
62
|
-
items.each do |item|
|
63
|
-
if direction == :up
|
64
|
-
item.position -= 1
|
65
|
-
else
|
66
|
-
item.position += 1
|
67
|
-
end
|
68
|
-
self.bulk_save_queue << item
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
module ExternalCollectionOrderedFindExtension
|
74
|
-
def items
|
75
|
-
if @item_class.property_names.include?(:position)
|
76
|
-
super @item_class, @owner_id_attribute_name => owner_id, :position => 1..CouchPotato::Ordering::MAX
|
77
|
-
else
|
78
|
-
super
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
CouchPotato::Persistence::ExternalCollection.send :include, ExternalCollectionOrderedFindExtension
|
83
|
-
end
|
84
|
-
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
class BulkSaveQueue
|
4
|
-
attr_reader :callbacks
|
5
|
-
|
6
|
-
def initialize
|
7
|
-
@other_queues = []
|
8
|
-
@callbacks = []
|
9
|
-
@instances = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def <<(instance)
|
13
|
-
if own?
|
14
|
-
@instances << instance
|
15
|
-
else
|
16
|
-
@other_queues.last << instance
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def push_queue(queue)
|
21
|
-
@other_queues.push queue
|
22
|
-
end
|
23
|
-
|
24
|
-
def pop_queue
|
25
|
-
@other_queues.pop
|
26
|
-
end
|
27
|
-
|
28
|
-
def own?
|
29
|
-
@other_queues.empty?
|
30
|
-
end
|
31
|
-
|
32
|
-
def save(&callback)
|
33
|
-
if own?
|
34
|
-
@callbacks << callback if callback
|
35
|
-
res = CouchPotato::Persistence.Db.bulk_save @instances
|
36
|
-
@instances.clear
|
37
|
-
@callbacks.each do |_callback|
|
38
|
-
_callback.call res
|
39
|
-
end
|
40
|
-
@callbacks.clear
|
41
|
-
else
|
42
|
-
@other_queues.last.callbacks << callback if callback
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
class Collection
|
4
|
-
attr_accessor :items, :item_class
|
5
|
-
|
6
|
-
def initialize(item_class)
|
7
|
-
@item_class = item_class
|
8
|
-
@items = []
|
9
|
-
end
|
10
|
-
|
11
|
-
def build(attributes)
|
12
|
-
item = @item_class.new(attributes)
|
13
|
-
self.<< item
|
14
|
-
item
|
15
|
-
end
|
16
|
-
|
17
|
-
def ==(other)
|
18
|
-
other.class == self.class && other.items == items && other.item_class == item_class
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_json(*args)
|
22
|
-
raise 'implement me in a subclass'
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.json_create(json)
|
26
|
-
raise 'implement me in a subclass'
|
27
|
-
end
|
28
|
-
|
29
|
-
delegate :[], :<<, :empty?, :any?, :each, :+, :size, :first, :last, :map, :inject, :join, :clear, :select, :reject, :to => :items
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
if Object.const_defined? 'WillPaginate'
|
36
|
-
module CouchPotato
|
37
|
-
module Persistence
|
38
|
-
class Collection
|
39
|
-
def paginate(options = {})
|
40
|
-
page = (options[:page] || 1).to_i
|
41
|
-
per_page = options[:per_page] || 20
|
42
|
-
collection = WillPaginate::Collection.new page, per_page, self.size
|
43
|
-
items[((page - 1) * per_page)..(page * (per_page - 1))].each do |item|
|
44
|
-
collection << item
|
45
|
-
end
|
46
|
-
collection
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
module CustomView
|
4
|
-
|
5
|
-
def self.included(base)
|
6
|
-
base.extend ClassMethods
|
7
|
-
end
|
8
|
-
|
9
|
-
module ClassMethods
|
10
|
-
|
11
|
-
def view(name, options)
|
12
|
-
(class << self; self; end).instance_eval do
|
13
|
-
if options[:properties]
|
14
|
-
define_method name do
|
15
|
-
ViewQuery.new(self.name.underscore, name, map_function(options[:key], options[:properties]), nil, {}, {}).query_view!['rows'].map{|doc| self.new(doc['value'].merge(:_id => doc['id']))}
|
16
|
-
end
|
17
|
-
else
|
18
|
-
define_method name do
|
19
|
-
ViewQuery.new(self.name.underscore, name, map_function(options[:key], options[:properties]), nil, {}, {:include_docs => true}).query_view!['rows'].map{|doc| self.new(doc['doc'])}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def map_function(key, properties)
|
26
|
-
"function(doc) {
|
27
|
-
emit(doc.#{key}, #{properties_for_map(properties)});
|
28
|
-
}"
|
29
|
-
end
|
30
|
-
|
31
|
-
def properties_for_map(properties)
|
32
|
-
if properties.nil?
|
33
|
-
'null'
|
34
|
-
else
|
35
|
-
'{' + properties.map{|p| "#{p}: doc.#{p}"}.join(', ') + '}'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/collection'
|
2
|
-
require File.dirname(__FILE__) + '/finder'
|
3
|
-
|
4
|
-
module CouchPotato
|
5
|
-
module Persistence
|
6
|
-
class ExternalCollection < Collection
|
7
|
-
|
8
|
-
attr_accessor :item_ids, :owner_id
|
9
|
-
|
10
|
-
def initialize(item_class, owner_id_attribute_name)
|
11
|
-
super item_class
|
12
|
-
@items = nil
|
13
|
-
@owner_id_attribute_name = owner_id_attribute_name
|
14
|
-
end
|
15
|
-
|
16
|
-
def all(options = {}, view_options = {})
|
17
|
-
if options.empty? && view_options.empty?
|
18
|
-
items
|
19
|
-
else
|
20
|
-
Finder.new.find @item_class, options.merge(@owner_id_attribute_name => @owner_id), view_options
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def first(options = {}, view_options = {})
|
25
|
-
if options.empty? && view_options.empty?
|
26
|
-
items.first
|
27
|
-
else
|
28
|
-
Finder.new.find(@item_class, options.merge(@owner_id_attribute_name => @owner_id), view_options).first
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def count(options = {}, view_options = {})
|
33
|
-
Finder.new.count @item_class, options.merge(@owner_id_attribute_name => @owner_id), view_options
|
34
|
-
end
|
35
|
-
|
36
|
-
def build(attributes = {})
|
37
|
-
item = @item_class.new(attributes)
|
38
|
-
self.<< item
|
39
|
-
item.send "#{@owner_id_attribute_name}=", owner_id
|
40
|
-
item
|
41
|
-
end
|
42
|
-
|
43
|
-
def create(attributes = {})
|
44
|
-
item = build(attributes)
|
45
|
-
item.save
|
46
|
-
item
|
47
|
-
end
|
48
|
-
|
49
|
-
def create!(attributes = {})
|
50
|
-
item = build(attributes)
|
51
|
-
item.save!
|
52
|
-
item
|
53
|
-
end
|
54
|
-
|
55
|
-
def dirty?
|
56
|
-
return unless @items
|
57
|
-
@original_item_ids != @items.map(&:_id) || @items.inject(false) {|res, item| res || item.dirty?}
|
58
|
-
end
|
59
|
-
|
60
|
-
def items
|
61
|
-
unless @items
|
62
|
-
@items = Finder.new.find @item_class, @owner_id_attribute_name => owner_id
|
63
|
-
@original_item_ids = @items.map(&:_id)
|
64
|
-
end
|
65
|
-
@items
|
66
|
-
end
|
67
|
-
|
68
|
-
def save
|
69
|
-
items.each do |item|
|
70
|
-
item.send "#{@owner_id_attribute_name}=", owner_id
|
71
|
-
item.save
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def destroy
|
76
|
-
items.each do |item|
|
77
|
-
item.destroy
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
@@ -1,72 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
class ExternalHasManyProperty
|
4
|
-
attr_accessor :name, :dependent
|
5
|
-
def initialize(owner_clazz, name, options = {})
|
6
|
-
@name, @owner_clazz = name, owner_clazz
|
7
|
-
@dependent = options[:dependent] || :nullify
|
8
|
-
getter = <<-ACCESORS
|
9
|
-
def #{name}
|
10
|
-
@#{name} ||= CouchPotato::Persistence::ExternalCollection.new(#{item_class_name}, :#{owner_clazz.name.underscore}_id)
|
11
|
-
end
|
12
|
-
|
13
|
-
def #{name}=(items)
|
14
|
-
items.each do |item|
|
15
|
-
#{name} << item
|
16
|
-
end
|
17
|
-
end
|
18
|
-
ACCESORS
|
19
|
-
owner_clazz.class_eval getter
|
20
|
-
end
|
21
|
-
|
22
|
-
def dirty?(object)
|
23
|
-
object.send("#{name}").dirty?
|
24
|
-
end
|
25
|
-
|
26
|
-
def save(object)
|
27
|
-
object.send(name).owner_id = object._id
|
28
|
-
object.send(name).each do |item|
|
29
|
-
item.send("#{@owner_clazz.name.underscore}_id=", object.id)
|
30
|
-
begin
|
31
|
-
item.bulk_save_queue.push_queue object.bulk_save_queue
|
32
|
-
item.save
|
33
|
-
ensure
|
34
|
-
item.bulk_save_queue.pop_queue
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def destroy(object)
|
40
|
-
object.send(name).each do |item|
|
41
|
-
if dependent == :destroy
|
42
|
-
begin
|
43
|
-
item.bulk_save_queue.push_queue object.bulk_save_queue
|
44
|
-
item.destroy
|
45
|
-
ensure
|
46
|
-
item.bulk_save_queue.pop_queue
|
47
|
-
end
|
48
|
-
else
|
49
|
-
item.send("#{@owner_clazz.name.underscore}_id=", nil)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def build(object, json)
|
55
|
-
collection = ExternalCollection.new(item_class_name.constantize, "#{@owner_clazz.name.underscore}_id")
|
56
|
-
collection.owner_id = object.id
|
57
|
-
object.send("#{name}").clear
|
58
|
-
object.send "#{name}=", collection
|
59
|
-
end
|
60
|
-
|
61
|
-
def serialize(json, object)
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def item_class_name
|
68
|
-
@name.to_s.singularize.camelcase
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
module Find
|
4
|
-
def first(options = {})
|
5
|
-
Finder.new.find(self, options).first
|
6
|
-
end
|
7
|
-
|
8
|
-
def last(options = {})
|
9
|
-
Finder.new.find(self, options, :descending => true).first
|
10
|
-
end
|
11
|
-
|
12
|
-
def all(options = {})
|
13
|
-
Finder.new.find(self, options)
|
14
|
-
end
|
15
|
-
|
16
|
-
def count(options = {})
|
17
|
-
Finder.new.count(self, options)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
|
3
|
-
module CouchPotato
|
4
|
-
module Persistence
|
5
|
-
class Finder
|
6
|
-
# finds all objects of a given type by the given attribute/value pairs
|
7
|
-
# options: attribute_name => value pairs to search for
|
8
|
-
# value can also be a range which will do a range search with startkey/endkey
|
9
|
-
# WARNING: calling this methods creates a new view in couchdb if it's not present already so don't overuse this
|
10
|
-
def find(clazz, conditions = {}, view_options = {})
|
11
|
-
to_instances clazz, ViewQuery.new(design_document(clazz), view(conditions), map_function(clazz, search_fields(conditions)), nil, conditions, view_options).query_view!
|
12
|
-
end
|
13
|
-
|
14
|
-
def count(clazz, conditions = {}, view_options = {})
|
15
|
-
ViewQuery.new(design_document(clazz), view(conditions) + '_count', map_function(clazz, search_fields(conditions)), count_reduce_function, conditions, view_options).query_view!['rows'].first.try(:[], 'value') || 0
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def db(name = nil)
|
21
|
-
::CouchPotato::Persistence.Db(name)
|
22
|
-
end
|
23
|
-
|
24
|
-
def design_document(clazz)
|
25
|
-
clazz.name.underscore
|
26
|
-
end
|
27
|
-
|
28
|
-
def map_function(clazz, search_fields)
|
29
|
-
"function(doc) {
|
30
|
-
if(doc.ruby_class == '#{clazz}') {
|
31
|
-
emit(
|
32
|
-
[#{search_fields.map{|attr| "doc[\"#{attr}\"]"}.join(', ')}], doc
|
33
|
-
);
|
34
|
-
}
|
35
|
-
}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def count_reduce_function
|
39
|
-
"function(keys, values, combine) {
|
40
|
-
if (combine) {
|
41
|
-
return sum(values);
|
42
|
-
} else {
|
43
|
-
return values.length;
|
44
|
-
}
|
45
|
-
}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_instances(clazz, query_result)
|
49
|
-
query_result['rows'].map{|doc| doc['value']}.map{|json| clazz.json_create json}
|
50
|
-
end
|
51
|
-
|
52
|
-
def view(conditions)
|
53
|
-
"by_#{view_name(conditions)}"
|
54
|
-
end
|
55
|
-
|
56
|
-
def search_fields(conditions)
|
57
|
-
conditions.to_a.sort_by{|f| f.first.to_s}.map(&:first)
|
58
|
-
end
|
59
|
-
|
60
|
-
def view_name(options)
|
61
|
-
options.to_a.sort_by{|f| f.first.to_s}.map(&:first).join('_and_')
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
class InlineHasManyProperty
|
2
|
-
attr_accessor :name
|
3
|
-
|
4
|
-
def initialize(owner_clazz, name, options = {})
|
5
|
-
@name = name
|
6
|
-
getter = <<-GETTER
|
7
|
-
def #{name}
|
8
|
-
@#{name} ||= CouchPotato::Persistence::InlineCollection.new(#{item_class_name})
|
9
|
-
end
|
10
|
-
GETTER
|
11
|
-
owner_clazz.class_eval getter
|
12
|
-
end
|
13
|
-
|
14
|
-
def build(object, json)
|
15
|
-
object.send("#{name}").clear
|
16
|
-
json[name.to_s].each do |item|
|
17
|
-
item.delete 'ruby_class'
|
18
|
-
object.send("#{name}").build item
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def dirty?(object)
|
23
|
-
object.send("#{name}").dirty?
|
24
|
-
end
|
25
|
-
|
26
|
-
def save(object)
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def serialize(json, object)
|
31
|
-
json[name.to_s] = object.send(name)
|
32
|
-
end
|
33
|
-
|
34
|
-
def destroy(object)
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def item_class_name
|
41
|
-
@name.to_s.singularize.camelcase
|
42
|
-
end
|
43
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Persistence
|
3
|
-
|
4
|
-
class ViewQuery
|
5
|
-
def initialize(design_document_name, view_name, map_function, reduce_function = nil, conditions = {}, view_options = {})
|
6
|
-
@design_document_name = design_document_name
|
7
|
-
@view_name = view_name
|
8
|
-
@map_function = map_function
|
9
|
-
@reduce_function = reduce_function
|
10
|
-
@conditions = conditions
|
11
|
-
@view_options = view_options
|
12
|
-
end
|
13
|
-
|
14
|
-
def query_view!
|
15
|
-
begin
|
16
|
-
query_view
|
17
|
-
rescue RestClient::ResourceNotFound => e
|
18
|
-
create_view
|
19
|
-
query_view
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
def create_view
|
26
|
-
# in couchdb 0.9 we could use only 1 view and pass reduce=false for find and count with reduce
|
27
|
-
design_doc = db.get "_design/#{@design_document_name}" rescue nil
|
28
|
-
design_doc ||= {'views' => {}, "_id" => "_design/#{@design_document_name}"}
|
29
|
-
design_doc['views'][@view_name.to_s] = {
|
30
|
-
'map' => @map_function,
|
31
|
-
'reduce' => @reduce_function
|
32
|
-
}
|
33
|
-
db.save(design_doc)
|
34
|
-
end
|
35
|
-
|
36
|
-
def db(name = nil)
|
37
|
-
::CouchPotato::Persistence.Db(name)
|
38
|
-
end
|
39
|
-
|
40
|
-
def query_view
|
41
|
-
db.view view_url, search_keys
|
42
|
-
end
|
43
|
-
|
44
|
-
def view_url
|
45
|
-
"#{@design_document_name}/#{@view_name}"
|
46
|
-
end
|
47
|
-
|
48
|
-
def search_keys
|
49
|
-
if search_values.select{|v| v.is_a?(Range)}.any?
|
50
|
-
{:startkey => search_values.map{|v| v.is_a?(Range) ? v.first : v}, :endkey => search_values.map{|v| v.is_a?(Range) ? v.last : v}}.merge(view_options)
|
51
|
-
elsif search_values.select{|v| v.is_a?(Array)}.any?
|
52
|
-
{:keys => prepare_multi_key_search(search_values)}.merge(view_options)
|
53
|
-
else
|
54
|
-
view_options.merge(search_values.any? ? {:key => search_values} : {})
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def search_values
|
59
|
-
conditions.to_a.sort_by{|f| f.first.to_s}.map(&:last)
|
60
|
-
end
|
61
|
-
|
62
|
-
def view_options
|
63
|
-
@view_options
|
64
|
-
end
|
65
|
-
|
66
|
-
def conditions
|
67
|
-
@conditions
|
68
|
-
end
|
69
|
-
|
70
|
-
def prepare_multi_key_search(values)
|
71
|
-
array = values.select{|v| v.is_a?(Array)}.first
|
72
|
-
index = values.index array
|
73
|
-
array.map do |item|
|
74
|
-
copy = values.dup
|
75
|
-
copy[index] = item
|
76
|
-
copy
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module CouchPotato
|
2
|
-
module Versioning
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
property :version
|
6
|
-
property :master_version_id
|
7
|
-
cattr_accessor :new_version_condition
|
8
|
-
before_create :set_version_default
|
9
|
-
before_update :prepare_for_new_version
|
10
|
-
|
11
|
-
def self.set_version_condition(lambda)
|
12
|
-
self.new_version_condition = lambda
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def versions(version_no = nil)
|
18
|
-
if version_no
|
19
|
-
CouchPotato::Persistence::Finder.new.find(self.class, :version => version_no).first
|
20
|
-
elsif version == 1
|
21
|
-
[self]
|
22
|
-
else
|
23
|
-
CouchPotato::Persistence::Finder.new.find(self.class, :master_version_id => _id).sort_by(&:version)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def set_version_default
|
30
|
-
self.version ||= 1
|
31
|
-
end
|
32
|
-
|
33
|
-
def prepare_for_new_version
|
34
|
-
if new_version_condition.nil? || new_version_condition.call(self)
|
35
|
-
copy = self.class.get self._id
|
36
|
-
copy._id = nil
|
37
|
-
copy._rev = nil
|
38
|
-
copy.master_version_id = self._id
|
39
|
-
copy.save_without_callbacks
|
40
|
-
self.master_version_id ||= self.id
|
41
|
-
self.version += 1
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
data/spec/attributes_spec.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
class Plant
|
4
|
-
include CouchPotato::Persistence
|
5
|
-
property :leaf_count
|
6
|
-
end
|
7
|
-
|
8
|
-
describe "attributes" do
|
9
|
-
before(:all) do
|
10
|
-
CouchPotato::Persistence.Db!
|
11
|
-
end
|
12
|
-
|
13
|
-
describe 'attributes=' do
|
14
|
-
it "should assign the attributes" do
|
15
|
-
plant = Plant.new
|
16
|
-
plant.attributes = {:leaf_count => 1}
|
17
|
-
plant.leaf_count.should == 1
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "attributes" do
|
22
|
-
it "should return the attributes" do
|
23
|
-
plant = Plant.new :leaf_count => 1
|
24
|
-
plant.attributes .should == {:leaf_count => 1}
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe 'update_attributes' do
|
29
|
-
it "should assign the attributes" do
|
30
|
-
plant = Plant.new
|
31
|
-
plant.update_attributes :leaf_count => 1
|
32
|
-
plant.leaf_count.should == 1
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should save the object" do
|
36
|
-
plant = Plant.new
|
37
|
-
plant.update_attributes :leaf_count => 1
|
38
|
-
plant.should_not be_new_document
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|