couch_potato 1.18.0 → 1.19.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 541fbb6f39b68bad864b70d9abb9f824ccf5b85a42b0a652282f9362c1fa4a5b
4
- data.tar.gz: 9684d42c720dad80be99d3e225a12fc0db0d413e6ef987accceddc0d46bab526
3
+ metadata.gz: 46b162f592d8c1c7dada2e150793fbfc5f8c76c1e9bb8a3364f8f2895505335b
4
+ data.tar.gz: eca37db69c74f6f58ec6bb518028a100e9b74ce1bfbe7edce16b899c5caa7406
5
5
  SHA512:
6
- metadata.gz: 6e882ea7f5a1cfaeab4d62b610b5e34b18b7231f1923499a7bfc8b77b2f89a845303597d9ef0a85b681d39ff2ece08c465c7a98e2d4f74baa9c923f199136902
7
- data.tar.gz: 2e6aef8d870ef30869c5154a7dd544f644592879ac8d46b3843854602eb378154850b07899c17f6fca99e0ca20e8b41598c116093ef9db2bf95c5fb89e312cf0
6
+ metadata.gz: c4f8edddc5e9a667bb09cb1fa9c5ee5bbb6f374088f27d039bfedd21ce59f13be2a963803bb40be0677916ab9d1d3543eb325849dd5f05010089092ceb0ce891
7
+ data.tar.gz: 4952e15f37cce9db1e07032f8588a24d28d990cba4e657b657cd4621cf8786a08af9289daadcc1c65a1f6d7f55ea4aef447f7e7e409c488bb706e6ea39e61c4f
@@ -24,11 +24,11 @@ jobs:
24
24
  - ruby: "jruby"
25
25
  gemfile: "active_support_8_0"
26
26
  steps:
27
- - uses: actions/checkout@v2
27
+ - uses: actions/checkout@v4
28
28
  - name: Set up CouchDB
29
- uses: cobot/couchdb-action@v4
29
+ uses: cobot/couchdb-action@v5
30
30
  with:
31
- couchdb version: "2.3.1"
31
+ couchdb-version: "2.3.1"
32
32
  - name: Set up Ruby
33
33
  uses: ruby/setup-ruby@v1
34
34
  with:
@@ -36,3 +36,5 @@ jobs:
36
36
  bundler-cache: true
37
37
  - name: Run tests
38
38
  run: bundle exec rake spec_ci
39
+ env:
40
+ DATABASE: http://admin:admin@localhost:5984/couch_potato_test
data/CHANGES.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## Changes
2
2
 
3
+ # 1.19.0 / rspec-matchers 4.2.0
4
+
5
+ - add `single_design_document` config option
6
+ - remove support for lists and lib
7
+
3
8
  # 1.18.0
4
9
 
5
10
  - add testing Rails 7.2/8 on CI
data/README.md CHANGED
@@ -80,6 +80,12 @@ Another switch allows you to store each CouchDB view in its own design document.
80
80
  CouchPotato::Config.split_design_documents_per_view = true
81
81
  ```
82
82
 
83
+ With the following switch, couch potato only creates a single design document for all views:
84
+
85
+ ```ruby
86
+ CouchPotato::Config.single_design_document = true
87
+ ```
88
+
83
89
  If you are using more than one database from your app, you can create aliases:
84
90
 
85
91
  ```ruby
@@ -95,6 +101,7 @@ Create a `config/couchdb.yml`:
95
101
  default: &default
96
102
  split_design_documents_per_view: true # optional, default is false
97
103
  digest_view_names: true # optional, default is false
104
+ single_design_document: true # optional, default is false
98
105
  default_language: :erlang # optional, default is javascript
99
106
  database_host: "http://127.0.0.1:5984"
100
107
 
@@ -299,7 +306,7 @@ user.valid? # => false
299
306
  user.errors[:name] # => ['can't be blank']
300
307
  ```
301
308
 
302
- #### Finding stuff / views / lists
309
+ #### Finding stuff / views
303
310
 
304
311
  In order to find data in your CouchDB you have to create a [view](http://books.couchdb.org/relax/design-documents/views) first. Couch Potato offers you to create and manage those views for you. All you have to do is declare them in your classes:
305
312
 
@@ -403,14 +410,6 @@ class User
403
410
  end
404
411
  ```
405
412
 
406
- commonJS modules can also be used in custom views:
407
-
408
- ```ruby
409
- class User
410
- view :all, :map => "function(doc) { emit(null, require("views/lib/test").test)}", :lib => {:test => "exports.test = 'test'"}, :include_docs => true, :type => :custom
411
- end
412
- ```
413
-
414
413
  If you don't want the results to be converted into models the raw view is your friend:
415
414
 
416
415
  ```ruby
@@ -450,49 +449,6 @@ You can pass in your own view specifications by passing in `:type => MyViewSpecC
450
449
 
451
450
  If turned on, Couch Potato will append an MD5 digest of the map function to each view name. This makes sure (together with split_design_documents_per_view) that no views/design documents are ever updated. Instead, new ones are created. Since reindexing can take a long time once your database is larger, you want to avoid blocking your app while CouchDB is busy. Instead, you create a new view, warm it up, and only then start using it.
452
451
 
453
- ##### Lists
454
-
455
- CouchPotato also supports [CouchDB lists](http://books.couchdb.org/relax/design-documents/lists). With lists you can process the result of a view query with another JavaScript function. This can be useful for example if you want to filter your results, or add some data to each document.
456
-
457
- Defining a list works similarly to views:
458
-
459
- ```ruby
460
- class User
461
- include CouchPotato::Persistence
462
-
463
- property :first_name
464
- view :with_full_name, key: first_namne, list: :add_last_name
465
- view :all, key: :first_name
466
-
467
- list :add_last_name, <<-JS
468
- function(head, req) {
469
- var row;
470
- send('{"rows": [');
471
- while(row = getRow()) {
472
- row.doc.name = row.doc.first_name + ' doe';
473
- send(JSON.stringify(row));
474
- };
475
- send(']}');
476
- }
477
- JS
478
- end
479
-
480
- CouchPotato.database.save User.new(first_name: 'joe')
481
- CouchPotato.database.view(User.with_full_name).first.name # => 'joe doe'
482
- ```
483
-
484
- You can also pass in the list at query time:
485
-
486
- ```ruby
487
- CouchPotato.database.view(User.all(list: :add_last_name))
488
- ```
489
-
490
- And you can pass parameters to the list:
491
-
492
- ```ruby
493
- CouchPotato.database.view(User.all(list: :add_last_name, list_params: {filter: '*'}))
494
- ```
495
-
496
452
  #### Associations
497
453
 
498
454
  Not supported. Not sure if they ever will be. You can implement those yourself using views and custom methods on your models.
@@ -273,8 +273,6 @@ module CouchPotato
273
273
  map: spec.map_function,
274
274
  reduce: spec.reduce_function
275
275
  } },
