From edc4d28424a4ee99da98d00f8523285301879c29 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 13:56:19 +0200 Subject: [PATCH 01/26] remove lists --- lib/couch_potato/database.rb | 1 - lib/couch_potato/rspec/matchers.rb | 5 - .../rspec/matchers/list_as_matcher.rb | 54 -------- lib/couch_potato/view/base_view_spec.rb | 15 +-- lib/couch_potato/view/flex_view_spec.rb | 2 +- lib/couch_potato/view/lists.rb | 23 ---- lib/couch_potato/view/view_query.rb | 21 +-- spec/unit/base_view_spec_spec.rb | 124 ++++++++---------- spec/unit/database_spec.rb | 19 +-- spec/unit/lists_spec.rb | 20 --- spec/unit/rspec_matchers_spec.rb | 32 ----- spec/unit/view_query_spec.rb | 64 ++------- spec/views_spec.rb | 35 +---- 13 files changed, 80 insertions(+), 335 deletions(-) delete mode 100644 lib/couch_potato/rspec/matchers/list_as_matcher.rb delete mode 100644 lib/couch_potato/view/lists.rb delete mode 100644 spec/unit/lists_spec.rb diff --git a/lib/couch_potato/database.rb b/lib/couch_potato/database.rb index f0a880d9..6cab5c00 100644 --- a/lib/couch_potato/database.rb +++ b/lib/couch_potato/database.rb @@ -273,7 +273,6 @@ def raw_view(spec) map: spec.map_function, reduce: spec.reduce_function } }, - ({ spec.list_name => spec.list_function } unless spec.list_name.nil?), spec.lib, spec.language ).query_view!(spec.view_parameters) diff --git a/lib/couch_potato/rspec/matchers.rb b/lib/couch_potato/rspec/matchers.rb index 1d900cd7..5dd65aa2 100644 --- a/lib/couch_potato/rspec/matchers.rb +++ b/lib/couch_potato/rspec/matchers.rb @@ -3,7 +3,6 @@ require 'couch_potato/rspec/matchers/map_to_matcher' require 'couch_potato/rspec/matchers/reduce_to_matcher' require 'couch_potato/rspec/matchers/map_reduce_to_matcher' -require 'couch_potato/rspec/matchers/list_as_matcher' module RSpec module Matchers @@ -19,10 +18,6 @@ def rereduce(keys, values) CouchPotato::RSpec::ReduceToProxy.new(keys, values, true) end - def list(results) - CouchPotato::RSpec::ListAsProxy.new(results) - end - def map_reduce(*docs) CouchPotato::RSpec::MapReduceToProxy.new(docs) end diff --git a/lib/couch_potato/rspec/matchers/list_as_matcher.rb b/lib/couch_potato/rspec/matchers/list_as_matcher.rb deleted file mode 100644 index 089fa0c0..00000000 --- a/lib/couch_potato/rspec/matchers/list_as_matcher.rb +++ /dev/null @@ -1,54 +0,0 @@ -module CouchPotato - module RSpec - class ListAsProxy - def initialize(results_ruby) - @results_ruby = results_ruby - end - - def as(expected_ruby) - ListAsMatcher.new(expected_ruby, @results_ruby) - end - end - - class ListAsMatcher - include ::RSpec::Matchers::Composable - - def initialize(expected_ruby, results_ruby) - @expected_ruby = expected_ruby - @results_ruby = results_ruby - end - - def matches?(view_spec) - js = <<-JS - (function() { - var results = #{@results_ruby.to_json}; - var listed = ''; - var list = #{view_spec.list_function}; - - var getRow = function() { - return results.rows.shift(); - }; - var send = function(text) { - listed = listed + text; - }; - list(); - return JSON.stringify(JSON.parse(listed)); - })() - - JS - @actual_ruby = JSON.parse(ExecJS.eval(js)) - - values_match? @expected_ruby, @actual_ruby - end - - def failure_message - "Expected to list as #{@expected_ruby.inspect} but got #{@actual_ruby.inspect}." - end - - def failure_message_when_negated - "Expected to not list as #{@expected_ruby.inspect} but did." - end - - end - end -end diff --git a/lib/couch_potato/view/base_view_spec.rb b/lib/couch_potato/view/base_view_spec.rb index 9ed55ac2..31cc3326 100644 --- a/lib/couch_potato/view/base_view_spec.rb +++ b/lib/couch_potato/view/base_view_spec.rb @@ -3,7 +3,7 @@ module CouchPotato module View class BaseViewSpec - attr_reader :reduce_function, :lib, :list_name, :list_function, :design_document, :view_name, :klass, :options, :language + attr_reader :reduce_function, :lib, :design_document, :view_name, :klass, :options, :language attr_accessor :view_parameters private :klass, :options @@ -11,7 +11,7 @@ class BaseViewSpec def initialize(klass, view_name, options, view_parameters) normalized_view_parameters = ViewParameters.normalize_view_parameters view_parameters - @list_name = normalized_view_parameters.delete(:list) || options[:list] + @language = options[:language] || Config.default_language assert_valid_view_parameters normalized_view_parameters @@ -19,16 +19,12 @@ def initialize(klass, view_name, options, view_parameters) @options = options @view_name = compute_view_name(view_name, options.key?(:digest_view_name) ? options[:digest_view_name] : Config.digest_view_names) - @design_document = translate_to_design_doc_name(klass.to_s, @view_name, @list_name) - @list_params = normalized_view_parameters.delete :list_params - - @list_function = klass.lists(@list_name) if @list_name + @design_document = translate_to_design_doc_name(klass.to_s, @view_name) @view_parameters = {} %i[group include_docs descending group_level limit].each do |key| @view_parameters[key] = options[key] if options.include?(key) end @view_parameters.merge!(normalized_view_parameters) - @view_parameters.merge!(@list_params) if @list_params end def process_results(results) @@ -56,10 +52,10 @@ def assert_valid_view_parameters(params) end def valid_view_parameters - %w[list_params key keys startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end] + %w[key keys startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end] end - def translate_to_design_doc_name(klass_name, view_name, list_name) + def translate_to_design_doc_name(klass_name, view_name) klass_name = klass_name.dup klass_name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') klass_name.gsub!(/([a-z\d])([A-Z])/, '\1_\2') @@ -68,7 +64,6 @@ def translate_to_design_doc_name(klass_name, view_name, list_name) if CouchPotato::Config.split_design_documents_per_view doc_name += "_view_#{view_name}" if view_name.present? - doc_name += "_list_#{list_name}" if list_name.present? end doc_name end diff --git a/lib/couch_potato/view/flex_view_spec.rb b/lib/couch_potato/view/flex_view_spec.rb index bb49b236..5484b67b 100644 --- a/lib/couch_potato/view/flex_view_spec.rb +++ b/lib/couch_potato/view/flex_view_spec.rb @@ -96,7 +96,7 @@ def initialize(klass, view_name, options, view_parameters) end delegate :view_name, :view_parameters, :design_document, :map_function, - :reduce_function, :list_name, :lib, :language, to: :view_spec_delegate + :reduce_function, :lib, :language, to: :view_spec_delegate def process_results(results) results = Results.new(results) diff --git a/lib/couch_potato/view/lists.rb b/lib/couch_potato/view/lists.rb deleted file mode 100644 index d0e0ce5c..00000000 --- a/lib/couch_potato/view/lists.rb +++ /dev/null @@ -1,23 +0,0 @@ -module CouchPotato - module View - module Lists - def self.included(base) - base.send :extend, ClassMethods - end - - module ClassMethods - def list(name, function) - lists[name] = function - end - - def lists(name = nil) - if name.nil? - @lists ||= {} - else - (@lists && @lists[name]) || (superclass.lists(name) if superclass.respond_to?(:lists)) - end - end - end - end - end -end \ No newline at end of file diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 473d86a5..02bf5199 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -2,7 +2,7 @@ module CouchPotato module View # 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. class ViewQuery - def initialize(couchrest_database, design_document_name, view, list = nil, lib = nil, language = :javascript) + def initialize(couchrest_database, design_document_name, view, lib = nil, language = :javascript) @database = couchrest_database @design_document_name = design_document_name @view_name = view.keys[0] @@ -10,10 +10,6 @@ def initialize(couchrest_database, design_document_name, view, list = nil, lib = @reduce_function = view.values[0][:reduce] @lib = lib @language = language - if list - @list_function = list.values[0] - @list_name = list.keys[0] - end end def query_view!(parameters = {}) @@ -42,18 +38,13 @@ def self.__updated_views def update_view design_doc = @database.get "_design/#{@design_document_name}" rescue nil original_views = design_doc && design_doc['views'].dup - original_lists = design_doc && design_doc['lists'] && design_doc['lists'].dup view_updated unless design_doc.nil? design_doc ||= empty_design_document design_doc['views'][@view_name.to_s] = view_functions if @lib design_doc['views']['lib'] = (design_doc['views']['lib'] || {}).merge(@lib) end - if @list_function - design_doc['lists'] ||= {} - design_doc['lists'][@list_name.to_s] = @list_function - end - @database.save_doc(design_doc) if original_views != design_doc['views'] || original_lists != design_doc['lists'] + @database.save_doc(design_doc) if original_views != design_doc['views'] end def view_functions @@ -65,7 +56,7 @@ def view_functions end def empty_design_document - {'views' => {}, 'lists' => {}, "_id" => "_design/#{@design_document_name}", "language" => @language.to_s} + {'views' => {}, "_id" => "_design/#{@design_document_name}", "language" => @language.to_s} end def view_has_been_updated? @@ -81,11 +72,7 @@ def updated_views end def query_view(parameters) - if @list_name - @database.connection.get CouchRest.paramify_url("/#{@database.name}/_design/#{@design_document_name}/_list/#{@list_name}/#{@view_name}", parameters) - else - @database.view view_url, parameters - end + @database.view view_url, parameters end def view_url diff --git a/spec/unit/base_view_spec_spec.rb b/spec/unit/base_view_spec_spec.rb index 078dc105..780e769a 100644 --- a/spec/unit/base_view_spec_spec.rb +++ b/spec/unit/base_view_spec_spec.rb @@ -33,8 +33,7 @@ :group_level => 1, :reduce => false, :include_docs => true, - :inclusive_end => true, - :list_params => {} + :inclusive_end => true } }.not_to raise_error end @@ -54,70 +53,62 @@ expect(spec.view_parameters).to eq({:key => '2'}) end - it 'merges the list params' do - spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, key: '2', list_params: {:x => 'y'} - expect(spec.view_parameters).to eq({:key => '2', :x => 'y'}) - end - - it "generates the design document path by snake_casing the class name but keeping double colons" do - spec = CouchPotato::View::BaseViewSpec.new 'Foo::BarBaz', '', {}, '' - expect(spec.design_document).to eq('foo::bar_baz') - end - - it "generates the design document independent of the view name by default" do - CouchPotato::Config.split_design_documents_per_view = false - spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' - expect(spec.design_document).to eq('user') - end - - it "generates the design document per view if configured to" do - CouchPotato::Config.split_design_documents_per_view = true - spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' - expect(spec.design_document).to eq('user_view_by_login_and_email') - end - - it 'adds the view name digest to the design doc name' do - CouchPotato::Config.split_design_documents_per_view = true - spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email', - {digest_view_name: true, map: 'function(doc) {}'}, '' - - expect(spec.design_document).to eq('user_view_by_login_and_email-375c815fcb4f977f330a2edfadc7f74d') - end - - it 'builds the name digest by hashing the map and reduce function if there is one' do - CouchPotato::Config.split_design_documents_per_view = true - spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email', - {digest_view_name: true, map: 'function(doc) {}', reduce: 'function(key, values) {}'}, '' - - expect(spec.design_document).to eq('user_view_by_login_and_email-c9f83cec3dab954a8ca56330006f187e') - end - - - it "generates the design document independent of the list name by default" do - CouchPotato::Config.split_design_documents_per_view = false - spec = CouchPotato::View::BaseViewSpec.new double(lists: nil, :to_s => 'User'), '', {list: 'test_list'}, {} - expect(spec.design_document).to eq('user') - end - - it "generates the design document per view if configured to" do - CouchPotato::Config.split_design_documents_per_view = true - spec = CouchPotato::View::BaseViewSpec.new double(lists: nil, :to_s => 'User'), '', {list: :test_list}, {} - expect(spec.design_document).to eq('user_list_test_list') - end - - it "extracts the list name from the options" do - spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {list: :test_list}, {} - expect(spec.list_name).to eq(:test_list) + context 'when single design document is enabled' do + before(:each) do + CouchPotato::Config.single_design_document = true + end + + end - it "extracts the list from the view parameters" do - spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {}, {list: :test_list} - expect(spec.list_name).to eq(:test_list) - end + context 'when single design document is disabled' do + before(:each) do + CouchPotato::Config.single_design_document = false + end + + context 'and split design documents per view is enabled' do + before(:each) do + CouchPotato::Config.split_design_documents_per_view = true + end + + it "generates one design document per view" do + spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' + expect(spec.design_document).to eq('user_view_by_login_and_email') + end + + it 'adds the view name digest to the design doc name' do + spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email', + {digest_view_name: true, map: 'function(doc) {}'}, '' + + expect(spec.design_document).to eq('user_view_by_login_and_email-375c815fcb4f977f330a2edfadc7f74d') + end + + it 'builds the name digest by hashing the map and reduce function if there is one' do + spec = CouchPotato::View::RawViewSpec.new 'User', 'by_login_and_email', + {digest_view_name: true, map: 'function(doc) {}', reduce: 'function(key, values) {}'}, '' + + expect(spec.design_document).to eq('user_view_by_login_and_email-c9f83cec3dab954a8ca56330006f187e') + end + + + end - it "prefers the list name from the view parameters over the one from the options" do - spec = CouchPotato::View::BaseViewSpec.new double(lists: nil), 'all', {list: 'my_list'}, list: :test_list - expect(spec.list_name).to eq(:test_list) + context 'and split design documents per view is disabled' do + before(:each) do + CouchPotato::Config.split_design_documents_per_view = false + end + + it "generates the design document path by snake_casing the class name but keeping double colons" do + spec = CouchPotato::View::BaseViewSpec.new 'Foo::BarBaz', '', {}, '' + expect(spec.design_document).to eq('foo::bar_baz') + end + + it "generates the design document independent of the view name" do + spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' + expect(spec.design_document).to eq('user') + end + end + end it 'returns the view name' do @@ -146,13 +137,6 @@ end end - it "returns the list function" do - klass = double 'class' - allow(klass).to receive(:lists).with('test_list').and_return('') - spec = CouchPotato::View::BaseViewSpec.new klass, 'all', {list: 'test_list'}, {} - expect(spec.list_function).to eq('') - end - it 'reads the language from the couch potato config by default' do CouchPotato::Config.default_language = :ruby spec = CouchPotato::View::BaseViewSpec.new Object, 'all', {}, {} diff --git a/spec/unit/database_spec.rb b/spec/unit/database_spec.rb index 9fdc8d29..476ee690 100644 --- a/spec/unit/database_spec.rb +++ b/spec/unit/database_spec.rb @@ -415,11 +415,10 @@ def set_errors allow(CouchPotato::View::ViewQuery).to receive_messages(new: double('view query', query_view!: { 'rows' => [@result] })) end - it 'initializes a view query with map/reduce/list/lib funtions' do + it 'initializes a view query with map/reduce/lib funtions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', - lib: { test: '' }, - list_name: 'my_list', list_function: '', language: 'javascript') + lib: { test: '' }, language: 'javascript') expect(CouchPotato::View::ViewQuery).to receive(:new).with( @couchrest_db, 'design_doc', @@ -427,17 +426,16 @@ def set_errors map: '', reduce: '' } }, - { 'my_list' => '' }, { test: '' }, 'javascript' ) @db.view(@spec) end - it 'initializes a view query with map/reduce/list funtions' do + it 'initializes a view query with map/reduce funtions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', - lib: nil, list_name: 'my_list', list_function: '', + lib: nil, language: 'javascript') expect(CouchPotato::View::ViewQuery).to receive(:new).with( @couchrest_db, @@ -446,7 +444,6 @@ def set_errors map: '', reduce: '' } }, - { 'my_list' => '' }, nil, 'javascript' ) @@ -456,7 +453,6 @@ def set_errors it 'initializes a view query with only map/reduce/lib functions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', - list_name: nil, list_function: nil, lib: { test: '' }) expect(CouchPotato::View::ViewQuery).to receive(:new).with( @couchrest_db, @@ -464,22 +460,21 @@ def set_errors { 'my_view' => { map: '', reduce: '' - } }, nil, { test: '' }, anything + } }, { test: '' }, anything ) @db.view(@spec) end it 'initializes a view query with only map/reduce functions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', - map_function: '', reduce_function: '', - lib: nil, list_name: nil, list_function: nil) + map_function: '', reduce_function: '') expect(CouchPotato::View::ViewQuery).to receive(:new).with( @couchrest_db, 'design_doc', { 'my_view' => { map: '', reduce: '' - } }, nil, nil, anything + } }, anything, anything ) @db.view(@spec) end diff --git a/spec/unit/lists_spec.rb b/spec/unit/lists_spec.rb deleted file mode 100644 index acce637c..00000000 --- a/spec/unit/lists_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'spec_helper' - -describe CouchPotato::View::Lists, '.list' do - it 'should make the list function available via .lists' do - clazz = Class.new - clazz.send :include, CouchPotato::View::Lists - clazz.list 'my_list', '' - - expect(clazz.lists('my_list')).to eq('') - end - - it 'should make the list available to subclasses' do - clazz = Class.new - clazz.send :include, CouchPotato::View::Lists - clazz.list 'my_list', '' - sub_clazz = Class.new clazz - - expect(sub_clazz.lists('my_list')).to eq('') - end -end diff --git a/spec/unit/rspec_matchers_spec.rb b/spec/unit/rspec_matchers_spec.rb index 9082f873..490afeb3 100644 --- a/spec/unit/rspec_matchers_spec.rb +++ b/spec/unit/rspec_matchers_spec.rb @@ -283,35 +283,3 @@ end end -describe CouchPotato::RSpec::ListAsMatcher do - before(:each) do - @view_spec = double(:list_function => "function() {var row = getRow(); send(JSON.stringify([{text: row.text + ' world'}]));}") - end - - it "should pass if the function return the expected json" do - expect(@view_spec).to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello world'}]) - end - - it "should not pass if the function does not return the expected json" do - expect(@view_spec).not_to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello there'}]) - end - - it "should work with date values" do - spec = double(:list_function => "function() { send(JSON.stringify([{date: new Date(1368802800000)}])); }") - expect(spec).to list({"rows" => [{}]}).as([{"date" => "2013-05-17T15:00:00.000Z"}]) - end - - describe "failing specs" do - it "should have a nice error message for failing should" do - expect { - expect(@view_spec).to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello there'}]) - }.to raise_error('Expected to list as [{"text"=>"hello there"}] but got [{"text"=>"hello world"}].') - end - - it "should have a nice error message for failing should not" do - expect { - expect(@view_spec).not_to list({'rows' => [{:text => 'hello'}]}).as([{'text' => 'hello world'}]) - }.to raise_error('Expected to not list as [{"text"=>"hello world"}] but did.') - end - end -end diff --git a/spec/unit/view_query_spec.rb b/spec/unit/view_query_spec.rb index f4cee60b..a71f952c 100644 --- a/spec/unit/view_query_spec.rb +++ b/spec/unit/view_query_spec.rb @@ -17,13 +17,12 @@ expect(db).to receive(:save_doc).with( { 'views' => {'view' => {'map' => '', 'reduce' => ''}, 'lib' => {'test' => ''}}, - 'lists' => {}, "_id" => "_design/design", "language" => "javascript" } ) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, nil, {'test' => ""}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, {'test' => ""}).query_view! end it 'only updates a view once' do @@ -50,25 +49,19 @@ expect(db).to receive(:save_doc).with( { 'views' => {'view' => {'map' => '', 'reduce' => ''}}, - 'lists' => {}, "_id" => "_design/design", "language" => "erlang" + "_id" => "_design/design", "language" => "erlang" } ) CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, - nil, nil, :erlang).query_view! + nil, :erlang).query_view! end it "does not update a view when the views object haven't changed" do allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '', 'reduce' => ''}}}) expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, nil, nil).query_view! - end - - it "does not update a view when the list function hasn't changed" do - allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '', 'reduce' => ''}}, 'lists' => {'list0' => ''}}) - expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, :list0 => '').query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, nil).query_view! end it "does not update a view when the lib function hasn't changed" do @@ -76,7 +69,7 @@ expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, nil, {'test' => ""}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, {'test' => ""}).query_view! end it 'updates a view when the map function has changed' do @@ -96,7 +89,7 @@ expect(db).to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view4 => {:map => ''}}, nil, {:test => ""}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view4 => {:map => ''}}, {:test => ""}).query_view! end it "doesn't override libs with different names" do @@ -107,7 +100,7 @@ 'lib' => {'test' => '', 'test1' => ''} } }) - CouchPotato::View::ViewQuery.new(db, 'design', {:view5 => {:map => ''}}, nil, {'test1' => ''}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view5 => {:map => ''}}, {'test1' => ''}).query_view! end it 'overrides libs with the same name' do @@ -120,7 +113,7 @@ }, }) - CouchPotato::View::ViewQuery.new(db, 'design', {:view6 => {:map => ''}}, nil, {'test' => ''}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view6 => {:map => ''}}, {'test' => ''}).query_view! end it 'does not pass in reduce or lib keys if there is no lib or reduce object' do @@ -134,45 +127,4 @@ expect(db).to receive(:save_doc) CouchPotato::View::ViewQuery.new(db, 'design', :view8 => {:map => '', :reduce => ''}).query_view! end - - it 'updates a view when the list function has changed' do - allow(db).to receive(:get).and_return({ - 'views' => {'view9' => {'map' => '', 'reduce' => ''}}, - 'lists' => {'list1' => ''} - }) - expect(db).to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view9 => {:map => '', :reduce => ''}}, :list1 => '').query_view! - end - - it "updates a view when there wasn't a list function but now there is one" do - allow(db).to receive(:get).and_return({ - 'views' => {'view10' => {'map' => '', 'reduce' => ''}} - }) - expect(db).to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view10 => {:map => '', :reduce => ''}}, :list1 => '').query_view! - end - - it "does not update a view when there is a list function but no list function is passed" do - allow(db).to receive(:get).and_return({ - 'views' => {'view11' => {'map' => '', 'reduce' => ''}}, - 'lists' => {'list1' => ''} - }) - expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view11 => {:map => '', :reduce => ''}}, {}).query_view! - end - - it "does not update a view when there were no lists before and no list function is passed" do - allow(db).to receive(:get).and_return({ - 'views' => {'view12' => {'map' => '', 'reduce' => ''}} - }) - expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view12 => {:map => '', :reduce => ''}}, {}).query_view! - end - - it "queries the database directly when querying a list" do - allow(db).to receive(:name){'my_database'} - - expect(db.connection).to receive(:get).with('/my_database/_design/my_design/_list/list1/view13?key=1') - CouchPotato::View::ViewQuery.new(db, 'my_design', {:view13 => {:map => '', :reduce => ''}}, :list1 => '').query_view!(:key => 1) - end end diff --git a/spec/views_spec.rb b/spec/views_spec.rb index 29e2fce8..f547d80d 100644 --- a/spec/views_spec.rb +++ b/spec/views_spec.rb @@ -225,7 +225,7 @@ class ErlangBuild describe 'with array as key' do it 'should create a map function with the composite key' do - expect(CouchPotato::View::ViewQuery).to receive(:new) do |_db, _design_name, view, _list| + expect(CouchPotato::View::ViewQuery).to receive(:new) do |_db, _design_name, view| expect(view['key_array_timeline'][:map]).to match(/emit\(\[doc\['time'\], doc\['state'\]\]/) double('view query', query_view!: { 'rows' => [] }) @@ -362,39 +362,6 @@ class ErlangBuild end end - describe 'list functions' do - class Coworker - include CouchPotato::Persistence - - property :name - - view :all_with_list, key: :name, list: :append_doe - view :all, key: :name - - list :append_doe, <<-JS - function(head, req) { - var row; - send('{"rows": ['); - while(row = getRow()) { - row.doc.name = row.doc.name + ' doe'; - send(JSON.stringify(row)); - }; - send(']}'); - } - JS - end - - it 'should use the list function declared at class level' do - @db.save! Coworker.new(name: 'joe') - expect(@db.view(Coworker.all_with_list).first.name).to eq('joe doe') - end - - it 'should use the list function passed at runtime' do - @db.save! Coworker.new(name: 'joe') - expect(@db.view(Coworker.all(list: :append_doe)).first.name).to eq('joe doe') - end - end - describe 'with stale views' do it 'does not return deleted documents' do build = Build.new From 36d0a204ce311d1ad9ee5764e14072e546f1debf Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 13:56:36 +0200 Subject: [PATCH 02/26] add single_design_document config --- CHANGES.md | 5 ++++ README.md | 51 +++++---------------------------- lib/couch_potato.rb | 4 ++- lib/couch_potato/persistence.rb | 4 +-- spec/unit/couch_potato_spec.rb | 2 ++ 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index c5865d55..0e51517f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ ## Changes +# 1.19.0 + +- add `single_design_document` config option +- remove support for lists + # 1.18.0 - add testing Rails 7.2/8 on CI diff --git a/README.md b/README.md index c10e67ac..7738c5d8 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,12 @@ Another switch allows you to store each CouchDB view in its own design document. CouchPotato::Config.split_design_documents_per_view = true ``` +With the following switch, couch potato only creates a single design document for all views: + +```ruby +CouchPotato::Config.single_design_document = true +``` + If you are using more than one database from your app, you can create aliases: ```ruby @@ -299,7 +305,7 @@ user.valid? # => false user.errors[:name] # => ['can't be blank'] ``` -#### Finding stuff / views / lists +#### Finding stuff / views 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: @@ -450,49 +456,6 @@ You can pass in your own view specifications by passing in `:type => MyViewSpecC 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. -##### Lists - -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. - -Defining a list works similarly to views: - -```ruby -class User - include CouchPotato::Persistence - - property :first_name - view :with_full_name, key: first_namne, list: :add_last_name - view :all, key: :first_name - - list :add_last_name, <<-JS - function(head, req) { - var row; - send('{"rows": ['); - while(row = getRow()) { - row.doc.name = row.doc.first_name + ' doe'; - send(JSON.stringify(row)); - }; - send(']}'); - } - JS -end - -CouchPotato.database.save User.new(first_name: 'joe') -CouchPotato.database.view(User.with_full_name).first.name # => 'joe doe' -``` - -You can also pass in the list at query time: - -```ruby -CouchPotato.database.view(User.all(list: :add_last_name)) -``` - -And you can pass parameters to the list: - -```ruby -CouchPotato.database.view(User.all(list: :add_last_name, list_params: {filter: '*'})) -``` - #### Associations Not supported. Not sure if they ever will be. You can implement those yourself using views and custom methods on your models. diff --git a/lib/couch_potato.rb b/lib/couch_potato.rb index 9da59fd7..aef67860 100644 --- a/lib/couch_potato.rb +++ b/lib/couch_potato.rb @@ -9,9 +9,10 @@ CouchRest.decode_json_objects = true module CouchPotato - Config = Struct.new(:database_host, :database_name, :digest_view_names, + Config = Struct.new(:database_host, :database_name, :digest_view_names, :single_design_document, :split_design_documents_per_view, :default_language, :additional_databases).new Config.split_design_documents_per_view = false + Config.single_design_document = false Config.digest_view_names = false Config.default_language = :javascript Config.database_host = 'http://127.0.0.1:5984' @@ -29,6 +30,7 @@ def self.configure(config) Config.database_host = config['database_host'] if config['database_host'] Config.additional_databases = config['additional_databases'].stringify_keys if config['additional_databases'] Config.split_design_documents_per_view = config['split_design_documents_per_view'] if config['split_design_documents_per_view'] + Config.single_design_document = config['single_design_document'] if config['single_design_document'] Config.digest_view_names = config['digest_view_names'] if config['digest_view_names'] Config.default_language = config['default_language'] if config['default_language'] end diff --git a/lib/couch_potato/persistence.rb b/lib/couch_potato/persistence.rb index 9cef8a1b..3beb12c9 100644 --- a/lib/couch_potato/persistence.rb +++ b/lib/couch_potato/persistence.rb @@ -12,7 +12,6 @@ require File.dirname(__FILE__) + '/persistence/revisions' require File.dirname(__FILE__) + '/forbidden_attributes_protection' require File.dirname(__FILE__) + '/view/custom_views' -require File.dirname(__FILE__) + '/view/lists' require File.dirname(__FILE__) + '/view/view_query' @@ -20,8 +19,7 @@ module CouchPotato module Persistence def self.included(base) #:nodoc: - base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews, - CouchPotato::View::Lists + base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews base.send :include, DirtyAttributes, GhostAttributes, Attachments base.send :include, MagicTimestamps, ActiveModelCompliance, ForbiddenAttributesProtection, Revisions diff --git a/spec/unit/couch_potato_spec.rb b/spec/unit/couch_potato_spec.rb index d702cced..e12c7dbb 100644 --- a/spec/unit/couch_potato_spec.rb +++ b/spec/unit/couch_potato_spec.rb @@ -35,12 +35,14 @@ test2: 'test2_db' }, split_design_documents_per_view: true, + single_design_document: true, digest_view_names: true, default_language: 'erlang' ) expect(CouchPotato::Config.database_name).to eq('testdb') expect(CouchPotato::Config.split_design_documents_per_view).to eq(true) + expect(CouchPotato::Config.single_design_document).to eq(true) expect(CouchPotato::Config.digest_view_names).to eq(true) expect(CouchPotato::Config.default_language).to eq('erlang') expect(CouchPotato::Config.database_host).to eq('http://10.0.0.1:2000') From 527050a0bedc74a986b82a517887709be6651a84 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 15:09:37 +0200 Subject: [PATCH 03/26] make single_design_document work --- README.md | 1 + lib/couch_potato.rb | 6 ++++ lib/couch_potato/view/base_view_spec.rb | 20 ++++++++++-- lib/couch_potato/view/custom_views.rb | 1 + lib/couch_potato/view/view_query.rb | 24 ++++++++++++-- spec/single_design_document_spec.rb | 42 +++++++++++++++++++++++++ spec/unit/base_view_spec_spec.rb | 16 ++++++++-- spec/unit/database_spec.rb | 33 ++----------------- 8 files changed, 103 insertions(+), 40 deletions(-) create mode 100644 spec/single_design_document_spec.rb diff --git a/README.md b/README.md index 7738c5d8..d1233351 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ Create a `config/couchdb.yml`: default: &default split_design_documents_per_view: true # optional, default is false digest_view_names: true # optional, default is false + single_design_document: true # optional, default is false default_language: :erlang # optional, default is javascript database_host: "http://127.0.0.1:5984" diff --git a/lib/couch_potato.rb b/lib/couch_potato.rb index aef67860..d25275a0 100644 --- a/lib/couch_potato.rb +++ b/lib/couch_potato.rb @@ -42,6 +42,12 @@ def self.models @models end + # returns all the classes that include the CouchPotato::View::CustomViews module + def self.views + @views ||= [] + @views + end + # 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. def self.database Thread.current[:__couch_potato_database] ||= Database.new(couchrest_database) diff --git a/lib/couch_potato/view/base_view_spec.rb b/lib/couch_potato/view/base_view_spec.rb index 31cc3326..7080baf5 100644 --- a/lib/couch_potato/view/base_view_spec.rb +++ b/lib/couch_potato/view/base_view_spec.rb @@ -19,7 +19,7 @@ def initialize(klass, view_name, options, view_parameters) @options = options @view_name = compute_view_name(view_name, options.key?(:digest_view_name) ? options[:digest_view_name] : Config.digest_view_names) - @design_document = translate_to_design_doc_name(klass.to_s, @view_name) + @design_document = design_doc_name @view_parameters = {} %i[group include_docs descending group_level limit].each do |key| @view_parameters[key] = options[key] if options.include?(key) @@ -38,10 +38,16 @@ def process_results(results) private def compute_view_name(view_name, digest) + name = if CouchPotato::Config.single_design_document + "#{translate_to_design_doc_name(klass.to_s, view_name)}-#{view_name}" + else + view_name + end + if digest - "#{view_name}-#{Digest::MD5.hexdigest(map_function + reduce_function.to_s)}" + "#{name}-#{Digest::MD5.hexdigest(map_function + reduce_function.to_s)}" else - view_name + name end end @@ -55,6 +61,14 @@ def valid_view_parameters %w[key keys startkey startkey_docid endkey endkey_docid limit stale descending skip group group_level reduce include_docs inclusive_end] end + def design_doc_name + if CouchPotato::Config.single_design_document + 'couch_potato' + else + translate_to_design_doc_name(klass.to_s, view_name) + end + end + def translate_to_design_doc_name(klass_name, view_name) klass_name = klass_name.dup klass_name.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') diff --git a/lib/couch_potato/view/custom_views.rb b/lib/couch_potato/view/custom_views.rb index 1b749945..20ff7e47 100644 --- a/lib/couch_potato/view/custom_views.rb +++ b/lib/couch_potato/view/custom_views.rb @@ -12,6 +12,7 @@ module CustomViews def self.included(base) #:nodoc: base.extend ClassMethods + CouchPotato.views << base end module ClassMethods diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 02bf5199..6ac0a92e 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -13,7 +13,7 @@ def initialize(couchrest_database, design_document_name, view, lib = nil, langua end def query_view!(parameters = {}) - update_view unless view_has_been_updated? + update_view if !view_has_been_updated? || CouchPotato::Config.single_design_document begin query_view parameters rescue CouchRest::NotFound @@ -40,11 +40,29 @@ def update_view original_views = design_doc && design_doc['views'].dup view_updated unless design_doc.nil? design_doc ||= empty_design_document - design_doc['views'][@view_name.to_s] = view_functions + if CouchPotato::Config.single_design_document + design_doc['views'] = all_views + else + design_doc['views'][@view_name.to_s] = view_functions + end if @lib design_doc['views']['lib'] = (design_doc['views']['lib'] || {}).merge(@lib) end - @database.save_doc(design_doc) if original_views != design_doc['views'] + if original_views != design_doc['views'] + @database.save_doc(design_doc) + end + end + + def all_views + CouchPotato.views.flat_map do |klass| + specs = klass.views.map { |view_name, view| klass.execute_view(view_name, {}) } + specs.map do |klass_spec| + { klass_spec.view_name => { + 'map' => klass_spec.map_function, + 'reduce' => klass_spec.reduce_function + } } + end + end.inject(&:merge) end def view_functions diff --git a/spec/single_design_document_spec.rb b/spec/single_design_document_spec.rb new file mode 100644 index 00000000..6003b4c3 --- /dev/null +++ b/spec/single_design_document_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe 'single design document' do + let(:db) { CouchPotato.database } + let(:couchrest_db) { db.couchrest_database } + + class Thing1 + include CouchPotato::Persistence + + property :title + + view :all, key: :title + end + + class Thing2 + include CouchPotato::Persistence + + property :name + + view :all, key: :name + end + + before(:each) do + recreate_db + CouchPotato::Config.single_design_document = true + end + + after(:each) do + CouchPotato::Config.single_design_document = false + end + + it 'creates a single design document for all views' do + thing1 = Thing1.new title: 't1' + db.save! thing1 + thing2 = Thing2.new name: 'n2' + db.save! thing2 + + db.view(Thing1.all) # create all views when querying the first one + + expect(couchrest_db.get('_design/couch_potato')['views'].keys).to eq(['thing1-all', 'thing2-all']) + end +end diff --git a/spec/unit/base_view_spec_spec.rb b/spec/unit/base_view_spec_spec.rb index 780e769a..8579c018 100644 --- a/spec/unit/base_view_spec_spec.rb +++ b/spec/unit/base_view_spec_spec.rb @@ -57,8 +57,16 @@ before(:each) do CouchPotato::Config.single_design_document = true end + + after(:each) do + CouchPotato::Config.single_design_document = false + end - + it 'generates one design document for all views' do + spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' + + expect(spec.design_document).to eq('couch_potato') + end end context 'when single design document is disabled' do @@ -70,6 +78,10 @@ before(:each) do CouchPotato::Config.split_design_documents_per_view = true end + + after(:each) do + CouchPotato::Config.split_design_documents_per_view = false + end it "generates one design document per view" do spec = CouchPotato::View::BaseViewSpec.new 'User', 'by_login_and_email', {}, '' @@ -89,8 +101,6 @@ expect(spec.design_document).to eq('user_view_by_login_and_email-c9f83cec3dab954a8ca56330006f187e') end - - end context 'and split design documents per view is disabled' do diff --git a/spec/unit/database_spec.rb b/spec/unit/database_spec.rb index 476ee690..020bb6be 100644 --- a/spec/unit/database_spec.rb +++ b/spec/unit/database_spec.rb @@ -415,7 +415,7 @@ def set_errors allow(CouchPotato::View::ViewQuery).to receive_messages(new: double('view query', query_view!: { 'rows' => [@result] })) end - it 'initializes a view query with map/reduce/lib funtions' do + it 'initializes a view query with map/reduce/lib functions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', lib: { test: '' }, language: 'javascript') @@ -432,7 +432,7 @@ def set_errors @db.view(@spec) end - it 'initializes a view query with map/reduce funtions' do + it 'initializes a view query with map/reduce functions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', lib: nil, @@ -450,35 +450,6 @@ def set_errors @db.view(@spec) end - it 'initializes a view query with only map/reduce/lib functions' do - allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', - map_function: '', reduce_function: '', - lib: { test: '' }) - expect(CouchPotato::View::ViewQuery).to receive(:new).with( - @couchrest_db, - 'design_doc', - { 'my_view' => { - map: '', - reduce: '' - } }, { test: '' }, anything - ) - @db.view(@spec) - end - - it 'initializes a view query with only map/reduce functions' do - allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', - map_function: '', reduce_function: '') - expect(CouchPotato::View::ViewQuery).to receive(:new).with( - @couchrest_db, - 'design_doc', - { 'my_view' => { - map: '', - reduce: '' - } }, anything, anything - ) - @db.view(@spec) - end - it 'sets itself on returned docs that have an accessor' do allow(@result).to receive(:respond_to?).and_return(false) allow(@result).to receive(:respond_to?).with(:database=).and_return(true) From f2c1d842bbe1f8d8d0e469845f1bc6279d438aca Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 15:51:56 +0200 Subject: [PATCH 04/26] remove lib support --- CHANGES.md | 2 +- README.md | 8 --- lib/couch_potato/database.rb | 1 - .../rspec/matchers/map_reduce_to_matcher.rb | 3 +- .../rspec/matchers/map_to_matcher.rb | 3 +- lib/couch_potato/view/base_view_spec.rb | 2 +- lib/couch_potato/view/custom_view_spec.rb | 4 -- lib/couch_potato/view/flex_view_spec.rb | 2 +- lib/couch_potato/view/raw_view_spec.rb | 8 +-- lib/couch_potato/view/view_query.rb | 6 +-- spec/single_design_document_spec.rb | 1 + spec/unit/couch_potato_spec.rb | 1 + spec/unit/database_spec.rb | 18 ------- spec/unit/rspec_matchers_spec.rb | 32 ----------- spec/unit/view_query_spec.rb | 54 ++----------------- 15 files changed, 14 insertions(+), 131 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0e51517f..b1b1bfa7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,7 +3,7 @@ # 1.19.0 - add `single_design_document` config option -- remove support for lists +- remove support for lists and lib # 1.18.0 diff --git a/README.md b/README.md index d1233351..340c32b6 100644 --- a/README.md +++ b/README.md @@ -410,14 +410,6 @@ class User end ``` -commonJS modules can also be used in custom views: - -```ruby -class User - view :all, :map => "function(doc) { emit(null, require("views/lib/test").test)}", :lib => {:test => "exports.test = 'test'"}, :include_docs => true, :type => :custom -end -``` - If you don't want the results to be converted into models the raw view is your friend: ```ruby diff --git a/lib/couch_potato/database.rb b/lib/couch_potato/database.rb index 6cab5c00..d0a17e83 100644 --- a/lib/couch_potato/database.rb +++ b/lib/couch_potato/database.rb @@ -273,7 +273,6 @@ def raw_view(spec) map: spec.map_function, reduce: spec.reduce_function } }, - spec.lib, spec.language ).query_view!(spec.view_parameters) end diff --git a/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb b/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb index 5904321e..b2e42231 100644 --- a/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb +++ b/lib/couch_potato/rspec/matchers/map_reduce_to_matcher.rb @@ -72,7 +72,6 @@ def matches?(view_spec) var options = #{@options.to_json}; var map = #{view_spec.map_function}; var reduce = #{view_spec.reduce_function}; - var lib = #{view_spec.respond_to?(:lib) && view_spec.lib.to_json}; var collate = (function() { var module = {exports: {}}; var exports = module.exports; eval(#{File.read(File.expand_path(File.dirname(__FILE__) + '/../../../../vendor/pouchdb-collate/pouchdb-collate.js')).to_json}); return module.exports.collate;})(); // Map the input docs @@ -80,7 +79,7 @@ def matches?(view_spec) var module = {exports: {}}; var exports = module.exports; var pathArray = modulePath.split("/").slice(2); - var result = lib; + var result = {}; for (var i in pathArray) { result = result[pathArray[i]]; } diff --git a/lib/couch_potato/rspec/matchers/map_to_matcher.rb b/lib/couch_potato/rspec/matchers/map_to_matcher.rb index c12404d6..10899a5c 100644 --- a/lib/couch_potato/rspec/matchers/map_to_matcher.rb +++ b/lib/couch_potato/rspec/matchers/map_to_matcher.rb @@ -26,13 +26,12 @@ def matches?(view_spec) (function() { var doc = #{@input_ruby.to_json}; var map = #{view_spec.map_function}; - var lib = #{view_spec.respond_to?(:lib) && view_spec.lib.to_json}; var result = []; var require = function(modulePath) { var module = {exports: {}}; var exports = module.exports; var pathArray = modulePath.split("/").slice(2); - var result = lib; + var result = {}; for (var i in pathArray) { result = result[pathArray[i]]; } diff --git a/lib/couch_potato/view/base_view_spec.rb b/lib/couch_potato/view/base_view_spec.rb index 7080baf5..81c3e515 100644 --- a/lib/couch_potato/view/base_view_spec.rb +++ b/lib/couch_potato/view/base_view_spec.rb @@ -3,7 +3,7 @@ module CouchPotato module View class BaseViewSpec - attr_reader :reduce_function, :lib, :design_document, :view_name, :klass, :options, :language + attr_reader :reduce_function, :design_document, :view_name, :klass, :options, :language attr_accessor :view_parameters private :klass, :options diff --git a/lib/couch_potato/view/custom_view_spec.rb b/lib/couch_potato/view/custom_view_spec.rb index ecc27813..cbbefe79 100644 --- a/lib/couch_potato/view/custom_view_spec.rb +++ b/lib/couch_potato/view/custom_view_spec.rb @@ -13,10 +13,6 @@ def reduce_function options[:reduce] end - def lib - options[:lib] - end - def view_parameters {:include_docs => options[:include_docs] || false}.merge(super) end diff --git a/lib/couch_potato/view/flex_view_spec.rb b/lib/couch_potato/view/flex_view_spec.rb index 5484b67b..d90566ff 100644 --- a/lib/couch_potato/view/flex_view_spec.rb +++ b/lib/couch_potato/view/flex_view_spec.rb @@ -96,7 +96,7 @@ def initialize(klass, view_name, options, view_parameters) end delegate :view_name, :view_parameters, :design_document, :map_function, - :reduce_function, :lib, :language, to: :view_spec_delegate + :reduce_function, :language, to: :view_spec_delegate def process_results(results) results = Results.new(results) diff --git a/lib/couch_potato/view/raw_view_spec.rb b/lib/couch_potato/view/raw_view_spec.rb index 4a4b7fd1..59bb731a 100644 --- a/lib/couch_potato/view/raw_view_spec.rb +++ b/lib/couch_potato/view/raw_view_spec.rb @@ -1,6 +1,6 @@ module CouchPotato module View - # A view for custom map/reduce functions that returns the raw data fromcouchdb + # A view for custom map/reduce functions that returns the raw data from couchdb # # example: # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :reduce => nil @@ -10,7 +10,7 @@ module View # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :results_filter => lambda{|results| results['rows].map{|row| row['value']}} # # example: - # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw, :lib => {:module => "exports.name = 'module';" + # view :my_custom_view, :map => "function(doc) { emit(doc._id, null); }", :type => :raw" class RawViewSpec < BaseViewSpec def map_function options[:map] @@ -19,10 +19,6 @@ def map_function def reduce_function options[:reduce] end - - def lib - options[:lib] - end end end end diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 6ac0a92e..3e533b7a 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -2,13 +2,12 @@ module CouchPotato module View # 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. class ViewQuery - def initialize(couchrest_database, design_document_name, view, lib = nil, language = :javascript) + def initialize(couchrest_database, design_document_name, view, language = :javascript) @database = couchrest_database @design_document_name = design_document_name @view_name = view.keys[0] @map_function = view.values[0][:map] @reduce_function = view.values[0][:reduce] - @lib = lib @language = language end @@ -45,9 +44,6 @@ def update_view else design_doc['views'][@view_name.to_s] = view_functions end - if @lib - design_doc['views']['lib'] = (design_doc['views']['lib'] || {}).merge(@lib) - end if original_views != design_doc['views'] @database.save_doc(design_doc) end diff --git a/spec/single_design_document_spec.rb b/spec/single_design_document_spec.rb index 6003b4c3..2fbde481 100644 --- a/spec/single_design_document_spec.rb +++ b/spec/single_design_document_spec.rb @@ -23,6 +23,7 @@ class Thing2 before(:each) do recreate_db CouchPotato::Config.single_design_document = true + CouchPotato.views.select! { |v| [Thing1, Thing2].include?(v) } # clear classes from other specs end after(:each) do diff --git a/spec/unit/couch_potato_spec.rb b/spec/unit/couch_potato_spec.rb index e12c7dbb..56a8d8c1 100644 --- a/spec/unit/couch_potato_spec.rb +++ b/spec/unit/couch_potato_spec.rb @@ -8,6 +8,7 @@ CouchPotato::Config.database_name = nil CouchPotato::Config.split_design_documents_per_view = false CouchPotato::Config.digest_view_names = false + CouchPotato::Config.single_design_document = false CouchPotato::Config.default_language = :javascript CouchPotato::Config.database_host = 'http://127.0.0.1:5984' CouchPotato::Config.additional_databases = {} diff --git a/spec/unit/database_spec.rb b/spec/unit/database_spec.rb index 020bb6be..d979aac7 100644 --- a/spec/unit/database_spec.rb +++ b/spec/unit/database_spec.rb @@ -415,27 +415,10 @@ def set_errors allow(CouchPotato::View::ViewQuery).to receive_messages(new: double('view query', query_view!: { 'rows' => [@result] })) end - it 'initializes a view query with map/reduce/lib functions' do - allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', - map_function: '', reduce_function: '', - lib: { test: '' }, language: 'javascript') - expect(CouchPotato::View::ViewQuery).to receive(:new).with( - @couchrest_db, - 'design_doc', - { 'my_view' => { - map: '', - reduce: '' - } }, - { test: '' }, - 'javascript' - ) - @db.view(@spec) - end it 'initializes a view query with map/reduce functions' do allow(@spec).to receive_messages(design_document: 'design_doc', view_name: 'my_view', map_function: '', reduce_function: '', - lib: nil, language: 'javascript') expect(CouchPotato::View::ViewQuery).to receive(:new).with( @couchrest_db, @@ -444,7 +427,6 @@ def set_errors map: '', reduce: '' } }, - nil, 'javascript' ) @db.view(@spec) diff --git a/spec/unit/rspec_matchers_spec.rb b/spec/unit/rspec_matchers_spec.rb index 490afeb3..64e58673 100644 --- a/spec/unit/rspec_matchers_spec.rb +++ b/spec/unit/rspec_matchers_spec.rb @@ -36,22 +36,6 @@ expect(spec).to map({}).to([nil, "2013-05-17T15:00:00.000Z"]) end - it "should work with commonJS modules that use 'exports'" do - spec = double( - :map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }", - :lib => {:test => "exports.test = 'test';"} - ) - expect(spec).to map({}).to([nil, "test"]) - end - - it "should work with commonJS modules that use 'module.exports'" do - spec = double( - :map_function => "function(doc) { var test = require('views/lib/test'); emit(null, test.test); }", - :lib => {:test => "module.exports.test = 'test';"} - ) - expect(spec).to map({}).to([nil, "test"]) - end - describe "failing specs" do before(:each) do @view_spec = double(:map_function => "function(doc) {emit(doc.name, null)}") @@ -145,22 +129,6 @@ expect(spec).to map_reduce({}).to({"key" => nil, "value" => "2013-05-17T15:00:00.000Z"}) end - it "should handle CommonJS requires for modules that use 'exports'" do - spec = double( - :map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }", - :reduce_function => "function(keys, values) { return 'test' }", - :lib => {:test => "exports.test = 'test'"}) - expect(spec).to map_reduce({}).to({"key" => nil, "value" => "test"}) - end - - it "should handle CommonJS requires for modules that use 'module.exports'" do - spec = double( - :map_function => "function() { var test = require('views/lib/test'); emit(null, test.test); }", - :reduce_function => "function(keys, values) { return 'test' }", - :lib => {:test => "module.exports.test = 'test'"}) - expect(spec).to map_reduce({}).to({"key" => nil, "value" => "test"}) - end - it "should handle sum function" do spec = double( :map_function => "function(doc) { emit(null, doc.age); }", diff --git a/spec/unit/view_query_spec.rb b/spec/unit/view_query_spec.rb index a71f952c..232616d3 100644 --- a/spec/unit/view_query_spec.rb +++ b/spec/unit/view_query_spec.rb @@ -16,13 +16,13 @@ it 'updates a view if it does not exist' do expect(db).to receive(:save_doc).with( { - 'views' => {'view' => {'map' => '', 'reduce' => ''}, 'lib' => {'test' => ''}}, + 'views' => {'view' => {'map' => '', 'reduce' => ''}}, "_id" => "_design/design", "language" => "javascript" } ) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, {'test' => ""}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}).query_view! end it 'only updates a view once' do @@ -55,21 +55,13 @@ CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, - nil, :erlang).query_view! + :erlang).query_view! end it "does not update a view when the views object haven't changed" do allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '', 'reduce' => ''}}}) expect(db).not_to receive(:save_doc) - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, nil).query_view! - end - - it "does not update a view when the lib function hasn't changed" do - allow(db).to receive(:get).and_return({'views' => {'view' => {'map' => '', 'reduce' => ''}, 'lib' => {'test' => ''}}}) - - expect(db).not_to receive(:save_doc) - - CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}, {'test' => ""}).query_view! + CouchPotato::View::ViewQuery.new(db, 'design', {:view => {:map => '', :reduce => ''}}).query_view! end it 'updates a view when the map function has changed' do @@ -84,44 +76,6 @@ CouchPotato::View::ViewQuery.new(db, 'design', :view3 => {:map => ''}).query_view! end - it 'updates a view when the lib hash has changed' do - allow(db).to receive(:get).and_return({'views' => {'view4' => {'map' => ''}}}, 'lib' => {'test' => ""}) - - expect(db).to receive(:save_doc) - - CouchPotato::View::ViewQuery.new(db, 'design', {:view4 => {:map => ''}}, {:test => ""}).query_view! - end - - it "doesn't override libs with different names" do - allow(db).to receive(:get).and_return({'views' => {'view5' => {'map' => ''}, 'lib' => {'test' => ""}}}) - expect(db).to receive(:save_doc).with({ - 'views' => { - 'view5' => {'map' => ''}, - 'lib' => {'test' => '', 'test1' => ''} - } - }) - CouchPotato::View::ViewQuery.new(db, 'design', {:view5 => {:map => ''}}, {'test1' => ''}).query_view! - end - - it 'overrides libs with the same name' do - allow(db).to receive(:get).and_return({'views' => {'view6' => {'map' => ''}, 'lib' => {'test' => ""}}}) - - expect(db).to receive(:save_doc).with({ - 'views' => { - 'view6' => {'map' => ''}, - 'lib' => {'test' => ''} - }, - }) - - CouchPotato::View::ViewQuery.new(db, 'design', {:view6 => {:map => ''}}, {'test' => ''}).query_view! - end - - it 'does not pass in reduce or lib keys if there is no lib or reduce object' do - allow(db).to receive(:get).and_return({'views' => {}}) - expect(db).to receive(:save_doc).with({'views' => {'view7' => {'map' => ''}}}) - CouchPotato::View::ViewQuery.new(db, 'design', :view7 => {:map => '', :reduce => nil}).query_view! - end - it 'updates a view when the reduce function has changed' do allow(db).to receive(:get).and_return({'views' => {'view8' => {'map' => '', 'reduce' => ''}}}) expect(db).to receive(:save_doc) From 38e6e52afde0f61e951c3f2db49990f2bc4bab09 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 16:08:02 +0200 Subject: [PATCH 05/26] remove nil reduce functions --- lib/couch_potato/view/view_query.rb | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 3e533b7a..52f76148 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -53,20 +53,13 @@ def all_views CouchPotato.views.flat_map do |klass| specs = klass.views.map { |view_name, view| klass.execute_view(view_name, {}) } specs.map do |klass_spec| - { klass_spec.view_name => { - 'map' => klass_spec.map_function, - 'reduce' => klass_spec.reduce_function - } } + { klass_spec.view_name => view_functions(klass_spec.map_function, klass_spec.reduce_function) } end end.inject(&:merge) end - def view_functions - if @reduce_function - {'map' => @map_function, 'reduce' => @reduce_function} - else - {'map' => @map_function} - end + def view_functions(map_function = @map_function, reduce_function = @reduce_function) + {'map' => @map_function, 'reduce' => @reduce_function}.compact end def empty_design_document From 5bc9c9e36f2ab568f5ab9f1a68c5a54b6d1490be Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 16:15:18 +0200 Subject: [PATCH 06/26] stop constantly updating views --- lib/couch_potato/view/view_query.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 52f76148..d7f57b06 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -12,7 +12,7 @@ def initialize(couchrest_database, design_document_name, view, language = :javas end def query_view!(parameters = {}) - update_view if !view_has_been_updated? || CouchPotato::Config.single_design_document + update_view if !view_has_been_updated? begin query_view parameters rescue CouchRest::NotFound From 40be67c025543879d2343ab62e35d313cb46b43e Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 16:20:53 +0200 Subject: [PATCH 07/26] fix update condition --- lib/couch_potato/view/view_query.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index d7f57b06..141fd5d4 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -67,7 +67,11 @@ def empty_design_document end def view_has_been_updated? - updated_views[[@design_document_name, @view_name]] + if CouchPotato::Config.single_design_document + updated_views.any? + else + updated_views[[@design_document_name, @view_name]] + end end def view_updated From bd65fffccd7f18c1e0faf8c44de8096b1800c882 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 16:53:00 +0200 Subject: [PATCH 08/26] fix map/reduce functions --- lib/couch_potato/view/view_query.rb | 6 +++--- spec/single_design_document_spec.rb | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/couch_potato/view/view_query.rb b/lib/couch_potato/view/view_query.rb index 141fd5d4..c9b72e20 100644 --- a/lib/couch_potato/view/view_query.rb +++ b/lib/couch_potato/view/view_query.rb @@ -12,7 +12,7 @@ def initialize(couchrest_database, design_document_name, view, language = :javas end def query_view!(parameters = {}) - update_view if !view_has_been_updated? + update_view unless view_has_been_updated? begin query_view parameters rescue CouchRest::NotFound @@ -37,7 +37,7 @@ def self.__updated_views def update_view design_doc = @database.get "_design/#{@design_document_name}" rescue nil original_views = design_doc && design_doc['views'].dup - view_updated unless design_doc.nil? + view_updated design_doc ||= empty_design_document if CouchPotato::Config.single_design_document design_doc['views'] = all_views @@ -59,7 +59,7 @@ def all_views end def view_functions(map_function = @map_function, reduce_function = @reduce_function) - {'map' => @map_function, 'reduce' => @reduce_function}.compact + {'map' => map_function, 'reduce' => reduce_function}.compact end def empty_design_document diff --git a/spec/single_design_document_spec.rb b/spec/single_design_document_spec.rb index 2fbde481..0d7264e8 100644 --- a/spec/single_design_document_spec.rb +++ b/spec/single_design_document_spec.rb @@ -40,4 +40,14 @@ class Thing2 expect(couchrest_db.get('_design/couch_potato')['views'].keys).to eq(['thing1-all', 'thing2-all']) end + + it 'returns the correct models' do + thing1 = Thing1.new title: 't1' + db.save! thing1 + thing2 = Thing2.new name: 'n2' + db.save! thing2 + + expect(db.view(Thing1.all('t1'))).to eq([thing1]) + expect(db.view(Thing2.all('n2'))).to eq([thing2]) + end end From c6b4c96f3d31954c2fb8f0fd2df2ebc12a93a6f2 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 17:11:26 +0200 Subject: [PATCH 09/26] track views for inherited classes --- lib/couch_potato/persistence.rb | 11 ++++++++--- lib/couch_potato/view/custom_views.rb | 11 +++++++++++ spec/single_design_document_spec.rb | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/couch_potato/persistence.rb b/lib/couch_potato/persistence.rb index 3beb12c9..f6629461 100644 --- a/lib/couch_potato/persistence.rb +++ b/lib/couch_potato/persistence.rb @@ -17,6 +17,12 @@ module CouchPotato module Persistence + module TrackModels + def inherited(child) + super + CouchPotato.models << child + end + end def self.included(base) #:nodoc: base.send :include, Properties, Callbacks, Json, CouchPotato::View::CustomViews @@ -29,9 +35,8 @@ def self.included(base) #:nodoc: alias_method :id, :_id alias_method :id=, :_id= - def self.inherited(child) - super - CouchPotato.models << child + class << self + prepend TrackModels end end diff --git a/lib/couch_potato/view/custom_views.rb b/lib/couch_potato/view/custom_views.rb index 20ff7e47..85ca77f5 100644 --- a/lib/couch_potato/view/custom_views.rb +++ b/lib/couch_potato/view/custom_views.rb @@ -9,10 +9,21 @@ module CouchPotato module View module CustomViews + module TrackViews + def inherited(child) + super + CouchPotato.views << child + end + end def self.included(base) #:nodoc: base.extend ClassMethods CouchPotato.views << base + base.class_eval do + class << self + prepend TrackViews + end + end end module ClassMethods diff --git a/spec/single_design_document_spec.rb b/spec/single_design_document_spec.rb index 0d7264e8..20ae65d9 100644 --- a/spec/single_design_document_spec.rb +++ b/spec/single_design_document_spec.rb @@ -20,10 +20,16 @@ class Thing2 view :all, key: :name end + class Thing3 < Thing1 # should work with inheritance + property :tag + + view :by_tag, key: :tag + end + before(:each) do recreate_db CouchPotato::Config.single_design_document = true - CouchPotato.views.select! { |v| [Thing1, Thing2].include?(v) } # clear classes from other specs + CouchPotato.views.select! { |v| [Thing1, Thing2, Thing3].include?(v) } # clear classes from other specs end after(:each) do @@ -38,7 +44,8 @@ class Thing2 db.view(Thing1.all) # create all views when querying the first one - expect(couchrest_db.get('_design/couch_potato')['views'].keys).to eq(['thing1-all', 'thing2-all']) + expect(couchrest_db.get('_design/couch_potato')['views'].keys) + .to(eq(['thing1-all', 'thing2-all', 'thing3-by_tag'])) end it 'returns the correct models' do @@ -46,8 +53,11 @@ class Thing2 db.save! thing1 thing2 = Thing2.new name: 'n2' db.save! thing2 + thing3 = Thing3.new tag: 'tag1' + db.save! thing3 expect(db.view(Thing1.all('t1'))).to eq([thing1]) expect(db.view(Thing2.all('n2'))).to eq([thing2]) + expect(db.view(Thing3.by_tag('tags1'))).to eq([thing3]) end end From 8c48550455b80cdf1221b63879a1750808b59c14 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Jun 2025 17:33:26 +0200 Subject: [PATCH 10/26] fix spec --- spec/single_design_document_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/single_design_document_spec.rb b/spec/single_design_document_spec.rb index 20ae65d9..97a4e337 100644 --- a/spec/single_design_document_spec.rb +++ b/spec/single_design_document_spec.rb @@ -58,6 +58,6 @@ class Thing3 < Thing1 # should work with inheritance expect(db.view(Thing1.all('t1'))).to eq([thing1]) expect(db.view(Thing2.all('n2'))).to eq([thing2]) - expect(db.view(Thing3.by_tag('tags1'))).to eq([thing3]) + expect(db.view(Thing3.by_tag('tag1'))).to eq([thing3]) end end From 5c8834fbb2db791c286b3f7e06e16d2407eee03a Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 10:34:12 +0200 Subject: [PATCH 11/26] bump couchdb action --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 77349208..14809b9e 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@v4 + uses: cobot/couchdb-action@v5 with: couchdb version: "2.3.1" - name: Set up Ruby From 73346db4aff8c2476defd0b2a5fe139a20b2dcdc Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 10:43:33 +0200 Subject: [PATCH 12/26] test couchdb-action --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 14809b9e..e89a4608 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@v5 + uses: cobot/couchdb-action@f6f727ab9b94a8da1a617c969243388ad21565ba with: couchdb version: "2.3.1" - name: Set up Ruby From 43796ee784002b4773d7d8bb73765b1f3bb1da7e Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 10:54:57 +0200 Subject: [PATCH 13/26] bump couchdb action --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index e89a4608..a699f850 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@f6f727ab9b94a8da1a617c969243388ad21565ba + uses: cobot/couchdb-action@0ca874024f27b21437abd2001a4f46755f2ee335 with: couchdb version: "2.3.1" - name: Set up Ruby From f884dd5624514960c312608aa0aa777e2e47eebc Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 10:58:23 +0200 Subject: [PATCH 14/26] bump --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index a699f850..0eb65a6c 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@0ca874024f27b21437abd2001a4f46755f2ee335 + uses: cobot/couchdb-action@409ca2b225e5d6d9fdbaae9ae05123143aa11d46 with: couchdb version: "2.3.1" - name: Set up Ruby From bad0e172f3cc51e50509e99c2e1a2324181cf994 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 11:36:44 +0200 Subject: [PATCH 15/26] bump --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 0eb65a6c..ac548c35 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@409ca2b225e5d6d9fdbaae9ae05123143aa11d46 + uses: cobot/couchdb-action@bef8173b230f74d4e125852b2402753324fb84f3 with: couchdb version: "2.3.1" - name: Set up Ruby From 4786ee9b7378beff617d24f02ade1328132a7cde Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 12:31:10 +0200 Subject: [PATCH 16/26] bump couchdb action --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index ac548c35..6a62e0eb 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@bef8173b230f74d4e125852b2402753324fb84f3 + uses: cobot/couchdb-action@27da46efdd678580a7d03a474ed5a5fc205ce32a with: couchdb version: "2.3.1" - name: Set up Ruby From e3f53344bf2b2956ca900645e5d0bfa12e629d98 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 12:42:19 +0200 Subject: [PATCH 17/26] bump couchdb --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 6a62e0eb..85ee2161 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@27da46efdd678580a7d03a474ed5a5fc205ce32a + uses: cobot/couchdb-action@26926cc0d96744df475eb2b28919c84806652f9a with: couchdb version: "2.3.1" - name: Set up Ruby From ea2fad3131a6deccf4980016adbff340e480d5d6 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 12:44:34 +0200 Subject: [PATCH 18/26] fix name --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 85ee2161..0c17dedb 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -28,7 +28,7 @@ jobs: - name: Set up CouchDB uses: cobot/couchdb-action@26926cc0d96744df475eb2b28919c84806652f9a with: - couchdb version: "2.3.1" + couchdb-version: "2.3.1" - name: Set up Ruby uses: ruby/setup-ruby@v1 with: From 3e20e878e76e9ce32a48930b743a3cff6359211e Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 12:48:01 +0200 Subject: [PATCH 19/26] bump again --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 0c17dedb..46b782d0 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -26,7 +26,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Set up CouchDB - uses: cobot/couchdb-action@26926cc0d96744df475eb2b28919c84806652f9a + uses: cobot/couchdb-action@eaaa17cf8baf421e7fb07e2d869f5457bb6a4de5 with: couchdb-version: "2.3.1" - name: Set up Ruby From e2d91c0a3b9f7a479a09576b1478482ab6362d50 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 12:54:31 +0200 Subject: [PATCH 20/26] add admin --- .github/workflows/ruby.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 46b782d0..94579851 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -36,3 +36,5 @@ jobs: bundler-cache: true - name: Run tests run: bundle exec rake spec_ci + env: + DATABASE: http://admin:admin@localhost:5984 From aee818e9a6ab83e65f15ff9da059a760c64a5493 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:08:57 +0200 Subject: [PATCH 21/26] fix db name --- .github/workflows/ruby.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 94579851..8cfb6f89 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -37,4 +37,4 @@ jobs: - name: Run tests run: bundle exec rake spec_ci env: - DATABASE: http://admin:admin@localhost:5984 + DATABASE: http://admin:admin@localhost:5984/couch_potato_test From e6685426aa858075eb489225f4864f5b1d457dee Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:15:02 +0200 Subject: [PATCH 22/26] bump actions --- .github/workflows/ruby.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 8cfb6f89..43a0bf71 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -24,9 +24,9 @@ jobs: - ruby: "jruby" gemfile: "active_support_8_0" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up CouchDB - uses: cobot/couchdb-action@eaaa17cf8baf421e7fb07e2d869f5457bb6a4de5 + uses: cobot/couchdb-action@v5 with: couchdb-version: "2.3.1" - name: Set up Ruby From a1596fabb89e77525eae5424d9aa8bcde4b84a46 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:36:57 +0200 Subject: [PATCH 23/26] fix specs --- spec/view_updates_spec.rb | 58 +++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/spec/view_updates_spec.rb b/spec/view_updates_spec.rb index 9f9736fe..229e825b 100644 --- a/spec/view_updates_spec.rb +++ b/spec/view_updates_spec.rb @@ -7,8 +7,27 @@ end it "should update a view that doesn't match the given functions" do - CouchPotato::View::ViewQuery.new(@db, 'test_design1', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view! # create view - 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! + CouchPotato::View::ViewQuery.new( + @db, + 'test_design1', { + 'test_view' => { + :map => 'function(doc) { }', + :reduce => 'function(key, values) { return []; }' + } + } + ).query_view! # create view + CouchPotato::View::ViewQuery.clear_cache + CouchPotato::View::ViewQuery.new( + @db, + 'test_design1', + { + 'test_view' => { + :map => 'function(doc) {emit(doc.id, null)}', + :reduce => 'function(key, values) {return sum(values)}' + } + } + ).query_view! + expect(CouchPotato.database.load('_design/test_design1')['views']['test_view']).to eq({ 'map' => 'function(doc) {emit(doc.id, null)}', 'reduce' => 'function(key, values) {return sum(values)}' @@ -16,9 +35,38 @@ end it "should only update a view once to avoid writing the view for every request" do - CouchPotato::View::ViewQuery.new(@db, 'test_design2', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view! # create view - 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! - CouchPotato::View::ViewQuery.new(@db, 'test_design2', {'test_view' => {:map => 'function(doc) {}', :reduce => 'function() {}'}}, nil).query_view! + CouchPotato::View::ViewQuery.new( + @db, + 'test_design2', + { + 'test_view' => { + :map => 'function(doc) {}', + :reduce => 'function() {}' + } + } + ).query_view! # create view + CouchPotato::View::ViewQuery.clear_cache + CouchPotato::View::ViewQuery.new( + @db, + 'test_design2', + { + 'test_view' => { + :map => 'function(doc) {emit(doc.id, null)}', + :reduce => 'function(key, values) {return sum(values)}' + } + } + ).query_view! + CouchPotato::View::ViewQuery.new( + @db, + 'test_design2', + { + 'test_view' => { + :map => 'function(doc) {}', + :reduce => 'function() {}' + } + } + ).query_view! + expect(CouchPotato.database.load('_design/test_design2')['views']['test_view']).to eq({ 'map' => 'function(doc) {emit(doc.id, null)}', 'reduce' => 'function(key, values) {return sum(values)}' From 1d9908067283186e35bba0b65fe4cc5b7a929c7a Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:38:01 +0200 Subject: [PATCH 24/26] bump versions --- CHANGES.md | 2 +- lib/couch_potato/version.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b1b1bfa7..8ee08650 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ ## Changes -# 1.19.0 +# 1.19.0 / rspec-matchers 4.2.0 - add `single_design_document` config option - remove support for lists and lib diff --git a/lib/couch_potato/version.rb b/lib/couch_potato/version.rb index 031699c3..5e22f5fc 100644 --- a/lib/couch_potato/version.rb +++ b/lib/couch_potato/version.rb @@ -1,4 +1,4 @@ module CouchPotato - VERSION = '1.18.0'.freeze - RSPEC_VERSION = '4.1.0'.freeze + VERSION = '1.19.0'.freeze + RSPEC_VERSION = '4.2.0'.freeze end From 0bd79d1dff101ffad3d0c86b9586f9d07363ecbe Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:47:11 +0200 Subject: [PATCH 25/26] fix jruby --- spec/unit/attributes_spec.rb | 2 +- spec/unit/rspec_matchers_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/unit/attributes_spec.rb b/spec/unit/attributes_spec.rb index 19d3c61d..c2e4a679 100644 --- a/spec/unit/attributes_spec.rb +++ b/spec/unit/attributes_spec.rb @@ -87,7 +87,7 @@ class SpecialPlant < Plant plant = Plant.new expect do plant.length - end.to raise_error(NoMethodError, /undefined method `length'/) + end.to raise_error(NoMethodError, /undefined method [`']length'/) end end diff --git a/spec/unit/rspec_matchers_spec.rb b/spec/unit/rspec_matchers_spec.rb index 64e58673..5458fa9e 100644 --- a/spec/unit/rspec_matchers_spec.rb +++ b/spec/unit/rspec_matchers_spec.rb @@ -208,13 +208,13 @@ it "should have a nice error message for failing should" do expect { expect(@view_spec).to map_reduce(@docs).with_options(:group => false).to({"key" => nil, "value" => 9}) - }.to raise_error('Expected to map/reduce to [{"key"=>nil, "value"=>9}] but got [{"key"=>nil, "value"=>8}].') + }.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}\].}) end it "should have a nice error message for failing should not" do expect { expect(@view_spec).not_to map_reduce(@docs).with_options(:group => false).to({"key" => nil, "value" => 8}) - }.to raise_error('Expected not to map/reduce to [{"key"=>nil, "value"=>8}] but did.') + }.to raise_error(%r{Expected not to map/reduce to \[{"key"\s*=>\s*nil, "value"\s*=>\s*8}\] but did.}) end end From 9e17d29ad9323c9d74096a099e37177331bd4449 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Tue, 3 Jun 2025 14:52:27 +0200 Subject: [PATCH 26/26] fix jruby --- spec/property_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/property_spec.rb b/spec/property_spec.rb index fdef3280..42c90bfe 100644 --- a/spec/property_spec.rb +++ b/spec/property_spec.rb @@ -418,7 +418,7 @@ def it_should_persist value it "should include complex datatypes fully inspected" do comment.title = {'en' => 'Blog post'} - expect(comment.inspect).to include('title: {"en"=>"Blog post"}') + expect(comment.inspect).to match(/title: {"en"\s*=>\s*"Blog post"}/) comment.title = nil expect(comment.inspect).to include('title: nil')