langalex-couch_potato 0.1.1 → 0.2.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/README.md +260 -0
- data/VERSION.yml +2 -2
- data/init.rb +3 -0
- data/lib/core_ext/date.rb +10 -0
- data/lib/core_ext/string.rb +15 -0
- data/lib/core_ext/time.rb +6 -9
- data/lib/couch_potato/database.rb +90 -0
- data/lib/couch_potato/persistence/belongs_to_property.rb +1 -1
- data/lib/couch_potato/persistence/callbacks.rb +14 -11
- data/lib/couch_potato/persistence/dirty_attributes.rb +13 -6
- data/lib/couch_potato/persistence/json.rb +9 -14
- data/lib/couch_potato/persistence/magic_timestamps.rb +13 -0
- data/lib/couch_potato/persistence/properties.rb +10 -8
- data/lib/couch_potato/persistence/simple_property.rb +14 -11
- data/lib/couch_potato/persistence.rb +11 -165
- data/lib/couch_potato/view/base_view_spec.rb +20 -0
- data/lib/couch_potato/view/custom_view_spec.rb +26 -0
- data/lib/couch_potato/view/custom_views.rb +30 -0
- data/lib/couch_potato/view/model_view_spec.rb +39 -0
- data/lib/couch_potato/view/properties_view_spec.rb +35 -0
- data/lib/couch_potato/view/raw_view_spec.rb +21 -0
- data/lib/couch_potato/view/view_query.rb +45 -0
- data/lib/couch_potato.rb +23 -6
- data/rails/init.rb +7 -0
- data/spec/callbacks_spec.rb +40 -43
- data/spec/create_spec.rb +9 -60
- data/spec/custom_view_spec.rb +93 -19
- data/spec/destroy_spec.rb +5 -4
- data/spec/property_spec.rb +22 -8
- data/spec/spec_helper.rb +12 -14
- data/spec/unit/attributes_spec.rb +26 -0
- data/spec/unit/create_spec.rb +58 -0
- data/spec/{dirty_attributes_spec.rb → unit/dirty_attributes_spec.rb} +31 -13
- data/spec/unit/string_spec.rb +13 -0
- data/spec/unit/view_query_spec.rb +2 -3
- data/spec/update_spec.rb +8 -7
- metadata +54 -32
- data/README.textile +0 -340
- data/lib/couch_potato/active_record/compatibility.rb +0 -9
- data/lib/couch_potato/ordering.rb +0 -84
- data/lib/couch_potato/persistence/bulk_save_queue.rb +0 -47
- data/lib/couch_potato/persistence/collection.rb +0 -51
- data/lib/couch_potato/persistence/custom_view.rb +0 -41
- data/lib/couch_potato/persistence/external_collection.rb +0 -83
- data/lib/couch_potato/persistence/external_has_many_property.rb +0 -72
- data/lib/couch_potato/persistence/find.rb +0 -21
- data/lib/couch_potato/persistence/finder.rb +0 -65
- data/lib/couch_potato/persistence/inline_has_many_property.rb +0 -43
- data/lib/couch_potato/persistence/view_query.rb +0 -81
- data/lib/couch_potato/versioning.rb +0 -46
- data/spec/attributes_spec.rb +0 -42
- data/spec/belongs_to_spec.rb +0 -55
- data/spec/find_spec.rb +0 -96
- data/spec/finder_spec.rb +0 -125
- data/spec/has_many_spec.rb +0 -241
- data/spec/inline_collection_spec.rb +0 -15
- data/spec/ordering_spec.rb +0 -95
- data/spec/reload_spec.rb +0 -50
- data/spec/unit/external_collection_spec.rb +0 -84
- data/spec/unit/finder_spec.rb +0 -10
- data/spec/versioning_spec.rb +0 -150
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
3
|
class Plate
|
4
4
|
include CouchPotato::Persistence
|
@@ -7,24 +7,25 @@ class Plate
|
|
7
7
|
end
|
8
8
|
|
9
9
|
describe 'dirty attribute tracking' do
|
10
|
-
before(:
|
11
|
-
|
10
|
+
before(:each) do
|
11
|
+
@couchrest_db = stub('database', :save_doc => {'id' => '1', 'rev' => '2'})
|
12
|
+
@db = CouchPotato::Database.new(@couchrest_db)
|
12
13
|
end
|
13
14
|
|
14
15
|
describe "save" do
|
15
16
|
it "should not save when nothing dirty" do
|
16
|
-
plate = Plate.
|
17
|
-
|
18
|
-
|
19
|
-
plate
|
17
|
+
plate = Plate.new :food => 'sushi'
|
18
|
+
@db.save_document!(plate)
|
19
|
+
@couchrest_db.should_not_receive(:save_doc)
|
20
|
+
@db.save_document(plate)
|
20
21
|
end
|
21
22
|
|
22
23
|
it "should save when there are dirty attributes" do
|
23
|
-
plate = Plate.
|
24
|
-
|
24
|
+
plate = Plate.new :food => 'sushi'
|
25
|
+
@db.save_document!(plate)
|
25
26
|
plate.food = 'burger'
|
26
|
-
|
27
|
-
plate
|
27
|
+
@couchrest_db.should_receive(:save_doc)
|
28
|
+
@db.save_document(plate)
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
@@ -50,13 +51,19 @@ describe 'dirty attribute tracking' do
|
|
50
51
|
it "should return false if attribute not changed" do
|
51
52
|
@plate.should_not be_food_changed
|
52
53
|
end
|
54
|
+
|
55
|
+
it "should return false if attribute forced not changed" do
|
56
|
+
@plate.food = 'burger'
|
57
|
+
@plate.food_not_changed
|
58
|
+
@plate.should_not be_food_changed
|
59
|
+
end
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
56
63
|
describe "object loaded from database" do
|
57
64
|
before(:each) do
|
58
|
-
|
59
|
-
@plate =
|
65
|
+
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'})
|
66
|
+
@plate = CouchPotato::Database.new(couchrest_db).load_document '1'
|
60
67
|
end
|
61
68
|
|
62
69
|
describe "access old values" do
|
@@ -79,4 +86,15 @@ describe 'dirty attribute tracking' do
|
|
79
86
|
end
|
80
87
|
|
81
88
|
|
89
|
+
describe "after save" do
|
90
|
+
it "should reset all attributes to not dirty" do
|
91
|
+
couchrest_db = stub('database', :get => {'_id' => '1', '_rev' => '2', 'food' => 'sushi', 'ruby_class' => 'Plate'}, :save_doc => {})
|
92
|
+
db = CouchPotato::Database.new(couchrest_db)
|
93
|
+
@plate = db.load_document '1'
|
94
|
+
@plate.food = 'burger'
|
95
|
+
db.save! @plate
|
96
|
+
@plate.should_not be_food_changed
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
82
100
|
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
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
|
-
describe CouchPotato::
|
3
|
+
describe CouchPotato::View::ViewQuery, 'query_view' do
|
4
4
|
it "should not pass a key if conditions are empty" do
|
5
5
|
db = mock 'db'
|
6
6
|
db.should_receive(:view).with(anything, {})
|
7
|
-
|
8
|
-
CouchPotato::Persistence::ViewQuery.new('', '', '', '', {}).query_view!
|
7
|
+
CouchPotato::View::ViewQuery.new(db, '', '', '', '').query_view!
|
9
8
|
end
|
10
9
|
end
|
data/spec/update_spec.rb
CHANGED
@@ -2,38 +2,39 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
2
2
|
|
3
3
|
describe "create" do
|
4
4
|
before(:all) do
|
5
|
-
|
5
|
+
recreate_db
|
6
6
|
end
|
7
7
|
|
8
8
|
before(:each) do
|
9
9
|
@comment = Comment.new :title => 'my_title'
|
10
|
-
@comment
|
10
|
+
CouchPotato.database.save_document! @comment
|
11
11
|
end
|
12
12
|
|
13
13
|
it "should update the revision" do
|
14
14
|
old_rev = @comment._rev
|
15
15
|
@comment.title = 'xyz'
|
16
|
-
@comment
|
16
|
+
CouchPotato.database.save_document! @comment
|
17
17
|
@comment._rev.should_not == old_rev
|
18
18
|
@comment._rev.should_not be_nil
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should not update created at" do
|
22
22
|
old_created_at = @comment.created_at
|
23
|
-
@comment.
|
23
|
+
@comment.title = 'xyz'
|
24
|
+
CouchPotato.database.save_document! @comment
|
24
25
|
@comment.created_at.should == old_created_at
|
25
26
|
end
|
26
27
|
|
27
28
|
it "should update updated at" do
|
28
29
|
old_updated_at = @comment.updated_at
|
29
30
|
@comment.title = 'xyz'
|
30
|
-
@comment
|
31
|
+
CouchPotato.database.save_document! @comment
|
31
32
|
@comment.updated_at.should > old_updated_at
|
32
33
|
end
|
33
34
|
|
34
35
|
it "should update the attributes" do
|
35
36
|
@comment.title = 'new title'
|
36
|
-
@comment
|
37
|
-
CouchPotato
|
37
|
+
CouchPotato.database.save_document! @comment
|
38
|
+
CouchPotato.couchrest_database.get("#{@comment.id}")['title'].should == 'new title'
|
38
39
|
end
|
39
40
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: langalex-couch_potato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Lang
|
@@ -9,71 +9,93 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-04-28 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: validatable
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: jchris-couchrest
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.12
|
44
|
+
version:
|
16
45
|
description: Ruby persistence layer for CouchDB
|
17
46
|
email: alex@upstream-berlin.com
|
18
47
|
executables: []
|
19
48
|
|
20
49
|
extensions: []
|
21
50
|
|
22
|
-
extra_rdoc_files:
|
23
|
-
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.md
|
24
53
|
files:
|
25
54
|
- MIT-LICENSE.txt
|
26
|
-
- README.
|
55
|
+
- README.md
|
27
56
|
- VERSION.yml
|
28
57
|
- lib/core_ext
|
58
|
+
- lib/core_ext/date.rb
|
29
59
|
- lib/core_ext/object.rb
|
60
|
+
- lib/core_ext/string.rb
|
30
61
|
- lib/core_ext/time.rb
|
31
62
|
- lib/couch_potato
|
32
|
-
- lib/couch_potato/
|
33
|
-
- lib/couch_potato/active_record/compatibility.rb
|
34
|
-
- lib/couch_potato/ordering.rb
|
63
|
+
- lib/couch_potato/database.rb
|
35
64
|
- lib/couch_potato/persistence
|
36
65
|
- lib/couch_potato/persistence/belongs_to_property.rb
|
37
|
-
- lib/couch_potato/persistence/bulk_save_queue.rb
|
38
66
|
- lib/couch_potato/persistence/callbacks.rb
|
39
|
-
- lib/couch_potato/persistence/collection.rb
|
40
|
-
- lib/couch_potato/persistence/custom_view.rb
|
41
67
|
- lib/couch_potato/persistence/dirty_attributes.rb
|
42
|
-
- lib/couch_potato/persistence/external_collection.rb
|
43
|
-
- lib/couch_potato/persistence/external_has_many_property.rb
|
44
|
-
- lib/couch_potato/persistence/find.rb
|
45
|
-
- lib/couch_potato/persistence/finder.rb
|
46
68
|
- lib/couch_potato/persistence/inline_collection.rb
|
47
|
-
- lib/couch_potato/persistence/inline_has_many_property.rb
|
48
69
|
- lib/couch_potato/persistence/json.rb
|
70
|
+
- lib/couch_potato/persistence/magic_timestamps.rb
|
49
71
|
- lib/couch_potato/persistence/properties.rb
|
50
72
|
- lib/couch_potato/persistence/simple_property.rb
|
51
|
-
- lib/couch_potato/persistence/view_query.rb
|
52
73
|
- lib/couch_potato/persistence.rb
|
53
|
-
- lib/couch_potato/
|
74
|
+
- lib/couch_potato/view
|
75
|
+
- lib/couch_potato/view/base_view_spec.rb
|
76
|
+
- lib/couch_potato/view/custom_view_spec.rb
|
77
|
+
- lib/couch_potato/view/custom_views.rb
|
78
|
+
- lib/couch_potato/view/model_view_spec.rb
|
79
|
+
- lib/couch_potato/view/properties_view_spec.rb
|
80
|
+
- lib/couch_potato/view/raw_view_spec.rb
|
81
|
+
- lib/couch_potato/view/view_query.rb
|
54
82
|
- lib/couch_potato.rb
|
55
|
-
- spec/attributes_spec.rb
|
56
|
-
- spec/belongs_to_spec.rb
|
57
83
|
- spec/callbacks_spec.rb
|
58
84
|
- spec/create_spec.rb
|
59
85
|
- spec/custom_view_spec.rb
|
60
86
|
- spec/destroy_spec.rb
|
61
|
-
- spec/dirty_attributes_spec.rb
|
62
|
-
- spec/find_spec.rb
|
63
|
-
- spec/finder_spec.rb
|
64
|
-
- spec/has_many_spec.rb
|
65
|
-
- spec/inline_collection_spec.rb
|
66
|
-
- spec/ordering_spec.rb
|
67
87
|
- spec/property_spec.rb
|
68
|
-
- spec/reload_spec.rb
|
69
88
|
- spec/spec.opts
|
70
89
|
- spec/spec_helper.rb
|
71
90
|
- spec/unit
|
72
|
-
- spec/unit/
|
73
|
-
- spec/unit/
|
91
|
+
- spec/unit/attributes_spec.rb
|
92
|
+
- spec/unit/create_spec.rb
|
93
|
+
- spec/unit/dirty_attributes_spec.rb
|
94
|
+
- spec/unit/string_spec.rb
|
74
95
|
- spec/unit/view_query_spec.rb
|
75
96
|
- spec/update_spec.rb
|
76
|
-
-
|
97
|
+
- rails/init.rb
|
98
|
+
- init.rb
|
77
99
|
has_rdoc: true
|
78
100
|
homepage: http://github.com/langalex/couch_potato
|
79
101
|
post_install_message:
|
data/README.textile
DELETED
@@ -1,340 +0,0 @@
|
|
1
|
-
h2. Couch Potato
|
2
|
-
|
3
|
-
... is a persistence layer written in ruby for CouchDB.
|
4
|
-
|
5
|
-
h3. Mission
|
6
|
-
|
7
|
-
The goal of Couch Potato is to create a migration path for users of ActiveRecord and other object relational mappers to port their applications to CouchDB. It therefore offers a basic set of the functionality provided by most ORMs and adds functionality unique to CouchDB on top.
|
8
|
-
|
9
|
-
h3. Core Features
|
10
|
-
|
11
|
-
Couch Potato is a work in progress so this list will hopefully grow over time.
|
12
|
-
|
13
|
-
* persisting objects by including the CouchPotato::Persistence module
|
14
|
-
* has_many/belongs_to relationships between persistant objects
|
15
|
-
* atomic write operations spanning multiple objects using bulk save queues
|
16
|
-
* extensive spec suite
|
17
|
-
* included versioning support via the CouchPotato::Versioning module
|
18
|
-
* included ordered lists support via the CouchPotato::Ordering module
|
19
|
-
|
20
|
-
h3. Installation
|
21
|
-
|
22
|
-
Couch Potato is hosted as a gem on github which you can install like this:
|
23
|
-
|
24
|
-
sudo gem source --add http://gems.github.com # if you haven't alread
|
25
|
-
sudo gem install langalex-couch_potato
|
26
|
-
|
27
|
-
h4. Using with your ruby application:
|
28
|
-
|
29
|
-
require 'rubygems'
|
30
|
-
gem 'couch_potato'
|
31
|
-
require 'couch_potato'
|
32
|
-
CouchPotato::Config.database_name = 'name of the db'
|
33
|
-
|
34
|
-
Alternatively you can download or clone the source repository and then require lib/couhc_potato.rb.
|
35
|
-
|
36
|
-
h4. Using with Rails
|
37
|
-
|
38
|
-
Add to your config/environment.rb:
|
39
|
-
|
40
|
-
config.gem 'langalex-couch_potato', :lib => 'couch_potato', :source => 'http://gems.github.com'
|
41
|
-
|
42
|
-
Then create a config/couchdb.yml:
|
43
|
-
|
44
|
-
development: development_db_name
|
45
|
-
test: test_db_name
|
46
|
-
production: production_db_name
|
47
|
-
|
48
|
-
Alternatively you can also install Couch Potato directly as a plugin.
|
49
|
-
|
50
|
-
h3. Introduction
|
51
|
-
|
52
|
-
This is a basic tutorial on how to use Couch Potato. If you want to know all the details feel free to read the specs.
|
53
|
-
|
54
|
-
h4. Save, load objects
|
55
|
-
|
56
|
-
First you need a class.
|
57
|
-
|
58
|
-
class User
|
59
|
-
end
|
60
|
-
|
61
|
-
To make instances of this class persistent include the persistence module:
|
62
|
-
|
63
|
-
class User
|
64
|
-
include CouchPotato::Persistence
|
65
|
-
end
|
66
|
-
|
67
|
-
If you want to store any properties you have to declare them:
|
68
|
-
|
69
|
-
class User
|
70
|
-
include CouchPotato::Persistence
|
71
|
-
|
72
|
-
property :name
|
73
|
-
end
|
74
|
-
|
75
|
-
Now you can save your objects:
|
76
|
-
|
77
|
-
user = User.new :name => 'joe'
|
78
|
-
user.save # or save!
|
79
|
-
|
80
|
-
Properties:
|
81
|
-
|
82
|
-
user.name # => 'joe'
|
83
|
-
user.name = {:first => ['joe', 'joey'], :last => 'doe', :middle => 'J'} # you can set any ruby object that responds_to :to_json (includes all core objects)
|
84
|
-
user._id # => "02097f33a0046123f1ebc0ebb6937269"
|
85
|
-
user._rev # => "2769180384"
|
86
|
-
user.created_at # => Fri Oct 24 19:05:54 +0200 2008
|
87
|
-
user.updated_at # => Fri Oct 24 19:05:54 +0200 2008
|
88
|
-
user.new_document? # => false, for compatibility new_record? will work as well
|
89
|
-
|
90
|
-
You can of course also retrieve your instance:
|
91
|
-
|
92
|
-
User.get "02097f33a0046123f1ebc0ebb6937269" # => <#User 0x3075>
|
93
|
-
|
94
|
-
h4. Object validations
|
95
|
-
|
96
|
-
Couch Potato uses the validatable library for vaidation (http://validatable.rubyforge.org/)\
|
97
|
-
|
98
|
-
class User
|
99
|
-
property :name
|
100
|
-
validates_presence_of :name
|
101
|
-
end
|
102
|
-
|
103
|
-
user = User.new
|
104
|
-
user.valid? # => false
|
105
|
-
user.errors.on(:name) # => [:name, 'can't be blank']
|
106
|
-
|
107
|
-
h4. Finding stuff
|
108
|
-
|
109
|
-
For running basic finds (e.g. creating/querying views) you can either use the CouchPotato::Persistence::Finder class:
|
110
|
-
|
111
|
-
joe = User.create! :first_name => 'joe', :position => 1
|
112
|
-
jane = User.create! :first_name => 'jane', :position => 2
|
113
|
-
Finder.new.find User, :first_name => 'joe' # => [joe]
|
114
|
-
Finder.new.find User, :first_name => ['joe', 'jane'] # => [joe, jane]
|
115
|
-
Finder.new.find User, :position => 1..2 # => [joe, jane]
|
116
|
-
|
117
|
-
You can also count:
|
118
|
-
|
119
|
-
user = User.create! :first_name => 'joe'
|
120
|
-
Finder.new.count User, :first_name => 'joe' # => 1
|
121
|
-
|
122
|
-
Or you can call first/all/count on a class persistent class which will call the Finder.find, e.g.:
|
123
|
-
|
124
|
-
User.first :login => 'alex'
|
125
|
-
User.all
|
126
|
-
User.count :activated => true
|
127
|
-
|
128
|
-
Be warned though that executing these finder methods will generate a new view for every new combination of class and attribute names it gets called with, so you really don't want to use this in a console on a production system.
|
129
|
-
|
130
|
-
Support for more sophisticated views will be added later.
|
131
|
-
|
132
|
-
h4. Associations
|
133
|
-
|
134
|
-
As of now has_many and belongs_to are supported. By default the associated objects are stored in separate documents linked via foreign keys just like in relational databases.
|
135
|
-
|
136
|
-
class User
|
137
|
-
has_many :addresses, :dependent => :destroy
|
138
|
-
end
|
139
|
-
|
140
|
-
class Address
|
141
|
-
belongs_to :user
|
142
|
-
property :street
|
143
|
-
end
|
144
|
-
|
145
|
-
user = User.new
|
146
|
-
user.addresses.build :street => 'potato way'
|
147
|
-
user.addresses.first # => <#Address 0x987>
|
148
|
-
user.addresses.create! # raises an exception as street is blank
|
149
|
-
user.addresses.first.user == user # => true
|
150
|
-
|
151
|
-
As CouchDB can not only store flat structures you also store associations inline:
|
152
|
-
|
153
|
-
class User
|
154
|
-
has_many :addresses, :stored => :inline
|
155
|
-
end
|
156
|
-
|
157
|
-
This will store the addresses of the user as an array within your CouchDB document.
|
158
|
-
|
159
|
-
You can also find stuff on associations (not the :stored => :inline):
|
160
|
-
|
161
|
-
user.addresses.all :street => 'potato way'
|
162
|
-
|
163
|
-
... returns only adresses belonging to this user instance and also matching the given conditions. You can call #count a well, #first and #last are not implemented here since those collide with the methods in Enumerable.
|
164
|
-
|
165
|
-
h4. callbacks
|
166
|
-
|
167
|
-
Couch Potato supports the usual lifecycle callbacks known from ActiveRecord:
|
168
|
-
|
169
|
-
class User
|
170
|
-
include CouchPotato::Persistence
|
171
|
-
|
172
|
-
before_create :do_something_before_create
|
173
|
-
after_update :do_something_else
|
174
|
-
end
|
175
|
-
|
176
|
-
This will call the method do_something_before_create before creating an object and do_something_else after updating one. Supported callbacks are: :before_validation_on_create, :before_validation_on_update, :before_validation_on_save, :before_create, :after_create, :before_update, :after_update, :before_save, :after_save, :before_destroy, :after_destroy
|
177
|
-
|
178
|
-
If you want to do any CouchDB update/create/delete operation in your callback methods...
|
179
|
-
|
180
|
-
class User
|
181
|
-
include CouchPotato::Persistence
|
182
|
-
has_many :comments
|
183
|
-
|
184
|
-
before_update :create_a_comment
|
185
|
-
|
186
|
-
private
|
187
|
-
def create_a_comment
|
188
|
-
comments.create :body => 'i was updated'
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
... and you want the entire operation including its hooks to be atomic you can do this:
|
193
|
-
|
194
|
-
class User
|
195
|
-
include CouchPotato::Persistence
|
196
|
-
has_many :comments
|
197
|
-
|
198
|
-
before_update :create_a_comment
|
199
|
-
|
200
|
-
private
|
201
|
-
def create_a_comment
|
202
|
-
bulk_save_queue << Comment.new(:body => 'i was updated')
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
h4. Custom Views
|
207
|
-
|
208
|
-
*This is still in very early in development and of limited use*
|
209
|
-
|
210
|
-
This is useful if you have a set of documents that has not been created with Couch Potato, for example doesn't have a ruby_class attribute but you still want to be able to load those documents as instances of a Couch Potato class.
|
211
|
-
|
212
|
-
Example: Assuming you have a document like this:
|
213
|
-
|
214
|
-
{name: "joe"}
|
215
|
-
|
216
|
-
And a class:
|
217
|
-
|
218
|
-
class User
|
219
|
-
include CouchPotato::Persistence
|
220
|
-
property :name
|
221
|
-
end
|
222
|
-
|
223
|
-
To be able to load that user all you have to do is this:
|
224
|
-
|
225
|
-
class User
|
226
|
-
...
|
227
|
-
|
228
|
-
view :everyone
|
229
|
-
end
|
230
|
-
|
231
|
-
User.everyone
|
232
|
-
|
233
|
-
This will load all documents in your database as instances of User and assign their _id and name attributes.
|
234
|
-
|
235
|
-
If you have larger structures and you only want to load some attributes you can customize the view:
|
236
|
-
|
237
|
-
{name: "joe", bio: "52 pages of text ...."}
|
238
|
-
|
239
|
-
class User
|
240
|
-
property :name
|
241
|
-
property :bio
|
242
|
-
|
243
|
-
view :everyone, :properties => [:name]
|
244
|
-
end
|
245
|
-
|
246
|
-
User.everyone.first.name # => "joe"
|
247
|
-
User.everyone.first.bio # => nil
|
248
|
-
|
249
|
-
|
250
|
-
h4. Versioning
|
251
|
-
|
252
|
-
Couch Potato supports versioning your objects, very similar to the popular acts_as_versioned plugin for ActiveRecord. To use it include the module:
|
253
|
-
|
254
|
-
class Document
|
255
|
-
include CouchPotato::Persistence
|
256
|
-
include CouchPotato::Versioning
|
257
|
-
end
|
258
|
-
|
259
|
-
After that your object will have a version that gets incremented on each save.
|
260
|
-
|
261
|
-
doc = Document.create
|
262
|
-
doc.version # => 1
|
263
|
-
doc.save
|
264
|
-
doc.version # => 2
|
265
|
-
|
266
|
-
You can access the older versions via the versions method.
|
267
|
-
|
268
|
-
doc.versions.first.version # => 1
|
269
|
-
|
270
|
-
When passing a version number the version method will only return that version:
|
271
|
-
|
272
|
-
doc.versions(1).version # => 1
|
273
|
-
|
274
|
-
You can set a condition for when to create a new version:
|
275
|
-
|
276
|
-
class Document
|
277
|
-
attr_accessor :update_version
|
278
|
-
include CouchPotato::Persistence
|
279
|
-
include CouchPotato::Versioning
|
280
|
-
|
281
|
-
set_version_condition lambda {|doc| doc.update_version}
|
282
|
-
end
|
283
|
-
|
284
|
-
doc = Document.create
|
285
|
-
doc.update_version = false
|
286
|
-
doc.version # => 1
|
287
|
-
doc.save
|
288
|
-
doc.version # => 1
|
289
|
-
doc.update_version = true
|
290
|
-
doc.save
|
291
|
-
doc.version # => 2
|
292
|
-
|
293
|
-
h4. Ordered Lists
|
294
|
-
|
295
|
-
Couch Potato supports ordered lists for has_many relationships (with the :stored => :separately option only), very similar to the popular acts_as_list plugin for ActiveRecord. To use it include the module:
|
296
|
-
|
297
|
-
class PersistenArray
|
298
|
-
include CouchPotato::Persistence
|
299
|
-
has_many :items
|
300
|
-
end
|
301
|
-
|
302
|
-
class Item
|
303
|
-
include CouchPotato::Ordering
|
304
|
-
belongs_to :persistent_array
|
305
|
-
set_ordering_scope :persistent_array_id
|
306
|
-
end
|
307
|
-
|
308
|
-
array = PersistenArray.new
|
309
|
-
item1 = array.items.create!
|
310
|
-
item1.position # => 1
|
311
|
-
item2 = array.items.create!
|
312
|
-
item2.position # => 2
|
313
|
-
|
314
|
-
You can move items up and down simply by changing the position:
|
315
|
-
|
316
|
-
item2.position = 1
|
317
|
-
item2.save!
|
318
|
-
item1.position # => 2
|
319
|
-
|
320
|
-
And you can insert new items at any position you want:
|
321
|
-
|
322
|
-
item3 = array.items.create! :position => 2
|
323
|
-
item1.position # => 3
|
324
|
-
|
325
|
-
And remove:
|
326
|
-
|
327
|
-
item3.destroy
|
328
|
-
item1.position # => 2
|
329
|
-
|
330
|
-
h3. Helping out
|
331
|
-
|
332
|
-
Please fix bugs, add more specs, implement new features by forking the github repo at http://github.com/langalex/couch_potato.
|
333
|
-
|
334
|
-
You can run all the specs by calling 'rake spec_unit' and 'rake spec_functional' in the root folder of Couch Potato. The specs require a running CouchDB instance at http://localhost:5984
|
335
|
-
|
336
|
-
I will only accept patches that are covered by specs - sorry.
|
337
|
-
|
338
|
-
h3. Contact
|
339
|
-
|
340
|
-
If you have any questions/suggestions etc. please contact me at alex at upstream-berlin.com or @langalex on twitter.
|