couchrest_model 1.1.0.beta5 → 1.1.0.rc1
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/Rakefile +9 -12
- data/VERSION +1 -1
- data/couchrest_model.gemspec +6 -6
- data/history.md +23 -0
- data/lib/couchrest/model/associations.rb +50 -54
- data/lib/couchrest/model/base.rb +10 -15
- data/lib/couchrest/model/casted_array.rb +16 -0
- data/lib/couchrest/model/class_proxy.rb +8 -1
- data/lib/couchrest/model/collection.rb +1 -0
- data/lib/couchrest/model/design_doc.rb +0 -2
- data/lib/couchrest/model/document_queries.rb +8 -8
- data/lib/couchrest/model/errors.rb +2 -0
- data/lib/couchrest/model/persistence.rb +20 -15
- data/lib/couchrest/model/properties.rb +17 -29
- data/lib/couchrest/model/property.rb +23 -7
- data/lib/couchrest/model/proxyable.rb +11 -4
- data/lib/couchrest/model/support/couchrest_database.rb +13 -0
- data/lib/couchrest/model/support/couchrest_design.rb +1 -1
- data/lib/couchrest/model/typecast.rb +1 -2
- data/lib/couchrest/model/validations/uniqueness.rb +29 -14
- data/lib/couchrest_model.rb +1 -1
- data/spec/couchrest/assocations_spec.rb +28 -1
- data/spec/couchrest/base_spec.rb +64 -26
- data/spec/couchrest/class_proxy_spec.rb +29 -0
- data/spec/couchrest/collection_spec.rb +6 -7
- data/spec/couchrest/design_doc_spec.rb +5 -1
- data/spec/couchrest/dirty_spec.rb +52 -0
- data/spec/couchrest/inherited_spec.rb +23 -30
- data/spec/couchrest/persistence_spec.rb +40 -18
- data/spec/couchrest/property_spec.rb +90 -4
- data/spec/couchrest/proxyable_spec.rb +14 -7
- data/spec/couchrest/validations_spec.rb +18 -1
- data/spec/fixtures/base.rb +4 -3
- data/spec/fixtures/more/article.rb +1 -0
- data/spec/fixtures/more/cat.rb +4 -0
- data/spec/fixtures/more/key_chain.rb +5 -0
- metadata +22 -21
data/Rakefile
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler'
|
3
|
-
|
4
|
-
|
5
|
-
require 'rake'
|
3
|
+
require 'rspec/core/rake_task'
|
6
4
|
require "rake/rdoctask"
|
7
5
|
|
8
|
-
|
9
|
-
require 'rspec/core/rake_task'
|
6
|
+
Bundler::GemHelper.install_tasks
|
10
7
|
|
11
8
|
desc "Run all specs"
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
10
|
+
spec.rspec_opts = ["--color"]
|
11
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
15
12
|
end
|
16
13
|
|
17
14
|
desc "Print specdocs"
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
RSpec::Core::RakeTask.new(:doc) do |spec|
|
16
|
+
spec.rspec_opts = ["--format", "specdoc"]
|
17
|
+
spec.pattern = 'spec/*_spec.rb'
|
21
18
|
end
|
22
19
|
|
23
20
|
desc "Generate the rdoc"
|
@@ -38,4 +35,4 @@ module Rake
|
|
38
35
|
end
|
39
36
|
|
40
37
|
Rake.remove_task("github:release")
|
41
|
-
Rake.remove_task("release")
|
38
|
+
Rake.remove_task("release")
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.0.
|
1
|
+
1.1.0.rc1
|
data/couchrest_model.gemspec
CHANGED
@@ -17,18 +17,18 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.homepage = %q{http://github.com/couchrest/couchrest_model}
|
18
18
|
s.rubygems_version = %q{1.3.7}
|
19
19
|
s.summary = %q{Extends the CouchRest Document for advanced modelling.}
|
20
|
-
|
20
|
+
|
21
21
|
s.files = `git ls-files`.split("\n")
|
22
22
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
23
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
24
|
s.require_paths = ["lib"]
|
25
|
-
|
26
|
-
s.add_dependency(%q<couchrest>, "1.1.0.
|
25
|
+
|
26
|
+
s.add_dependency(%q<couchrest>, "1.1.0.pre3")
|
27
27
|
s.add_dependency(%q<mime-types>, "~> 1.15")
|
28
|
-
s.add_dependency(%q<activemodel>, "~> 3.0
|
28
|
+
s.add_dependency(%q<activemodel>, "~> 3.0")
|
29
29
|
s.add_dependency(%q<tzinfo>, "~> 0.3.22")
|
30
|
-
s.
|
31
|
-
s.add_development_dependency(%q<
|
30
|
+
s.add_development_dependency(%q<rspec>, "~> 2.6.0")
|
31
|
+
s.add_development_dependency(%q<json>, ["~> 1.5.1"])
|
32
32
|
s.add_development_dependency(%q<rack-test>, ">= 0.5.7")
|
33
33
|
# s.add_development_dependency("jruby-openssl", ">= 0.7.3")
|
34
34
|
end
|
data/history.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# CouchRest Model Change History
|
2
2
|
|
3
|
+
## 1.1.0.rc - 2011-06-08
|
4
|
+
|
5
|
+
* New Features
|
6
|
+
* Properties with a nil value are now no longer sent to the database.
|
7
|
+
* Now possible to build new objects via CastedArray#build
|
8
|
+
* Implement #get! and #find! class methods
|
9
|
+
* Now is possible delete particular elements in casted array(Kostiantyn Kahanskyi)
|
10
|
+
|
11
|
+
* Minor fixes
|
12
|
+
* #as_json now correctly uses ActiveSupports methods.
|
13
|
+
* Rails 3.1 support (Peter Williams)
|
14
|
+
* Initialization blocks when creating new models (Peter Williams)
|
15
|
+
* Removed railties dependency (DAddYE)
|
16
|
+
* DesignDoc cache refreshed if a database is deleted.
|
17
|
+
* Fixing dirty tracking on collection_of association.
|
18
|
+
* Uniqueness Validation views created on initialization, not on demand!
|
19
|
+
* #destroy freezes object instead of removing _id and _rev, better for callbacks (pointer by karmi)
|
20
|
+
* #destroyed? method now available
|
21
|
+
* #reload no longer uses Hash#merge! which was causing issues with dirty tracking on casted models. (pointer by kostia)
|
22
|
+
* Non-property mass assignment on #new no longer possible without :directly_set_attributes option.
|
23
|
+
* Using CouchRest 1.1.0.pre3. (No more Hashes!)
|
24
|
+
* Fixing problem assigning a CastedHash to a property declared as a Hash (Kostiantyn Kahanskyi, gfmtim)
|
25
|
+
|
3
26
|
## 1.1.0.beta5 - 2011-04-30
|
4
27
|
|
5
28
|
* Major changes:
|
@@ -153,7 +153,7 @@ module CouchRest
|
|
153
153
|
def #{attrib}(reload = false)
|
154
154
|
return @#{attrib} unless @#{attrib}.nil? or reload
|
155
155
|
ary = self.#{options[:foreign_key]}.collect{|i| #{options[:proxy]}.get(i)}
|
156
|
-
@#{attrib} = ::CouchRest::CollectionOfProxy.new(ary,
|
156
|
+
@#{attrib} = ::CouchRest::Model::CollectionOfProxy.new(ary, find_property('#{options[:foreign_key]}'), self)
|
157
157
|
end
|
158
158
|
EOS
|
159
159
|
end
|
@@ -161,7 +161,7 @@ module CouchRest
|
|
161
161
|
def create_collection_of_setter(attrib, options)
|
162
162
|
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
163
163
|
def #{attrib}=(value)
|
164
|
-
@#{attrib} = ::CouchRest::CollectionOfProxy.new(value,
|
164
|
+
@#{attrib} = ::CouchRest::Model::CollectionOfProxy.new(value, find_property('#{options[:foreign_key]}'), self)
|
165
165
|
end
|
166
166
|
EOS
|
167
167
|
end
|
@@ -169,67 +169,63 @@ module CouchRest
|
|
169
169
|
end
|
170
170
|
|
171
171
|
end
|
172
|
-
end
|
173
172
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
173
|
+
# Special proxy for a collection of items so that adding and removing
|
174
|
+
# to the list automatically updates the associated property.
|
175
|
+
class CollectionOfProxy < CastedArray
|
176
|
+
|
177
|
+
def initialize(array, property, parent)
|
178
|
+
(array ||= []).compact!
|
179
|
+
super(array, property, parent)
|
180
|
+
casted_by[casted_by_property.to_s] = [] # replace the original array!
|
181
|
+
array.compact.each do |obj|
|
182
|
+
check_obj(obj)
|
183
|
+
casted_by[casted_by_property.to_s] << obj.id
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def << obj
|
186
188
|
check_obj(obj)
|
187
|
-
casted_by[
|
189
|
+
casted_by[casted_by_property.to_s] << obj.id
|
190
|
+
super(obj)
|
191
|
+
end
|
192
|
+
|
193
|
+
def push(obj)
|
194
|
+
check_obj(obj)
|
195
|
+
casted_by[casted_by_property.to_s].push obj.id
|
196
|
+
super(obj)
|
197
|
+
end
|
198
|
+
|
199
|
+
def unshift(obj)
|
200
|
+
check_obj(obj)
|
201
|
+
casted_by[casted_by_property.to_s].unshift obj.id
|
202
|
+
super(obj)
|
188
203
|
end
|
189
|
-
super(array)
|
190
|
-
end
|
191
|
-
|
192
|
-
def << obj
|
193
|
-
check_obj(obj)
|
194
|
-
casted_by[property.to_s] << obj.id
|
195
|
-
super(obj)
|
196
|
-
end
|
197
|
-
|
198
|
-
def push(obj)
|
199
|
-
check_obj(obj)
|
200
|
-
casted_by[property.to_s].push obj.id
|
201
|
-
super(obj)
|
202
|
-
end
|
203
|
-
|
204
|
-
def unshift(obj)
|
205
|
-
check_obj(obj)
|
206
|
-
casted_by[property.to_s].unshift obj.id
|
207
|
-
super(obj)
|
208
|
-
end
|
209
204
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
205
|
+
def []= index, obj
|
206
|
+
check_obj(obj)
|
207
|
+
casted_by[casted_by_property.to_s][index] = obj.id
|
208
|
+
super(index, obj)
|
209
|
+
end
|
215
210
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
211
|
+
def pop
|
212
|
+
casted_by[casted_by_property.to_s].pop
|
213
|
+
super
|
214
|
+
end
|
215
|
+
|
216
|
+
def shift
|
217
|
+
casted_by[casted_by_property.to_s].shift
|
218
|
+
super
|
219
|
+
end
|
225
220
|
|
226
|
-
|
221
|
+
protected
|
222
|
+
|
223
|
+
def check_obj(obj)
|
224
|
+
raise "Object cannot be added to #{casted_by.class.to_s}##{casted_by_property.to_s} collection unless saved" if obj.new?
|
225
|
+
end
|
227
226
|
|
228
|
-
def check_obj(obj)
|
229
|
-
raise "Object cannot be added to #{casted_by.class.to_s}##{property.to_s} collection unless saved" if obj.new?
|
230
227
|
end
|
231
228
|
|
232
229
|
end
|
233
230
|
|
234
|
-
|
235
231
|
end
|
data/lib/couchrest/model/base.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module CouchRest
|
2
2
|
module Model
|
3
|
-
class Base < Document
|
3
|
+
class Base < CouchRest::Document
|
4
4
|
|
5
5
|
extend ActiveModel::Naming
|
6
6
|
|
@@ -49,14 +49,19 @@ module CouchRest
|
|
49
49
|
# * :directly_set_attributes: true when data comes directly from database
|
50
50
|
# * :database: provide an alternative database
|
51
51
|
#
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
# If a block is provided the new model will be passed into the
|
53
|
+
# block so that it can be populated.
|
54
|
+
def initialize(attributes = {}, options = {})
|
55
|
+
super()
|
56
|
+
prepare_all_attributes(attributes, options)
|
57
|
+
# set the instance's database, if provided
|
55
58
|
self.database = options[:database] unless options[:database].nil?
|
56
|
-
super(doc)
|
57
59
|
unless self['_id'] && self['_rev']
|
58
60
|
self[self.model_type_key] = self.class.to_s
|
59
61
|
end
|
62
|
+
|
63
|
+
yield self if block_given?
|
64
|
+
|
60
65
|
after_initialize if respond_to?(:after_initialize)
|
61
66
|
end
|
62
67
|
|
@@ -75,16 +80,6 @@ module CouchRest
|
|
75
80
|
super
|
76
81
|
end
|
77
82
|
|
78
|
-
## Compatibility with ActiveSupport and older frameworks
|
79
|
-
|
80
|
-
# Hack so that CouchRest::Document, which descends from Hash,
|
81
|
-
# doesn't appear to Rails routing as a Hash of options
|
82
|
-
def is_a?(klass)
|
83
|
-
return false if klass == Hash
|
84
|
-
super
|
85
|
-
end
|
86
|
-
alias :kind_of? :is_a?
|
87
|
-
|
88
83
|
def persisted?
|
89
84
|
!new?
|
90
85
|
end
|
@@ -50,6 +50,22 @@ module CouchRest::Model
|
|
50
50
|
super
|
51
51
|
end
|
52
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
|
+
|
53
69
|
protected
|
54
70
|
|
55
71
|
def instantiate_and_cast(obj, change = true)
|
@@ -87,7 +87,14 @@ module CouchRest
|
|
87
87
|
doc
|
88
88
|
end
|
89
89
|
alias :find :get
|
90
|
-
|
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
|
+
|
91
98
|
# Views
|
92
99
|
|
93
100
|
def has_view?(view)
|
@@ -1,13 +1,10 @@
|
|
1
1
|
module CouchRest
|
2
2
|
module Model
|
3
3
|
module DocumentQueries
|
4
|
-
|
5
|
-
|
6
|
-
base.extend(ClassMethods)
|
7
|
-
end
|
8
|
-
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
9
6
|
module ClassMethods
|
10
|
-
|
7
|
+
|
11
8
|
# Load all documents that have the model_type_key's field equal to the
|
12
9
|
# name of the current class. Take the standard set of
|
13
10
|
# CouchRest::Database#view options.
|
@@ -73,7 +70,7 @@ module CouchRest
|
|
73
70
|
end
|
74
71
|
end
|
75
72
|
alias :find :get
|
76
|
-
|
73
|
+
|
77
74
|
# Load a document from the database by id
|
78
75
|
# An exception will be raised if the document isn't found
|
79
76
|
#
|
@@ -86,9 +83,12 @@ module CouchRest
|
|
86
83
|
# id<String, Integer>:: Document ID
|
87
84
|
# db<Database>:: optional option to pass a custom database to use
|
88
85
|
def get!(id, db = database)
|
89
|
-
raise
|
86
|
+
raise CouchRest::Model::DocumentNotFound if id.blank?
|
87
|
+
|
90
88
|
doc = db.get id
|
91
89
|
build_from_database(doc)
|
90
|
+
rescue RestClient::ResourceNotFound
|
91
|
+
raise CouchRest::Model::DocumentNotFound
|
92
92
|
end
|
93
93
|
alias :find! :get!
|
94
94
|
|
@@ -21,8 +21,8 @@ module CouchRest
|
|
21
21
|
|
22
22
|
# Creates the document in the db. Raises an exception
|
23
23
|
# if the document is not created properly.
|
24
|
-
def create!
|
25
|
-
self.class.fail_validate!(self) unless self.create
|
24
|
+
def create!(options = {})
|
25
|
+
self.class.fail_validate!(self) unless self.create(options)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Trigger the callbacks (before, after, around)
|
@@ -54,19 +54,21 @@ module CouchRest
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# Deletes the document from the database. Runs the :destroy callbacks.
|
57
|
-
# Removes the <tt>_id</tt> and <tt>_rev</tt> fields, preparing the
|
58
|
-
# document to be saved to a new <tt>_id</tt> if required.
|
59
57
|
def destroy
|
60
58
|
_run_destroy_callbacks do
|
61
59
|
result = database.delete_doc(self)
|
62
60
|
if result['ok']
|
63
|
-
|
64
|
-
self.
|
61
|
+
@_destroyed = true
|
62
|
+
self.freeze
|
65
63
|
end
|
66
64
|
result['ok']
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
68
|
+
def destroyed?
|
69
|
+
!!@_destroyed
|
70
|
+
end
|
71
|
+
|
70
72
|
# Update the document's attributes and save. For example:
|
71
73
|
#
|
72
74
|
# doc.update_attributes :name => "Fred"
|
@@ -85,7 +87,7 @@ module CouchRest
|
|
85
87
|
#
|
86
88
|
# Returns self.
|
87
89
|
def reload
|
88
|
-
|
90
|
+
prepare_all_attributes(database.get(id), :directly_set_attributes => true)
|
89
91
|
self
|
90
92
|
end
|
91
93
|
|
@@ -104,22 +106,25 @@ module CouchRest
|
|
104
106
|
|
105
107
|
module ClassMethods
|
106
108
|
|
107
|
-
# Creates a new instance, bypassing attribute protection
|
109
|
+
# Creates a new instance, bypassing attribute protection and
|
110
|
+
# uses the type field to determine which model to use to instanatiate
|
111
|
+
# the new object.
|
108
112
|
#
|
109
113
|
# ==== Returns
|
110
114
|
# a document instance
|
111
115
|
#
|
112
|
-
def build_from_database(doc = {})
|
113
|
-
|
114
|
-
base.
|
116
|
+
def build_from_database(doc = {}, options = {}, &block)
|
117
|
+
src = doc[model_type_key]
|
118
|
+
base = (src.blank? || src == self.to_s) ? self : src.constantize
|
119
|
+
base.new(doc, options.merge(:directly_set_attributes => true), &block)
|
115
120
|
end
|
116
121
|
|
117
122
|
# Defines an instance and save it directly to the database
|
118
123
|
#
|
119
124
|
# ==== Returns
|
120
125
|
# returns the reloaded document
|
121
|
-
def create(attributes = {})
|
122
|
-
instance = new(attributes)
|
126
|
+
def create(attributes = {}, &block)
|
127
|
+
instance = new(attributes, &block)
|
123
128
|
instance.create
|
124
129
|
instance
|
125
130
|
end
|
@@ -128,8 +133,8 @@ module CouchRest
|
|
128
133
|
#
|
129
134
|
# ==== Returns
|
130
135
|
# returns the reloaded document or raises an exception
|
131
|
-
def create!(attributes = {})
|
132
|
-
instance = new(attributes)
|
136
|
+
def create!(attributes = {}, &block)
|
137
|
+
instance = new(attributes, &block)
|
133
138
|
instance.create!
|
134
139
|
instance
|
135
140
|
end
|
@@ -5,25 +5,15 @@ module CouchRest
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
|
9
|
-
|
8
|
+
class_attribute(:properties) unless self.respond_to?(:properties)
|
9
|
+
class_attribute(:properties_by_name) unless self.respond_to?(:properties_by_name)
|
10
10
|
self.properties ||= []
|
11
11
|
self.properties_by_name ||= {}
|
12
12
|
raise "You can only mixin Properties in a class responding to [] and []=, if you tried to mixin CastedModel, make sure your class inherits from Hash or responds to the proper methods" unless (method_defined?(:[]) && method_defined?(:[]=))
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
# ==== Returns
|
18
|
-
# Array:: the list of properties for model's class
|
19
|
-
def properties
|
20
|
-
self.class.properties
|
21
|
-
end
|
22
|
-
|
23
|
-
# Returns all the class's properties as a Hash where the key is the name
|
24
|
-
# of the property.
|
25
|
-
def properties_by_name
|
26
|
-
self.class.properties_by_name
|
15
|
+
def as_json(options = nil)
|
16
|
+
Hash[self].reject{|k,v| v.nil?}.as_json(options)
|
27
17
|
end
|
28
18
|
|
29
19
|
# Returns the Class properties with their values
|
@@ -90,17 +80,18 @@ module CouchRest
|
|
90
80
|
self.disable_dirty = dirty
|
91
81
|
end
|
92
82
|
|
93
|
-
def prepare_all_attributes(
|
83
|
+
def prepare_all_attributes(attrs = {}, options = {})
|
94
84
|
self.disable_dirty = !!options[:directly_set_attributes]
|
95
85
|
apply_all_property_defaults
|
96
86
|
if options[:directly_set_attributes]
|
97
|
-
directly_set_read_only_attributes(
|
87
|
+
directly_set_read_only_attributes(attrs)
|
88
|
+
directly_set_attributes(attrs, true)
|
98
89
|
else
|
99
|
-
|
90
|
+
attrs = remove_protected_attributes(attrs)
|
91
|
+
directly_set_attributes(attrs)
|
100
92
|
end
|
101
|
-
res = doc.nil? ? doc : directly_set_attributes(doc)
|
102
93
|
self.disable_dirty = false
|
103
|
-
|
94
|
+
self
|
104
95
|
end
|
105
96
|
|
106
97
|
def find_property!(property)
|
@@ -111,16 +102,13 @@ module CouchRest
|
|
111
102
|
|
112
103
|
# Set all the attributes and return a hash with the attributes
|
113
104
|
# that have not been accepted.
|
114
|
-
def directly_set_attributes(hash)
|
115
|
-
hash.
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
elsif
|
120
|
-
self[
|
121
|
-
true
|
122
|
-
else
|
123
|
-
false
|
105
|
+
def directly_set_attributes(hash, mass_assign = false)
|
106
|
+
return if hash.nil?
|
107
|
+
hash.reject do |key, value|
|
108
|
+
if self.respond_to?("#{key}=")
|
109
|
+
self.send("#{key}=", value)
|
110
|
+
elsif mass_assign || mass_assign_any_attribute
|
111
|
+
self[key] = value
|
124
112
|
end
|
125
113
|
end
|
126
114
|
end
|
@@ -27,19 +27,15 @@ module CouchRest::Model
|
|
27
27
|
if value.nil?
|
28
28
|
value = []
|
29
29
|
elsif [Hash, HashWithIndifferentAccess].include?(value.class)
|
30
|
-
# Assume provided as a
|
31
|
-
|
32
|
-
value = [ ]
|
33
|
-
data.keys.sort.each do |k|
|
34
|
-
value << data[k]
|
35
|
-
end
|
30
|
+
# Assume provided as a params hash where key is index
|
31
|
+
value = parameter_hash_to_array(value)
|
36
32
|
elsif !value.is_a?(Array)
|
37
33
|
raise "Expecting an array or keyed hash for property #{parent.class.name}##{self.name}"
|
38
34
|
end
|
39
35
|
arr = value.collect { |data| cast_value(parent, data) }
|
40
36
|
# allow casted_by calls to be passed up chain by wrapping in CastedArray
|
41
37
|
CastedArray.new(arr, self, parent)
|
42
|
-
elsif (type == Object || type == Hash) && (value.
|
38
|
+
elsif (type == Object || type == Hash) && (value.is_a?(Hash))
|
43
39
|
# allow casted_by calls to be passed up chain by wrapping in CastedHash
|
44
40
|
CastedHash[value, self, parent]
|
45
41
|
elsif !value.nil?
|
@@ -64,8 +60,28 @@ module CouchRest::Model
|
|
64
60
|
end
|
65
61
|
end
|
66
62
|
|
63
|
+
# Initialize a new instance of a property's type ready to be
|
64
|
+
# used. If a proc is defined for the init method, it will be used instead of
|
65
|
+
# a normal call to the class.
|
66
|
+
def build(*args)
|
67
|
+
raise StandardError, "Cannot build property without a class" if @type_class.nil?
|
68
|
+
if @init_method.is_a?(Proc)
|
69
|
+
@init_method.call(*args)
|
70
|
+
else
|
71
|
+
@type_class.send(@init_method, *args)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
67
75
|
private
|
68
76
|
|
77
|
+
def parameter_hash_to_array(source)
|
78
|
+
value = [ ]
|
79
|
+
source.keys.each do |k|
|
80
|
+
value[k.to_i] = source[k]
|
81
|
+
end
|
82
|
+
value.compact
|
83
|
+
end
|
84
|
+
|
69
85
|
def associate_casted_value_to_parent(parent, value)
|
70
86
|
value.casted_by = parent if value.respond_to?(:casted_by)
|
71
87
|
value.casted_by_property = self if value.respond_to?(:casted_by_property)
|
@@ -73,12 +73,12 @@ module CouchRest
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# Base
|
76
|
-
def new(
|
77
|
-
|
76
|
+
def new(attrs = {}, options = {}, &block)
|
77
|
+
proxy_block_update(:new, attrs, options, &block)
|
78
78
|
end
|
79
79
|
|
80
|
-
def build_from_database(
|
81
|
-
|
80
|
+
def build_from_database(attrs = {}, options = {}, &block)
|
81
|
+
proxy_block_update(:build_from_database, attrs, options, &block)
|
82
82
|
end
|
83
83
|
|
84
84
|
def method_missing(m, *args, &block)
|
@@ -170,6 +170,13 @@ module CouchRest
|
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
|
+
def proxy_block_update(method, *args, &block)
|
174
|
+
model.send(method, *args) do |doc|
|
175
|
+
proxy_update(doc)
|
176
|
+
yield doc if block_given?
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
173
180
|
end
|
174
181
|
end
|
175
182
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#
|
2
|
+
# Extend CouchRest's normal database delete! method to ensure any caches are
|
3
|
+
# also emptied. Given that this is a rare event, and the consequences are not
|
4
|
+
# very severe, we just completely empty the cache.
|
5
|
+
#
|
6
|
+
CouchRest::Database.class_eval do
|
7
|
+
|
8
|
+
def delete!
|
9
|
+
Thread.current[:couchrest_design_cache] = { }
|
10
|
+
CouchRest.delete @root
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -18,7 +18,7 @@ CouchRest::Design.class_eval do
|
|
18
18
|
flatten =
|
19
19
|
lambda {|r|
|
20
20
|
(recurse = lambda {|v|
|
21
|
-
if v.is_a?(Hash)
|
21
|
+
if v.is_a?(Hash) || v.is_a?(CouchRest::Document)
|
22
22
|
v.to_a.map{|v| recurse.call(v)}.flatten
|
23
23
|
elsif v.is_a?(Array)
|
24
24
|
v.flatten.map{|v| recurse.call(v)}
|
@@ -14,8 +14,7 @@ module CouchRest
|
|
14
14
|
elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
|
15
15
|
send('typecast_to_'+klass.to_s.downcase, value)
|
16
16
|
else
|
17
|
-
|
18
|
-
property.init_method.is_a?(Proc) ? property.init_method.call(value) : klass.send(property.init_method, value)
|
17
|
+
property.build(value)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|