couchrest_model 2.0.0.beta2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/.travis.yml +8 -0
  2. data/Gemfile +1 -1
  3. data/README.md +1 -1
  4. data/Rakefile +9 -24
  5. data/VERSION +1 -1
  6. data/couchrest_model.gemspec +7 -5
  7. data/history.md +17 -1
  8. data/lib/couchrest/model/associations.rb +16 -11
  9. data/lib/couchrest/model/base.rb +17 -15
  10. data/lib/couchrest/model/casted_array.rb +7 -1
  11. data/lib/couchrest/model/core_extensions/time_parsing.rb +0 -23
  12. data/lib/couchrest/model/design.rb +282 -0
  13. data/lib/couchrest/model/designs/design_mapper.rb +79 -0
  14. data/lib/couchrest/model/designs/view.rb +9 -6
  15. data/lib/couchrest/model/designs.rb +37 -70
  16. data/lib/couchrest/model/persistence.rb +5 -5
  17. data/lib/couchrest/model/properties.rb +5 -16
  18. data/lib/couchrest/model/property.rb +34 -16
  19. data/lib/couchrest/model/translation.rb +22 -0
  20. data/lib/couchrest/model/typecast.rb +54 -43
  21. data/lib/couchrest/model/utils/migrate.rb +106 -0
  22. data/lib/couchrest_model.rb +4 -2
  23. data/lib/tasks/migrations.rake +5 -5
  24. data/spec/fixtures/models/course.rb +1 -0
  25. data/spec/fixtures/models/designs.rb +22 -0
  26. data/spec/spec_helper.rb +1 -0
  27. data/spec/unit/assocations_spec.rb +7 -0
  28. data/spec/unit/base_spec.rb +3 -1
  29. data/spec/unit/{designs/design_spec.rb → design_spec.rb} +6 -6
  30. data/spec/unit/designs/design_mapper_spec.rb +124 -0
  31. data/spec/unit/designs/view_spec.rb +30 -4
  32. data/spec/unit/designs_spec.rb +5 -140
  33. data/spec/unit/dirty_spec.rb +15 -1
  34. data/spec/unit/embeddable_spec.rb +2 -2
  35. data/spec/unit/property_spec.rb +70 -28
  36. data/spec/unit/translations_spec.rb +31 -0
  37. data/spec/unit/typecast_spec.rb +99 -19
  38. data/spec/unit/utils/migrate_spec.rb +25 -0
  39. metadata +43 -19
  40. data/lib/couchrest/model/designs/design.rb +0 -284
  41. data/lib/couchrest/model/migrate.rb +0 -92
@@ -75,6 +75,13 @@ describe "Assocations" do
75
75
  @invoice.client_id.should be_nil
76
76
  end
77
77
 
78
+ it "should allow replacement of object after updating key" do
79
+ @invoice.client = @client
80
+ @invoice.client.should eql(@client)
81
+ @invoice.client_id = nil
82
+ @invoice.client.should be_nil
83
+ end
84
+
78
85
  it "should allow override of foreign key" do
79
86
  @invoice.respond_to?(:alternate_client).should be_true
80
87
  @invoice.respond_to?("alternate_client=").should be_true
@@ -469,6 +469,7 @@ describe "Model Base" do
469
469
 
470
470
  it "should define the updated_at and created_at getters and set the values" do
471
471
  @obj.save
472
+ json = @obj.to_json
472
473
  obj = WithDefaultValues.get(@obj.id)
473
474
  obj.should be_an_instance_of(WithDefaultValues)
474
475
  obj.created_at.should be_an_instance_of(Time)
@@ -487,7 +488,8 @@ describe "Model Base" do
487
488
  it "should set the time on create" do
488
489
  (Time.now - @art.created_at).should < 2
489
490
  foundart = Article.get @art.id
490
- foundart.created_at.should == foundart.updated_at
491
+ # Use string for comparison to cope with microsecond differences
492
+ foundart.created_at.to_s.should == foundart.updated_at.to_s
491
493
  end
492
494
  it "should set the time on update" do
493
495
  @art.title = "new title" # only saved if @art.changed? == true
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe CouchRest::Model::Designs::Design do
5
+ describe CouchRest::Model::Design do
6
6
 
7
7
  before :all do
8
8
  reset_test_db!
@@ -26,7 +26,7 @@ describe CouchRest::Model::Designs::Design do
26
26
  describe "class methods" do
27
27
 
28
28
  before :all do
