couchrest_model 1.1.2 → 1.2.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +8 -2
- data/VERSION +1 -1
- data/couchrest_model.gemspec +2 -1
- data/history.md +8 -0
- data/lib/couchrest/model/base.rb +0 -20
- data/lib/couchrest/model/configuration.rb +2 -0
- data/lib/couchrest/model/core_extensions/time_parsing.rb +35 -9
- data/lib/couchrest/model/designs/design.rb +182 -0
- data/lib/couchrest/model/designs/view.rb +91 -48
- data/lib/couchrest/model/designs.rb +72 -19
- data/lib/couchrest/model/document_queries.rb +15 -45
- data/lib/couchrest/model/properties.rb +43 -2
- data/lib/couchrest/model/proxyable.rb +20 -54
- data/lib/couchrest/model/typecast.rb +1 -1
- data/lib/couchrest/model/validations/uniqueness.rb +7 -6
- data/lib/couchrest_model.rb +1 -5
- data/spec/fixtures/models/article.rb +22 -20
- data/spec/fixtures/models/base.rb +15 -7
- data/spec/fixtures/models/course.rb +7 -4
- data/spec/fixtures/models/project.rb +4 -1
- data/spec/fixtures/models/sale_entry.rb +5 -3
- data/spec/unit/base_spec.rb +51 -5
- data/spec/unit/core_extensions/time_parsing.rb +41 -0
- data/spec/unit/designs/design_spec.rb +291 -0
- data/spec/unit/designs/view_spec.rb +135 -40
- data/spec/unit/designs_spec.rb +341 -30
- data/spec/unit/dirty_spec.rb +67 -0
- data/spec/unit/inherited_spec.rb +2 -2
- data/spec/unit/property_protection_spec.rb +3 -1
- data/spec/unit/property_spec.rb +43 -3
- data/spec/unit/proxyable_spec.rb +57 -98
- data/spec/unit/subclass_spec.rb +14 -5
- data/spec/unit/validations_spec.rb +14 -12
- metadata +172 -129
- data/lib/couchrest/model/class_proxy.rb +0 -135
- data/lib/couchrest/model/collection.rb +0 -273
- data/lib/couchrest/model/design_doc.rb +0 -115
- data/lib/couchrest/model/support/couchrest_design.rb +0 -33
- data/lib/couchrest/model/views.rb +0 -148
- data/spec/unit/class_proxy_spec.rb +0 -167
- data/spec/unit/collection_spec.rb +0 -86
- data/spec/unit/design_doc_spec.rb +0 -212
- data/spec/unit/view_spec.rb +0 -352
@@ -1,167 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
class UnattachedDoc < CouchRest::Model::Base
|
4
|
-
# Note: no use_database here
|
5
|
-
property :title
|
6
|
-
property :questions
|
7
|
-
property :professor
|
8
|
-
view_by :title
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
describe "Proxy Class" do
|
13
|
-
|
14
|
-
before(:all) do
|
15
|
-
reset_test_db!
|
16
|
-
# setup the class default doc to save the design doc
|
17
|
-
UnattachedDoc.use_database nil # just to be sure it is really unattached
|
18
|
-
@us = UnattachedDoc.on(DB)
|
19
|
-
%w{aaa bbb ddd eee}.each do |title|
|
20
|
-
u = @us.new(:title => title)
|
21
|
-
u.save
|
22
|
-
@first_id ||= u.id
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should query all" do
|
27
|
-
rs = @us.all
|
28
|
-
rs.length.should == 4
|
29
|
-
end
|
30
|
-
it "should count" do
|
31
|
-
@us.count.should == 4
|
32
|
-
end
|
33
|
-
it "should make the design doc upon first query" do
|
34
|
-
@us.by_title
|
35
|
-
doc = @us.design_doc
|
36
|
-
doc['views']['all']['map'].should include('UnattachedDoc')
|
37
|
-
end
|
38
|
-
it "should merge query params" do
|
39
|
-
rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
|
40
|
-
rs.length.should == 3
|
41
|
-
end
|
42
|
-
it "should query via view" do
|
43
|
-
view = @us.view :by_title
|
44
|
-
designed = @us.by_title
|
45
|
-
view.should == designed
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should query via first_from_view" do
|
49
|
-
UnattachedDoc.should_receive(:first_from_view).with('by_title', 'bbb', {:database => DB})
|
50
|
-
@us.first_from_view('by_title', 'bbb')
|
51
|
-
end
|
52
|
-
|
53
|
-
it "should query via first_from_view with complex options" do
|
54
|
-
UnattachedDoc.should_receive(:first_from_view).with('by_title', {:key => 'bbb', :database => DB})
|
55
|
-
@us.first_from_view('by_title', :key => 'bbb')
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should query via first_from_view with complex extra options" do
|
59
|
-
UnattachedDoc.should_receive(:first_from_view).with('by_title', 'bbb', {:limit => 1, :database => DB})
|
60
|
-
@us.first_from_view('by_title', 'bbb', :limit => 1)
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should allow dynamic view matching for single elements" do
|
64
|
-
@us.should_receive(:first_from_view).with('by_title', 'bbb')
|
65
|
-
@us.find_by_title('bbb')
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should yield" do
|
69
|
-
things = []
|
70
|
-
@us.view(:by_title) do |thing|
|
71
|
-
things << thing
|
72
|
-
end
|
73
|
-
things[0]["doc"]["title"].should =='aaa'
|
74
|
-
end
|
75
|
-
it "should yield with by_key method" do
|
76
|
-
things = []
|
77
|
-
@us.by_title do |thing|
|
78
|
-
things << thing
|
79
|
-
end
|
80
|
-
things[0]["doc"]["title"].should =='aaa'
|
81
|
-
end
|
82
|
-
it "should get from specific database" do
|
83
|
-
u = @us.get(@first_id)
|
84
|
-
u.title.should == "aaa"
|
85
|
-
end
|
86
|
-
it "should get first" do
|
87
|
-
u = @us.first
|
88
|
-
u.should == @us.all.first
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should get last" do
|
92
|
-
u = @us.last
|
93
|
-
u.should == @us.all.last
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should set database on first retreived document" do
|
97
|
-
u = @us.first
|
98
|
-
u.database.should === DB
|
99
|
-
end
|
100
|
-
it "should set database on all retreived documents" do
|
101
|
-
@us.all.each do |u|
|
102
|
-
u.database.should === DB
|
103
|
-
end
|
104
|
-
end
|
105
|
-
it "should set database on each retreived document" do
|
106
|
-
rs = @us.by_title :startkey=>"bbb", :endkey=>"eee"
|
107
|
-
rs.length.should == 3
|
108
|
-
rs.each do |u|
|
109
|
-
u.database.should === DB
|
110
|
-
end
|
111
|
-
end
|
112
|
-
it "should set database on document retreived by id" do
|
113
|
-
u = @us.get(@first_id)
|
114
|
-
u.database.should === DB
|
115
|
-
end
|
116
|
-
it "should not attempt to set database on raw results using :all" do
|
117
|
-
@us.all(:raw => true).each do |u|
|
118
|
-
u.respond_to?(:database).should be_false
|
119
|
-
end
|
120
|
-
end
|
121
|
-
it "should not attempt to set database on raw results using view" do
|
122
|
-
@us.by_title(:raw => true).each do |u|
|
123
|
-
u.respond_to?(:database).should be_false
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
describe "#get!" do
|
128
|
-
it "raises exception when passed a nil" do
|
129
|
-
expect { @us.get!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
130
|
-
end
|
131
|
-
|
132
|
-
it "raises exception when passed an empty string " do
|
133
|
-
expect { @us.get!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
134
|
-
end
|
135
|
-
|
136
|
-
it "raises exception when document with provided id does not exist" do
|
137
|
-
expect { @us.get!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
describe "#find!" do
|
142
|
-
it "raises exception when passed a nil" do
|
143
|
-
expect { @us.find!(nil)}.to raise_error(CouchRest::Model::DocumentNotFound)
|
144
|
-
end
|
145
|
-
|
146
|
-
it "raises exception when passed an empty string " do
|
147
|
-
expect { @us.find!("")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
148
|
-
end
|
149
|
-
|
150
|
-
it "raises exception when document with provided id does not exist" do
|
151
|
-
expect { @us.find!("thisisnotreallyadocumentid")}.to raise_error(CouchRest::Model::DocumentNotFound)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# Sam Lown 2010-04-07
|
156
|
-
# Removed as unclear why this should happen as before my changes
|
157
|
-
# this happend by accident, not explicitly.
|
158
|
-
# If requested, this feature should be added as a specific method.
|
159
|
-
#
|
160
|
-
#it "should clean up design docs left around on specific database" do
|
161
|
-
# @us.by_title
|
162
|
-
# original_id = @us.model_design_doc['_rev']
|
163
|
-
# Unattached.view_by :professor
|
164
|
-
# @us.by_professor
|
165
|
-
# @us.model_design_doc['_rev'].should_not == original_id
|
166
|
-
#end
|
167
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe "Collections" do
|
4
|
-
|
5
|
-
before(:all) do
|
6
|
-
reset_test_db!
|
7
|
-
titles = ["very uniq one", "really interesting", "some fun",
|
8
|
-
"really awesome", "crazy bob", "this rocks", "super rad"]
|
9
|
-
titles.each_with_index do |title,i|
|
10
|
-
a = Article.new(:title => title, :date => Date.today)
|
11
|
-
a.save
|
12
|
-
end
|
13
|
-
|
14
|
-
titles = ["yesterday very uniq one", "yesterday really interesting", "yesterday some fun",
|
15
|
-
"yesterday really awesome", "yesterday crazy bob", "yesterday this rocks"]
|
16
|
-
titles.each_with_index do |title,i|
|
17
|
-
a = Article.new(:title => title, :date => Date.today - 1)
|
18
|
-
a.save
|
19
|
-
end
|
20
|
-
end
|
21
|
-
it "should return a proxy that looks like an array of 7 Article objects" do
|
22
|
-
articles = Article.collection_proxy_for('Article', 'by_date', :descending => true,
|
23
|
-
:key => Date.today, :include_docs => true)
|
24
|
-
articles.class.should == Array
|
25
|
-
articles.size.should == 7
|
26
|
-
end
|
27
|
-
it "should provide a class method for paginate" do
|
28
|
-
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
29
|
-
:per_page => 3, :descending => true, :key => Date.today)
|
30
|
-
articles.size.should == 3
|
31
|
-
|
32
|
-
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
33
|
-
:per_page => 3, :page => 2, :descending => true, :key => Date.today)
|
34
|
-
articles.size.should == 3
|
35
|
-
|
36
|
-
articles = Article.paginate(:design_doc => 'Article', :view_name => 'by_date',
|
37
|
-
:per_page => 3, :page => 3, :descending => true, :key => Date.today)
|
38
|
-
articles.size.should == 1
|
39
|
-
end
|
40
|
-
it "should provide a class method for paginated_each" do
|
41
|
-
options = { :design_doc => 'Article', :view_name => 'by_date',
|
42
|
-
:per_page => 3, :page => 1, :descending => true, :key => Date.today }
|
43
|
-
Article.paginated_each(options) do |a|
|
44
|
-
a.should_not be_nil
|
45
|
-
end
|
46
|
-
end
|
47
|
-
it "should provide a class method to get a collection for a view" do
|
48
|
-
articles = Article.find_all_article_details(:key => Date.today)
|
49
|
-
articles.class.should == Array
|
50
|
-
articles.size.should == 7
|
51
|
-
end
|
52
|
-
it "should get a subset of articles using paginate" do
|
53
|
-
articles = Article.collection_proxy_for('Article', 'by_date', :key => Date.today, :include_docs => true)
|
54
|
-
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
55
|
-
articles.paginate(:page => 2, :per_page => 3).size.should == 3
|
56
|
-
articles.paginate(:page => 3, :per_page => 3).size.should == 1
|
57
|
-
end
|
58
|
-
it "should get all articles, a few at a time, using paginated each" do
|
59
|
-
articles = Article.collection_proxy_for('Article', 'by_date', :key => Date.today, :include_docs => true)
|
60
|
-
articles.paginated_each(:per_page => 3) do |a|
|
61
|
-
a.should_not be_nil
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
it "should raise an exception if design_doc is not provided" do
|
66
|
-
lambda{Article.collection_proxy_for(nil, 'by_date')}.should raise_error
|
67
|
-
lambda{Article.paginate(:view_name => 'by_date')}.should raise_error
|
68
|
-
end
|
69
|
-
it "should raise an exception if view_name is not provided" do
|
70
|
-
lambda{Article.collection_proxy_for('Article', nil)}.should raise_error
|
71
|
-
lambda{Article.paginate(:design_doc => 'Article')}.should raise_error
|
72
|
-
end
|
73
|
-
it "should be able to span multiple keys" do
|
74
|
-
articles = Article.collection_proxy_for('Article', 'by_date', :startkey => Date.today - 1, :endkey => Date.today, :include_docs => true)
|
75
|
-
articles.paginate(:page => 1, :per_page => 3).size.should == 3
|
76
|
-
articles.paginate(:page => 3, :per_page => 3).size.should == 3
|
77
|
-
articles.paginate(:page => 5, :per_page => 3).size.should == 1
|
78
|
-
end
|
79
|
-
it "should pass database parameter to pager" do
|
80
|
-
proxy = mock(:proxy)
|
81
|
-
proxy.stub!(:paginate)
|
82
|
-
::CouchRest::Model::Collection::CollectionProxy.should_receive(:new).with('database', anything(), anything(), anything(), anything()).and_return(proxy)
|
83
|
-
Article.paginate(:design_doc => 'Article', :view_name => 'by_date', :database => 'database')
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
@@ -1,212 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe CouchRest::Model::DesignDoc do
|
5
|
-
|
6
|
-
before :all do
|
7
|
-
reset_test_db!
|
8
|
-
end
|
9
|
-
|
10
|
-
describe "CouchRest Extension" do
|
11
|
-
|
12
|
-
it "should have created a checksum! method" do
|
13
|
-
::CouchRest::Design.new.should respond_to(:checksum!)
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should calculate a consistent checksum for model" do
|
17
|
-
WithTemplateAndUniqueID.design_doc.checksum!.should eql('caa2b4c27abb82b4e37421de76d96ffc')
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should calculate checksum for complex model" do
|
21
|
-
Article.design_doc.checksum!.should eql('70dff8caea143bf40fad09adf0701104')
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should cache the generated checksum value" do
|
25
|
-
Article.design_doc.checksum!
|
26
|
-
Article.design_doc['couchrest-hash'].should_not be_blank
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe "class methods" do
|
31
|
-
|
32
|
-
describe ".design_doc" do
|
33
|
-
it "should provide Design document" do
|
34
|
-
Article.design_doc.should be_a(::CouchRest::Design)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe ".design_doc_id" do
|
39
|
-
it "should provide a reasonable id" do
|
40
|
-
Article.design_doc_id.should eql("_design/Article")
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe ".design_doc_slug" do
|
45
|
-
it "should provide slug part of design doc" do
|
46
|
-
Article.design_doc_slug.should eql('Article')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe ".design_doc_uri" do
|
51
|
-
it "should provide complete url" do
|
52
|
-
Article.design_doc_uri.should eql("#{COUCHHOST}/#{TESTDB}/_design/Article")
|
53
|
-
end
|
54
|
-
it "should provide complete url for new DB" do
|
55
|
-
db = mock("Database")
|
56
|
-
db.should_receive(:root).and_return('db')
|
57
|
-
Article.design_doc_uri(db).should eql("db/_design/Article")
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe ".stored_design_doc" do
|
62
|
-
it "should load a stored design from the database" do
|
63
|
-
Article.by_date
|
64
|
-
Article.stored_design_doc['_rev'].should_not be_blank
|
65
|
-
end
|
66
|
-
it "should return nil if not already stored" do
|
67
|
-
WithDefaultValues.stored_design_doc.should be_nil
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
describe ".save_design_doc" do
|
72
|
-
it "should call up the design updater" do
|
73
|
-
Article.should_receive(:update_design_doc).with('db', false)
|
74
|
-
Article.save_design_doc('db')
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe ".save_design_doc!" do
|
79
|
-
it "should call save_design_doc with force" do
|
80
|
-
Article.should_receive(:save_design_doc).with('db', true)
|
81
|
-
Article.save_design_doc!('db')
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "basics" do
|
88
|
-
|
89
|
-
before :all do
|
90
|
-
reset_test_db!
|
91
|
-
end
|
92
|
-
|
93
|
-
it "should have been instantiated with views" do
|
94
|
-
d = Article.design_doc
|
95
|
-
d['views']['all']['map'].should include('Article')
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should not have been saved yet" do
|
99
|
-
lambda { Article.database.get(Article.design_doc.id) }.should raise_error(RestClient::ResourceNotFound)
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "after requesting a view" do
|
103
|
-
before :each do
|
104
|
-
Article.all
|
105
|
-
end
|
106
|
-
it "should have saved the design doc after view request" do
|
107
|
-
Article.database.get(Article.design_doc.id).should_not be_nil
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "model with simple views" do
|
112
|
-
before(:all) do
|
113
|
-
Article.all.map{|a| a.destroy(true)}
|
114
|
-
Article.database.bulk_delete
|
115
|
-
written_at = Time.now - 24 * 3600 * 7
|
116
|
-
@titles = ["this and that", "also interesting", "more fun", "some junk"]
|
117
|
-
@titles.each do |title|
|
118
|
-
a = Article.new(:title => title)
|
119
|
-
a.date = written_at
|
120
|
-
a.save
|
121
|
-
written_at += 24 * 3600
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
it "will send request for the saved design doc on view request" do
|
126
|
-
reset_test_db!
|
127
|
-
Article.should_receive(:stored_design_doc).and_return(nil)
|
128
|
-
Article.by_date
|
129
|
-
end
|
130
|
-
|
131
|
-
it "should have generated a design doc" do
|
132
|
-
Article.design_doc["views"]["by_date"].should_not be_nil
|
133
|
-
end
|
134
|
-
it "should save the design doc when view requested" do
|
135
|
-
Article.by_date
|
136
|
-
doc = Article.database.get Article.design_doc.id
|
137
|
-
doc['views']['by_date'].should_not be_nil
|
138
|
-
end
|
139
|
-
it "should save design doc if a view changed" do
|
140
|
-
Article.by_date
|
141
|
-
orig = Article.stored_design_doc
|
142
|
-
design = Article.design_doc
|
143
|
-
view = design['views']['by_date']['map']
|
144
|
-
design['views']['by_date']['map'] = view + ' ' # little bit of white space
|
145
|
-
Article.by_date
|
146
|
-
Article.stored_design_doc['_rev'].should_not eql(orig['_rev'])
|
147
|
-
orig['views']['by_date']['map'].should_not eql(Article.design_doc['views']['by_date']['map'])
|
148
|
-
end
|
149
|
-
it "should not save design doc if not changed" do
|
150
|
-
Article.by_date
|
151
|
-
orig = Article.stored_design_doc['_rev']
|
152
|
-
Article.by_date
|
153
|
-
Article.stored_design_doc['_rev'].should eql(orig)
|
154
|
-
end
|
155
|
-
it "should recreate the design doc if database deleted" do
|
156
|
-
Article.database.recreate!
|
157
|
-
lambda { Article.by_date }.should_not raise_error(RestClient::ResourceNotFound)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
describe "when auto_update_design_doc false" do
|
162
|
-
|
163
|
-
before :all do
|
164
|
-
Article.auto_update_design_doc = false
|
165
|
-
Article.save_design_doc!
|
166
|
-
end
|
167
|
-
|
168
|
-
after :all do
|
169
|
-
Article.auto_update_design_doc = true
|
170
|
-
end
|
171
|
-
|
172
|
-
it "will not send a request for the saved design doc" do
|
173
|
-
Article.should_not_receive(:stored_design_doc)
|
174
|
-
Article.by_date
|
175
|
-
end
|
176
|
-
|
177
|
-
it "will not update stored design doc if view changed" do
|
178
|
-
Article.by_date
|
179
|
-
orig = Article.stored_design_doc
|
180
|
-
design = Article.design_doc
|
181
|
-
view = design['views']['by_date']['map']
|
182
|
-
design['views']['by_date']['map'] = view + ' '
|
183
|
-
Article.by_date
|
184
|
-
Article.stored_design_doc['_rev'].should eql(orig['_rev'])
|
185
|
-
end
|
186
|
-
|
187
|
-
it "will update stored design if forced" do
|
188
|
-
Article.by_date
|
189
|
-
orig = Article.stored_design_doc
|
190
|
-
design = Article.design_doc
|
191
|
-
view = design['views']['by_date']['map']
|
192
|
-
design['views']['by_date']['map'] = view + ' '
|
193
|
-
Article.save_design_doc!
|
194
|
-
Article.stored_design_doc['_rev'].should_not eql(orig['_rev'])
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
describe "lazily refreshing the design document" do
|
200
|
-
before(:all) do
|
201
|
-
@db = reset_test_db!
|
202
|
-
WithTemplateAndUniqueID.new('slug' => '1').save
|
203
|
-
end
|
204
|
-
it "should not save the design doc twice" do
|
205
|
-
WithTemplateAndUniqueID.all
|
206
|
-
rev = WithTemplateAndUniqueID.design_doc['_rev']
|
207
|
-
WithTemplateAndUniqueID.design_doc['_rev'].should eql(rev)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
|
212
|
-
end
|