couchrest_model 2.1.0.rc1 → 2.2.0.beta1
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 +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +15 -4
- data/Gemfile.activesupport-4.x +4 -0
- data/Gemfile.activesupport-5.x +4 -0
- data/README.md +2 -0
- data/VERSION +1 -1
- data/couchrest_model.gemspec +3 -2
- data/history.md +14 -1
- data/lib/couchrest/model/associations.rb +3 -8
- data/lib/couchrest/model/base.rb +15 -7
- data/lib/couchrest/model/casted_array.rb +22 -34
- data/lib/couchrest/model/configuration.rb +2 -0
- data/lib/couchrest/model/design.rb +4 -3
- data/lib/couchrest/model/designs/view.rb +37 -32
- data/lib/couchrest/model/dirty.rb +93 -19
- data/lib/couchrest/model/embeddable.rb +2 -14
- data/lib/couchrest/model/extended_attachments.rb +2 -4
- data/lib/couchrest/model/persistence.rb +14 -17
- data/lib/couchrest/model/properties.rb +46 -54
- data/lib/couchrest/model/property.rb +0 -3
- data/lib/couchrest/model/proxyable.rb +20 -4
- data/lib/couchrest/model/validations/uniqueness.rb +4 -1
- data/lib/couchrest_model.rb +2 -2
- data/spec/fixtures/models/article.rb +1 -1
- data/spec/fixtures/models/card.rb +2 -1
- data/spec/fixtures/models/person.rb +1 -0
- data/spec/fixtures/models/project.rb +3 -0
- data/spec/unit/assocations_spec.rb +73 -73
- data/spec/unit/attachment_spec.rb +34 -34
- data/spec/unit/base_spec.rb +102 -102
- data/spec/unit/casted_array_spec.rb +7 -7
- data/spec/unit/casted_spec.rb +7 -7
- data/spec/unit/configuration_spec.rb +11 -11
- data/spec/unit/connection_spec.rb +30 -30
- data/spec/unit/core_extensions/{time_parsing.rb → time_parsing_spec.rb} +21 -21
- data/spec/unit/design_spec.rb +38 -38
- data/spec/unit/designs/design_mapper_spec.rb +26 -26
- data/spec/unit/designs/migrations_spec.rb +13 -13
- data/spec/unit/designs/view_spec.rb +319 -274
- data/spec/unit/designs_spec.rb +39 -39
- data/spec/unit/dirty_spec.rb +188 -103
- data/spec/unit/embeddable_spec.rb +119 -117
- data/spec/unit/inherited_spec.rb +4 -4
- data/spec/unit/persistence_spec.rb +122 -122
- data/spec/unit/properties_spec.rb +466 -16
- data/spec/unit/property_protection_spec.rb +32 -32
- data/spec/unit/property_spec.rb +45 -436
- data/spec/unit/proxyable_spec.rb +140 -82
- data/spec/unit/subclass_spec.rb +14 -14
- data/spec/unit/translations_spec.rb +5 -5
- data/spec/unit/typecast_spec.rb +131 -131
- data/spec/unit/utils/migrate_spec.rb +2 -2
- data/spec/unit/validations_spec.rb +31 -31
- metadata +27 -12
- data/lib/couchrest/model/casted_hash.rb +0 -84
@@ -4,9 +4,12 @@ module CouchRest
|
|
4
4
|
module Proxyable
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
-
def proxy_database
|
7
|
+
def proxy_database(assoc_name)
|
8
8
|
raise StandardError, "Please set the #proxy_database_method" if self.class.proxy_database_method.nil?
|
9
|
-
|
9
|
+
db_name = self.send(self.class.proxy_database_method)
|
10
|
+
db_suffix = self.class.proxy_database_suffixes[assoc_name.to_sym]
|
11
|
+
@proxy_databases ||= {}
|
12
|
+
@proxy_databases[assoc_name.to_sym] ||= self.class.prepare_database([db_name, db_suffix].compact.reject(&:blank?).join(self.class.connection[:join]))
|
10
13
|
end
|
11
14
|
|
12
15
|
module ClassMethods
|
@@ -15,13 +18,16 @@ module CouchRest
|
|
15
18
|
# Define a collection that will use the base model for the database connection
|
16
19
|
# details.
|
17
20
|
def proxy_for(assoc_name, options = {})
|
18
|
-
db_method = options[:database_method] || "proxy_database"
|
21
|
+
db_method = (options[:database_method] || "proxy_database").to_sym
|
22
|
+
db_suffix = options[:database_suffix] || (options[:use_suffix] ? assoc_name.to_s : nil)
|
19
23
|
options[:class_name] ||= assoc_name.to_s.singularize.camelize
|
20
24
|
proxy_method_names << assoc_name.to_sym unless proxy_method_names.include?(assoc_name.to_sym)
|
21
25
|
proxied_model_names << options[:class_name] unless proxied_model_names.include?(options[:class_name])
|
26
|
+
proxy_database_suffixes[assoc_name.to_sym] = db_suffix
|
27
|
+
db_method_call = "#{db_method}(:#{assoc_name.to_s})"
|
22
28
|
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
23
29
|
def #{assoc_name}
|
24
|
-
@#{assoc_name} ||= CouchRest::Model::Proxyable::ModelProxy.new(::#{options[:class_name]}, self, self.class.to_s.underscore, #{
|
30
|
+
@#{assoc_name} ||= CouchRest::Model::Proxyable::ModelProxy.new(::#{options[:class_name]}, self, self.class.to_s.underscore, #{db_method_call})
|
25
31
|
end
|
26
32
|
EOS
|
27
33
|
end
|
@@ -57,6 +63,10 @@ module CouchRest
|
|
57
63
|
@proxied_model_names ||= []
|
58
64
|
end
|
59
65
|
|
66
|
+
def proxy_database_suffixes
|
67
|
+
@proxy_database_suffixes ||= {}
|
68
|
+
end
|
69
|
+
|
60
70
|
private
|
61
71
|
|
62
72
|
# Ensure that no attempt is made to autoload a database connection
|
@@ -156,6 +166,12 @@ module CouchRest
|
|
156
166
|
end
|
157
167
|
end
|
158
168
|
|
169
|
+
private
|
170
|
+
|
171
|
+
def method_missing(m, *args, &block)
|
172
|
+
model.respond_to?(m) ? model.send(m, self, *args, &block) : super
|
173
|
+
end
|
174
|
+
|
159
175
|
end
|
160
176
|
end
|
161
177
|
end
|
data/lib/couchrest_model.rb
CHANGED
@@ -17,6 +17,7 @@ require "enumerator"
|
|
17
17
|
require "time"
|
18
18
|
require "digest/md5"
|
19
19
|
require "yaml"
|
20
|
+
require "hashdiff"
|
20
21
|
|
21
22
|
require "bigdecimal" # used in typecast
|
22
23
|
require "bigdecimal/util" # used in typecast
|
@@ -25,6 +26,7 @@ require "couchrest"
|
|
25
26
|
|
26
27
|
require "couchrest/model"
|
27
28
|
require "couchrest/model/errors"
|
29
|
+
require "couchrest/model/configuration"
|
28
30
|
require "couchrest/model/translation"
|
29
31
|
require "couchrest/model/persistence"
|
30
32
|
require "couchrest/model/typecast"
|
@@ -34,14 +36,12 @@ require "couchrest/model/property"
|
|
34
36
|
require "couchrest/model/property_protection"
|
35
37
|
require "couchrest/model/properties"
|
36
38
|
require "couchrest/model/casted_array"
|
37
|
-
require "couchrest/model/casted_hash"
|
38
39
|
require "couchrest/model/validations"
|
39
40
|
require "couchrest/model/callbacks"
|
40
41
|
require "couchrest/model/document_queries"
|
41
42
|
require "couchrest/model/extended_attachments"
|
42
43
|
require "couchrest/model/proxyable"
|
43
44
|
require "couchrest/model/associations"
|
44
|
-
require "couchrest/model/configuration"
|
45
45
|
require "couchrest/model/connection"
|
46
46
|
require "couchrest/model/designs/migrations"
|
47
47
|
require "couchrest/model/designs/design_mapper"
|
@@ -33,6 +33,6 @@ class Article < CouchRest::Model::Base
|
|
33
33
|
before_save :generate_slug_from_title
|
34
34
|
|
35
35
|
def generate_slug_from_title
|
36
|
-
self['slug'] = title.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new?
|
36
|
+
self['slug'] = title.to_s.downcase.gsub(/[^a-z0-9]/,'-').squeeze('-').gsub(/^\-|\-$/,'') if new?
|
37
37
|
end
|
38
38
|
end
|
@@ -9,7 +9,8 @@ class Card < CouchRest::Model::Base
|
|
9
9
|
property :last_name, :alias => :family_name
|
10
10
|
property :read_only_value, :read_only => true
|
11
11
|
property :cast_alias, Person, :alias => :calias
|
12
|
-
property :fg_color, :default => '#000'
|
12
|
+
property :fg_color, String, :default => '#000'
|
13
|
+
property :bg_color, String, :protected => true
|
13
14
|
|
14
15
|
timestamps!
|
15
16
|
|
@@ -12,22 +12,22 @@ describe "Assocations" do
|
|
12
12
|
|
13
13
|
it "should return a default set of options" do
|
14
14
|
o = SaleInvoice.merge_assoc_opts(:cat)
|
15
|
-
o[:foreign_key].
|
16
|
-
o[:class_name].
|
17
|
-
o[:proxy_name].
|
18
|
-
o[:proxy].
|
15
|
+
expect(o[:foreign_key]).to eql('cat_id')
|
16
|
+
expect(o[:class_name]).to eql('Cat')
|
17
|
+
expect(o[:proxy_name]).to eql('cats')
|
18
|
+
expect(o[:proxy]).to eql('Cat') # same as class name
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should merge with provided options" do
|
22
22
|
o = SaleInvoice.merge_assoc_opts(:cat, :foreign_key => 'somecat_id', :proxy => 'some_cats')
|
23
|
-
o[:foreign_key].
|
24
|
-
o[:proxy].
|
23
|
+
expect(o[:foreign_key]).to eql('somecat_id')
|
24
|
+
expect(o[:proxy]).to eql('some_cats')
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should generate a proxy string if proxied" do
|
28
|
-
SaleInvoice.
|
28
|
+
allow(SaleInvoice).to receive(:proxy_owner_method).twice.and_return('company')
|
29
29
|
o = SaleInvoice.merge_assoc_opts(:cat)
|
30
|
-
o[:proxy].
|
30
|
+
expect(o[:proxy]).to eql('self.company.cats')
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
@@ -40,59 +40,59 @@ describe "Assocations" do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should create a foreign key property with setter and getter" do
|
43
|
-
@invoice.properties.find{|p| p.name == 'client_id'}.
|
44
|
-
@invoice.respond_to?(:client_id).
|
45
|
-
@invoice.respond_to?("client_id=").
|
43
|
+
expect(@invoice.properties.find{|p| p.name == 'client_id'}).not_to be_nil
|
44
|
+
expect(@invoice.respond_to?(:client_id)).to be_truthy
|
45
|
+
expect(@invoice.respond_to?("client_id=")).to be_truthy
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should set the property and provide object when set" do
|
49
49
|
@invoice.client = @client
|
50
|
-
@invoice.client_id.
|
51
|
-
@invoice.client.
|
50
|
+
expect(@invoice.client_id).to eql(@client.id)
|
51
|
+
expect(@invoice.client).to eql(@client)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should set the attribute, save and return" do
|
55
55
|
@invoice.client = @client
|
56
56
|
@invoice.save
|
57
57
|
@invoice = SaleInvoice.get(@invoice.id)
|
58
|
-
@invoice.client.id.
|
58
|
+
expect(@invoice.client.id).to eql(@client.id)
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should remove the association if nil is provided" do
|
62
62
|
@invoice.client = @client
|
63
63
|
@invoice.client = nil
|
64
|
-
@invoice.client_id.
|
64
|
+
expect(@invoice.client_id).to be_nil
|
65
65
|
end
|
66
66
|
|
67
67
|
it "should not try to search for association if foreign_key is nil" do
|
68
68
|
@invoice.client_id = nil
|
69
|
-
Client.
|
69
|
+
expect(Client).not_to receive(:get)
|
70
70
|
@invoice.client
|
71
71
|
end
|
72
72
|
|
73
73
|
it "should ignore blank ids" do
|
74
74
|
@invoice.client_id = ""
|
75
|
-
@invoice.client_id.
|
75
|
+
expect(@invoice.client_id).to be_nil
|
76
76
|
end
|
77
77
|
|
78
78
|
it "should allow replacement of object after updating key" do
|
79
79
|
@invoice.client = @client
|
80
|
-
@invoice.client.
|
80
|
+
expect(@invoice.client).to eql(@client)
|
81
81
|
@invoice.client_id = nil
|
82
|
-
@invoice.client.
|
82
|
+
expect(@invoice.client).to be_nil
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should allow override of foreign key" do
|
86
|
-
@invoice.respond_to?(:alternate_client).
|
87
|
-
@invoice.respond_to?("alternate_client=").
|
88
|
-
@invoice.properties.find{|p| p.name == 'alt_client_id'}.
|
86
|
+
expect(@invoice.respond_to?(:alternate_client)).to be_truthy
|
87
|
+
expect(@invoice.respond_to?("alternate_client=")).to be_truthy
|
88
|
+
expect(@invoice.properties.find{|p| p.name == 'alt_client_id'}).not_to be_nil
|
89
89
|
end
|
90
90
|
|
91
91
|
it "should allow override of foreign key and save" do
|
92
92
|
@invoice.alternate_client = @client
|
93
93
|
@invoice.save
|
94
94
|
@invoice = SaleInvoice.get(@invoice.id)
|
95
|
-
@invoice.alternate_client.id.
|
95
|
+
expect(@invoice.alternate_client.id).to eql(@client.id)
|
96
96
|
end
|
97
97
|
|
98
98
|
end
|
@@ -109,95 +109,95 @@ describe "Assocations" do
|
|
109
109
|
end
|
110
110
|
|
111
111
|
it "should create an associated property and collection proxy" do
|
112
|
-
@invoice.respond_to?('entry_ids').
|
113
|
-
@invoice.respond_to?('entry_ids=').
|
114
|
-
@invoice.entries.class.
|
112
|
+
expect(@invoice.respond_to?('entry_ids')).to be_truthy
|
113
|
+
expect(@invoice.respond_to?('entry_ids=')).to be_truthy
|
114
|
+
expect(@invoice.entries.class).to eql(::CouchRest::Model::CollectionOfProxy)
|
115
115
|
end
|
116
116
|
|
117
117
|
it "should allow replacement of objects" do
|
118
118
|
@invoice.entries = @entries
|
119
|
-
@invoice.entries.length.
|
120
|
-
@invoice.entry_ids.length.
|
121
|
-
@invoice.entries.first.
|
122
|
-
@invoice.entry_ids.first.
|
119
|
+
expect(@invoice.entries.length).to eql(3)
|
120
|
+
expect(@invoice.entry_ids.length).to eql(3)
|
121
|
+
expect(@invoice.entries.first).to eql(@entries.first)
|
122
|
+
expect(@invoice.entry_ids.first).to eql(@entries.first.id)
|
123
123
|
end
|
124
124
|
|
125
125
|
it "should allow ids to be set directly and load entries" do
|
126
126
|
@invoice.entry_ids = @entries.collect{|i| i.id}
|
127
|
-
@invoice.entries.length.
|
128
|
-
@invoice.entries.first.
|
129
|
-
@invoice.changed
|
127
|
+
expect(@invoice.entries.length).to eql(3)
|
128
|
+
expect(@invoice.entries.first).to eql(@entries.first)
|
129
|
+
expect(@invoice.changed?).to be_truthy
|
130
130
|
end
|
131
131
|
|
132
132
|
it "should ignore blank ids when set directly" do
|
133
133
|
@invoice.entry_ids = ["", @entries.first.id]
|
134
|
-
@invoice.entry_ids.length.
|
134
|
+
expect(@invoice.entry_ids.length).to be(1)
|
135
135
|
end
|
136
136
|
|
137
137
|
it "should replace collection if ids replaced" do
|
138
138
|
@invoice.entry_ids = @entries.collect{|i| i.id}
|
139
|
-
@invoice.entries.length.
|
139
|
+
expect(@invoice.entries.length).to eql(3) # load once
|
140
140
|
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
141
|
-
@invoice.entries.length.
|
141
|
+
expect(@invoice.entries.length).to eql(2)
|
142
142
|
end
|
143
143
|
|
144
144
|
it "should allow forced collection update if ids changed" do
|
145
145
|
@invoice.entry_ids = @entries[0..1].collect{|i| i.id}
|
146
|
-
@invoice.entries.length.
|
146
|
+
expect(@invoice.entries.length).to eql(2) # load once
|
147
147
|
@invoice.entry_ids << @entries[2].id
|
148
|
-
@invoice.entry_ids.length.
|
149
|
-
@invoice.entries.length.
|
150
|
-
@invoice.entries(true).length.
|
148
|
+
expect(@invoice.entry_ids.length).to eql(3)
|
149
|
+
expect(@invoice.entries.length).to eql(2) # cached!
|
150
|
+
expect(@invoice.entries(true).length).to eql(3)
|
151
151
|
end
|
152
152
|
|
153
153
|
it "should empty arrays when nil collection provided" do
|
154
154
|
@invoice.entries = @entries
|
155
155
|
@invoice.entries = nil
|
156
|
-
@invoice.entry_ids.
|
157
|
-
@invoice.entries.
|
156
|
+
expect(@invoice.entry_ids).to be_empty
|
157
|
+
expect(@invoice.entries).to be_empty
|
158
158
|
end
|
159
159
|
|
160
160
|
it "should empty arrays when nil ids array provided" do
|
161
161
|
@invoice.entries = @entries
|
162
162
|
@invoice.entry_ids = nil
|
163
|
-
@invoice.entry_ids.
|
164
|
-
@invoice.entries.
|
163
|
+
expect(@invoice.entry_ids).to be_empty
|
164
|
+
expect(@invoice.entries).to be_empty
|
165
165
|
end
|
166
166
|
|
167
167
|
it "should ignore nil entries" do
|
168
168
|
@invoice.entries = [ nil ]
|
169
|
-
@invoice.entry_ids.
|
170
|
-
@invoice.entries.
|
169
|
+
expect(@invoice.entry_ids).to be_empty
|
170
|
+
expect(@invoice.entries).to be_empty
|
171
171
|
end
|
172
172
|
|
173
173
|
# Account for dirty tracking
|
174
174
|
describe "dirty tracking" do
|
175
175
|
it "should register changes on replacement" do
|
176
176
|
@invoice.entries = @entries
|
177
|
-
@invoice.changed
|
177
|
+
expect(@invoice.changed?).to be_truthy
|
178
178
|
end
|
179
179
|
it "should register changes on push" do
|
180
|
-
@invoice.changed
|
180
|
+
expect(@invoice.changed?).to be_falsey
|
181
181
|
@invoice.entries << @entries[0]
|
182
|
-
@invoice.changed
|
182
|
+
expect(@invoice.changed?).to be_truthy
|
183
183
|
end
|
184
184
|
it "should register changes on pop" do
|
185
185
|
@invoice.entries << @entries[0]
|
186
186
|
@invoice.save
|
187
|
-
@invoice.changed
|
187
|
+
expect(@invoice.changed?).to be_falsey
|
188
188
|
@invoice.entries.pop
|
189
|
-
@invoice.changed
|
189
|
+
expect(@invoice.changed?).to be_truthy
|
190
190
|
end
|
191
191
|
it "should register id changes on push" do
|
192
192
|
@invoice.entry_ids << @entries[0].id
|
193
|
-
@invoice.changed
|
193
|
+
expect(@invoice.changed?).to be_truthy
|
194
194
|
end
|
195
195
|
it "should register id changes on pop" do
|
196
196
|
@invoice.entry_ids << @entries[0].id
|
197
197
|
@invoice.save
|
198
|
-
@invoice.changed
|
198
|
+
expect(@invoice.changed?).to be_falsey
|
199
199
|
@invoice.entry_ids.pop
|
200
|
-
@invoice.changed
|
200
|
+
expect(@invoice.changed?).to be_truthy
|
201
201
|
end
|
202
202
|
end
|
203
203
|
|
@@ -205,53 +205,53 @@ describe "Assocations" do
|
|
205
205
|
|
206
206
|
it "should ensure new entries to proxy are matched" do
|
207
207
|
@invoice.entries << @entries.first
|
208
|
-
@invoice.entry_ids.first.
|
209
|
-
@invoice.entries.first.
|
208
|
+
expect(@invoice.entry_ids.first).to eql(@entries.first.id)
|
209
|
+
expect(@invoice.entries.first).to eql(@entries.first)
|
210
210
|
@invoice.entries << @entries[1]
|
211
|
-
@invoice.entries.count.
|
212
|
-
@invoice.entry_ids.count.
|
213
|
-
@invoice.entry_ids.last.
|
214
|
-
@invoice.entries.last.
|
211
|
+
expect(@invoice.entries.count).to eql(2)
|
212
|
+
expect(@invoice.entry_ids.count).to eql(2)
|
213
|
+
expect(@invoice.entry_ids.last).to eql(@entries[1].id)
|
214
|
+
expect(@invoice.entries.last).to eql(@entries[1])
|
215
215
|
end
|
216
216
|
|
217
217
|
it "should support push method" do
|
218
218
|
@invoice.entries.push(@entries.first)
|
219
|
-
@invoice.entry_ids.first.
|
219
|
+
expect(@invoice.entry_ids.first).to eql(@entries.first.id)
|
220
220
|
end
|
221
221
|
|
222
222
|
it "should support []= method" do
|
223
223
|
@invoice.entries[0] = @entries.first
|
224
|
-
@invoice.entry_ids.first.
|
224
|
+
expect(@invoice.entry_ids.first).to eql(@entries.first.id)
|
225
225
|
end
|
226
226
|
|
227
227
|
it "should support unshift method" do
|
228
228
|
@invoice.entries.unshift(@entries.first)
|
229
|
-
@invoice.entry_ids.first.
|
229
|
+
expect(@invoice.entry_ids.first).to eql(@entries.first.id)
|
230
230
|
@invoice.entries.unshift(@entries[1])
|
231
|
-
@invoice.entry_ids.first.
|
231
|
+
expect(@invoice.entry_ids.first).to eql(@entries[1].id)
|
232
232
|
end
|
233
233
|
|
234
234
|
it "should support pop method" do
|
235
235
|
@invoice.entries.push(@entries.first)
|
236
|
-
@invoice.entries.pop.
|
237
|
-
@invoice.entries.empty
|
238
|
-
@invoice.entry_ids.empty
|
236
|
+
expect(@invoice.entries.pop).to eql(@entries.first)
|
237
|
+
expect(@invoice.entries.empty?).to be_truthy
|
238
|
+
expect(@invoice.entry_ids.empty?).to be_truthy
|
239
239
|
end
|
240
240
|
|
241
241
|
it "should support shift method" do
|
242
242
|
@invoice.entries.push(@entries[0])
|
243
243
|
@invoice.entries.push(@entries[1])
|
244
|
-
@invoice.entries.shift.
|
245
|
-
@invoice.entries.first.
|
246
|
-
@invoice.entry_ids.first.
|
244
|
+
expect(@invoice.entries.shift).to eql(@entries[0])
|
245
|
+
expect(@invoice.entries.first).to eql(@entries[1])
|
246
|
+
expect(@invoice.entry_ids.first).to eql(@entries[1].id)
|
247
247
|
end
|
248
248
|
|
249
249
|
it "should raise error when adding un-persisted entries" do
|
250
|
-
SaleEntry.find_by_description('test entry').
|
250
|
+
expect(SaleEntry.find_by_description('test entry')).to be_nil
|
251
251
|
entry = SaleEntry.new(:description => 'test entry', :price => 500)
|
252
|
-
|
252
|
+
expect {
|
253
253
|
@invoice.entries << entry
|
254
|
-
}.
|
254
|
+
}.to raise_error(/Object cannot be added/)
|
255
255
|
# In the future maybe?
|
256
256
|
# @invoice.save.should be_true
|
257
257
|
# SaleEntry.find_by_description('test entry').should_not be_nil
|
@@ -6,35 +6,35 @@ describe "Model attachments" do
|
|
6
6
|
before(:each) do
|
7
7
|
reset_test_db!
|
8
8
|
@obj = Basic.new
|
9
|
-
@obj.save.
|
9
|
+
expect(@obj.save).to be_truthy
|
10
10
|
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
11
11
|
@attachment_name = 'my_attachment'
|
12
12
|
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should return false if there is no attachment' do
|
16
|
-
@obj.has_attachment?('bogus').
|
16
|
+
expect(@obj.has_attachment?('bogus')).to be_falsey
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should return true if there is an attachment' do
|
20
|
-
@obj.has_attachment?(@attachment_name).
|
20
|
+
expect(@obj.has_attachment?(@attachment_name)).to be_truthy
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should return true if an object with an attachment is reloaded' do
|
24
|
-
@obj.save.
|
24
|
+
expect(@obj.save).to be_truthy
|
25
25
|
reloaded_obj = Basic.get(@obj.id)
|
26
|
-
reloaded_obj.has_attachment?(@attachment_name).
|
26
|
+
expect(reloaded_obj.has_attachment?(@attachment_name)).to be_truthy
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should return false if an attachment has been removed' do
|
30
30
|
@obj.delete_attachment(@attachment_name)
|
31
|
-
@obj.has_attachment?(@attachment_name).
|
31
|
+
expect(@obj.has_attachment?(@attachment_name)).to be_falsey
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'should return false if an attachment has been removed and reloaded' do
|
35
35
|
@obj.delete_attachment(@attachment_name)
|
36
36
|
reloaded_obj = Basic.get(@obj.id)
|
37
|
-
reloaded_obj.has_attachment?(@attachment_name).
|
37
|
+
expect(reloaded_obj.has_attachment?(@attachment_name)).to be_falsey
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|
@@ -42,7 +42,7 @@ describe "Model attachments" do
|
|
42
42
|
describe "creating an attachment" do
|
43
43
|
before(:each) do
|
44
44
|
@obj = Basic.new
|
45
|
-
@obj.save.
|
45
|
+
expect(@obj.save).to be_truthy
|
46
46
|
@file_ext = File.open(FIXTURE_PATH + '/attachments/test.html')
|
47
47
|
@file_no_ext = File.open(FIXTURE_PATH + '/attachments/README')
|
48
48
|
@attachment_name = 'my_attachment'
|
@@ -51,41 +51,41 @@ describe "Model attachments" do
|
|
51
51
|
|
52
52
|
it "should create an attachment from file with an extension" do
|
53
53
|
@obj.create_attachment(:file => @file_ext, :name => @attachment_name)
|
54
|
-
@obj.save.
|
54
|
+
expect(@obj.save).to be_truthy
|
55
55
|
reloaded_obj = Basic.get(@obj.id)
|
56
|
-
reloaded_obj.attachments[@attachment_name].
|
56
|
+
expect(reloaded_obj.attachments[@attachment_name]).not_to be_nil
|
57
57
|
end
|
58
58
|
|
59
59
|
it "should create an attachment from file without an extension" do
|
60
60
|
@obj.create_attachment(:file => @file_no_ext, :name => @attachment_name)
|
61
|
-
@obj.save.
|
61
|
+
expect(@obj.save).to be_truthy
|
62
62
|
reloaded_obj = Basic.get(@obj.id)
|
63
|
-
reloaded_obj.attachments[@attachment_name].
|
63
|
+
expect(reloaded_obj.attachments[@attachment_name]).not_to be_nil
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should raise ArgumentError if :file is missing' do
|
67
|
-
|
67
|
+
expect{ @obj.create_attachment(:name => @attachment_name) }.to raise_error(ArgumentError, /:file/)
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'should raise ArgumentError if :name is missing' do
|
71
|
-
|
71
|
+
expect{ @obj.create_attachment(:file => @file_ext) }.to raise_error(ArgumentError, /:name/)
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'should set the content-type if passed' do
|
75
75
|
@obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
|
76
|
-
@obj.attachments[@attachment_name]['content_type'].
|
76
|
+
expect(@obj.attachments[@attachment_name]['content_type']).to eq(@content_type)
|
77
77
|
end
|
78
78
|
|
79
79
|
it "should detect the content-type automatically" do
|
80
80
|
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
81
|
-
@obj.attachments['couchdb.png']['content_type'].
|
81
|
+
expect(@obj.attachments['couchdb.png']['content_type']).to eq("image/png")
|
82
82
|
end
|
83
83
|
|
84
84
|
it "should use name to detect the content-type automatically if no file" do
|
85
85
|
file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
|
86
|
-
file.
|
86
|
+
allow(file).to receive(:path).and_return("badfilname")
|
87
87
|
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
88
|
-
@obj.attachments['couchdb.png']['content_type'].
|
88
|
+
expect(@obj.attachments['couchdb.png']['content_type']).to eq("image/png")
|
89
89
|
end
|
90
90
|
|
91
91
|
end
|
@@ -96,37 +96,37 @@ describe "Model attachments" do
|
|
96
96
|
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
97
97
|
@attachment_name = 'my_attachment'
|
98
98
|
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
99
|
-
@obj.save.
|
99
|
+
expect(@obj.save).to be_truthy
|
100
100
|
@file.rewind
|
101
101
|
@content_type = 'media/mp3'
|
102
102
|
end
|
103
103
|
|
104
104
|
it 'should read an attachment that exists' do
|
105
|
-
@obj.read_attachment(@attachment_name).
|
105
|
+
expect(@obj.read_attachment(@attachment_name)).to eq(@file.read)
|
106
106
|
end
|
107
107
|
|
108
108
|
it 'should update an attachment that exists' do
|
109
109
|
file = File.open(FIXTURE_PATH + '/attachments/README')
|
110
|
-
@file.
|
110
|
+
expect(@file).not_to eq(file)
|
111
111
|
@obj.update_attachment(:file => file, :name => @attachment_name)
|
112
112
|
@obj.save
|
113
113
|
reloaded_obj = Basic.get(@obj.id)
|
114
114
|
file.rewind
|
115
|
-
reloaded_obj.read_attachment(@attachment_name).
|
116
|
-
reloaded_obj.read_attachment(@attachment_name).
|
115
|
+
expect(reloaded_obj.read_attachment(@attachment_name)).not_to eq(@file.read)
|
116
|
+
expect(reloaded_obj.read_attachment(@attachment_name)).to eq(file.read)
|
117
117
|
end
|
118
118
|
|
119
119
|
it 'should set the content-type if passed' do
|
120
120
|
file = File.open(FIXTURE_PATH + '/attachments/README')
|
121
|
-
@file.
|
121
|
+
expect(@file).not_to eq(file)
|
122
122
|
@obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
|
123
|
-
@obj.attachments[@attachment_name]['content_type'].
|
123
|
+
expect(@obj.attachments[@attachment_name]['content_type']).to eq(@content_type)
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'should delete an attachment that exists' do
|
127
127
|
@obj.delete_attachment(@attachment_name)
|
128
128
|
@obj.save
|
129
|
-
|
129
|
+
expect{Basic.get(@obj.id).read_attachment(@attachment_name)}.to raise_error(/404 Not Found/)
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
@@ -136,19 +136,19 @@ describe "Model attachments" do
|
|
136
136
|
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
137
137
|
@attachment_name = 'my_attachment'
|
138
138
|
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
139
|
-
@obj.save.
|
139
|
+
expect(@obj.save).to be_truthy
|
140
140
|
end
|
141
141
|
|
142
142
|
it 'should return nil if attachment does not exist' do
|
143
|
-
@obj.attachment_url('bogus').
|
143
|
+
expect(@obj.attachment_url('bogus')).to be_nil
|
144
144
|
end
|
145
145
|
|
146
146
|
it 'should return the attachment URL as specified by CouchDB HttpDocumentApi' do
|
147
|
-
@obj.attachment_url(@attachment_name).
|
147
|
+
expect(@obj.attachment_url(@attachment_name)).to eq("#{Basic.database}/#{@obj.id}/#{@attachment_name}")
|
148
148
|
end
|
149
149
|
|
150
150
|
it 'should return the attachment URI' do
|
151
|
-
@obj.attachment_uri(@attachment_name).
|
151
|
+
expect(@obj.attachment_uri(@attachment_name)).to eq("#{Basic.database.uri}/#{@obj.id}/#{@attachment_name}")
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|
@@ -158,18 +158,18 @@ describe "Model attachments" do
|
|
158
158
|
@file = File.open(FIXTURE_PATH + '/attachments/test.html')
|
159
159
|
@attachment_name = 'my_attachment'
|
160
160
|
@obj.create_attachment(:file => @file, :name => @attachment_name)
|
161
|
-
@obj.save.
|
161
|
+
expect(@obj.save).to be_truthy
|
162
162
|
end
|
163
163
|
|
164
164
|
it 'should return an empty Hash when document does not have any attachment' do
|
165
165
|
new_obj = Basic.new
|
166
|
-
new_obj.save.
|
167
|
-
new_obj.attachments.
|
166
|
+
expect(new_obj.save).to be_truthy
|
167
|
+
expect(new_obj.attachments).to eq({})
|
168
168
|
end
|
169
169
|
|
170
170
|
it 'should return a Hash with all attachments' do
|
171
171
|
@file.rewind
|
172
|
-
@obj.attachments.
|
172
|
+
expect(@obj.attachments).to eq({ @attachment_name =>{ "data" => "PCFET0NUWVBFIGh0bWw+CjxodG1sPgogIDxoZWFkPgogICAgPHRpdGxlPlRlc3Q8L3RpdGxlPgogIDwvaGVhZD4KICA8Ym9keT4KICAgIDxwPgogICAgICBUZXN0CiAgICA8L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg==", "content_type" => "text/html"}})
|
173
173
|
end
|
174
174
|
|
175
175
|
end
|