langalex-couch_potato 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|