276
- ({ spec.list_name => spec.list_function } unless spec.list_name.nil?),
277
- spec.lib,
278
276
  spec.language
279
277
  ).query_view!(spec.view_parameters)
280
278
  end
@@ -12,16 +12,20 @@ require File.dirname(__FILE__) + '/persistence/type_caster'
12
12
  require File.dirname(__FILE__) + '/persistence/revisions'
13
13
  require File.dirname(__FILE__) + '/forbidden_attributes_protection'
14
14
  require File.dirname(__FILE__) + '/view/custom_views'
15
- require File.dirname(__FILE__) + '/view/lists'
16
15
  require File.dirname(__FILE__) + '/view/view_query'
17
16
 
18
17
 
19
18
  module CouchPotato
20
19
  module Persistence
20
+ module TrackModels
21
+ def inherited(child)
22
+ super
23
+ CouchPotato.models << child
24
+ end
25
+ end
21
26
 
22
27
  def self.included(base) #:nodoc:
23
- base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews,
24
- CouchPotato::View::Lists
28
+ base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews
25
29
  base.send :include, DirtyAttributes, GhostAttributes, Attachments
26
30
  base.send :include, MagicTimestamps, ActiveModelCompliance,
27
31
  ForbiddenAttributesProtection, Revisions
@@ -31,9 +35,8 @@ module CouchPotato
31
35
  alias_method :id, :_id
32
36
  alias_method :id=, :_id=
33
37
 
34
- def self.inherited(child)
35
- super
36
- CouchPotato.models << child
38
+ class << self
39
+ prepend TrackModels
37
40
  end
38
41
  end
39
42
 
@@ -1,4 +1,4 @@
1
1
  module CouchPotato
2
- VERSION = '1.18.0'.freeze
3
- RSPEC_VERSION = '4.1.0'.freeze
2
+ VERSION = '1.19.0'.freeze
3
+ RSPEC_VERSION = '4.2.0'.freeze
4
4
  end
@@ -3,7 +3,7 @@
3
3
  module CouchPotato
4
4
  module View
5
5
  class BaseViewSpec
6
- attr_reader :reduce_function, :lib, :list_name, :list_function, :design_document, :view_name, :klass, :options, :language
6
+ attr_reader :reduce_function, :design_document, :view_name, :klass, :options, :language
7
7
  attr_accessor :view_parameters
8
8
 
9
9
  private :klass, :options
@@ -11,7 +11,7 @@ module CouchPotato
11
11
  def initialize(klass, view_name, options, view_parameters)
12
12
  normalized_view_parameters = ViewParameters.normalize_view_parameters view_parameters
13
13
 
14
- @list_name = normalized_view_parameters.delete(:list) || options[:list]
14
+
15
15
  @language = options[:language] || Config.default_language
16
16
 
17
17
  assert_valid_view_parameters normalized_view_parameters
@@ -19,16 +19,12 @@ module CouchPotato
19
19
  @options = options
20
20
  @view_name = compute_view_name(view_name,
21
21
  options.key?(:digest_view_name) ? options[:digest_view_name] : Config.digest_view_names)
22
- @design_document = translate_to_design_doc_name(klass.to_s, @view_name, @list_name)
23
- @list_params = normalized_view_parameters.delete :list_params
24
-
25
- @list_function = klass.lists(@list_name) if @list_name
22
+ @design_document = design_doc_name
26
23
  @view_parameters = {}
27
24
  %i[group include_docs descending group_level limit].each do |key|
28
25
  @view_parameters[key] = options[key] if options.include?(key)
29
26
  end
30
27
  @view_parameters.merge!(normalized_view_parameters)
31
- @view_parameters.merge!(@list_params) if @list_params
32
28
  end
33
29
 
34
30
  def process_results(results)
@@ -42,10 +38,16 @@ module CouchPotato
42
38
  private
43
39
 
44
40
  def compute_view_name(view_name, digest)
41
+ name = if CouchPotato::Config.single_design_document
42
+ "#{translate_to_design_doc_name(klass.to_s, view_name)}-#{view_name}"
43
+ else
44
+ view_name
45
+ end
46
+
45
47
  if digest
46
- "#{view_name}-#{Digest::MD5.hexdigest(map_function + reduce_function.to_s)}"
48
+ "#{name}-#{Digest::MD5.hexdigest(map_function + reduce_function.to_s)}"
47
49
  else
48
- view_name
50
+ name
49
51
  end
50
52
  end
51
53
 
@@ -56,10 +58,18 @@ module CouchPotato
56
58
  end
57
59
 
58
60
  def valid_view_parameters
59
- %w[list_params key keys startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end]
61
+ %w[key keys startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end]
62
+ end
63
+
64
+ def design_doc_name
65
+ if CouchPotato::Config.single_design_document
66
+ 'couch_potato'
67
+ else
68
+ translate_to_design_doc_name(klass.to_s, view_name)
69
+ end
60
70
  end
61
71
 
62
- def translate_to_design_doc_name(klass_name, view_name, list_name)
72
+ def translate_to_design_doc_name(klass_name, view_name)
63
73
  klass_name = klass_name.dup
64
74
  klass_name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
65
75
  klass_name.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
@@ -68,7 +78,6 @@ module CouchPotato
68
78
 
69
79
  if CouchPotato::Config.split_design_documents_per_view
70
80
  doc_name += "_view_#{view_name}" if view_name.present?
71
- doc_name += "_list_#{list_name}" if list_name.present?
72
81
  end
73
82
  doc_name
74
83
  end
@@ -13,10 +13,6 @@ module CouchPotato
13
13
  options[:reduce]
14
14
  end
15
15
 
16
- def lib
17
- options[:lib]
18
- end
19
-
20
16
  def view_parameters
21
17
  {:include_docs => options[:include_docs] || false}.merge(super)
22
18
  end
@@ -9,9 +9,21 @@ require 'couch_potato/view/view_parameters'
9
9
  module CouchPotato
10
10
  module View
11
11
  module CustomViews
12
+ module TrackViews
13
+ def inherited(child)
14
+ super
15
+ CouchPotato.views << child
16
+ end
17
+ end
12
18
 
13
19
  def self.included(base) #:nodoc:
14
20
  base.extend ClassMethods
21
+ CouchPotato.views << base
22
+ base.class_eval do
23
+ class << self
24
+ prepend TrackViews
25
+ end
26
+ end
15
27
  end
16
28
 
17
29
  module ClassMethods
@@ -96,7 +96,7 @@ module CouchPotato
96
96
  end
97
97
 
98
98
  delegate :view_name, :view_parameters, :design_document, :map_function,
99
- :reduce_function, :list_name, :lib, :language, to: :view_spec_delegate
99
+ :reduce_function, :language, to: :view_spec_delegate
100
100
 
101
101
  def process_results(results)
102
102
  results = Results.new(results)
@@ -1,6 +1,6 @@
1
1
  module CouchPotato
2
2
  module View
