couchrest_model 1.1.0.beta5 → 1.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|