langalex-couch_potato 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -20,21 +20,26 @@ Lastly Couch Potato aims to provide a seamless integration with Ruby on Rails, e
20
20
 
21
21
  ### Installation
22
22
 
23
- Couch Potato requires Ruby 1.9.
24
-
25
23
  Couch Potato is hosted as a gem on github which you can install like this:
26
24
 
27
25
  sudo gem source --add http://gems.github.com # if you haven't already
28
26
  sudo gem install langalex-couch_potato
29
-
27
+
30
28
  #### Using with your ruby application:
31
29
 
32
30
  require 'rubygems'
33
31
  gem 'langalex-couch_potato'
34
32
  require 'couch_potato'
33
+
34
+ Alternatively you can download or clone the source repository and then require lib/couch_potato.rb.
35
+
36
+ You MUST specificy the name of the database:
37
+
35
38
  CouchPotato::Config.database_name = 'name of the db'
36
-
37
- Alternatively you can download or clone the source repository and then require lib/couch_potato.rb.
39
+
40
+ The server URL will default to http://localhost:5984/ unless specified with:
41
+
42
+ CouchPotato::Config.database_server = "http://example.com:5984/"
38
43
 
39
44
  #### Using with Rails
40
45
 
@@ -48,7 +53,7 @@ Then create a config/couchdb.yml:
48
53
  test: test_db_name
49
54
  production: http://db.server/production_db_name
50
55
 
51
- Alternatively you can also install Couch Potato directly as a plugin.
56
+ Alternatively you can also install Couch Potato directly as a plugin.
52
57
 
53
58
  ### Introduction
54
59
 
@@ -71,15 +76,15 @@ If you want to store any properties you have to declare them:
71
76
 
72
77
  class User
73
78
  include CouchPotato::Persistence
74
-
79
+
75
80
  property :name
76
81
  end
77
-
82
+
78
83
  Properties can be of any type:
79
84
 
80
85
  class User
81
86
  include CouchPotato::Persistence
82
-
87
+
83
88
  property :address, :type => Address
84
89
  end
85
90
 
@@ -87,7 +92,7 @@ Now you can save your objects. All database operations are encapsulated in the C
87
92
 
88
93
  user = User.new :name => 'joe'
89
94
  CouchPotato.database.save_document user # or save_document!
90
-
95
+
91
96
  You can of course also retrieve your instance:
92
97
 
93
98
  CouchPotato.database.load_document "id_of_the_user_document" # => <#User 0x3075>
@@ -104,13 +109,13 @@ You can access the properties you declared above through normal attribute access
104
109
  user.created_at # => Fri Oct 24 19:05:54 +0200 2008
105
110
  user.updated_at # => Fri Oct 24 19:05:54 +0200 2008
106
111
  user.new? # => false
107
-
112
+
108
113
  If you want to have properties that don't map to any JSON type, i.e. other than String, Number, Boolean, Hash or Array you have to define the type like this:
109
114
 
110
115
  class User
111
116
  property :date_of_birth, :type => Date
112
117
  end
113
-
118
+
114
119
  The date_of_birth property is now automatically serialized to JSON and back when storing/retrieving objects.
115
120
 
116
121
  #### Dirty tracking
@@ -121,15 +126,15 @@ CouchPotato tracks the dirty state of attributes in the same way ActiveRecord do
121
126
  user.name # => 'joe'
122
127
  user.name_changed? # => false
123
128
  user.name_was # => nil
124
-
129
+
125
130
  You can also force a dirty state:
126
-
131
+
127
132
  user.name = 'jane'
128
133
  user.name_changed? # => true
129
134
  user.name_not_changed
130
135
  user.name_changed? # => false
131
136
  CouchPotato.database.save_document user # does nothing as no attributes are dirty
132
-
137
+
133
138
 
134
139
  #### Object validations
135
140
 
@@ -151,12 +156,12 @@ In order to find data in your CouchDB you have to create a view first. Couch Pot
151
156
  class User
152
157
  include CouchPotato::Persistence
153
158
  property :name