3
- # A view for custom map/reduce functions that returns the raw data fromcouchdb
3
+ # A view for custom map/reduce functions that returns the raw data from couchdb
4
4
  #
5
5
  # example:
6
6
  # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :reduce => nil
@@ -10,7 +10,7 @@ module CouchPotato
10
10
  # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :results_filter => lambda{|results| results['rows].map{|row| row['value']}}
11
11
  #
12
12
  # example:
13
- # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :lib => {:module => "exports.name = 'module';"
13
+ # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw"
14
14
  class RawViewSpec < BaseViewSpec
15
15
  def map_function
16
16
  options[:map]
@@ -19,10 +19,6 @@ module CouchPotato
19
19
  def reduce_function
20
20
  options[:reduce]
21
21
  end
22
-
23
- def lib
24
- options[:lib]
25
- end
26
22
  end
27
23
  end
28
24
  end
@@ -2,18 +2,13 @@ module CouchPotato
2
2
  module View
3
3
  # Used to query views (and create them if they don't exist). Usually you won't have to use this class directly. Instead it is used internally by the CouchPotato::Database.view method.
4
4
  class ViewQuery
5
- def initialize(couchrest_database, design_document_name, view, list = nil, lib = nil, language = :javascript)
5
+ def initialize(couchrest_database, design_document_name, view, language = :javascript)
6
6
  @database = couchrest_database
7
7
  @design_document_name = design_document_name
8
8
  @view_name = view.keys[0]
9
9
  @map_function = view.values[0][:map]
10
10
  @reduce_function = view.values[0][:reduce]
11
- @lib = lib
12
11
  @language = language
13
- if list
14
- @list_function = list.values[0]
15
- @list_name = list.keys[0]
16
- end
17
12
  end
18
13
 
19
14
  def query_view!(parameters = {})
@@ -42,34 +37,41 @@ module CouchPotato
42
37
  def update_view
43
38
  design_doc = @database.get "_design/#{@design_document_name}" rescue nil
44
39
  original_views = design_doc && design_doc['views'].dup
45
- original_lists = design_doc && design_doc['lists'] && design_doc['lists'].dup
46
- view_updated unless design_doc.nil?
40
+ view_updated
47
41
  design_doc ||= empty_design_document
48
- design_doc['views'][@view_name.to_s] = view_functions
49
- if @lib
50
- design_doc['views']['lib'] = (design_doc['views']['lib'] || {}).merge(@lib)
42
+ if CouchPotato::Config.single_design_document
43
+ design_doc['views'] = all_views
44
+ else
45
+ design_doc['views'][@view_name.to_s] = view_functions
51
46
  end
52
- if @list_function
53
- design_doc['lists'] ||= {}
54
- design_doc['lists'][@list_name.to_s] = @list_function
47
+ if original_views != design_doc['views']
48
+ @database.save_doc(design_doc)
55
49
  end
56
- @database.save_doc(design_doc) if original_views != design_doc['views'] || original_lists != design_doc['lists']
57
50
  end
58
51
 
59
- def view_functions
60
- if @reduce_function
61
- {'map' => @map_function, 'reduce' => @reduce_function}
62
- else
63
- {'map' => @map_function}
64
- end
52
+ def all_views
53
+ CouchPotato.views.flat_map do |klass|
54
+ specs = klass.views.map { |view_name, view| klass.execute_view(view_name, {}) }
55
+ specs.map do |klass_spec|
56
+ { klass_spec.view_name => view_functions(klass_spec.map_function, klass_spec.reduce_function) }
57
+ end
58
+ end.inject(&:merge)
59
+ end
60
+
61
+ def view_functions(map_function = @map_function, reduce_function = @reduce_function)
62
+ {'map' => map_function, 'reduce' => reduce_function}.compact
65
63
  end
66
64
 
67
65
  def empty_design_document
68
- {'views' => {}, 'lists' => {}, "_id" => "_design/#{@design_document_name}", "language" => @language.to_s}
66
+ {'views' => {}, "_id" => "_design/#{@design_document_name}", "language" => @language.to_s}
69
67
  end
70
68
 
71
69
  def view_has_been_updated?
72
- updated_views[[@design_document_name, @view_name]]
70
+ if CouchPotato::Config.single_design_document
71
+ updated_views.any?
72
+ else
73
+ updated_views[[@design_document_name, @view_name]]
74
+ end
73
75
  end
74
76
 
75
77
  def view_updated
@@ -81,11 +83,7 @@ module CouchPotato
81
83
  end
82
84
 
83
85
  def query_view(parameters)
84
- if @list_name
85
- @database.connection.get CouchRest.paramify_url("/#{@database.name}/_design/#{@design_document_name}/_list/#{@list_name}/#{@view_name}", parameters)
86
- else
87
- @database.view view_url, parameters
88
- end
86
+ @database.view view_url, parameters
89
87
  end
90
88
 
91
89
  def view_url
data/lib/couch_potato.rb CHANGED
@@ -9,9 +9,10 @@ JSON.create_id = 'ruby_class'
9
9
  CouchRest.decode_json_objects = true
10
10
 
11
11
  module CouchPotato