29
- @klass = CouchRest::Model::Designs::Design
29
+ @klass = CouchRest::Model::Design
30
30
  end
31
31
 
32
32
  describe ".method_name" do
@@ -46,7 +46,7 @@ describe CouchRest::Model::Designs::Design do
46
46
  before :each do
47
47
  @model = mock("ModelExample")
48
48
  @model.stub(:to_s).and_return("ModelExample")
49
- @obj = CouchRest::Model::Designs::Design.new(@model)
49
+ @obj = CouchRest::Model::Design.new(@model)
50
50
  end
51
51
 
52
52
 
@@ -68,13 +68,13 @@ describe CouchRest::Model::Designs::Design do
68
68
  describe "initialisation with prefix" do
69
69
 
70
70
  it "should associate model and set method name" do
71
- @obj = CouchRest::Model::Designs::Design.new(@model, 'stats')
71
+ @obj = CouchRest::Model::Design.new(@model, 'stats')
72
72
  @obj.model.should eql(@model)
73
73
  @obj.method_name.should eql("stats_design_doc")
74
74
  end
75
75
 
76
76
  it "should generate correct id with prefix" do
77
- @obj = CouchRest::Model::Designs::Design.new(@model, 'stats')
77
+ @obj = CouchRest::Model::Design.new(@model, 'stats')
78
78
  @obj['_id'].should eql("_design/ModelExample_stats")
79
79
  end
80
80
 
@@ -358,7 +358,7 @@ describe CouchRest::Model::Designs::Design do
358
358
 
359
359
  it "should calculate checksum for complex model" do
360
360
  #Article.design_doc.checksum.should eql('70dff8caea143bf40fad09adf0701104')
361
- Article.design_doc.checksum.should eql('0f25a2d9f86e31ebd61b29863a41d5ed')
361
+ Article.design_doc.checksum.should eql('81f6553c44ecc3fe12a39331b0cdee46')
362
362
  end
363
363
 
364
364
  it "should cache the generated checksum value" do
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe CouchRest::Model::Designs::DesignMapper do
6
+
7
+ before :all do
8
+ @klass = CouchRest::Model::Designs::DesignMapper
9
+ end
10
+
11
+ describe 'initialize without prefix' do
12
+
13
+ before :all do
14
+ @object = @klass.new(DesignModel)
15
+ end
16
+
17
+ it "should set basic variables" do
18
+ @object.send(:model).should eql(DesignModel)
19
+ @object.send(:prefix).should be_nil
20
+ @object.send(:method).should eql('design_doc')
21
+ end
22
+
23
+ it "should add design doc to list" do
24
+ @object.model.design_docs.should include(@object.model.design_doc)
25
+ end
26
+
27
+ it "should create a design doc method" do
28
+ @object.model.should respond_to('design_doc')
29
+ @object.design_doc.should eql(@object.model.design_doc)
30
+ end
31
+
32
+ it "should use default for autoupdate" do
33
+ @object.design_doc.auto_update.should be_true
34
+ end
35
+
36
+ end
37
+
38
+ describe 'initialize with prefix' do
39
+ before :all do
40
+ @object = @klass.new(DesignModel, 'stats')
41
+ end
42
+
43
+ it "should set basics" do
44
+ @object.send(:model).should eql(DesignModel)
45
+ @object.send(:prefix).should eql('stats')
46
+ @object.send(:method).should eql('stats_design_doc')
47
+ end
48
+
49
+ it "should add design doc to list" do
50
+ @object.model.design_docs.should include(@object.model.stats_design_doc)
51
+ end
52
+
53
+ it "should not create an all method" do
54
+ @object.model.should_not respond_to('all')
55
+ end
56
+
57
+ it "should create a design doc method" do
58
+ @object.model.should respond_to('stats_design_doc')
59
+ @object.design_doc.should eql(@object.model.stats_design_doc)
60
+ end
61
+
62
+ end
63
+
64
+ describe "#disable_auto_update" do
65
+ it "should disable auto updates" do
66
+ @object = @klass.new(DesignModel)
67
+ @object.disable_auto_update
68
+ @object.design_doc.auto_update.should be_false
69
+ end
70
+ end
71
+
72
+ describe "#enable_auto_update" do
73
+ it "should enable auto updates" do
74
+ @object = @klass.new(DesignModel)
75
+ @object.enable_auto_update
76
+ @object.design_doc.auto_update.should be_true
77
+ end
78
+ end
79
+
80
+ describe "#model_type_key" do
81
+ it "should return models type key" do
82
+ @object = @klass.new(DesignModel)
83
+ @object.model_type_key.should eql(@object.model.model_type_key)
84
+ end
85
+ end
86
+
87
+ describe "#view" do
88
+
89
+ before :each do
90
+ @object = @klass.new(DesignModel)
91
+ end
92
+
93
+ it "should call create method on view" do
94
+ CouchRest::Model::Designs::View.should_receive(:define).with(@object.design_doc, 'test', {})
95
+ @object.view('test')
96
+ end
97
+
98
+ it "should create a method on parent model" do
99
+ CouchRest::Model::Designs::View.stub!(:define)
100
+ @object.view('test_view')
101
+ DesignModel.should respond_to(:test_view)
102
+ end
103
+
104
+ it "should create a method for view instance" do
105
+ @object.design_doc.should_receive(:create_view).with('test', {})
106
+ @object.view('test')
107
+ end
108
+ end
109
+
110
+ describe "#filter" do
111
+
112
+ before :each do
113
+ @object = @klass.new(DesignModel)
114
+ end
115
+
116
+ it "should add the provided function to the design doc" do
117
+ @object.filter(:important, "function(doc, req) { return doc.priority == 'high'; }")
118
+ DesignModel.design_doc['filters'].should_not be_empty
119
+ DesignModel.design_doc['filters']['important'].should_not be_blank
120
+ end
121
+ end
122
+
123
+ end
124
+
@@ -118,13 +118,25 @@ describe "Design View" do
118
118
  @design_doc['views']['by_title']['reduce'].should eql(true)