154
-
159
+
155
160
  view :all, :key => :created_at
156
161
  end
157
-
162
+
158
163
  This will create a view called "all" in the "user" design document with a map function that emits "created_at" for every user document.
159
-
164
+
160
165
  CouchPotato.database.view User.all
161
166
 
162
167
  This will load all user documents in your database sorted by created_at.
@@ -169,10 +174,10 @@ Composite keys are also possible:
169
174
 
170
175
  class User
171
176
  property :name
172
-
177
+
173
178
  view :all, :key => [:created_at, :name]
174
179
  end
175
-
180
+
176
181
  The creation of views is based on view specification classes (see the CouchPotato::View module). The above code uses the ModelViewSpec class which is used to find models by their properties. For more sophisticated searches you can use other view specifications (either use the built-in or provide your own) by passing a type parameter:
177
182
 
178
183
  If you have larger structures and you only want to load some attributes you can use the PropertiesViewSpec (the full class name is automatically derived):
@@ -180,25 +185,25 @@ If you have larger structures and you only want to load some attributes you can
180
185
  class User
181
186
  property :name
182
187
  property :bio
183
-
188
+
184
189
  view :all, :key => :created_at, :properties => [:name], :type => :properties
185
190
  end
186
-
191
+
187
192
  CouchPotato.database.view(User.everyone).first.name # => "joe"
188
193
  CouchPotato.database.view(User.everyone).first.bio # => nil
189
-
194
+
190
195
  You can also pass in custom map/reduce functions with the custom view spec:
191
196
 
192
197
  class User
193
198
  view :all, :map => "function(doc) { emit(doc.created_at, null)}", :include_docs => true, :type => :custom
194
199
  end
195
-
200
+
196
201
  If you don't want the results to be converted into models the raw view is your friend:
197
202
 
198
203
  class User
199
204
  view :all, :map => "function(doc) { emit(doc.created_at, doc.name)}", :type => :raw
200
205
  end
201
-
206
+
202
207
  When querying this view you will get the raw data returned by CouchDB which looks something like this: {'total_entries': 2, 'rows': [{'value': 'alex', 'key': '2009-01-03 00:02:34 +000', 'id': '75976rgi7546gi02a'}]}
203
208
 
204
209
  To process this raw data you can also pass in a results filter:
@@ -221,7 +226,7 @@ Couch Potato supports the usual lifecycle callbacks known from ActiveRecord:
221
226
 
222
227
  class User
223
228
  include CouchPotato::Persistence
224
-
229
+
225
230
  before_create :do_something_before_create
226
231
  before_update {|user, db| user.do_something_on_update}
227
232
  end
@@ -230,25 +235,25 @@ This will call the method do_something_before_create before creating an object a
230
235
 
231
236
  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.
232
237
 
233
- #### Testing
238
+ #### Testing
234
239
 
235
240
  To make testing easier and faster database logic has been put into its own class, which you can replace and stub out in whatever way you want:
236
241
 
237
242
  class User
238
243
  include CouchPotato::Persistence
239
244
  end
240
-
245
+
241
246
  # RSpec
242
247
  describe 'save a user' do
243
248
  it 'should save' do
244
- couchrest_db = stub 'couchrest_db',
249
+ couchrest_db = stub 'couchrest_db',
245
250
  database = CouchPotato::Database.new couchrest_db
246
251
  user = User.new
247
252
  couchrest_db.should_receive(:save_doc).with(...)
248
253
  database.save_document user
249
254
  end
250
255
  end
251
-
256
+
252
257
  By creating you own instances of CouchPotato::Database and passing them a fake CouchRest database instance you can completely disconnect your unit tests/spec from the database.
253
258
 
254
259
  ### Helping out
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 2
4
- :patch: 6
4
+ :patch: 7
@@ -10,26 +10,26 @@ require 'validatable'
10
10
 
11
11
  module CouchPotato
12
12
  Config = OpenStruct.new
13
-
13
+
14
14
  # Returns a database instance which you can then use to create objects and query views. You have to set the CouchPotato::Config.database_name before this works.