12
- Config = Struct.new(:database_host, :database_name, :digest_view_names,
12
+ Config = Struct.new(:database_host, :database_name, :digest_view_names, :single_design_document,
13
13
  :split_design_documents_per_view, :default_language, :additional_databases).new
14
14
  Config.split_design_documents_per_view = false
15
+ Config.single_design_document = false
15
16
  Config.digest_view_names = false
16
17
  Config.default_language = :javascript
17
18
  Config.database_host = 'http://127.0.0.1:5984'
@@ -29,6 +30,7 @@ module CouchPotato
29
30
  Config.database_host = config['database_host'] if config['database_host']
30
31
  Config.additional_databases = config['additional_databases'].stringify_keys if config['additional_databases']
31
32
  Config.split_design_documents_per_view = config['split_design_documents_per_view'] if config['split_design_documents_per_view']
33
+ Config.single_design_document = config['single_design_document'] if config['single_design_document']
32
34
  Config.digest_view_names = config['digest_view_names'] if config['digest_view_names']
33
35
  Config.default_language = config['default_language'] if config['default_language']
34
36
  end
@@ -40,6 +42,12 @@ module CouchPotato
40
42
  @models
41
43
  end
42
44
 
45
+ # returns all the classes that include the CouchPotato::View::CustomViews module
46
+ def self.views
47
+ @views ||= []
48
+ @views
49
+ end
50
+
43
51
  # 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.
44
52
  def self.database
45
53
  Thread.current[:__couch_potato_database] ||= Database.new(couchrest_database)
@@ -418,7 +418,7 @@ describe 'properties' do
418
418
 
419
419
  it "should include complex datatypes fully inspected" do
420
420
  comment.title = {'en' => 'Blog post'}
421
- expect(comment.inspect).to include('title: {"en"=>"Blog post"}')
421
+ expect(comment.inspect).to match(/title: {"en"\s*=>\s*"Blog post"}/)
422
422
 
423
423
  comment.title = nil
424
424
  expect(comment.inspect).to include('title: nil')
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'single design document' do
4
+ let(:db) { CouchPotato.database }
5
+ let(:couchrest_db) { db.couchrest_database }
6
+
7
+ class Thing1
8
+ include CouchPotato::Persistence
9
+
10
+ property :title
11
+
12
+ view :all, key: :title
13
+ end
14
+
15
+ class Thing2
16
+ include CouchPotato::Persistence
17
+
18
+ property :name
19
+
20
+ view :all, key: :name
21
+ end
22
+
23
+ class Thing3 < Thing1 # should work with inheritance
24
+ property :tag
25
+
26
+ view :by_tag, key: :tag
27
+ end
28
+
29
+ before(:each) do
30
+ recreate_db
31
+ CouchPotato::Config.single_design_document = true
32
+ CouchPotato.views.select! { |v| [Thing1, Thing2, Thing3].include?(v) } # clear classes from other specs
33
+ end
34
+
35
+ after(:each) do
36
+ CouchPotato::Config.single_design_document = false
37
+ end
38
+
39
+ it 'creates a single design document for all views' do
40
+ thing1 = Thing1.new title: 't1'
41
+ db.save! thing1
42
+ thing2 = Thing2.new name: 'n2'
43
+ db.save! thing2
44
+
45
+ db.view(Thing1.all) # create all views when querying the first one
46
+
47
+ expect(couchrest_db.get('_design/couch_potato')['views'].keys)
48
+ .to(eq(['thing1-all', 'thing2-all', 'thing3-by_tag']))
49
+ end
50
+
51
+ it 'returns the correct models' do
52
+ thing1 = Thing1.new title: 't1'
53
+ db.save! thing1
54
+ thing2 = Thing2.new name: 'n2'
55
+ db.save! thing2
56
+ thing3 = Thing3.new tag: 'tag1'
57
+ db.save! thing3
58
+
59
+ expect(db.view(Thing1.all('t1'))).to eq([thing1])
60
+ expect(db.view(Thing2.all('n2'))).to eq([thing2])
61
+ expect(db.view(Thing3.by_tag('tag1'))).to eq([thing3])
62
+ end
63
+ end
@@ -87,7 +87,7 @@ describe 'attributes' do
87
87
  plant = Plant.new
88
88
  expect do
89
89
  plant.length
90
- end.to raise_error(NoMethodError, /undefined method `length'/)
90
+ end.to raise_error(NoMethodError, /undefined method [`']length'/)
91
91
  end
92
92
  end
93
93
 
@@ -33,8 +33,7 @@ describe CouchPotato::View::BaseViewSpec, 'initialize' do
33
33
  :group_level => 1,
34
34
  :reduce => false,
35
35
  :include_docs => true,
36
- :inclusive_end => true,
37
- :list_params => {}
36
+ :inclusive_end => true
38
37
  }
39
38
  }.not_to raise_error
40
39
  end
@@ -54,70 +53,72 @@ describe CouchPotato::View::BaseViewSpec, 'initialize' do
54
53
  expect(spec.view_parameters).to eq({:key => '2'})
55
54
  end
56
55
 
57
- it 'merges the list params' do
58
- spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, key: '2', list_params: {:x => 'y'}
59
- expect(spec.view_parameters).to eq({:key => '2', :x => 'y'})
60
- end
61
-
62
- it "generates the design document path by snake_casing the class name but keeping double colons" do
63
- spec = CouchPotato::View::BaseViewSpec.new 'Foo::BarBaz', '', {}, ''
64
- expect(spec.design_document).to eq('foo::bar_baz')
65
- end
66
-
67
- it "generates the design document independent of the view name by default" do
68
- CouchPotato::Config.split_design_documents_per_view = false
69
- spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, ''
70
- expect(spec.design_document).to eq('user')
71
- end
72
-
73
- it "generates the design document per view if configured to" do
74
- CouchPotato::Config.split_design_documents_per_view = true
75
- spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, ''
76
- expect(spec.design_document).to eq('user_view_by_login_and_email')
77
- end
78
-
79
- it 'adds the view name digest to the design doc name' do
80
- CouchPotato::Config.split_design_documents_per_view = true
81
- spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email',
82
- {digest_view_name: true, map: 'function(doc) {}'}, ''
83
-
84
- expect(spec.design_document).to eq('user_view_by_login_and_email-375c815fcb4f977f330a2edfadc7f74d')
85
- end
86
-
87
- it 'builds the name digest by hashing the map and reduce function if there is one' do
88
- CouchPotato::Config.split_design_documents_per_view = true
89
- spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email',
90
- {digest_view_name: true, map: 'function(doc) {}', reduce: 'function(key, values) {}'}, ''
91
-
92
- expect(spec.design_document).to eq('user_view_by_login_and_email-c9f83cec3dab954a8ca56330006f187e')
93
- end
94
-
95
-
96
- it "generates the design document independent of the list name by default" do
97
- CouchPotato::Config.split_design_documents_per_view = false
98
- spec = CouchPotato::View::BaseViewSpec.new double(lists: nil, :to_s => 'User'), '', {list: 'test_list'}, {}
99
- expect(spec.design_document).to eq('user')
100
- end
56
+ context 'when single design document is enabled' do
57
+ before(:each) do
58
+ CouchPotato::Config.single_design_document = true
59
+ end
101
60
 
102
- it "generates the design document per view if configured to" do
103
- CouchPotato::Config.split_design_documents_per_view = true
104
- spec = CouchPotato::View::BaseViewSpec.new double(lists: nil, :to_s => 'User'), '', {list: :test_list}, {}
105
- expect(spec.design_document).to eq('user_list_test_list')
106
- end
61
+ after(:each) do
62
+ CouchPotato::Config.single_design_document = false
63
+ end
64
+
65
+ it 'generates one design document for all views' do
66
+ spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, ''
107
67
 
108
- it "extracts the list name from the options" do
109
- spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {list: :test_list}, {}
110
- expect(spec.list_name).to eq(:test_list)
68
+ expect(spec.design_document).to eq('couch_potato')
69
+ end
111
70
  end
112
71
 
