From 329e05353fe8a16822832a910d16cadc475ef38c Mon Sep 17 00:00:00 2001 From: Andrew Kane Date: Fri, 18 Feb 2022 15:07:18 -0800 Subject: [PATCH] Use lazy loading for searches [skip ci] --- CHANGELOG.md | 1 + README.md | 12 ++++++++++++ lib/searchkick.rb | 13 ++++++++----- lib/searchkick/query.rb | 2 +- lib/searchkick/relation.rb | 38 ++++++++++++++++++++++++++++++++++++++ test/search_test.rb | 8 ++++---- 6 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 lib/searchkick/relation.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index d1b9f91..bd232c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## 5.0.0 (unreleased) +- Searches now use lazy loading (similar to Active Record) - Anchor regular expressions by default - Raise error when `search` called on relations - Raise `ArgumentError` (instead of warning) for invalid regular expression modifiers diff --git a/README.md b/README.md index dac1a77..c1e3098 100644 --- a/README.md +++ b/README.md @@ -2053,6 +2053,18 @@ gem "elasticsearch" If using the deprecated `faraday_middleware-aws-signers-v4` gem, switch to `faraday_middleware-aws-sigv4`. +Also, searches now use lazy loading: + +```ruby +# search not executed +products = Product.search("milk") + +# search executed +products.each do |product| + # ... +end +``` + Check out the [changelog](https://github.com/ankane/searchkick/blob/master/CHANGELOG.md) for the full list of changes. ## History diff --git a/lib/searchkick.rb b/lib/searchkick.rb index 17a17f0..c79618d 100644 --- a/lib/searchkick.rb +++ b/lib/searchkick.rb @@ -15,6 +15,7 @@ require "searchkick/query" require "searchkick/reindex_queue" require "searchkick/record_data" require "searchkick/record_indexer" +require "searchkick/relation" require "searchkick/results" require "searchkick/version" @@ -150,16 +151,18 @@ module Searchkick end end - options = options.merge(block: block) if block - query = Searchkick::Query.new(klass, term, **options) + # TODO remove in Searchkick 6.0 if options[:execute] == false - query - else - query.execute + Searchkick.warn("The execute option is no longer needed") + options.delete(:execute) end + + options = options.merge(block: block) if block + Searchkick::Relation.new(klass, term, **options) end def self.multi_search(queries) + queries = queries.map { |q| q.send(:query) } Searchkick::MultiSearch.new(queries).perform end diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index c14cf4c..5272801 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -18,7 +18,7 @@ module Searchkick def initialize(klass, term = "*", **options) unknown_keywords = options.keys - [:aggs, :block, :body, :body_options, :boost, - :boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :execute, :explain, + :boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :explain, :fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load, :match, :misspellings, :models, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile, :request_params, :routing, :scope_results, :scroll, :select, :similar, :smart_aggs, :suggest, :total_entries, :track, :type, :where] diff --git a/lib/searchkick/relation.rb b/lib/searchkick/relation.rb new file mode 100644 index 0000000..412615a --- /dev/null +++ b/lib/searchkick/relation.rb @@ -0,0 +1,38 @@ +require "active_support/core_ext/module/delegation" + +module Searchkick + class Relation + # note: modifying body directly is not supported + # and has no impact on query after being executed + # TODO freeze body object? + delegate :body, :params, to: :@query + delegate_missing_to :private_execute + + def initialize(klass, term = "*", **options) + @query = Query.new(klass, term, **options) + end + + # same as Active Record + def inspect + entries = results.first(11).map!(&:inspect) + entries[10] = "..." if entries.size == 11 + "#<#{self.class.name} [#{entries.join(', ')}]>" + end + + def execute + Searchkick.warn("The execute method is no longer needed") + private_execute + self + end + + private + + def private_execute + @execute ||= @query.execute + end + + def query + @query + end + end +end diff --git a/test/search_test.rb b/test/search_test.rb index 307f6d1..a229bd3 100644 --- a/test/search_test.rb +++ b/test/search_test.rb @@ -56,14 +56,14 @@ class SearchTest < Minitest::Test def test_bad_mapping Product.searchkick_index.delete store_names ["Product A"] - error = assert_raises(Searchkick::InvalidQueryError) { Product.search "test" } + error = assert_raises(Searchkick::InvalidQueryError) { Product.search("test").to_a } assert_equal "Bad mapping - run Product.reindex", error.message ensure Product.reindex end def test_missing_index - assert_raises(Searchkick::MissingIndexError) { Product.search("test", index_name: "not_found") } + assert_raises(Searchkick::MissingIndexError) { Product.search("test", index_name: "not_found").to_a } end def test_unsupported_version @@ -77,11 +77,11 @@ class SearchTest < Minitest::Test end end Searchkick.client.stub :search, raises_exception do - assert_raises(Searchkick::UnsupportedVersionError) { Product.search("test") } + assert_raises(Searchkick::UnsupportedVersionError) { Product.search("test").to_a } end end def test_invalid_body - assert_raises(Searchkick::InvalidQueryError) { Product.search(body: {boom: true}) } + assert_raises(Searchkick::InvalidQueryError) { Product.search(body: {boom: true}).to_a } end end -- libgit2 0.21.0