15
15
  def self.database
16
16
  @@__database ||= Database.new(self.couchrest_database)
17
17
  end
18
-
18
+
19
19
  # Returns the underlying CouchRest database object if you want low level access to your CouchDB. You have to set the CouchPotato::Config.database_name before this works.
20
20
  def self.couchrest_database
21
21
  @@__couchrest_database ||= CouchRest.database(full_url_to_database)
22
22
  end
23
-
23
+
24
24
  private
25
-
25
+
26
26
  def self.full_url_to_database
27
- database_name = CouchPotato::Config.database_name || raise('No Database configured. Set CouchPotato::Config.database_name')
28
- url = database_name
29
- if url !~ /^http:\/\//
30
- url = "http://localhost:5984/#{database_name}"
27
+ raise('No Database configured. Set CouchPotato::Config.database_name') unless CouchPotato::Config.database_name
28
+ if CouchPotato::Config.database_server
29
+ return "#{CouchPotato::Config.database_server}#{CouchPotato::Config.database_name}"
30
+ else
31
+ return "http://127.0.0.1:5984/#{CouchPotato::Config.database_name}"
31
32
  end
32
- url
33
33
  end
34
34
  end
35
35
 
@@ -37,5 +37,6 @@ require File.dirname(__FILE__) + '/core_ext/object'
37
37
  require File.dirname(__FILE__) + '/core_ext/time'
38
38
  require File.dirname(__FILE__) + '/core_ext/date'
39
39
  require File.dirname(__FILE__) + '/core_ext/string'
40
+ require File.dirname(__FILE__) + '/core_ext/symbol'
40
41
  require File.dirname(__FILE__) + '/couch_potato/persistence'
41
42
 
@@ -35,10 +35,10 @@ module CouchPotato
35
35
  alias_method :save!, :save_document!
36
36
 
37
37
  def destroy_document(document)
38
- document.run_callbacks :before_destroy, self
38
+ document.run_callbacks :before_destroy
39
39
  document._deleted = true
40
40
  database.delete_doc document.to_hash
41
- document.run_callbacks :after_destroy, self
41
+ document.run_callbacks :after_destroy
42
42
  document._id = nil
43
43
  document._rev = nil
44
44
  end
@@ -48,7 +48,9 @@ module CouchPotato
48
48
  raise "Can't load a document without an id (got nil)" if id.nil?
49
49
  begin
50
50
  json = database.get(id)
51
- Class.const_get(json['ruby_class']).json_create json
51
+ instance = Class.const_get(json['ruby_class']).json_create json
52
+ instance.database = self
53
+ instance
52
54
  rescue(RestClient::ResourceNotFound)
53
55
  nil
54
56
  end
@@ -62,29 +64,30 @@ module CouchPotato
62
64
  private
63
65
 
64
66
  def create_document(document)
65
- document.run_callbacks :before_validation_on_save, self
66
- document.run_callbacks :before_validation_on_create, self
67
+ document.database = self
68
+ document.run_callbacks :before_validation_on_save
69
+ document.run_callbacks :before_validation_on_create
67
70
  return unless document.valid?
68
- document.run_callbacks :before_save, self
69
- document.run_callbacks :before_create, self
71
+ document.run_callbacks :before_save
72
+ document.run_callbacks :before_create
70
73
  res = database.save_doc document.to_hash
71
74
  document._rev = res['rev']
72
75
  document._id = res['id']
73
- document.run_callbacks :after_save, self
74
- document.run_callbacks :after_create, self
76
+ document.run_callbacks :after_save
77
+ document.run_callbacks :after_create
75
78
  true
76
79
  end
77
80
 
78
81
  def update_document(document)
79
- document.run_callbacks :before_validation_on_save, self
80
- document.run_callbacks :before_validation_on_update, self
82
+ document.run_callbacks :before_validation_on_save
83
+ document.run_callbacks :before_validation_on_update
81
84
  return unless document.valid?