113
- it "extracts the list from the view parameters" do
114
- spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {}, {list: :test_list}
115
- expect(spec.list_name).to eq(:test_list)
116
- end
72
+ context 'when single design document is disabled' do
73
+ before(:each) do
74
+ CouchPotato::Config.single_design_document = false
75
+ end
76
+
77
+ context 'and split design documents per view is enabled' do
78
+ before(:each) do
79
+ CouchPotato::Config.split_design_documents_per_view = true
80
+ end
81
+
82
+ after(:each) do
83
+ CouchPotato::Config.split_design_documents_per_view = false
84
+ end
85
+
86
+ it "generates one design document per view" do
87
+ spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, ''
88
+ expect(spec.design_document).to eq('user_view_by_login_and_email')
89
+ end
90
+
91
+ it 'adds the view name digest to the design doc name' do
92
+ spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email',
93
+ {digest_view_name: true, map: 'function(doc) {}'}, ''
94
+
95
+ expect(spec.design_document).to eq('user_view_by_login_and_email-375c815fcb4f977f330a2edfadc7f74d')
96
+ end
97
+
98
+ it 'builds the name digest by hashing the map and reduce function if there is one' do
99
+ spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email',
100
+ {digest_view_name: true, map: 'function(doc) {}', reduce: 'function(key, values) {}'}, ''
101
+
102
+ expect(spec.design_document).to eq('user_view_by_login_and_email-c9f83cec3dab954a8ca56330006f187e')
103
+ end
104
+ end
117
105
 
118
- it "prefers the list name from the view parameters over the one from the options" do
119
- spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {list: 'my_list'}, list: :test_list
120
- expect(spec.list_name).to eq(:test_list)
106
+ context 'and split design documents per view is disabled' do
107
+ before(:each) do
108
+ CouchPotato::Config.split_design_documents_per_view = false
109
+ end
110
+
111
+ it "generates the design document path by snake_casing the class name but keeping double colons" do
112
+ spec = CouchPotato::View::BaseViewSpec.new 'Foo::BarBaz', '', {}, ''
113
+ expect(spec.design_document).to eq('foo::bar_baz')
114
+ end
115
+
116
+ it "generates the design document independent of the view name" do
117
+ spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, ''
118
+ expect(spec.design_document).to eq('user')
119
+ end
120
+ end
121
+
121
122
  end
122
123
 
123
124
  it 'returns the view name' do
@@ -146,13 +147,6 @@ describe CouchPotato::View::BaseViewSpec, 'initialize' do
146
147
  end
147
148
  end
148
149
 
149
- it "returns the list function" do
150
- klass = double 'class'
151
- allow(klass).to receive(:lists).with('test_list').and_return('<list_code>')
152
- spec = CouchPotato::View::BaseViewSpec.new klass, 'all', {list: 'test_list'}, {}
153
- expect(spec.list_function).to eq('<list_code>')
154
- end
155
-
156
150
  it 'reads the language from the couch potato config by default' do
157
151
  CouchPotato::Config.default_language = :ruby
158
152
  spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, {}
@@ -8,6 +8,7 @@ describe CouchPotato, '.configure' do
8
8
  CouchPotato::Config.database_name = nil
9
9
  CouchPotato::Config.split_design_documents_per_view = false
10
10
  CouchPotato::Config.digest_view_names = false
11
+ CouchPotato::Config.single_design_document = false
11
12
  CouchPotato::Config.default_language = :javascript
12
13
  CouchPotato::Config.database_host = 'http://127.0.0.1:5984'
13
14
  CouchPotato::Config.additional_databases = {}
@@ -35,12 +36,14 @@ describe CouchPotato, '.configure' do
35
36
  test2: 'test2_db'
36
37
  },
37
38
  split_design_documents_per_view: true,
39
+ single_design_document: true,
38
40
  digest_view_names: true,
39
41
  default_language: 'erlang'
40
42
  )
41
43
 
42
44
  expect(CouchPotato::Config.database_name).to eq('testdb')
43
45
  expect(CouchPotato::Config.split_design_documents_per_view).to eq(true)
46
+ expect(CouchPotato::Config.single_design_document).to eq(true)
44
47
  expect(CouchPotato::Config.digest_view_names).to eq(true)
45
48
  expect(CouchPotato::Config.default_language).to eq('erlang')
46
49
  expect(CouchPotato::Config.database_host).to eq('http://10.0.0.1:2000')
@@ -415,29 +415,10 @@ describe CouchPotato::Database, 'view' do
415
415
  allow(CouchPotato::View::ViewQuery).to receive_messages(new: double('view query', query_view!: { 'rows' => [@result] }))
416
416
  end
417
417
 
418
- it 'initializes a view query with map/reduce/list/lib funtions' do
419
- allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view',
420
- map_function: '<map_code>', reduce_function: '<reduce_code>',
421
- lib: { test: '<test_code>' },
422
- list_name: 'my_list', list_function: '<list_code>', language: 'javascript')
423
- expect(CouchPotato::View::ViewQuery).to receive(:new).with(
424
- @couchrest_db,
425
- 'design_doc',
426
- { 'my_view' => {
427
- map: '<map_code>',
428
- reduce: '<reduce_code>'
429
- } },
430
- { 'my_list' => '<list_code>' },
431
- { test: '<test_code>' },
432
- 'javascript'
433
- )
434
- @db.view(@spec)
435
- end
436
418
 
437
- it 'initializes a view query with map/reduce/list funtions' do
419
+ it 'initializes a view query with map/reduce functions' do
438
420
  allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view',
439
421
  map_function: '<map_code>', reduce_function: '<reduce_code>',
440
- lib: nil, list_name: 'my_list', list_function: '<list_code>',
441
422
  language: 'javascript')
442
423
  expect(CouchPotato::View::ViewQuery).to receive(:new).with(
443
424
  @couchrest_db,
@@ -446,44 +427,11 @@ describe CouchPotato::Database, 'view' do
446
427
  map: '<map_code>',
447
428
  reduce: '<reduce_code>'
448
429
  } },
449
- { 'my_list' => '<list_code>' },
450
- nil,
451
430
  'javascript'
452
431
  )
453
432
  @db.view(@spec)
454
433
  end
455
434
 
456
- it 'initializes a view query with only map/reduce/lib functions' do
457
- allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view',
458
- map_function: '<map_code>', reduce_function: '<reduce_code>',
459
- list_name: nil, list_function: nil,
460
- lib: { test: '<test_code>' })
461
- expect(CouchPotato::View::ViewQuery).to receive(:new).with(
462
- @couchrest_db,
463
- 'design_doc',
464
- { 'my_view' => {
465
- map: '<map_code>',
466
- reduce: '<reduce_code>'
467
- } }, nil, { test: '<test_code>' }, anything
468
- )
469
- @db.view(@spec)
470
- end
471
-
472
- it 'initializes a view query with only map/reduce functions' do
473
- allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view',
474
- map_function: '<map_code>', reduce_function: '<reduce_code>',
475
- lib: nil, list_name: nil, list_function: nil)
476
- expect(CouchPotato::View::ViewQuery).to receive(:new).with(
477
- @couchrest_db,
478
- 'design_doc',
479
- { 'my_view' => {
480
- map: '<map_code>',
481
- reduce: '<reduce_code>'
482
- } }, nil, nil, anything
483
- )
484
- @db.view(@spec)
485
- end
486
-
487
435
  it 'sets itself on returned docs that have an accessor' do
488
436
  allow(@result).to receive(:respond_to?).and_return(false)
489
437
  allow(@result).to receive(:respond_to?).with(:database=).and_return(true)
