couch_potato 1.7.1 → 1.9.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.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +38 -0
- data/.gitignore +3 -0
- data/CHANGES.md +169 -131
- data/Gemfile +4 -0
- data/README.md +55 -75
- data/Rakefile +11 -10
- data/couch_potato-rspec.gemspec +2 -1
- data/couch_potato.gemspec +8 -6
- data/gemfiles/active_support_5_0 +1 -5
- data/gemfiles/active_support_5_1 +7 -0
- data/gemfiles/active_support_5_2 +7 -0
- data/gemfiles/active_support_6_0 +7 -0
- data/gemfiles/active_support_6_1 +7 -0
- data/lib/couch_potato/database.rb +165 -70
- data/lib/couch_potato/persistence/dirty_attributes.rb +3 -21
- data/lib/couch_potato/persistence/magic_timestamps.rb +3 -3
- data/lib/couch_potato/persistence/properties.rb +15 -10
- data/lib/couch_potato/persistence/simple_property.rb +0 -4
- data/lib/couch_potato/persistence/type_caster.rb +9 -6
- data/lib/couch_potato/persistence.rb +0 -1
- data/lib/couch_potato/railtie.rb +6 -11
- data/lib/couch_potato/validation.rb +8 -0
- data/lib/couch_potato/version.rb +1 -1
- data/lib/couch_potato/view/base_view_spec.rb +8 -32
- data/lib/couch_potato/view/custom_views.rb +4 -3
- data/lib/couch_potato/view/flex_view_spec.rb +121 -0
- data/lib/couch_potato/view/view_parameters.rb +34 -0
- data/lib/couch_potato.rb +32 -9
- data/spec/callbacks_spec.rb +45 -19
- data/spec/conflict_handling_spec.rb +0 -1
- data/spec/property_spec.rb +2 -2
- data/spec/railtie_spec.rb +10 -0
- data/spec/spec_helper.rb +4 -3
- data/spec/unit/active_model_compliance_spec.rb +7 -3
- data/spec/unit/attributes_spec.rb +1 -1
- data/spec/unit/caching_spec.rb +105 -0
- data/spec/unit/couch_potato_spec.rb +70 -5
- data/spec/unit/create_spec.rb +5 -4
- data/spec/unit/database_spec.rb +235 -135
- data/spec/unit/dirty_attributes_spec.rb +5 -26
- data/spec/unit/flex_view_spec_spec.rb +17 -0
- data/spec/unit/model_view_spec_spec.rb +1 -1
- data/spec/unit/rspec_stub_db_spec.rb +31 -0
- data/spec/unit/validation_spec.rb +42 -2
- data/spec/views_spec.rb +214 -103
- data/vendor/pouchdb-collate/LICENSE +202 -0
- data/vendor/pouchdb-collate/pouchdb-collate.js +430 -0
- metadata +46 -42
- data/.ruby-version +0 -1
- data/.travis.yml +0 -21
- data/gemfiles/active_support_4_0 +0 -11
- data/gemfiles/active_support_4_1 +0 -11
- data/gemfiles/active_support_4_2 +0 -11
- data/lib/couch_potato/persistence/deep_dirty_attributes.rb +0 -180
- data/spec/unit/deep_dirty_attributes_spec.rb +0 -434
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'couch_potato/view/base_view_spec'
|
2
|
+
require 'couch_potato/view/flex_view_spec'
|
2
3
|
require 'couch_potato/view/model_view_spec'
|
3
4
|
require 'couch_potato/view/properties_view_spec'
|
4
5
|
require 'couch_potato/view/custom_view_spec'
|
5
6
|
require 'couch_potato/view/raw_view_spec'
|
6
|
-
|
7
|
+
require 'couch_potato/view/view_parameters'
|
7
8
|
|
8
9
|
module CouchPotato
|
9
10
|
module View
|
@@ -25,7 +26,7 @@ module CouchPotato
|
|
25
26
|
def execute_view(view_name, view_parameters) #:nodoc:
|
26
27
|
view_spec_class(views(view_name)[:type]).new(self, view_name, views(view_name), view_parameters)
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
# Declare a CouchDB view, for examples on how to use see the *ViewSpec classes in CouchPotato::View
|
30
31
|
def view(view_name, options)
|
31
32
|
view_name = view_name.to_s
|
@@ -42,7 +43,7 @@ module CouchPotato
|
|
42
43
|
CouchPotato::View.const_get("#{name}ViewSpec")
|
43
44
|
end
|
44
45
|
end
|
45
|
-
|
46
|
+
|
46
47
|
def _find_view(view) #:nodoc:
|
47
48
|
(@views && @views[view]) || (superclass._find_view(view) if superclass.respond_to?(:_find_view))
|
48
49
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CouchPotato
|
4
|
+
module View
|
5
|
+
# A flexible view spec.
|
6
|
+
# It allows to either just define a key and option conditions like
|
7
|
+
# the model view spec or custom map/reduce functions.
|
8
|
+
# In addition, it returns a result object that allows convenient access
|
9
|
+
# to either the raw result, the keys, values, ids or docs. The result object can
|
10
|
+
# be extended with custom module, too.
|
11
|
+
# Examples:
|
12
|
+
# class Thing
|
13
|
+
# module ResultsExt
|
14
|
+
# def average_time
|
15
|
+
# keys.sum / keys.size # can access other result methods
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# property :time
|
19
|
+
# view :by_time, type: :flex, key: :time, extend_results: ResultsExt
|
20
|
+
# view :by_custom_time, type: :flex,
|
21
|
+
# reduce: '_sum'
|
22
|
+
# map: <<~JS
|
23
|
+
# function(doc) {
|
24
|
+
# emit(doc.time, 1);
|
25
|
+
# }
|
26
|
+
# JS
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# usage:
|
30
|
+
# irb> result = db.view Thing.by_time
|
31
|
+
# irb> result.raw # raw CouchDB results
|
32
|
+
# irb> result.ids # ids of rows
|
33
|
+
# irb> result.keys # keys emitted in map function
|
34
|
+
# irb> result.values # values emitted in map function
|
35
|
+
# irb> result.average_time # custom method from ResultsExt module
|
36
|
+
# irb> db.view(Thing.by_time(include_docs: true)).docs # documents
|
37
|
+
# irb> db.view(Thing.by_time(reduce: true)).reduce_value # value of first row, i.e. result of the reduce function (without grouping)
|
38
|
+
class FlexViewSpec
|
39
|
+
attr_reader :klass
|
40
|
+
|
41
|
+
class Results
|
42
|
+
attr_accessor :database # set by database
|
43
|
+
|
44
|
+
def initialize(raw_results)
|
45
|
+
@raw_results = raw_results
|
46
|
+
end
|
47
|
+
|
48
|
+
def raw
|
49
|
+
@raw_results
|
50
|
+
end
|
51
|
+
|
52
|
+
def ids
|
53
|
+
rows.map { |row| row['id'] }
|
54
|
+
end
|
55
|
+
|
56
|
+
def keys
|
57
|
+
rows.map { |row| row['key'] }
|
58
|
+
end
|
59
|
+
|
60
|
+
def values
|
61
|
+
rows.map { |row| row['value'] }
|
62
|
+
end
|
63
|
+
|
64
|
+
def reduce_value
|
65
|
+
rows.dig(0, 'value')
|
66
|
+
end
|
67
|
+
|
68
|
+
# returns a count from a CouchDB reduce. returns 0 when the result
|
69
|
+
# set is empty (which would result in `nil` when calling #reduce_value).
|
70
|
+
# you still have to pass reduce=true to the view call.
|
71
|
+
def reduce_count
|
72
|
+
reduce_value || 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def docs
|
76
|
+
rows.map do |row|
|
77
|
+
doc = row['doc']
|
78
|
+
doc.database = database if doc.respond_to?(:database=)
|
79
|
+
doc
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def rows
|
84
|
+
@raw_results['rows']
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def initialize(klass, view_name, options, view_parameters)
|
89
|
+
@extend_results_module = options[:extend_results]
|
90
|
+
@klass = klass
|
91
|
+
@view_name = view_name
|
92
|
+
@options = options.except(:extend_results)
|
93
|
+
@view_parameters = view_parameters
|
94
|
+
end
|
95
|
+
|
96
|
+
delegate :view_name, :view_parameters, :design_document, :map_function,
|
97
|
+
:reduce_function, :list_name, :lib, :language, to: :view_spec_delegate
|
98
|
+
|
99
|
+
def process_results(results)
|
100
|
+
results = Results.new(results)
|
101
|
+
results.extend @extend_results_module if @extend_results_module
|
102
|
+
results
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def view_spec_delegate
|
108
|
+
unless @view_spec_delegate
|
109
|
+
view_spec_class = @options[:map] ? RawViewSpec : ModelViewSpec
|
110
|
+
@view_spec_delegate = view_spec_class.new(
|
111
|
+
@klass, @view_name, @options,
|
112
|
+
ViewParameters
|
113
|
+
.normalize_view_parameters(@view_parameters)
|
114
|
+
.reverse_merge(reduce: false, include_docs: false)
|
115
|
+
)
|
116
|
+
end
|
117
|
+
@view_spec_delegate
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module CouchPotato
|
2
|
+
module View
|
3
|
+
module ViewParameters
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def normalize_view_parameters(params)
|
7
|
+
hash = wrap_in_hash params
|
8
|
+
remove_nil_stale(replace_range_key(hash))
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_nil_stale(params)
|
12
|
+
params.reject{|name, value| name.to_s == 'stale' && value.nil?}
|
13
|
+
end
|
14
|
+
|
15
|
+
def wrap_in_hash(params)
|
16
|
+
if params.is_a?(Hash)
|
17
|
+
params
|
18
|
+
else
|
19
|
+
{:key => params}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def replace_range_key(params)
|
24
|
+
if((key = params[:key]).is_a?(Range))
|
25
|
+
params.delete :key
|
26
|
+
params[:startkey] = key.first
|
27
|
+
params[:endkey] = key.last
|
28
|
+
end
|
29
|
+
params
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/couch_potato.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'couchrest'
|
2
4
|
require 'json'
|
3
5
|
|
@@ -8,15 +10,30 @@ CouchRest.decode_json_objects = true
|
|
8
10
|
|
9
11
|
module CouchPotato
|
10
12
|
Config = Struct.new(:database_host, :database_name, :digest_view_names,
|
11
|
-
|
13
|
+
:split_design_documents_per_view, :default_language, :additional_databases).new
|
12
14
|
Config.split_design_documents_per_view = false
|
13
15
|
Config.digest_view_names = false
|
14
16
|
Config.default_language = :javascript
|
15
17
|
Config.database_host = 'http://127.0.0.1:5984'
|
18
|
+
Config.additional_databases = {}
|
16
19
|
|
17
20
|
class NotFound < StandardError; end
|
18
21
|
class Conflict < StandardError; end
|
19
22
|
|
23
|
+
def self.configure(config)
|
24
|
+
if config.is_a?(String)
|
25
|
+
Config.database_name = config
|
26
|
+
else
|
27
|
+
config = config.stringify_keys
|
28
|
+
Config.database_name = config['database']
|
29
|
+
Config.database_host = config['database_host'] if config['database_host']
|
30
|
+
Config.additional_databases = config['additional_databases'].stringify_keys if config['additional_databases']
|
31
|
+
Config.split_design_documents_per_view = config['split_design_documents_per_view'] if config['split_design_documents_per_view']
|
32
|
+
Config.digest_view_names = config['digest_view_names'] if config['digest_view_names']
|
33
|
+
Config.default_language = config['default_language'] if config['default_language']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
20
37
|
# returns all the classes that include the CouchPotato::Persistence module
|
21
38
|
def self.models
|
22
39
|
@models ||= []
|
@@ -35,12 +52,17 @@ module CouchPotato
|
|
35
52
|
|
36
53
|
# Returns a specific database instance
|
37
54
|
def self.use(database_name)
|
55
|
+
resolved_database_name = resolve_database_name(database_name)
|
38
56
|
Thread.current[:__couch_potato_databases] ||= {}
|
39
|
-
Thread.current[:__couch_potato_databases][
|
40
|
-
Thread.current[:__couch_potato_databases][database_name]
|
57
|
+
Thread.current[:__couch_potato_databases][resolved_database_name] ||= Database.new(couchrest_database_for_name!(resolved_database_name), name: database_name)
|
41
58
|
end
|
42
59
|
|
43
|
-
#
|
60
|
+
# resolves a name to a database name/full url configured under additional databases
|
61
|
+
def self.resolve_database_name(database_name)
|
62
|
+
Config.additional_databases[database_name] || database_name
|
63
|
+
end
|
64
|
+
|
65
|
+
# Executes a block of code and yields a database with the given name.
|
44
66
|
#
|
45
67
|
# example:
|
46
68
|
# CouchPotato.with_database('couch_customer') do |couch|
|
@@ -48,23 +70,24 @@ module CouchPotato
|
|
48
70
|
# end
|
49
71
|
#
|
50
72
|
def self.with_database(database_name)
|
51
|
-
|
52
|
-
Thread.current[:__couch_potato_databases][database_name] = Database.new(couchrest_database_for_name(database_name)) unless Thread.current[:__couch_potato_databases][database_name]
|
53
|
-
yield Thread.current[:__couch_potato_databases][database_name]
|
73
|
+
yield use(database_name)
|
54
74
|
end
|
55
75
|
|
56
76
|
# Returns a CouchRest-Database for directly accessing that functionality.
|
57
77
|
def self.couchrest_database_for_name(database_name)
|
58
|
-
|
78
|
+
Thread.current[:__couchrest_databases] ||= {}
|
79
|
+
Thread.current[:__couchrest_databases][database_name] ||= CouchRest.database(full_url_to_database(database_name, CouchPotato::Config.database_host))
|
59
80
|
end
|
60
81
|
|
61
82
|
# Creates a CouchRest-Database for directly accessing that functionality.
|
62
83
|
def self.couchrest_database_for_name!(database_name)
|
63
|
-
|
84
|
+
Thread.current[:__couchrest_databases] ||= {}
|
85
|
+
Thread.current[:__couchrest_databases][database_name] ||= CouchRest.database!(full_url_to_database(database_name))
|
64
86
|
end
|
65
87
|
|
66
88
|
def self.full_url_to_database(database_name = CouchPotato::Config.database_name, database_host = CouchPotato::Config.database_host)
|
67
89
|
raise('No Database configured. Set CouchPotato::Config.database_name') unless database_name
|
90
|
+
|
68
91
|
if database_name.match(%r{https?://})
|
69
92
|
database_name
|
70
93
|
else
|
data/spec/callbacks_spec.rb
CHANGED
@@ -382,13 +382,13 @@ describe "validation callbacks and filter halt" do
|
|
382
382
|
|
383
383
|
property :name
|
384
384
|
before_validation :check_name
|
385
|
-
before_validation_on_update :
|
385
|
+
before_validation_on_update :abort_callback
|
386
386
|
|
387
387
|
def check_name
|
388
388
|
errors.add(:name, 'should be Paul') unless name == "Paul"
|
389
389
|
end
|
390
390
|
|
391
|
-
def
|
391
|
+
def abort_callback
|
392
392
|
false
|
393
393
|
end
|
394
394
|
end
|
@@ -398,14 +398,14 @@ describe "validation callbacks and filter halt" do
|
|
398
398
|
|
399
399
|
property :name
|
400
400
|
before_validation :check_name
|
401
|
-
before_validation_on_save :
|
402
|
-
before_validation_on_create :
|
401
|
+
before_validation_on_save :abort_callback
|
402
|
+
before_validation_on_create :abort_callback
|
403
403
|
|
404
404
|
def check_name
|
405
405
|
errors.add(:name, 'should be Paul') unless name == "Paul"
|
406
406
|
end
|
407
407
|
|
408
|
-
def
|
408
|
+
def abort_callback
|
409
409
|
false
|
410
410
|
end
|
411
411
|
end
|
@@ -414,9 +414,9 @@ describe "validation callbacks and filter halt" do
|
|
414
414
|
include CouchPotato::Persistence
|
415
415
|
|
416
416
|
property :name
|
417
|
-
before_update :
|
417
|
+
before_update :abort_callback
|
418
418
|
|
419
|
-
def
|
419
|
+
def abort_callback
|
420
420
|
false
|
421
421
|
end
|
422
422
|
end
|
@@ -425,10 +425,10 @@ describe "validation callbacks and filter halt" do
|
|
425
425
|
include CouchPotato::Persistence
|
426
426
|
|
427
427
|
property :name
|
428
|
-
before_save :
|
429
|
-
before_create :
|
428
|
+
before_save :abort_callback
|
429
|
+
before_create :abort_callback
|
430
430
|
|
431
|
-
def
|
431
|
+
def abort_callback
|
432
432
|
false
|
433
433
|
end
|
434
434
|
end
|
@@ -450,16 +450,42 @@ describe "validation callbacks and filter halt" do
|
|
450
450
|
expect(@db.save_document(@user)).to eq(false)
|
451
451
|
end
|
452
452
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
453
|
+
if ActiveModel.version.segments.first < 5
|
454
|
+
it "should return false on saving a document when a before update filter returned false" do
|
455
|
+
@user = FilterSaveUpdateUser.new(:name => "Paul")
|
456
|
+
expect(@db.save_document(@user)).to eq(true)
|
457
|
+
@user.name = 'Bert'
|
458
|
+
expect(@db.save_document(@user)).to eq(false)
|
459
|
+
end
|
459
460
|
|
460
|
-
|
461
|
-
|
462
|
-
|
461
|
+
it "should return false on saving a document when a before save or before create filter returned false" do
|
462
|
+
@user = FilterSaveCreateUser.new(:name => "Bert")
|
463
|
+
expect(@db.save_document(@user)).to eq(false)
|
464
|
+
end
|
465
|
+
else
|
466
|
+
class FilterSaveCreateUser5 < FilterSaveCreateUser
|
467
|
+
def abort_callback
|
468
|
+
throw :abort
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
class FilterSaveUpdateUser5 < FilterSaveUpdateUser
|
473
|
+
def abort_callback
|
474
|
+
throw :abort
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
it "returns false on saving a document when a before update filter throws :abort" do
|
479
|
+
@user = FilterSaveUpdateUser5.new(:name => "Paul")
|
480
|
+
expect(@db.save_document(@user)).to eq(true)
|
481
|
+
@user.name = 'Bert'
|
482
|
+
expect(@db.save_document(@user)).to eq(false)
|
483
|
+
end
|
484
|
+
|
485
|
+
it "returns false on saving a document when a before save or before create filter throws :abort" do
|
486
|
+
@user = FilterSaveCreateUser5.new(:name => "Bert")
|
487
|
+
expect(@db.save_document(@user)).to eq(false)
|
488
|
+
end
|
463
489
|
end
|
464
490
|
|
465
491
|
end
|
data/spec/property_spec.rb
CHANGED
@@ -93,10 +93,10 @@ describe 'properties' do
|
|
93
93
|
|
94
94
|
it "should persist a big decimal" do
|
95
95
|
require 'bigdecimal'
|
96
|
-
c = BigDecimalContainer.new :number => BigDecimal
|
96
|
+
c = BigDecimalContainer.new :number => BigDecimal( '42.42' )
|
97
97
|
CouchPotato.database.save_document! c
|
98
98
|
c = CouchPotato.database.load_document c.id
|
99
|
-
expect(c.number).to eq(BigDecimal
|
99
|
+
expect(c.number).to eq(BigDecimal( '42.42' ))
|
100
100
|
end
|
101
101
|
|
102
102
|
it "should persist a hash" do
|
data/spec/railtie_spec.rb
CHANGED
@@ -83,6 +83,16 @@ describe "railtie" do
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
context 'yaml file contains additional_databases' do
|
87
|
+
it 'assigns additional_databases to config' do
|
88
|
+
allow(File).to receive_messages(:read => "test:\n database: test\n additional_databases:\n db2: test2")
|
89
|
+
|
90
|
+
expect(CouchPotato::Config).to receive(:additional_databases=).with('db2' => 'test2')
|
91
|
+
|
92
|
+
CouchPotato.rails_init
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
86
96
|
it "should process the yml file with erb" do
|
87
97
|
allow(File).to receive_messages(:read => "test: \n database: <%= 'db' %>")
|
88
98
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'rspec'
|
3
5
|
require 'time'
|
4
6
|
require 'active_support'
|
5
7
|
require 'timecop'
|
6
8
|
|
7
|
-
|
9
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
8
10
|
|
9
11
|
require 'couch_potato'
|
10
12
|
|
@@ -13,7 +15,7 @@ CouchPotato::Config.database_name = ENV['DATABASE'] || 'couch_potato_test'
|
|
13
15
|
# silence deprecation warnings from ActiveModel as the Spec uses Errors#on
|
14
16
|
begin
|
15
17
|
ActiveSupport::Deprecation.silenced = true
|
16
|
-
rescue
|
18
|
+
rescue StandardError
|
17
19
|
# ignore errors, ActiveSupport is probably not installed
|
18
20
|
end
|
19
21
|
|
@@ -64,5 +66,4 @@ RSpec::Matchers.define :eql_ignoring_indentation do |expected|
|
|
64
66
|
def strip_indentation(string)
|
65
67
|
string.gsub(/^\s+/m, '')
|
66
68
|
end
|
67
|
-
|
68
69
|
end
|
@@ -12,8 +12,12 @@ begin
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
def assert_equal(one, other)
|
16
|
-
expect(one).to
|
15
|
+
def assert_equal(one, other, _message = nil)
|
16
|
+
expect(one).to eq(other)
|
17
|
+
end
|
18
|
+
|
19
|
+
def assert_respond_to(receiver, method)
|
20
|
+
expect(receiver).to respond_to(method)
|
17
21
|
end
|
18
22
|
|
19
23
|
class ActiveComment
|
@@ -62,7 +66,7 @@ begin
|
|
62
66
|
describe "#errors" do
|
63
67
|
it "should return a single error as array" do
|
64
68
|
@model.valid?
|
65
|
-
expect(@model.errors[:name]).to
|
69
|
+
expect(@model.errors[:name]).to eq(["can't be blank"])
|
66
70
|
end
|
67
71
|
|
68
72
|
it "should return multiple errors as array" do
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'database caching' do
|
6
|
+
let(:couchrest_db) do
|
7
|
+
double(:couchrest_db, info: double(:info),
|
8
|
+
root: '', get: double.as_null_object)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:db) do
|
12
|
+
CouchPotato::Database.new(couchrest_db).tap do |db|
|
13
|
+
db.cache = cache
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:cache) do
|
18
|
+
{}
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'gets an object from the cache the 2nd time via #load_documemt' do
|
22
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
23
|
+
|
24
|
+
db.load_document '1'
|
25
|
+
db.load_document '1'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'gets an object from the cache the 2nd time via #load' do
|
29
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
30
|
+
|
31
|
+
db.load '1'
|
32
|
+
db.load '1'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'gets an object from the cache the 2nd time via #load!' do
|
36
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(1).times
|
37
|
+
|
38
|
+
db.load! '1'
|
39
|
+
db.load! '1'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns the correct object' do
|
43
|
+
doc = double(:doc, 'database=': nil)
|
44
|
+
allow(couchrest_db).to receive_messages(get: doc)
|
45
|
+
|
46
|
+
db.load_document '1'
|
47
|
+
expect(db.load_document('1')).to eql(doc)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not cache bulk loads' do
|
51
|
+
allow(couchrest_db).to receive_messages(bulk_load: {'rows' => []})
|
52
|
+
expect(couchrest_db).to receive(:bulk_load).with(['1']).exactly(2).times
|
53
|
+
|
54
|
+
db.load_document ['1']
|
55
|
+
db.load_document ['1']
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'clears the cache when destroying a document via #destroy_document' do
|
59
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
60
|
+
|
61
|
+
db.load_document '1'
|
62
|
+
db.destroy_document double.as_null_object
|
63
|
+
db.load_document '1'
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'clears the cache when destroying a document via #destroy' do
|
67
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
68
|
+
|
69
|
+
db.load_document '1'
|
70
|
+
db.destroy double.as_null_object
|
71
|
+
db.load_document '1'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'clears the cache when updating a document via #save_document' do
|
75
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
76
|
+
|
77
|
+
db.load_document '1'
|
78
|
+
db.save_document double.as_null_object
|
79
|
+
db.load_document '1'
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'clears the cache when updating a document via #save_document!' do
|
83
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
84
|
+
|
85
|
+
db.load_document '1'
|
86
|
+
db.save_document! double.as_null_object
|
87
|
+
db.load_document '1'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'clears the cache when updating a document via #save' do
|
91
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
92
|
+
|
93
|
+
db.load_document '1'
|
94
|
+
db.save double.as_null_object
|
95
|
+
db.load_document '1'
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'clears the cache when updating a document via #save!' do
|
99
|
+
expect(couchrest_db).to receive(:get).with('1').exactly(2).times
|
100
|
+
|
101
|
+
db.load_document '1'
|
102
|
+
db.save! double.as_null_object
|
103
|
+
db.load_document '1'
|
104
|
+
end
|
105
|
+
end
|