82
- document.run_callbacks :before_save, self
83
- document.run_callbacks :before_update, self
85
+ document.run_callbacks :before_save
86
+ document.run_callbacks :before_update
84
87
  res = database.save_doc document.to_hash
85
88
  document._rev = res['rev']
86
- document.run_callbacks :after_save, self
87
- document.run_callbacks :after_update, self
89
+ document.run_callbacks :after_save
90
+ document.run_callbacks :after_update
88
91
  true
89
92
  end
90
93
 
@@ -17,7 +17,7 @@ module CouchPotato
17
17
  base.send :include, DirtyAttributes
18
18
  base.send :include, MagicTimestamps
19
19
  base.class_eval do
20
- attr_accessor :_id, :_rev, :_attachments, :_deleted
20
+ attr_accessor :_id, :_rev, :_attachments, :_deleted, :database
21
21
  alias_method :id, :_id
22
22
  end
23
23
  end
@@ -1,75 +1,38 @@
1
1
  module CouchPotato
2
2
  module Persistence
3
3
  module Callbacks
4
-
5
- class Callback #:nodoc:
6
- def initialize(model, name, database)
7
- @model, @name, @database = model, name, database
8
- end
9
-
10
- def run
11
- if @name.is_a?(Symbol)
12
- run_method_callback @name
13
- elsif @name.is_a?(Proc)
14
- run_lambda_callback @name
15
- else
16
- raise "Don't know how to handle callback of type #{name.class.name}"
17
- end
18
- end
19
-
20
- private
21
-
22
- def run_method_callback(name)
23
- if callback_method(name).arity == 0
24
- @model.send name
25
- elsif callback_method(name).arity == 1
26
- @model.send name, @database
27
- else
28
- raise "Don't know how to handle method callback with #{callback_method(name).arity} arguments"
29
- end
30
- end
31
-
32
- def callback_method(name)
33
- @model.method(name)
34
- end
35
-
36
- def run_lambda_callback(lambda)
37
- if lambda.arity == 1
38
- lambda.call @model
39
- elsif lambda.arity == 2
40
- lambda.call @model, @database
41
- else raise "Don't know how to handle lambda callback with #{lambda.arity} arguments"
42
- end
43
- end
44
-
45
- end
46
-
47
4
  def self.included(base)
48
5
  base.extend ClassMethods
49
-
6
+
50
7
  base.class_eval do
51
8
  attr_accessor :skip_callbacks
52
9
  def self.callbacks
53
10
  @callbacks ||= {}
