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