@@ -36,22 +36,6 @@ describe CouchPotato::RSpec::MapToMatcher do
36
36
  expect(spec).to map({}).to([nil, "2013-05-17T15:00:00.000Z"])
37
37
  end
38
38
 
39
- it "should work with commonJS modules that use 'exports'" do
40
- spec = double(
41
- :map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }",
42
- :lib => {:test => "exports.test = 'test';"}
43
- )
44
- expect(spec).to map({}).to([nil, "test"])
45
- end
46
-
47
- it "should work with commonJS modules that use 'module.exports'" do
48
- spec = double(
49
- :map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }",
50
- :lib => {:test => "module.exports.test = 'test';"}
51
- )
52
- expect(spec).to map({}).to([nil, "test"])
53
- end
54
-
55
39
  describe "failing specs" do
56
40
  before(:each) do
57
41
  @view_spec = double(:map_function => "function(doc) {emit(doc.name, null)}")
@@ -145,22 +129,6 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
145
129
  expect(spec).to map_reduce({}).to({"key" => nil, "value" => "2013-05-17T15:00:00.000Z"})
146
130
  end
147
131
 
148
- it "should handle CommonJS requires for modules that use 'exports'" do
149
- spec = double(
150
- :map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }",
151
- :reduce_function => "function(keys, values) { return 'test' }",
152
- :lib => {:test => "exports.test = 'test'"})
153
- expect(spec).to map_reduce({}).to({"key" => nil, "value" => "test"})
154
- end
155
-
156
- it "should handle CommonJS requires for modules that use 'module.exports'" do
157
- spec = double(
158
- :map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }",
159
- :reduce_function => "function(keys, values) { return 'test' }",
160
- :lib => {:test => "module.exports.test = 'test'"})
161
- expect(spec).to map_reduce({}).to({"key" => nil, "value" => "test"})
162
- end
163
-
164
132
  it "should handle sum function" do
165
133
  spec = double(
166
134
  :map_function => "function(doc) { emit(null, doc.age); }",
@@ -240,13 +208,13 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
240
208
  it "should have a nice error message for failing should" do
241
209
  expect {
242
210
  expect(@view_spec).to map_reduce(@docs).with_options(:group => false).to({"key" => nil, "value" => 9})
243
- }.to raise_error('Expected to map/reduce to [{"key"=>nil, "value"=>9}] but got [{"key"=>nil, "value"=>8}].')
211
+ }.to raise_error(%r{Expected to map/reduce to \[{"key"\s*=>\s*nil, "value"\s*=>\s*9}\] but got \[{"key"\s*=>\s*nil, "value"\s*=>\s*8}\].})
244
212
  end
245
213
 
246
214
  it "should have a nice error message for failing should not" do
247
215
  expect {
248
216
  expect(@view_spec).not_to map_reduce(@docs).with_options(:group => false).to({"key" => nil, "value" => 8})
249
- }.to raise_error('Expected not to map/reduce to [{"key"=>nil, "value"=>8}] but did.')
217
+ }.to raise_error(%r{Expected not to map/reduce to \[{"key"\s*=>\s*nil, "value"\s*=>\s*8}\] but did.})
250
218
  end
251
219
  end
252
220
 
@@ -283,35 +251,3 @@ describe CouchPotato::RSpec::MapReduceToMatcher do
283
251
  end
284
252
  end
285
253
 
286
- describe CouchPotato::RSpec::ListAsMatcher do
287
- before(:each) do
288
- @view_spec = double(:list_function => "function() {var row = getRow(); send(JSON.stringify([{text: row.text + ' world'}]));}")
289
- end
290
-
291
- it "should pass if the function return the expected json" do
292
- expect(@view_spec).to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello world'}])
293
- end
294
-
295
- it "should not pass if the function does not return the expected json" do
296
- expect(@view_spec).not_to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello there'}])
297
- end
298
-
299
- it "should work with date values" do
300
- spec = double(:list_function => "function() { send(JSON.stringify([{date: new Date(1368802800000)}])); }")
301
- expect(spec).to list({"rows" => [{}]}).as([{"date" => "2013-05-17T15:00:00.000Z"}])
302
- end
303
-
304
- describe "failing specs" do
305
- it "should have a nice error message for failing should" do
306
- expect {
307
- expect(@view_spec).to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello there'}])
308
- }.to raise_error('Expected to list as [{"text"=>"hello there"}] but got [{"text"=>"hello world"}].')
309
- end
310
-
311
- it "should have a nice error message for failing should not" do
312
- expect {
313
- expect(@view_spec).not_to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello world'}])
314
- }.to raise_error('Expected to not list as [{"text"=>"hello world"}] but did.')
315
- end
316
- end
317
- end
@@ -16,14 +16,13 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
16
16
  it 'updates a view if it does not exist' do
17
17
  expect(db).to receive(:save_doc).with(
18
18
  {
19
- 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}, 'lib' => {'test' => '<lib_code>'}},
20
- 'lists' => {},
19
+ 'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
21
20
  "_id" => "_design/design",
22
21
  "language" => "javascript"
23
22
  }
24
23
  )
25
24
 
26
- CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, {'test' => "<lib_code>"}).query_view!
25
+ CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}).query_view!
27
26
  end
28
27
 
29
28
  it 'only updates a view once' do
@@ -50,33 +49,19 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
50
49
  expect(db).to receive(:save_doc).with(
51
50
  {
52
51
  'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
53
- 'lists' => {}, "_id" => "_design/design", "language" => "erlang"
52
+ "_id" => "_design/design", "language" => "erlang"
54
53
  }
55
54
  )
56
55
 
57
56
  CouchPotato::View::ViewQuery.new(db, 'design',
58
57
  {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}},
59
- nil, nil, :erlang).query_view!
58
+ :erlang).query_view!
60
59
  end
61
60
 
62
61
  it "does not update a view when the views object haven't changed" do
63
62
  allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}}})
64
63
  expect(db).not_to receive(:save_doc)
65
- CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, nil).query_view!
66
- end
67
-
68
- it "does not update a view when the list function hasn't changed" do
69
- allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}}, 'lists' => {'list0' => '<list_code>'}})
70
- expect(db).not_to receive(:save_doc)
71
- CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, :list0 => '<list_code>').query_view!
72
- end
73
-
74
- it "does not update a view when the lib function hasn't changed" do
75
- allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}, 'lib' => {'test' => '<lib_code>'}}})
76
-
77
- expect(db).not_to receive(:save_doc)
78
-
79
- CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}, nil, {'test' => "<lib_code>"}).query_view!
64
+ CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '<map_code>', :reduce => '<reduce_code>'}}).query_view!
80
65
  end
81
66
 
82
67
  it 'updates a view when the map function has changed' do
@@ -91,88 +76,9 @@ describe CouchPotato::View::ViewQuery, 'query_view!' do
91
76
  CouchPotato::View::ViewQuery.new(db, 'design', :view3 => {:map => '<new map_code>'}).query_view!