54
- @callbacks[self.name] ||= {:before_validation_on_create => [],
55
- :before_validation_on_update => [], :before_validation_on_save => [], :before_create => [],
11
+ @callbacks[self.name] ||= {:before_validation_on_create => [],
12
+ :before_validation_on_update => [], :before_validation_on_save => [], :before_create => [],
56
13
  :after_create => [], :before_update => [], :after_update => [],
57
14
  :before_save => [], :after_save => [],
58
15
  :before_destroy => [], :after_destroy => []}
59
16
  end
60
17
  end
61
18
  end
62
-
19
+
63
20
  # Runs all callbacks on a model with the given name, i.g. :after_create.
64
21
  #
65
22
  # This method is called by the CouchPotato::Database object when saving/destroying an object
66
- def run_callbacks(name, database)
23
+ def run_callbacks(name)
67
24
  return if skip_callbacks
68
25
  self.class.callbacks[name].uniq.each do |callback|
69
- Callback.new(self, callback, database).run
26
+ if callback.is_a?(Symbol)
27
+ send callback
28
+ elsif callback.is_a?(Proc)
29
+ callback.call self
30
+ else
31
+ raise "Don't know how to handle callback of type #{name.class.name}"
32
+ end
70
33
  end
71
34
  end
72
-
35
+
73
36
  module ClassMethods
74
37
  [
75
38
  :before_validation_on_create,
@@ -13,7 +13,7 @@ module CouchPotato
13
13
  end
14
14
  end
15
15
  end
16
-
16
+
17
17
  module ClassMethods
18
18
  # returns all the property names of a model class that have been defined using the #property method
19
19
  #
@@ -26,13 +26,13 @@ module CouchPotato
26
26
  def property_names
27
27
  properties.map(&:name)
28
28
  end
29
-
29
+
30
30
  def json_create(json) #:nodoc:
31
31
  instance = super
32
32
  instance.send(:assign_attribute_copies_for_dirty_tracking)
33
33
  instance
34
34
  end
35
-
35
+
36
36
  # Declare a proprty on a model class. properties are not typed by default. You can use any of the basic types by JSON (String, Integer, Fixnum, Array, Hash). If you want a property to be of a custom class you have to define it using the :class option.
37
37
  #
38
38
  # example:
@@ -3,15 +3,19 @@ module CouchPotato
3
3
  class BaseViewSpec
4
4
  attr_reader :reduce_function, :design_document, :view_name, :view_parameters, :klass, :options
5
5
  private :klass, :options
6
-
6
+
7
7
  def initialize(klass, view_name, options, view_parameters)
8
8
  @klass = klass
9
9
  @design_document = klass.to_s.underscore
10
10
  @view_name = view_name
11
11
  @options = options
12
- @view_parameters = options.select{|key, value| [:group, :include_docs, :descending, :group_level, :limit].include?(key.to_sym)}.merge(view_parameters)
12
+ @view_parameters = {}
13
+ [:group, :include_docs, :descending, :group_level, :limit].each do |key|
14
+ @view_parameters[key] = options[key] if options.include?(key)
15
+ end
16
+ @view_parameters.merge!(view_parameters)
13
17
  end
14
-
18
+
15
19
  def process_results(results)
16
20
  results
17
21
  end
@@ -8,21 +8,28 @@ require File.dirname(__FILE__) + '/raw_view_spec'
8
8
  module CouchPotato
9
9
  module View
10
10
  module CustomViews
11
-
11
+
12
12
  def self.included(base)
13
13
  base.extend ClassMethods
14
14
  end
15
-
15
+
16
16
  module ClassMethods
17
17
  # Declare a CouchDB view, for examples on how to use see the *ViewSpec classes in CouchPotato::View
18
+ def views
19
+ @views ||= {}
20
+ end
21
+
22
+ def execute_view(view_name, view_parameters)
23
+ view_spec_class(views[view_name][:type]).new(self, view_name, views[view_name], view_parameters)
24
+ end
25
+
18
26
  def view(view_name, options)
19
- self.class.instance_eval do
20
- define_method view_name do |view_parameters = {}|
21
- view_spec_class(options[:type]).new self, view_name, options, view_parameters
22
- end
23
- end
27
+ view_name = view_name.to_s
28
+ views[view_name] = options
29
+ method_str = "def #{view_name}(view_parameters = {}); execute_view(\"#{view_name}\", view_parameters); end"
30
+ self.instance_eval(method_str)
24
31
  end
25
-
32
+
26
33
  def view_spec_class(type)
27
34
  if type && type.is_a?(Class)
28
35
  type
@@ -9,18 +9,18 @@ module CouchPotato
9
9
  @map_function = map_function
10
10
  @reduce_function = reduce_function
11
11
  end
12
-
12
+
13
13
  def query_view!(parameters = {})
14
14
  begin
15
15
  query_view parameters
16
- rescue RestClient::ResourceNotFound => e
16
+ rescue RestClient::ResourceNotFound# => e
17
17
  create_view
18
18
  retry
19
19
  end
20
20
  end
21
-
21
+
22
22
  private
23
-
23
+
24
24
  def create_view
25
25
  design_doc = @database.get "_design/#{@design_document_name}" rescue nil
26
26
  design_doc ||= {'views' => {}, "_id" => "_design/#{@design_document_name}"}
@@ -30,11 +30,11 @@ module CouchPotato
30
30
  }
31
31
  @database.save_doc(design_doc)
32
32
  end
33
-
33
+
34
34
  def query_view(parameters)
35
35
  @database.view view_url, parameters
36
36
  end
37
-
37
+
38
38
  def view_url
39
39
  "#{@design_document_name}/#{@view_name}"
40
40
  end
@@ -24,8 +24,6 @@ class CallbackRecorder
24
24
 
25
25
  attr_accessor :lambda_works
26
26
  before_create lambda {|model| model.lambda_works = true }
27
- after_create lambda {|model, db| db.view CallbackRecorder.all}
28
- before_update :method_callback_with_argument
29
27
 
30
28
  def callbacks
31
29
  @callbacks ||= []
@@ -246,26 +244,10 @@ describe "destroy callbacks" do
246
244
  end
247
245
  end
248
246
 
249
- describe "method callbacks" do
250
- it "should pass the database to a method with arity 1" do
251
- recorder = CallbackRecorder.new
252
- db = stub 'db'
253
- db.should_receive(:view)
254
- recorder.run_callbacks :before_update, db
255
- end
256
- end
257
-
258
247
  describe "lambda callbacks" do
259
248
  it "should run the lambda" do
260
249
  recorder = CallbackRecorder.new
261
- recorder.run_callbacks :before_create, stub('db')
250
+ recorder.run_callbacks :before_create
262
251
  recorder.lambda_works.should be_true
263
252
  end
264
-
265
- it "should pass the database to a lambda with arity 2" do
266
- recorder = CallbackRecorder.new
267
- db = stub 'db'
268
- db.should_receive(:view)
269
- recorder.run_callbacks :after_create, db
270
- end
271
253
  end
@@ -2,10 +2,10 @@ require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  class Build
4
4
  include CouchPotato::Persistence
5
-
5
+
6
6
  property :state
7
7
  property :time
8
-
8
+
9
9
  view :timeline, :key => :time
10
10
  view :count, :key => :time, :reduce => true
11
11
  view :minimal_timeline, :key => :time, :properties => [:state], :type => :properties
@@ -21,50 +21,51 @@ describe 'view' do
21
21
  before(:each) do
22
22
  recreate_db
23
23
  end
24
-
24
+
25
25
  it "should return instances of the class" do
26
26
  CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
27
- CouchPotato.database.view(Build.timeline).map(&:class).should == [Build]
27
+ results = CouchPotato.database.view(Build.timeline)
28
+ results.map(&:class).should == [Build]
28
29
  end
29
-
30
- it "should pass the view options to the viw query" do
30
+
31
+ it "should pass the view options to the view query" do
31
32
  query = mock 'query'
32
33
  CouchPotato::View::ViewQuery.stub!(:new).and_return(query)
33
34
  query.should_receive(:query_view!).with(hash_including(:key => 1)).and_return('rows' => [])
34
35
  CouchPotato.database.view Build.timeline(:key => 1)
35
36
  end
36
-
37
+
37
38
  it "should not return documents that don't have a matching ruby_class" do
38
39
  CouchPotato.couchrest_database.save_doc({:time => 'x'})
39
40
  CouchPotato.database.view(Build.timeline).should == []
40
41
  end
41
-
42
+
42
43
  it "should count documents" do
43
44
  CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
44
45
  CouchPotato.database.view(Build.count(:reduce => true)).should == 1
45
46
  end
46
-
47
+
47
48
  it "should count zero documents" do
48
49
  CouchPotato.database.view(Build.count(:reduce => true)).should == 0
49
50
  end
50
-
51
+
51
52
  describe "properties defined" do
52
53
  it "should assign the configured properties" do
53
54
  CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
54
55
  CouchPotato.database.view(Build.minimal_timeline).first.state.should == 'success'
55
56
  end
56
-
57
+
57
58
  it "should not assign the properties not configured" do
58
59
  CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')
59
60
  CouchPotato.database.view(Build.minimal_timeline).first.time.should be_nil
60
61
  end
61
-
62
+
62
63
  it "should assign the id even if it is not configured" do
63
64
  id = CouchPotato.couchrest_database.save_doc(:state => 'success', :time => '2008-01-01', :ruby_class => 'Build')['id']
64
65
  CouchPotato.database.view(Build.minimal_timeline).first._id.should == id
65
66
  end
66
67
  end
67
-
68
+
68
69
  describe "no properties defined" do
69
70
  it "should assign all properties to the objects by default" do
70
71
  id = CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01', :ruby_class => 'Build'})['id']
@@ -74,60 +75,60 @@ describe 'view' do
74
75
  result._id.should == id
75
76
  end
76
77
  end
77
-
78
+
78
79
  describe "map function given" do
79
80
  it "should still return instances of the class" do
80
81
  CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
81
82
  CouchPotato.database.view(Build.custom_timeline).map(&:class).should == [Build]
82
83
  end
83
-
84
+
84
85
  it "should assign the properties from the value" do
85
86
  CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
86
87
  CouchPotato.database.view(Build.custom_timeline).map(&:state).should == ['custom_success']
87
88
  end
88
-
89
+
89
90
  it "should leave the other properties blank" do
90
91
  CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
91
92
  CouchPotato.database.view(Build.custom_timeline).map(&:time).should == [nil]
92
93
  end
93
-
94
+
94
95
  describe "that returns null documents" do
95
96
  it "should return instances of the class" do
96
97
  CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
97
98
  CouchPotato.database.view(Build.custom_timeline_returns_docs).map(&:class).should == [Build]
98
99
  end
99
-
100
+
100
101
  it "should assign the properties from the value" do
101
102
  CouchPotato.couchrest_database.save_doc({:state => 'success', :time => '2008-01-01'})
102
103
  CouchPotato.database.view(Build.custom_timeline_returns_docs).map(&:state).should == ['success']
103
104
  end
104
105
  end
105
106
  end
106
-
107
+
107
108
  describe "with array as key" do
108
109
  it "should create a map function with the composite key" do
109
110
  CouchPotato::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)