119
119
  end
120
120
 
121
+ it "should replace reduce symbol with string name" do
122
+ @klass.define(@design_doc, 'by_title', :reduce => :sum)
123
+ @design_doc['views']['by_title']['map'].should_not be_blank
124
+ @design_doc['views']['by_title']['reduce'].should eql('_sum')
125
+ end
126
+
127
+ it "should replace reduce symbol with string if map function present" do
128
+ @klass.define(@design_doc, 'by_title', :map => "function(d) { }", :reduce => :sum)
129
+ @design_doc['views']['by_title']['map'].should_not be_blank
130
+ @design_doc['views']['by_title']['reduce'].should eql('_sum')
131
+ end
132
+
121
133
  it "should auto generate mapping from name" do
122
134
  lambda { @klass.define(@design_doc, 'by_title') }.should_not raise_error
123
135
  str = @design_doc['views']['by_title']['map']
124
136
  str.should include("((doc['#{DesignViewModel.model_type_key}'] == 'DesignViewModel') && (doc['title'] != null))")
125
137
  str.should include("emit(doc['title'], 1);")
126
138
  str = @design_doc['views']['by_title']['reduce']
127
- str.should include("return sum(values);")
139
+ str.should include("_sum")
128
140
  end
129
141
 
130
142
  it "should auto generate mapping from name with and" do
@@ -133,7 +145,12 @@ describe "Design View" do
133
145
  str.should include("(doc['title'] != null) && (doc['name'] != null)")
134
146
  str.should include("emit([doc['title'], doc['name']], 1);")
135
147
  str = @design_doc['views']['by_title_and_name']['reduce']
136
- str.should include("return sum(values);")
148
+ str.should include("_sum")
149
+ end
150
+
151
+ it "should allow reduce methods as symbols" do
152
+ @klass.define(@design_doc, 'by_title', :reduce => :stats)
153
+ @design_doc['views']['by_title']['reduce'].should eql('_stats')
137
154
  end
138
155
  end
139
156
 
@@ -719,6 +736,15 @@ describe "Design View" do
719
736
  end
720
737
  end
721
738
 
739
+ describe "#total_pages" do
740
+ it "should use total_count and limit_value" do
741
+ @obj.should_receive(:total_count).and_return(200)
742
+ @obj.should_receive(:limit_value).and_return(25)
743
+ @obj.total_pages.should eql(8)
744
+ end
745
+ end
746
+
747
+ # `num_pages` aliases to `total_pages` for compatibility for Kaminari '< 0.14'
722
748
  describe "#num_pages" do
723
749
  it "should use total_count and limit_value" do
724
750
  @obj.should_receive(:total_count).and_return(200)
@@ -887,7 +913,7 @@ describe "Design View" do
887
913
  end
888
914
 
889
915
  it "should calculate number of pages" do