92
77
  end
93
78
 
94
- it 'updates a view when the lib hash has changed' do
95
- allow(db).to receive(:get).and_return({'views' => {'view4' => {'map' => '<map_code>'}}}, 'lib' => {'test' => "<test_lib>"})
96
-
97
- expect(db).to receive(:save_doc)
98
-
99
- CouchPotato::View::ViewQuery.new(db, 'design', {:view4 => {:map => '<map_code>'}}, nil, {:test => "<test_lib>"}).query_view!
100
- end
101
-
102
- it "doesn't override libs with different names" do
103
- allow(db).to receive(:get).and_return({'views' => {'view5' => {'map' => '<map_code>'}, 'lib' => {'test' => "<test_lib>"}}})
104
- expect(db).to receive(:save_doc).with({
105
- 'views' => {
106
- 'view5' => {'map' => '<map_code>'},
107
- 'lib' => {'test' => '<test_lib>', 'test1' => '<test1_lib>'}
108
- }
109
- })
110
- CouchPotato::View::ViewQuery.new(db, 'design', {:view5 => {:map => '<map_code>'}}, nil, {'test1' => '<test1_lib>'}).query_view!
111
- end
112
-
113
- it 'overrides libs with the same name' do
114
- allow(db).to receive(:get).and_return({'views' => {'view6' => {'map' => '<map_code>'}, 'lib' => {'test' => "<test_lib>"}}})
115
-
116
- expect(db).to receive(:save_doc).with({
117
- 'views' => {
118
- 'view6' => {'map' => '<map_code>'},
119
- 'lib' => {'test' => '<test1_lib>'}
120
- },
121
- })
122
-
123
- CouchPotato::View::ViewQuery.new(db, 'design', {:view6 => {:map => '<map_code>'}}, nil, {'test' => '<test1_lib>'}).query_view!
124
- end
125
-
126
- it 'does not pass in reduce or lib keys if there is no lib or reduce object' do
127
- allow(db).to receive(:get).and_return({'views' => {}})
128
- expect(db).to receive(:save_doc).with({'views' => {'view7' => {'map' => '<map code>'}}})
129
- CouchPotato::View::ViewQuery.new(db, 'design', :view7 => {:map => '<map code>', :reduce => nil}).query_view!
130
- end
131
-
132
79
  it 'updates a view when the reduce function has changed' do
133
80
  allow(db).to receive(:get).and_return({'views' => {'view8' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}}})
134
81
  expect(db).to receive(:save_doc)
135
82
  CouchPotato::View::ViewQuery.new(db, 'design', :view8 => {:map => '<map_code>', :reduce => '<new reduce_code>'}).query_view!
136
83
  end
137
-
138
- it 'updates a view when the list function has changed' do
139
- allow(db).to receive(:get).and_return({
140
- 'views' => {'view9' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
141
- 'lists' => {'list1' => '<list_code>'}
142
- })
143
- expect(db).to receive(:save_doc)
144
- CouchPotato::View::ViewQuery.new(db, 'design', {:view9 => {:map => '<map_code>', :reduce => '<reduce_code>'}}, :list1 => '<new_list_code>').query_view!
145
- end
146
-
147
- it "updates a view when there wasn't a list function but now there is one" do
148
- allow(db).to receive(:get).and_return({
149
- 'views' => {'view10' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}}
150
- })
151
- expect(db).to receive(:save_doc)
152
- CouchPotato::View::ViewQuery.new(db, 'design', {:view10 => {:map => '<map_code>', :reduce => '<reduce_code>'}}, :list1 => '<new_list_code>').query_view!
153
- end
154
-
155
- it "does not update a view when there is a list function but no list function is passed" do
156
- allow(db).to receive(:get).and_return({
157
- 'views' => {'view11' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}},
158
- 'lists' => {'list1' => '<list_code>'}
159
- })
160
- expect(db).not_to receive(:save_doc)
161
- CouchPotato::View::ViewQuery.new(db, 'design', {:view11 => {:map => '<map_code>', :reduce => '<reduce_code>'}}, {}).query_view!
162
- end
163
-
164
- it "does not update a view when there were no lists before and no list function is passed" do
165
- allow(db).to receive(:get).and_return({
166
- 'views' => {'view12' => {'map' => '<map_code>', 'reduce' => '<reduce_code>'}}
167
- })
168
- expect(db).not_to receive(:save_doc)
169
- CouchPotato::View::ViewQuery.new(db, 'design', {:view12 => {:map => '<map_code>', :reduce => '<reduce_code>'}}, {}).query_view!
170
- end
171
-
172
- it "queries the database directly when querying a list" do
173
- allow(db).to receive(:name){'my_database'}
174
-
175
- expect(db.connection).to receive(:get).with('/my_database/_design/my_design/_list/list1/view13?key=1')
176
- CouchPotato::View::ViewQuery.new(db, 'my_design', {:view13 => {:map => '<map_code>', :reduce => '<reduce_code>'}}, :list1 => '<new_list_code>').query_view!(:key => 1)
177
- end
178
84
  end
@@ -7,8 +7,27 @@ describe "automatic view updates" do
7
7
  end
8
8
 
9
9
  it "should update a view that doesn't match the given functions" do
