couch_tomato 0.1.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.
- data/MIT-LICENSE.txt +19 -0
- data/README.md +96 -0
- data/init.rb +3 -0
- data/lib/core_ext/date.rb +10 -0
- data/lib/core_ext/duplicable.rb +43 -0
- data/lib/core_ext/extract_options.rb +14 -0
- data/lib/core_ext/inheritable_attributes.rb +222 -0
- data/lib/core_ext/object.rb +5 -0
- data/lib/core_ext/string.rb +19 -0
- data/lib/core_ext/symbol.rb +15 -0
- data/lib/core_ext/time.rb +12 -0
- data/lib/couch_tomato/database.rb +279 -0
- data/lib/couch_tomato/js_view_source.rb +182 -0
- data/lib/couch_tomato/migration.rb +52 -0
- data/lib/couch_tomato/migrator.rb +235 -0
- data/lib/couch_tomato/persistence/base.rb +62 -0
- data/lib/couch_tomato/persistence/belongs_to_property.rb +58 -0
- data/lib/couch_tomato/persistence/callbacks.rb +60 -0
- data/lib/couch_tomato/persistence/dirty_attributes.rb +27 -0
- data/lib/couch_tomato/persistence/json.rb +48 -0
- data/lib/couch_tomato/persistence/magic_timestamps.rb +15 -0
- data/lib/couch_tomato/persistence/properties.rb +58 -0
- data/lib/couch_tomato/persistence/simple_property.rb +97 -0
- data/lib/couch_tomato/persistence/validation.rb +18 -0
- data/lib/couch_tomato/persistence.rb +85 -0
- data/lib/couch_tomato/replicator.rb +50 -0
- data/lib/couch_tomato.rb +46 -0
- data/lib/tasks/couch_tomato.rake +128 -0
- data/rails/init.rb +7 -0
- data/spec/callbacks_spec.rb +271 -0
- data/spec/comment.rb +8 -0
- data/spec/create_spec.rb +22 -0
- data/spec/custom_view_spec.rb +134 -0
- data/spec/destroy_spec.rb +29 -0
- data/spec/fixtures/address.rb +9 -0
- data/spec/fixtures/person.rb +6 -0
- data/spec/property_spec.rb +103 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/unit/attributes_spec.rb +26 -0
- data/spec/unit/callbacks_spec.rb +33 -0
- data/spec/unit/create_spec.rb +58 -0
- data/spec/unit/customs_views_spec.rb +15 -0
- data/spec/unit/database_spec.rb +38 -0
- data/spec/unit/dirty_attributes_spec.rb +113 -0
- data/spec/unit/string_spec.rb +13 -0
- data/spec/unit/view_query_spec.rb +9 -0
- data/spec/update_spec.rb +40 -0
- data/test/test_helper.rb +63 -0
- data/test/unit/database_test.rb +285 -0
- data/test/unit/js_view_test.rb +362 -0
- data/test/unit/property_test.rb +193 -0
- metadata +133 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
# class Build
|
4
|
+
# include CouchTomato::Persistence
|
5
|
+
#
|
6
|
+
# property :state
|
7
|
+
# property :time
|
8
|
+
#
|
9
|
+
# view :timeline, :key => :time
|
10
|
+
# view :count, :key => :time, :reduce => true
|
11
|
+
# view :minimal_timeline, :key => :time, :properties => [:state], :type => :properties
|
12
|
+
# view :key_array_timeline, :key => [:time, :state]
|
13
|
+
# view :custom_timeline, :map => "function(doc) { emit(doc._id, {state: 'custom_' + doc.state}); }", :type => :custom
|
14
|
+
# view :custom_timeline_returns_docs, :map => "function(doc) { emit(doc._id, null); }", :include_docs => true, :type => :custom
|
15
|
+
# view :raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}"
|
16
|
+
# view :filtered_raw, :type => :raw, :map => "function(doc) {emit(doc._id, doc.state)}", :results_filter => lambda{|res| res['rows'].map{|row| row['value']}}
|
17
|
+
# view :with_view_options, :group => true, :key => :time
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# describe 'view' do
|
21
|
+
# before(:each) do
|
22
|
+
# recreate_db
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# it "should return instances of the class" do
|
26
|
+
# CouchTomato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
27
|
+
# results = CouchTomato.database.view(Build.timeline)
|
28
|
+
# results.map(&:class).should == [Build]
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# it "should pass the view options to the view query" do
|
32
|
+
# query = mock 'query'
|
33
|
+
# CouchTomato::View::ViewQuery.stub!(:new).and_return(query)
|
34
|
+
# query.should_receive(:query_view!).with(hash_including(:key => 1)).and_return('rows' => [])
|
35
|
+
# CouchTomato.database.view Build.timeline(:key => 1)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# it "should not return documents that don't have a matching ruby_class" do
|
39
|
+
# CouchTomato.couchrest_database.save_doc({:time => 'x'})
|
40
|
+
# CouchTomato.database.view(Build.timeline).should == []
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# it "should count documents" do
|
44
|
+
# CouchTomato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
45
|
+
# CouchTomato.database.view(Build.count(:reduce => true)).should == 1
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# it "should count zero documents" do
|
49
|
+
# CouchTomato.database.view(Build.count(:reduce => true)).should == 0
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# describe "properties defined" do
|
53
|
+
# it "should assign the configured properties" do
|
54
|
+
# CouchTomato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
|
55
|
+
# CouchTomato.database.view(Build.minimal_timeline).first.state.should == 'success'
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# it "should not assign the properties not configured" do
|
59
|
+
# CouchTomato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
|
60
|
+
# CouchTomato.database.view(Build.minimal_timeline).first.time.should be_nil
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# it "should assign the id even if it is not configured" do
|
64
|
+
# id = CouchTomato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')['id']
|
65
|
+
# CouchTomato.database.view(Build.minimal_timeline).first._id.should == id
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# describe "no properties defined" do
|
70
|
+
# it "should assign all properties to the objects by default" do
|
71
|
+
# id = CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', :ruby_class => 'Build'})['id']
|
72
|
+
# result = CouchTomato.database.view(Build.timeline).first
|
73
|
+
# result.state.should == 'success'
|
74
|
+
# result.time.should == '2008-01-01'
|
75
|
+
# result._id.should == id
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# describe "map function given" do
|
80
|
+
# it "should still return instances of the class" do
|
81
|
+
# CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
82
|
+
# CouchTomato.database.view(Build.custom_timeline).map(&:class).should == [Build]
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# it "should assign the properties from the value" do
|
86
|
+
# CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
87
|
+
# CouchTomato.database.view(Build.custom_timeline).map(&:state).should == ['custom_success']
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# it "should leave the other properties blank" do
|
91
|
+
# CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
92
|
+
# CouchTomato.database.view(Build.custom_timeline).map(&:time).should == [nil]
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# describe "that returns null documents" do
|
96
|
+
# it "should return instances of the class" do
|
97
|
+
# CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
98
|
+
# CouchTomato.database.view(Build.custom_timeline_returns_docs).map(&:class).should == [Build]
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# it "should assign the properties from the value" do
|
102
|
+
# CouchTomato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
|
103
|
+
# CouchTomato.database.view(Build.custom_timeline_returns_docs).map(&:state).should == ['success']
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# describe "with array as key" do
|
109
|
+
# it "should create a map function with the composite key" do
|
110
|
+
# CouchTomato::View::ViewQuery.should_receive(:new).with(anything, anything, anything, string_matching(/emit\(\[doc\['time'\], doc\['state'\]\]/), anything).and_return(stub('view query').as_null_object)
|
111
|
+
# CouchTomato.database.view Build.key_array_timeline
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# describe "raw view" do
|
116
|
+
# it "should return the raw data" do
|
117
|
+
# CouchTomato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
118
|
+
# CouchTomato.database.view(Build.raw)['rows'][0]['value'].should == 'success'
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# it "should return filtred raw data" do
|
122
|
+
# CouchTomato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
|
123
|
+
# CouchTomato.database.view(Build.filtered_raw).should == ['success']
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# it "should pass view options declared in the view declaration to the query" do
|
127
|
+
# view_query = mock 'view_query'
|
128
|
+
# CouchTomato::View::ViewQuery.stub!(:new).and_return(view_query)
|
129
|
+
# view_query.should_receive(:query_view!).with(hash_including(:group => true)).and_return({'rows' => []})
|
130
|
+
# CouchTomato.database.view(Build.with_view_options)
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe 'destroy' do
|
4
|
+
before(:all) do
|
5
|
+
recreate_db
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@comment = Comment.new :title => 'title'
|
10
|
+
CouchTomato.database.save_document! @comment
|
11
|
+
@comment_id = @comment.id
|
12
|
+
CouchTomato.database.destroy_document @comment
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should unset the id" do
|
16
|
+
@comment._id.should be_nil
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should unset the revision" do
|
20
|
+
@comment._rev.should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should remove the document from the database" do
|
24
|
+
lambda {
|
25
|
+
CouchTomato.couchrest_database.get(@comment_id).should
|
26
|
+
}.should raise_error(RestClient::ResourceNotFound)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require File.join(File.dirname(__FILE__), 'fixtures', 'address')
|
3
|
+
require File.join(File.dirname(__FILE__), 'fixtures', 'person')
|
4
|
+
|
5
|
+
class Watch
|
6
|
+
include CouchTomato::Persistence
|
7
|
+
|
8
|
+
property :time, :type => Time
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
describe 'properties' do
|
13
|
+
before(:all) do
|
14
|
+
recreate_db
|
15
|
+
reload_test_class("Comment")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return the property names" do
|
19
|
+
Comment.property_names.should == [:created_at, :updated_at, :title, :commenter]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should persist a string" do
|
23
|
+
c = Comment.new :title => 'my title'
|
24
|
+
CouchTomato.database.save_document! c
|
25
|
+
c = CouchTomato.database.load_document c.id
|
26
|
+
c.title.should == 'my title'
|
27
|
+
end
|
28
|
+
|
29
|
+
# Explicitly declaring `:type => String` on a property raises an exception
|
30
|
+
# "wrong argument type String (expected Hash)" on load. The json gem defines a
|
31
|
+
# String.json_create method that expects a hash in the form `{'raw' => [0x61,
|
32
|
+
# 0x62]}` where `[0x61, 0x62].pack => 'ab'`
|
33
|
+
#
|
34
|
+
# CouchTomato expects various `json_create` methods to accept a String (and
|
35
|
+
# return an instance). Currently, if `:type` is not specified, the type of the
|
36
|
+
# value is assumed to be String and `json_create` is not called.
|
37
|
+
|
38
|
+
it "Should raise an exception if a property is of a JSON native type" do
|
39
|
+
[Float, String, Integer, Array, Hash, Fixnum].each do |klass|
|
40
|
+
doing {
|
41
|
+
Comment.class_eval do
|
42
|
+
property :name, :type => klass
|
43
|
+
end
|
44
|
+
}.should raise_error("#{klass} is a native JSON type, only custom types should be specified")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should persist a number" do
|
49
|
+
c = Comment.new :title => 3
|
50
|
+
CouchTomato.database.save_document! c
|
51
|
+
c = CouchTomato.database.load_document c.id
|
52
|
+
c.title.should == 3
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should persist a hash" do
|
56
|
+
c = Comment.new :title => {'key' => 'value'}
|
57
|
+
CouchTomato.database.save_document! c
|
58
|
+
c = CouchTomato.database.load_document c.id
|
59
|
+
c.title.should == {'key' => 'value'}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should persist a Time object" do
|
63
|
+
w = Watch.new :time => Time.now
|
64
|
+
CouchTomato.database.save_document! w
|
65
|
+
w = CouchTomato.database.load_document w.id
|
66
|
+
w.time.year.should == Time.now.year
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should persist an object" do
|
70
|
+
p = Person.new :name => 'Bob'
|
71
|
+
a = Address.new :city => 'Denver'
|
72
|
+
p.ship_address = a
|
73
|
+
CouchTomato.database.save_document! p
|
74
|
+
p = CouchTomato.database.load_document p.id
|
75
|
+
p.ship_address.should === a
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should persist null for a null " do
|
79
|
+
p = Person.new :name => 'Bob'
|
80
|
+
p.ship_address = nil
|
81
|
+
CouchTomato.database.save_document! p
|
82
|
+
p = CouchTomato.database.load_document p.id
|
83
|
+
p.ship_address.should be_nil
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "predicate" do
|
87
|
+
it "should return true if property set" do
|
88
|
+
Comment.new(:title => 'title').title?.should be_true
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return false if property nil" do
|
92
|
+
Comment.new.title?.should be_false
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return false if property false" do
|
96
|
+
Comment.new(:title => false).title?.should be_false
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return false if property blank" do
|
100
|
+
Comment.new(:title => '').title?.should be_false
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
5
|
+
alias :doing :lambda
|
6
|
+
|
7
|
+
require 'couch_tomato'
|
8
|
+
require File.dirname(__FILE__) + "/comment"
|
9
|
+
|
10
|
+
CouchTomato::Config.database_name = 'couch_tomato_test'
|
11
|
+
CouchTomato::Config.database_server = 'http://127.0.0.1:5984/'
|
12
|
+
|
13
|
+
|
14
|
+
def recreate_db
|
15
|
+
CouchTomato.couchrest_database.delete! rescue nil
|
16
|
+
CouchTomato.couchrest_database.server.create_db CouchTomato::Config.database_name
|
17
|
+
end
|
18
|
+
recreate_db
|
19
|
+
|
20
|
+
Spec::Matchers.define :string_matching do |regex|
|
21
|
+
match do |string|
|
22
|
+
string =~ regex
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def reload_test_class (class_name)
|
27
|
+
Object.class_eval do
|
28
|
+
if const_defined? class_name
|
29
|
+
remove_const class_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
file_name = class_name.gsub(/::/, '/').
|
34
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
35
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
36
|
+
tr("-", "_").
|
37
|
+
downcase
|
38
|
+
|
39
|
+
load File.dirname(__FILE__) + "/#{file_name}.rb"
|
40
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class Plant
|
4
|
+
include CouchTomato::Persistence
|
5
|
+
property :leaf_count
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "attributes" do
|
9
|
+
|
10
|
+
describe 'attributes=' do
|
11
|
+
it "should assign the attributes" do
|
12
|
+
plant = Plant.new
|
13
|
+
plant.attributes = {:leaf_count => 1}
|
14
|
+
plant.leaf_count.should == 1
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "attributes" do
|
19
|
+
it "should return the attributes" do
|
20
|
+
plant = Plant.new(:leaf_count => 1)
|
21
|
+
plant.attributes.should == {:leaf_count => 1, :created_at => nil, :updated_at => nil}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class Tree
|
4
|
+
include CouchTomato::Persistence
|
5
|
+
before_validation :water!
|
6
|
+
before_validation lambda {|tree| tree.root_count += 1 }
|
7
|
+
|
8
|
+
property :leaf_count
|
9
|
+
property :root_count
|
10
|
+
|
11
|
+
def water!
|
12
|
+
self.leaf_count += 1
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
describe 'before_validation callback' do
|
18
|
+
before :each do
|
19
|
+
@tree = Tree.new(:leaf_count => 1, :root_count => 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should call water! when validated" do
|
23
|
+
@tree.leaf_count.should == 1
|
24
|
+
@tree.should be_valid
|
25
|
+
@tree.leaf_count.should == 2
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should call lambda when validated" do
|
29
|
+
@tree.root_count.should == 1
|
30
|
+
@tree.should be_valid
|
31
|
+
@tree.root_count.should == 2
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe "create" do
|
4
|
+
|
5
|
+
describe "succeeds" do
|
6
|
+
before(:each) do
|
7
|
+
@comment = Comment.new :title => 'my_title'
|
8
|
+
CouchTomato::Database.new(stub('database', :save_doc => {'rev' => '123', 'id' => '456'}, :info => nil)).save_document!(@comment)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should assign the id" do
|
12
|
+
@comment._id.should == '456'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should assign the revision" do
|
16
|
+
@comment._rev.should == '123'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set created at" do
|
20
|
+
@comment.created_at.should >= Time.now - 10
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should set updated at" do
|
24
|
+
@comment.updated_at.should >= Time.now - 10
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "fails" do
|
29
|
+
before(:each) do
|
30
|
+
@comment = Comment.new
|
31
|
+
CouchTomato::Database.new(stub('database', :info => nil)).save_document(@comment)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should not assign an id" do
|
35
|
+
@comment._id.should be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not assign a revision" do
|
39
|
+
@comment._rev.should be_nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should not set created at" do
|
43
|
+
@comment.created_at.should be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should set updated at" do
|
47
|
+
@comment.updated_at.should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "with bank" do
|
51
|
+
it "should raise an exception" do
|
52
|
+
lambda {
|
53
|
+
@comment.save!
|
54
|
+
}.should raise_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe CouchTomato::View::CustomViews do
|
4
|
+
|
5
|
+
class MyViewSpec; end
|
6
|
+
class ModelWithView
|
7
|
+
include CouchTomato::Persistence
|
8
|
+
view :all, :type => MyViewSpec
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should use a custom viewspec class" do
|
12
|
+
MyViewSpec.should_receive(:new)
|
13
|
+
ModelWithView.all
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class DbTestUser
|
4
|
+
end
|
5
|
+
|
6
|
+
describe CouchTomato::Database, 'new' do
|
7
|
+
it "should raise an exception if the database doesn't exist" do
|
8
|
+
lambda {
|
9
|
+
CouchTomato::Database.new CouchRest.database('couch_tomato_invalid')
|
10
|
+
}.should raise_error('Database \'couch_tomato_invalid\' does not exist.')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe CouchTomato::Database, 'load' do
|
15
|
+
it "should raise an exception if nil given" do
|
16
|
+
db = CouchTomato::Database.new(stub('couchrest db', :info => nil))
|
17
|
+
lambda {
|
18
|
+
db.load nil
|
19
|
+
}.should raise_error("Can't load a document without an id (got nil)")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set itself on the model" do
|
23
|
+
user = mock 'user'
|
24
|
+
DbTestUser.stub!(:new).and_return(user)
|
25
|
+
db = CouchTomato::Database.new(stub('couchrest db', :info => nil, :get => {'ruby_class' => 'DbTestUser'}))
|
26
|
+
user.should_receive(:database=).with(db)
|
27
|
+
db.load '1'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe CouchTomato::Database, 'save_document' do
|
32
|
+
it "should set itself on the model for a new object before doing anything else" do
|
33
|
+
db = CouchTomato::Database.new(stub('couchrest db', :info => nil))
|
34
|
+
user = stub('user', :new? => true, :valid? => false).as_null_object
|
35
|
+
user.should_receive(:database=).with(db)
|
36
|
+
db.save_document user
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class Plate
|
4
|
+
include CouchTomato::Persistence
|
5
|
+
|
6
|
+
property :food
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'dirty attribute tracking' do
|
10
|
+
before(:each) do
|
11
|
+
@couchrest_db = stub('database', :save_doc => {'id' => '1', 'rev' => '2'}, :info => nil)
|
12
|
+
@db = CouchTomato::Database.new(@couchrest_db)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "save" do
|
16
|
+
it "should not save when nothing dirty" do
|
17
|
+
plate = Plate.new :food => 'sushi'
|
18
|
+
@db.save_document!(plate)
|
19
|
+
@couchrest_db.should_not_receive(:save_doc)
|
20
|
+
@db.save_document(plate)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return true when not dirty" do
|
24
|
+
plate = Plate.new :food => 'sushi'
|
25
|
+
@db.save_document!(plate)
|
26
|
+
@db.save_document(plate).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should save when there are dirty attributes" do
|
30
|
+
plate = Plate.new :food => 'sushi'
|
31
|
+
@db.save_document!(plate)
|
32
|
+
plate.food = 'burger'
|
33
|
+
@couchrest_db.should_receive(:save_doc)
|
34
|
+
@db.save_document(plate)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "newly created object" do
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
@plate = Plate.new :food => 'sushi'
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "access old values" do
|
45
|
+
it "should return the old value" do
|
46
|
+
@plate.food = 'burger'
|
47
|
+
@plate.food_was.should == 'sushi'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "check for dirty" do
|
52
|
+
it "should return true if attribute changed" do
|
53
|
+
@plate.food = 'burger'
|
54
|
+
@plate.should be_food_changed
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return false if attribute not changed" do
|
58
|
+
@plate.should_not be_food_changed
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return false if attribute forced not changed" do
|
62
|
+
@plate.food = 'burger'
|
63
|
+
@plate.food_not_changed
|
64
|
+
@plate.should_not be_food_changed
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "object loaded from database" do
|
70
|
+
before(:each) do
|
71
|
+
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil)
|
72
|
+
@plate = CouchTomato::Database.new(couchrest_db).load_document '1'
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "access old values" do
|
76
|
+
it "should return the old value" do
|
77
|
+
@plate.food = 'burger'
|
78
|
+
@plate.food_was.should == 'sushi'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "check for dirty" do
|
83
|
+
it "should return true if attribute changed" do
|
84
|
+
@plate.food = 'burger'
|
85
|
+
@plate.should be_food_changed
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return true if array attribute changed" do
|
89
|
+
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => ['sushi'], 'ruby_class' => 'Plate'}, :info => nil)
|
90
|
+
plate = CouchTomato::Database.new(couchrest_db).load_document '1'
|
91
|
+
plate.food << 'burger'
|
92
|
+
plate.should be_food_changed
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return false if attribute not changed" do
|
96
|
+
@plate.should_not be_food_changed
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
describe "after save" do
|
103
|
+
it "should reset all attributes to not dirty" do
|
104
|
+
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :info => nil, :save_doc => {})
|
105
|
+
db = CouchTomato::Database.new(couchrest_db)
|
106
|
+
@plate = db.load_document '1'
|
107
|
+
@plate.food = 'burger'
|
108
|
+
db.save! @plate
|
109
|
+
@plate.should_not be_food_changed
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe String, 'camelize' do
|
4
|
+
it "should camelize a string" do
|
5
|
+
'my_string'.camelize.should == 'MyString'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe String, 'underscore' do
|
10
|
+
it "should underscore a string" do
|
11
|
+
'MyString'.underscore.should == 'my_string'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe CouchTomato::View::ViewQuery, 'query_view' do
|
4
|
+
it "should not pass a key if conditions are empty" do
|
5
|
+
db = mock 'db'
|
6
|
+
db.should_receive(:view).with(anything, {})
|
7
|
+
CouchTomato::View::ViewQuery.new(db, '', '', '', '').query_view!
|
8
|
+
end
|
9
|
+
end
|
data/spec/update_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe "create" do
|
4
|
+
before(:all) do
|
5
|
+
recreate_db
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@comment = Comment.new :title => 'my_title'
|
10
|
+
CouchTomato.database.save_document! @comment
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should update the revision" do
|
14
|
+
old_rev = @comment._rev
|
15
|
+
@comment.title = 'xyz'
|
16
|
+
CouchTomato.database.save_document! @comment
|
17
|
+
@comment._rev.should_not == old_rev
|
18
|
+
@comment._rev.should_not be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not update created at" do
|
22
|
+
old_created_at = @comment.created_at
|
23
|
+
@comment.title = 'xyz'
|
24
|
+
CouchTomato.database.save_document! @comment
|
25
|
+
@comment.created_at.should == old_created_at
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should update updated at" do
|
29
|
+
old_updated_at = @comment.updated_at
|
30
|
+
@comment.title = 'xyz'
|
31
|
+
CouchTomato.database.save_document! @comment
|
32
|
+
@comment.updated_at.should > old_updated_at
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should update the attributes" do
|
36
|
+
@comment.title = 'new title'
|
37
|
+
CouchTomato.database.save_document! @comment
|
38
|
+
CouchTomato.couchrest_database.get("#{@comment.id}")['title'].should == 'new title'
|
39
|
+
end
|
40
|
+
end
|