890
- @view.num_pages.should eql(2)
916
+ @view.total_pages.should eql(2)
891
917
  end
892
918
  it "should return results from first page" do
893
919
  @view.all.first.name.should eql('Judith')
@@ -900,7 +926,7 @@ describe "Design View" do
900
926
 
901
927
  it "should allow overriding per page count" do
902
928
  @view = @view.per(10)
903
- @view.num_pages.should eql(1)
929
+ @view.total_pages.should eql(1)
904
930
  @view.all.last.name.should eql('Vilma')
905
931
  end
906
932
  end
@@ -1,9 +1,5 @@
1
1
  require "spec_helper"
2
2
 
3
- class DesignModel < CouchRest::Model::Base
4
- use_database DB
5
- property :name
6
- end
7
3
 
8
4
  describe CouchRest::Model::Designs do
9
5
 
@@ -16,7 +12,7 @@ describe CouchRest::Model::Designs do
16
12
  describe ".design" do
17
13
 
18
14
  before :each do
19
- @klass = DesignModel.dup
15
+ @klass = DesignsModel.dup
20
16
  end
21
17
 
22
18
  describe "without block" do
@@ -36,14 +32,14 @@ describe CouchRest::Model::Designs do
36
32
  @klass.design
37
33
  blocks = @klass.instance_variable_get(:@_design_blocks)
38
34
  blocks.length.should eql(1)
39
- blocks.first.should eql({:args => [nil], :block => nil})
35
+ blocks.first.should eql({:args => [], :block => nil})
40
36
  end
41
37
 
42
38
  it "should have added itself to a design_blocks array" do
43
39
  @klass.design
44
40
  blocks = @klass.instance_variable_get(:@_design_blocks)
45
41
  blocks.length.should eql(1)
46
- blocks.first.should eql({:args => [nil], :block => nil})
42
+ blocks.first.should eql({:args => [], :block => nil})
47
43
  end
48
44
 
49
45
  it "should have added itself to a design_blocks array with prefix" do
@@ -69,7 +65,7 @@ describe CouchRest::Model::Designs do
69
65
  it "should have added itself to a design_blocks array" do
70
66
  blocks = @klass.instance_variable_get(:@_design_blocks)
71
67
  blocks.length.should eql(1)
72
- blocks.first.should eql({:args => [nil], :block => @block})
68
+ blocks.first.should eql({:args => [], :block => @block})
73
69
  end
74
70
 
75
71
  it "should handle multiple designs" do
@@ -79,7 +75,7 @@ describe CouchRest::Model::Designs do
79
75
  @klass.design :stats, &@block2
80
76
  blocks = @klass.instance_variable_get(:@_design_blocks)
81
77
  blocks.length.should eql(2)
82
- blocks.first.should eql({:args => [nil], :block => @block})
78
+ blocks.first.should eql({:args => [], :block => @block})
83
79
  blocks.last.should eql({:args => [:stats], :block => @block2})
84
80
  end
85
81
  end
@@ -115,137 +111,6 @@ describe CouchRest::Model::Designs do
115
111
  end
116
112
  end
117
113
 