10
- CouchPotato::View::ViewQuery.new(@db, 'test_design1', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view! # create view
11
- CouchPotato::View::ViewQuery.new(@db, 'test_design1', {'test_view' => {:map => 'function(doc) {emit(doc.id, null)}', :reduce => 'function(key, values) {return sum(values)}'}}, nil).query_view!
10
+ CouchPotato::View::ViewQuery.new(
11
+ @db,
12
+ 'test_design1', {
13
+ 'test_view' => {
14
+ :map => 'function(doc) { }',
15
+ :reduce => 'function(key, values) { return []; }'
16
+ }
17
+ }
18
+ ).query_view! # create view
19
+ CouchPotato::View::ViewQuery.clear_cache
20
+ CouchPotato::View::ViewQuery.new(
21
+ @db,
22
+ 'test_design1',
23
+ {
24
+ 'test_view' => {
25
+ :map => 'function(doc) {emit(doc.id, null)}',
26
+ :reduce => 'function(key, values) {return sum(values)}'
27
+ }
28
+ }
29
+ ).query_view!
30
+
12
31
  expect(CouchPotato.database.load('_design/test_design1')['views']['test_view']).to eq({
13
32
  'map' => 'function(doc) {emit(doc.id, null)}',
14
33
  'reduce' => 'function(key, values) {return sum(values)}'
@@ -16,9 +35,38 @@ describe "automatic view updates" do
16
35
  end
17
36
 
18
37
  it "should only update a view once to avoid writing the view for every request" do
19
- CouchPotato::View::ViewQuery.new(@db, 'test_design2', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view! # create view
20
- CouchPotato::View::ViewQuery.new(@db, 'test_design2', {'test_view' => {:map => 'function(doc) {emit(doc.id, null)}', :reduce => 'function(key, values) {return sum(values)}'}}, nil).query_view!
21
- CouchPotato::View::ViewQuery.new(@db, 'test_design2', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view!
38
+ CouchPotato::View::ViewQuery.new(
39
+ @db,
40
+ 'test_design2',
41
+ {
42
+ 'test_view' => {
43
+ :map => 'function(doc) {}',
44
+ :reduce => 'function() {}'
45
+ }
46
+ }
47
+ ).query_view! # create view
48
+ CouchPotato::View::ViewQuery.clear_cache
49
+ CouchPotato::View::ViewQuery.new(
50
+ @db,
51
+ 'test_design2',
52
+ {
53
+ 'test_view' => {
54
+ :map => 'function(doc) {emit(doc.id, null)}',
55
+ :reduce => 'function(key, values) {return sum(values)}'
56
+ }
57
+ }
58
+ ).query_view!
59
+ CouchPotato::View::ViewQuery.new(
60
+ @db,
61
+ 'test_design2',
62
+ {
63
+ 'test_view' => {
64
+ :map => 'function(doc) {}',
65
+ :reduce => 'function() {}'
66
+ }
67
+ }
68
+ ).query_view!
69
+
22
70
  expect(CouchPotato.database.load('_design/test_design2')['views']['test_view']).to eq({
23
71
  'map' => 'function(doc) {emit(doc.id, null)}',
24
72
  'reduce' => 'function(key, values) {return sum(values)}'
data/spec/views_spec.rb CHANGED
@@ -225,7 +225,7 @@ describe 'views' do
225
225
 
226
226
  describe 'with array as key' do
227
227
  it 'should create a map function with the composite key' do
228
- expect(CouchPotato::View::ViewQuery).to receive(:new) do |_db, _design_name, view, _list|
228
+ expect(CouchPotato::View::ViewQuery).to receive(:new) do |_db, _design_name, view|
229
229
  expect(view['key_array_timeline'][:map]).to match(/emit\(\[doc\['time'\], doc\['state'\]\]/)
230
230
 
231
231
  double('view query', query_view!: { 'rows' => [] })
@@ -362,39 +362,6 @@ describe 'views' do
362
362
  end
363
363
  end
364
364
 
365
- describe 'list functions' do
366
- class Coworker
367
- include CouchPotato::Persistence
368
-
369
- property :name
370
-
371
- view :all_with_list, key: :name, list: :append_doe
372
- view :all, key: :name
373
-
374
- list :append_doe, <<-JS
375
- function(head, req) {
376
- var row;
377
- send('{"rows": [');
378
- while(row = getRow()) {
379
- row.doc.name = row.doc.name + ' doe';
380
- send(JSON.stringify(row));
381
- };
382
- send(']}');
383
- }
384
- JS
385
- end
386
-
387
- it 'should use the list function declared at class level' do
388
- @db.save! Coworker.new(name: 'joe')
389
- expect(@db.view(Coworker.all_with_list).first.name).to eq('joe doe')
390
- end
391
-
392
- it 'should use the list function passed at runtime' do
393
- @db.save! Coworker.new(name: 'joe')
394
- expect(@db.view(Coworker.all(list: :append_doe)).first.name).to eq('joe doe')
395
- end
396
- end
397
-
398
365
  describe 'with stale views' do
399
366
  it 'does not return deleted documents' do
400
367
  build = Build.new
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couch_potato
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.18.0
4
+ version: 1.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Lang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-15 00:00:00.000000000 Z
11
+ date: 2025-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -159,7 +159,6 @@ files:
159
159
  - lib/couch_potato/view/custom_view_spec.rb
160
160
  - lib/couch_potato/view/custom_views.rb
161
161
  - lib/couch_potato/view/flex_view_spec.rb
162
- - lib/couch_potato/view/lists.rb
163
162
  - lib/couch_potato/view/model_view_spec.rb
164
163
  - lib/couch_potato/view/properties_view_spec.rb
165
164
  - lib/couch_potato/view/raw_view_spec.rb
@@ -179,6 +178,7 @@ files:
179
178
  - spec/railtie_spec.rb
180
179
  - spec/reload_spec.rb
181
180
  - spec/revisions_spec.rb
181
+ - spec/single_design_document_spec.rb
182
182
  - spec/spec.opts
183
183
  - spec/spec_helper.rb
184
184
  - spec/unit/active_model_compliance_spec.rb
@@ -197,7 +197,6 @@ files:
197
197
  - spec/unit/forbidden_attributes_protection_spec.rb
198
198
  - spec/unit/initialize_spec.rb
199
199
  - spec/unit/json_spec.rb
200
- - spec/unit/lists_spec.rb
201
200
  - spec/unit/model_view_spec_spec.rb
202
201
  - spec/unit/persistence_spec.rb
203
202
  - spec/unit/properties_view_spec_spec.rb
@@ -248,6 +247,7 @@ test_files:
248
247
  - spec/railtie_spec.rb
249
248
  - spec/reload_spec.rb
250
249
  - spec/revisions_spec.rb
250
+ - spec/single_design_document_spec.rb
251
251
  - spec/spec.opts
252
252
  - spec/spec_helper.rb
253
253
  - spec/unit/active_model_compliance_spec.rb
@@ -266,7 +266,6 @@ test_files:
266
266
  - spec/unit/forbidden_attributes_protection_spec.rb
267
267
  - spec/unit/initialize_spec.rb
268
268
  - spec/unit/json_spec.rb
269
- - spec/unit/lists_spec.rb
270
269
  - spec/unit/model_view_spec_spec.rb
271
270
  - spec/unit/persistence_spec.rb
272
271
  - spec/unit/properties_view_spec_spec.rb
@@ -1,23 +0,0 @@
1
- module CouchPotato
2
- module View
3
- module Lists
4
- def self.included(base)
5
- base.send :extend, ClassMethods
6
- end
7
-
8
- module ClassMethods
9
- def list(name, function)
10
- lists[name] = function
11
- end
12
-
13
- def lists(name = nil)
14
- if name.nil?
15
- @lists ||= {}
16
- else
17
- (@lists && @lists[name]) || (superclass.lists(name) if superclass.respond_to?(:lists))
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe CouchPotato::View::Lists, '.list' do
4
- it 'should make the list function available via .lists' do
5
- clazz = Class.new
6
- clazz.send :include, CouchPotato::View::Lists
7
- clazz.list 'my_list', '<list_code>'
8
-
9
- expect(clazz.lists('my_list')).to eq('<list_code>')
10
- end
11
-
12
- it 'should make the list available to subclasses' do
13
- clazz = Class.new
14
- clazz.send :include, CouchPotato::View::Lists
15
- clazz.list 'my_list', '<list_code>'
16
- sub_clazz = Class.new clazz
17
-
18
- expect(sub_clazz.lists('my_list')).to eq('<list_code>')
19
- end
20
- end