110
111
  CouchPotato.database.view Build.key_array_timeline
111
112
  end
112
113
  end
113
-
114
+
114
115
  describe "raw view" do
115
116
  it "should return the raw data" do
116
117
  CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
117
118
  CouchPotato.database.view(Build.raw)['rows'][0]['value'].should == 'success'
118
119
  end
119
-
120
+
120
121
  it "should return filtred raw data" do
121
122
  CouchPotato.database.save_document Build.new(:state => 'success', :time => '2008-01-01')
122
123
  CouchPotato.database.view(Build.filtered_raw).should == ['success']
123
124
  end
124
-
125
+
125
126
  it "should pass view options declared in the view declaration to the query" do
126
- view_query = mock 'view_query'
127
+ view_query = mock 'view_query'
127
128
  CouchPotato::View::ViewQuery.stub!(:new).and_return(view_query)
128
129
  view_query.should_receive(:query_view!).with(hash_including(:group => true)).and_return({'rows' => []})
129
130
  CouchPotato.database.view(Build.with_view_options)
130
131
  end
131
132
  end
132
-
133
+
133
134
  end
@@ -6,13 +6,14 @@ $:.unshift(File.dirname(__FILE__) + '/../lib')
6
6
  require 'couch_potato'
7
7
 
8
8
  CouchPotato::Config.database_name = 'couch_potato_test'
9
+ CouchPotato::Config.database_server = 'http://127.0.0.1:5984/'
9
10
 
10
11
 
11
12
  class Comment
12
13
  include CouchPotato::Persistence
13
-
14
+
14
15
  validates_presence_of :title
15
-
16
+
16
17
  property :title
17
18
  belongs_to :commenter
18
19
  end
@@ -1,5 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
+ class DbTestUser
4
+ end
5
+
3
6
  describe CouchPotato::Database, 'new' do
4
7
  it "should raise an exception if the database doesn't exist" do
5
8
  lambda {
@@ -15,4 +18,21 @@ describe CouchPotato::Database, 'load' do
15
18
  db.load nil
16
19
  }.should raise_error("Can't load a document without an id (got nil)")
17
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 = CouchPotato::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 CouchPotato::Database, 'save_document' do
32
+ it "should set itself on the model for a new object before doing anything else" do
33
+ db = CouchPotato::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
18
38
  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.2.6
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Lang