118
- describe "DesignMapper" do
119
-
120
- before :all do
121
- @klass = CouchRest::Model::Designs::DesignMapper
122
- end
123
-
124
- describe 'initialize without prefix' do
125
-
126
- before :all do
127
- @object = @klass.new(DesignModel)
128
- end
129
-
130
- it "should set basic variables" do
131
- @object.send(:model).should eql(DesignModel)
132
- @object.send(:prefix).should be_nil
133
- @object.send(:method).should eql('design_doc')
134
- end
135
-
136
- it "should add design doc to list" do
137
- @object.model.design_docs.should include(@object.model.design_doc)
138
- end
139
-
140
- it "should create a design doc method" do
141
- @object.model.should respond_to('design_doc')
142
- @object.design_doc.should eql(@object.model.design_doc)
143
- end
144
-
145
- it "should use default for autoupdate" do
146
- @object.design_doc.auto_update.should be_true
147
- end
148
-
149
- end
150
-
151
- describe 'initialize with prefix' do
152
- before :all do
153
- @object = @klass.new(DesignModel, 'stats')
154
- end
155
-
156
- it "should set basics" do
157
- @object.send(:model).should eql(DesignModel)
158
- @object.send(:prefix).should eql('stats')
159
- @object.send(:method).should eql('stats_design_doc')
160
- end
161
-
162
- it "should add design doc to list" do
163
- @object.model.design_docs.should include(@object.model.stats_design_doc)
164
- end
165
-
166
- it "should not create an all method" do
167
- @object.model.should_not respond_to('all')
168
- end
169
-
170
- it "should create a design doc method" do
171
- @object.model.should respond_to('stats_design_doc')
172
- @object.design_doc.should eql(@object.model.stats_design_doc)
173
- end
174
-
175
- end
176
-
177
- describe "#disable_auto_update" do
178
- it "should disable auto updates" do
179
- @object = @klass.new(DesignModel)
180
- @object.disable_auto_update
181
- @object.design_doc.auto_update.should be_false
182
- end
183
- end
184
-
185
- describe "#enable_auto_update" do
186
- it "should enable auto updates" do
187
- @object = @klass.new(DesignModel)
188
- @object.enable_auto_update
189
- @object.design_doc.auto_update.should be_true
190
- end
191
- end
192
-
193
- describe "#model_type_key" do
194
- it "should return models type key" do
195
- @object = @klass.new(DesignModel)
196
- @object.model_type_key.should eql(@object.model.model_type_key)
197
- end
198
- end
199
-
200
- describe "#view" do
201
-
202
- before :each do
203
- @object = @klass.new(DesignModel)
204
- end
205
-
206
- it "should call create method on view" do
207
- CouchRest::Model::Designs::View.should_receive(:define).with(@object.design_doc, 'test', {})
208
- @object.view('test')
209
- end
210
-
211
- it "should create a method on parent model" do
212
- CouchRest::Model::Designs::View.stub!(:define)
213
- @object.view('test_view')
214
- DesignModel.should respond_to(:test_view)
215
- end
216
-
217
- it "should create a method for view instance" do
218
- @object.design_doc.should_receive(:create_view).with('test', {})
219
- @object.view('test')
220
- end
221
- end
222
-
223
- describe "#filter" do
224
-
225
- before :each do
226
- @object = @klass.new(DesignModel)
227
- end
228
-
229
- it "should add the provided function to the design doc" do
230
- @object.filter(:important, "function(doc, req) { return doc.priority == 'high'; }")
231
- DesignModel.design_doc['filters'].should_not be_empty
232
- DesignModel.design_doc['filters']['important'].should_not be_blank
233
- end
234
- end
235
-
236
- end
237
-
238
-
239
- class DesignsNoAutoUpdate < CouchRest::Model::Base
240
- use_database DB
241
- property :title, String
242
- design do
243
- disable_auto_update
244
- view :by_title_fail, :by => ['title']
245
- view :by_title, :reduce => true
246
- end
247
- end
248
-
249
114
  describe "Scenario testing" do
250
115
 
251
116
  describe "with auto update disabled" do
@@ -14,7 +14,7 @@ class DirtyModel < CouchRest::Model::Base
14
14
  property :title, :default => 'Sample Title'
15
15
  property :details, Object, :default => { 'color' => 'blue' }
16
16
  property :keywords, [String], :default => ['default-keyword']
17
- property :sub_models do
17
+ property :sub_models, :array => true do
18
18
  property :title
19
19
  end
20
20
  end
@@ -270,6 +270,20 @@ describe "Dirty" do
270
270
  end
271
271
  end
272
272
 
273
+ it "should report changes if item is inserted into array" do
274
+ should_change_array do |array, obj|
275
+ array.insert(0, 'keyword')
276
+ obj.keywords[0].should eql('keyword')
277
+ end
278
+ end
279
+
280
+ it "should report changes if items are inserted into array" do
281
+ should_change_array do |array, obj|
282
+ array.insert(1, 'keyword', 'keyword2')
283
+ obj.keywords[2].should eql('keyword2')
284
+ end
285
+ end
286
+
273
287
  it "should report changes if an array is popped" do
274
288
  should_change_array do |array, obj|
275
289
  array.pop
@@ -20,10 +20,10 @@ class DummyModel < CouchRest::Model::Base
20
20
  property :casted_attribute, WithCastedModelMixin
21
21
  property :keywords, [String]
22
22
  property :old_casted_attribute, OldFashionedMixin
23
- property :sub_models do |child|
23
+ property :sub_models, :array => true do |child|
24
24
  child.property :title
25
25
  end
26
- property :param_free_sub_models do
26
+ property :param_free_sub_models, :array => true do
27
27
  property :title
28
28
  end
29
29
  end