openlogic-couchrest_model 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +11 -0
- data/.rspec +4 -0
- data/Gemfile +4 -0
- data/LICENSE +176 -0
- data/README.md +137 -0
- data/Rakefile +38 -0
- data/THANKS.md +21 -0
- data/VERSION +1 -0
- data/benchmarks/dirty.rb +118 -0
- data/couchrest_model.gemspec +36 -0
- data/history.md +309 -0
- data/init.rb +1 -0
- data/lib/couchrest/model.rb +10 -0
- data/lib/couchrest/model/associations.rb +231 -0
- data/lib/couchrest/model/base.rb +129 -0
- data/lib/couchrest/model/callbacks.rb +28 -0
- data/lib/couchrest/model/casted_array.rb +83 -0
- data/lib/couchrest/model/casted_by.rb +33 -0
- data/lib/couchrest/model/casted_hash.rb +84 -0
- data/lib/couchrest/model/class_proxy.rb +135 -0
- data/lib/couchrest/model/collection.rb +273 -0
- data/lib/couchrest/model/configuration.rb +67 -0
- data/lib/couchrest/model/connection.rb +70 -0
- data/lib/couchrest/model/core_extensions/hash.rb +9 -0
- data/lib/couchrest/model/core_extensions/time_parsing.rb +66 -0
- data/lib/couchrest/model/design_doc.rb +128 -0
- data/lib/couchrest/model/designs.rb +91 -0
- data/lib/couchrest/model/designs/view.rb +513 -0
- data/lib/couchrest/model/dirty.rb +39 -0
- data/lib/couchrest/model/document_queries.rb +99 -0
- data/lib/couchrest/model/embeddable.rb +78 -0
- data/lib/couchrest/model/errors.rb +25 -0
- data/lib/couchrest/model/extended_attachments.rb +83 -0
- data/lib/couchrest/model/persistence.rb +178 -0
- data/lib/couchrest/model/properties.rb +228 -0
- data/lib/couchrest/model/property.rb +114 -0
- data/lib/couchrest/model/property_protection.rb +71 -0
- data/lib/couchrest/model/proxyable.rb +183 -0
- data/lib/couchrest/model/support/couchrest_database.rb +13 -0
- data/lib/couchrest/model/support/couchrest_design.rb +33 -0
- data/lib/couchrest/model/typecast.rb +154 -0
- data/lib/couchrest/model/validations.rb +80 -0
- data/lib/couchrest/model/validations/casted_model.rb +16 -0
- data/lib/couchrest/model/validations/locale/en.yml +5 -0
- data/lib/couchrest/model/validations/uniqueness.rb +69 -0
- data/lib/couchrest/model/views.rb +151 -0
- data/lib/couchrest/railtie.rb +24 -0
- data/lib/couchrest_model.rb +66 -0
- data/lib/rails/generators/couchrest_model.rb +16 -0
- data/lib/rails/generators/couchrest_model/config/config_generator.rb +18 -0
- data/lib/rails/generators/couchrest_model/config/templates/couchdb.yml +21 -0
- data/lib/rails/generators/couchrest_model/model/model_generator.rb +27 -0
- data/lib/rails/generators/couchrest_model/model/templates/model.rb +2 -0
- data/spec/.gitignore +1 -0
- data/spec/fixtures/attachments/README +3 -0
- data/spec/fixtures/attachments/couchdb.png +0 -0
- data/spec/fixtures/attachments/test.html +11 -0
- data/spec/fixtures/config/couchdb.yml +10 -0
- data/spec/fixtures/models/article.rb +36 -0
- data/spec/fixtures/models/base.rb +164 -0
- data/spec/fixtures/models/card.rb +19 -0
- data/spec/fixtures/models/cat.rb +23 -0
- data/spec/fixtures/models/client.rb +6 -0
- data/spec/fixtures/models/course.rb +27 -0
- data/spec/fixtures/models/event.rb +8 -0
- data/spec/fixtures/models/invoice.rb +14 -0
- data/spec/fixtures/models/key_chain.rb +5 -0
- data/spec/fixtures/models/membership.rb +4 -0
- data/spec/fixtures/models/person.rb +11 -0
- data/spec/fixtures/models/project.rb +6 -0
- data/spec/fixtures/models/question.rb +7 -0
- data/spec/fixtures/models/sale_entry.rb +9 -0
- data/spec/fixtures/models/sale_invoice.rb +14 -0
- data/spec/fixtures/models/service.rb +10 -0
- data/spec/fixtures/models/user.rb +22 -0
- data/spec/fixtures/views/lib.js +3 -0
- data/spec/fixtures/views/test_view/lib.js +3 -0
- data/spec/fixtures/views/test_view/only-map.js +4 -0
- data/spec/fixtures/views/test_view/test-map.js +3 -0
- data/spec/fixtures/views/test_view/test-reduce.js +3 -0
- data/spec/functional/validations_spec.rb +8 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/unit/active_model_lint_spec.rb +30 -0
- data/spec/unit/assocations_spec.rb +242 -0
- data/spec/unit/attachment_spec.rb +176 -0
- data/spec/unit/base_spec.rb +537 -0
- data/spec/unit/casted_spec.rb +72 -0
- data/spec/unit/class_proxy_spec.rb +167 -0
- data/spec/unit/collection_spec.rb +86 -0
- data/spec/unit/configuration_spec.rb +77 -0
- data/spec/unit/connection_spec.rb +148 -0
- data/spec/unit/core_extensions/time_parsing.rb +77 -0
- data/spec/unit/design_doc_spec.rb +241 -0
- data/spec/unit/designs/view_spec.rb +831 -0
- data/spec/unit/designs_spec.rb +134 -0
- data/spec/unit/dirty_spec.rb +436 -0
- data/spec/unit/embeddable_spec.rb +498 -0
- data/spec/unit/inherited_spec.rb +33 -0
- data/spec/unit/persistence_spec.rb +481 -0
- data/spec/unit/property_protection_spec.rb +192 -0
- data/spec/unit/property_spec.rb +481 -0
- data/spec/unit/proxyable_spec.rb +376 -0
- data/spec/unit/subclass_spec.rb +85 -0
- data/spec/unit/typecast_spec.rb +521 -0
- data/spec/unit/validations_spec.rb +140 -0
- data/spec/unit/view_spec.rb +367 -0
- metadata +301 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module CouchRest
|
|
2
|
+
module Model
|
|
3
|
+
class Base < CouchRest::Document
|
|
4
|
+
|
|
5
|
+
extend ActiveModel::Naming
|
|
6
|
+
|
|
7
|
+
include CouchRest::Model::Configuration
|
|
8
|
+
include CouchRest::Model::Connection
|
|
9
|
+
include CouchRest::Model::Persistence
|
|
10
|
+
include CouchRest::Model::DocumentQueries
|
|
11
|
+
include CouchRest::Model::Views
|
|
12
|
+
include CouchRest::Model::DesignDoc
|
|
13
|
+
include CouchRest::Model::ExtendedAttachments
|
|
14
|
+
include CouchRest::Model::ClassProxy
|
|
15
|
+
include CouchRest::Model::Proxyable
|
|
16
|
+
include CouchRest::Model::Collection
|
|
17
|
+
include CouchRest::Model::PropertyProtection
|
|
18
|
+
include CouchRest::Model::Associations
|
|
19
|
+
include CouchRest::Model::Validations
|
|
20
|
+
include CouchRest::Model::Callbacks
|
|
21
|
+
include CouchRest::Model::Designs
|
|
22
|
+
include CouchRest::Model::CastedBy
|
|
23
|
+
include CouchRest::Model::Dirty
|
|
24
|
+
include CouchRest::Model::Callbacks
|
|
25
|
+
|
|
26
|
+
def self.subclasses
|
|
27
|
+
@subclasses ||= []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.inherited(subklass)
|
|
31
|
+
super
|
|
32
|
+
subklass.send(:include, CouchRest::Model::Properties)
|
|
33
|
+
|
|
34
|
+
subklass.class_eval <<-EOS, __FILE__, __LINE__ + 1
|
|
35
|
+
def self.inherited(subklass)
|
|
36
|
+
super
|
|
37
|
+
subklass.properties = self.properties.dup
|
|
38
|
+
# This is nasty:
|
|
39
|
+
subklass._validators = self._validators.dup
|
|
40
|
+
end
|
|
41
|
+
EOS
|
|
42
|
+
subclasses << subklass
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Instantiate a new CouchRest::Model::Base by preparing all properties
|
|
46
|
+
# using the provided document hash.
|
|
47
|
+
#
|
|
48
|
+
# Options supported:
|
|
49
|
+
#
|
|
50
|
+
# * :directly_set_attributes, true when data comes directly from database
|
|
51
|
+
# * :database, provide an alternative database
|
|
52
|
+
#
|
|
53
|
+
# If a block is provided the new model will be passed into the
|
|
54
|
+
# block so that it can be populated.
|
|
55
|
+
def initialize(attributes = {}, options = {})
|
|
56
|
+
super()
|
|
57
|
+
prepare_all_attributes(attributes, options)
|
|
58
|
+
# set the instance's database, if provided
|
|
59
|
+
self.database = options[:database] unless options[:database].nil?
|
|
60
|
+
unless self['_id'] && self['_rev']
|
|
61
|
+
self[self.model_type_key] = self.class.to_s
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
yield self if block_given?
|
|
65
|
+
|
|
66
|
+
after_initialize if respond_to?(:after_initialize)
|
|
67
|
+
run_callbacks(:initialize) { self }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Temp solution to make the view_by methods available
|
|
72
|
+
def self.method_missing(m, *args, &block)
|
|
73
|
+
if has_view?(m)
|
|
74
|
+
query = args.shift || {}
|
|
75
|
+
return view(m, query, *args, &block)
|
|
76
|
+
elsif m.to_s =~ /^find_(by_.+)/
|
|
77
|
+
view_name = $1
|
|
78
|
+
if has_view?(view_name)
|
|
79
|
+
return first_from_view(view_name, *args)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
super
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# compatbility for 1.8, it does not use respond_to_missing?
|
|
86
|
+
# thing is, when using it like this only, doing method(:find_by_view)
|
|
87
|
+
# will throw an error
|
|
88
|
+
def self.respond_to?(m, include_private = false)
|
|
89
|
+
super || respond_to_missing?(m, include_private)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# ruby 1.9 feature
|
|
93
|
+
# this allows ruby to know that the method is defined using
|
|
94
|
+
# method_missing, and as such, method(:find_by_view) will actually
|
|
95
|
+
# give a Method back, and not throw an error like in 1.8!
|
|
96
|
+
def self.respond_to_missing?(m, include_private = false)
|
|
97
|
+
has_view?(m) || has_view?(m.to_s[/^find_(by_.+)/, 1])
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def to_key
|
|
101
|
+
new? ? nil : [id]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
alias :to_param :id
|
|
105
|
+
alias :new_record? :new?
|
|
106
|
+
alias :new_document? :new?
|
|
107
|
+
|
|
108
|
+
# Compare this model with another by confirming to see
|
|
109
|
+
# if the IDs and their databases match!
|
|
110
|
+
#
|
|
111
|
+
# Camparison of the database is required in case the
|
|
112
|
+
# model has been proxied or loaded elsewhere.
|
|
113
|
+
#
|
|
114
|
+
# A Basic CouchRest document will only ever compare using
|
|
115
|
+
# a Hash comparison on the attributes.
|
|
116
|
+
def == other
|
|
117
|
+
return false unless other.is_a?(Base)
|
|
118
|
+
if id.nil? && other.id.nil?
|
|
119
|
+
# no ids? assume comparing nested and revert to hash comparison
|
|
120
|
+
to_hash == other.to_hash
|
|
121
|
+
else
|
|
122
|
+
database == other.database && id == other.id
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
alias :eql? :==
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module CouchRest #:nodoc:
|
|
4
|
+
module Model #:nodoc:
|
|
5
|
+
|
|
6
|
+
module Callbacks
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
CALLBACKS = [
|
|
10
|
+
:before_validation, :after_validation,
|
|
11
|
+
:after_initialize,
|
|
12
|
+
:before_create, :around_create, :after_create,
|
|
13
|
+
:before_destroy, :around_destroy, :after_destroy,
|
|
14
|
+
:before_save, :around_save, :after_save,
|
|
15
|
+
:before_update, :around_update, :after_update,
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
included do
|
|
19
|
+
extend ActiveModel::Callbacks
|
|
20
|
+
include ActiveModel::Validations::Callbacks
|
|
21
|
+
|
|
22
|
+
define_model_callbacks :initialize, :only => :after
|
|
23
|
+
define_model_callbacks :create, :destroy, :save, :update
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Wrapper around Array so that the casted_by attribute is set in all
|
|
3
|
+
# elements of the array.
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
module CouchRest::Model
|
|
7
|
+
class CastedArray < Array
|
|
8
|
+
include CouchRest::Model::CastedBy
|
|
9
|
+
include CouchRest::Model::Dirty
|
|
10
|
+
attr_accessor :casted_by_property
|
|
11
|
+
|
|
12
|
+
def initialize(array, property, parent = nil)
|
|
13
|
+
self.casted_by_property = property
|
|
14
|
+
self.casted_by = parent unless parent.nil?
|
|
15
|
+
super(array)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Adding new entries
|
|
19
|
+
|
|
20
|
+
def << obj
|
|
21
|
+
super(instantiate_and_cast(obj))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def push(obj)
|
|
25
|
+
super(instantiate_and_cast(obj))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def unshift(obj)
|
|
29
|
+
super(instantiate_and_cast(obj))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def []= index, obj
|
|
33
|
+
value = instantiate_and_cast(obj, false)
|
|
34
|
+
couchrest_parent_will_change! if use_dirty? && value != self[index]
|
|
35
|
+
super(index, value)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def pop
|
|
39
|
+
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def shift
|
|
44
|
+
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def clear
|
|
49
|
+
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
|
50
|
+
super
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def delete(obj)
|
|
54
|
+
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
|
55
|
+
super(obj)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def delete_at(index)
|
|
59
|
+
couchrest_parent_will_change! if use_dirty? && self.length > 0
|
|
60
|
+
super(index)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def build(*args)
|
|
64
|
+
obj = casted_by_property.build(*args)
|
|
65
|
+
self.push(obj)
|
|
66
|
+
obj
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
protected
|
|
70
|
+
|
|
71
|
+
def instantiate_and_cast(obj, change = true)
|
|
72
|
+
property = casted_by_property
|
|
73
|
+
couchrest_parent_will_change! if change && use_dirty?
|
|
74
|
+
if casted_by && property && obj.class != property.type_class
|
|
75
|
+
property.cast_value(casted_by, obj)
|
|
76
|
+
else
|
|
77
|
+
obj.casted_by = casted_by if obj.respond_to?(:casted_by)
|
|
78
|
+
obj.casted_by_property = casted_by_property if obj.respond_to?(:casted_by_property)
|
|
79
|
+
obj
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
module CouchRest::Model
|
|
3
|
+
module CastedBy
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
self.send(:attr_accessor, :casted_by)
|
|
7
|
+
self.send(:attr_accessor, :casted_by_property)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Gets a reference to the actual document in the DB
|
|
11
|
+
# Calls up to the next document if there is one,
|
|
12
|
+
# Otherwise we're at the top and we return self
|
|
13
|
+
def base_doc
|
|
14
|
+
return self if base_doc?
|
|
15
|
+
casted_by ? casted_by.base_doc : nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Checks if we're the top document
|
|
19
|
+
def base_doc?
|
|
20
|
+
!casted_by
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Provide the property this casted model instance has been
|
|
24
|
+
# used by. If it has not been set, search through the
|
|
25
|
+
# casted_by objects properties to try and find it.
|
|
26
|
+
#def casted_by_property
|
|
27
|
+
# return nil unless casted_by
|
|
28
|
+
# attrs = casted_by.attributes
|
|
29
|
+
# @casted_by_property ||= casted_by.properties.detect{ |k| attrs[k.to_s] === self }
|
|
30
|
+
#end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Wrapper around Hash so that the casted_by attribute is set.
|
|
3
|
+
|
|
4
|
+
module CouchRest::Model
|
|
5
|
+
class CastedHash < Hash
|
|
6
|
+
include CouchRest::Model::CastedBy
|
|
7
|
+
include CouchRest::Model::Dirty
|
|
8
|
+
attr_accessor :casted_by_property
|
|
9
|
+
|
|
10
|
+
def self.[](hash, property, parent = nil)
|
|
11
|
+
obj = super(hash)
|
|
12
|
+
obj.casted_by_property = property
|
|
13
|
+
obj.casted_by = parent unless parent.nil?
|
|
14
|
+
obj
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# needed for dirty
|
|
18
|
+
def attributes
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def []= key, obj
|
|
23
|
+
couchrest_attribute_will_change!(key) if use_dirty? && obj != self[key]
|
|
24
|
+
super(key, obj)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def delete(key)
|
|
28
|
+
couchrest_attribute_will_change!(key) if use_dirty? && include?(key)
|
|
29
|
+
super(key)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def merge!(other_hash)
|
|
33
|
+
if use_dirty? && other_hash && other_hash.kind_of?(Hash)
|
|
34
|
+
other_hash.keys.each do |key|
|
|
35
|
+
if self[key] != other_hash[key] || !include?(key)
|
|
36
|
+
couchrest_attribute_will_change!(key)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
super(other_hash)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def replace(other_hash)
|
|
44
|
+
if use_dirty? && other_hash && other_hash.kind_of?(Hash)
|
|
45
|
+
# new keys and changed keys
|
|
46
|
+
other_hash.keys.each do |key|
|
|
47
|
+
if self[key] != other_hash[key] || !include?(key)
|
|
48
|
+
couchrest_attribute_will_change!(key)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
# old keys
|
|
52
|
+
old_keys = self.keys.reject { |key| other_hash.include?(key) }
|
|
53
|
+
old_keys.each { |key| couchrest_attribute_will_change!(key) }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
super(other_hash)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def clear
|
|
60
|
+
self.keys.each { |key| couchrest_attribute_will_change!(key) } if use_dirty?
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def delete_if
|
|
65
|
+
if use_dirty? && block_given?
|
|
66
|
+
self.keys.each do |key|
|
|
67
|
+
couchrest_attribute_will_change!(key) if yield key, self[key]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
super
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# ruby 1.9
|
|
74
|
+
def keep_if
|
|
75
|
+
if use_dirty? && block_given?
|
|
76
|
+
self.keys.each do |key|
|
|
77
|
+
couchrest_attribute_will_change!(key) if !yield key, self[key]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
super
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
module CouchRest
|
|
2
|
+
module Model
|
|
3
|
+
module ClassProxy
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
|
|
11
|
+
# Return a proxy object which represents a model class on a
|
|
12
|
+
# chosen database instance. This allows you to DRY operations
|
|
13
|
+
# where a database is chosen dynamically.
|
|
14
|
+
#
|
|
15
|
+
# ==== Example:
|
|
16
|
+
#
|
|
17
|
+
# db = CouchRest::Database.new(...)
|
|
18
|
+
# articles = Article.on(db)
|
|
19
|
+
#
|
|
20
|
+
# articles.all { ... }
|
|
21
|
+
# articles.by_title { ... }
|
|
22
|
+
#
|
|
23
|
+
# u = articles.get("someid")
|
|
24
|
+
#
|
|
25
|
+
# u = articles.new(:title => "I like plankton")
|
|
26
|
+
# u.save # saved on the correct database
|
|
27
|
+
|
|
28
|
+
def on(database)
|
|
29
|
+
Proxy.new(self, database)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Proxy #:nodoc:
|
|
34
|
+
def initialize(klass, database)
|
|
35
|
+
@klass = klass
|
|
36
|
+
@database = database
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Base
|
|
40
|
+
|
|
41
|
+
def new(*args)
|
|
42
|
+
doc = @klass.new(*args)
|
|
43
|
+
doc.database = @database
|
|
44
|
+
doc
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(m, *args, &block)
|
|
48
|
+
if has_view?(m)
|
|
49
|
+
query = args.shift || {}
|
|
50
|
+
return view(m, query, *args, &block)
|
|
51
|
+
elsif m.to_s =~ /^find_(by_.+)/
|
|
52
|
+
view_name = $1
|
|
53
|
+
if has_view?(view_name)
|
|
54
|
+
return first_from_view(view_name, *args)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# DocumentQueries
|
|
61
|
+
|
|
62
|
+
def all(opts = {}, &block)
|
|
63
|
+
docs = @klass.all({:database => @database}.merge(opts), &block)
|
|
64
|
+
docs.each { |doc| doc.database = @database if doc.respond_to?(:database) } if docs
|
|
65
|
+
docs
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def count(opts = {}, &block)
|
|
69
|
+
@klass.all({:database => @database, :raw => true, :limit => 0}.merge(opts), &block)['total_rows']
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def first(opts = {})
|
|
73
|
+
doc = @klass.first({:database => @database}.merge(opts))
|
|
74
|
+
doc.database = @database if doc && doc.respond_to?(:database)
|
|
75
|
+
doc
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def last(opts = {})
|
|
79
|
+
doc = @klass.last({:database => @database}.merge(opts))
|
|
80
|
+
doc.database = @database if doc && doc.respond_to?(:database)
|
|
81
|
+
doc
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def get(id)
|
|
85
|
+
doc = @klass.get(id, @database)
|
|
86
|
+
doc.database = @database if doc && doc.respond_to?(:database)
|
|
87
|
+
doc
|
|
88
|
+
end
|
|
89
|
+
alias :find :get
|
|
90
|
+
|
|
91
|
+
def get!(id)
|
|
92
|
+
doc = @klass.get!(id, @database)
|
|
93
|
+
doc.database = @database if doc && doc.respond_to?(:database)
|
|
94
|
+
doc
|
|
95
|
+
end
|
|
96
|
+
alias :find! :get!
|
|
97
|
+
|
|
98
|
+
# Views
|
|
99
|
+
|
|
100
|
+
def has_view?(view)
|
|
101
|
+
@klass.has_view?(view)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def view(name, query={}, &block)
|
|
105
|
+
docs = @klass.view(name, {:database => @database}.merge(query), &block)
|
|
106
|
+
docs.each { |doc| doc.database = @database if doc.respond_to?(:database) } if docs
|
|
107
|
+
docs
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def first_from_view(name, *args)
|
|
111
|
+
# add to first hash available, or add to end
|
|
112
|
+
(args.last.is_a?(Hash) ? args.last : (args << {}).last)[:database] = @database
|
|
113
|
+
doc = @klass.first_from_view(name, *args)
|
|
114
|
+
doc.database = @database if doc && doc.respond_to?(:database)
|
|
115
|
+
doc
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# DesignDoc
|
|
119
|
+
|
|
120
|
+
def design_doc
|
|
121
|
+
@klass.design_doc
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def refresh_design_doc
|
|
125
|
+
@klass.refresh_design_doc(@database)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def save_design_doc
|
|
129
|
+
@klass.save_design_doc(@database)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|