Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make default index scope cleanup behavior configurable #925

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### New Features

* [#925](https://github.com/toptal/chewy/pull/925): Add configuration option for default scope cleanup behavior. ([@barthez][])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please provide a readme


### Changes

### Bugs Fixed
Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,24 @@ While using the `before_es_request_filter`, please consider the following:
* The return value of the proc is disregarded. This filter is intended for inspection or modification of the query rather than generating a response.
* Any exception raised inside the callback will propagate upward and halt the execution of the query. It is essential to handle potential errors adequately to ensure the stability of your search functionality.

### Import scope clean-up behavior

Whenever you set the `import_scope` for the index, in the case of ActiveRecord,
options for order, offset and limit will be removed. You can set the behavior of
chewy, before the clean-up itself.

The default behavior is a warning sent to the Chewy logger (`:warn`). Another more
restrictive option is raising an exception (`:raise`). Both options have a
negative impact on performance since verifying whether the code uses any of
these options requires building AREL query.

To avoid the loading time impact, you can ignore the check (`:ignore`) before
the clean-up.

```
Chewy.import_scope_cleanup_behavior = :ignore
```

## Contributing

1. Fork it (http://github.com/toptal/chewy/fork)
Expand Down
6 changes: 5 additions & 1 deletion lib/chewy/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ class Config
# Default field type for any field in any Chewy type. Defaults to 'text'.
:default_field_type,
# Callback called on each search request to be done into ES
:before_es_request_filter
:before_es_request_filter,
# Behavior when import scope for index includes order, offset or limit.
# Can be :ignore, :warn, :raise. Defaults to :warn
:import_scope_cleanup_behavior

attr_reader :transport_logger, :transport_tracer,
# Chewy search request DSL base class, used by every index.
Expand All @@ -62,6 +65,7 @@ def initialize
@indices_path = 'app/chewy'
@default_root_options = {}
@default_field_type = 'text'.freeze
@import_scope_cleanup_behavior = :warn
@search_class = build_search_class(Chewy::Search::Request)
end

Expand Down
3 changes: 3 additions & 0 deletions lib/chewy/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ def initialize(join_field_type, join_field_name, relations)
super("`#{join_field_type}` set for the join field `#{join_field_name}` is not on the :relations list (#{relations})")
end
end

class ImportScopeCleanupError < Error
end
end
14 changes: 12 additions & 2 deletions lib/chewy/index/adapter/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,19 @@ def self.accepts?(target)
private

def cleanup_default_scope!
if Chewy.logger && (@default_scope.arel.orders.present? ||
behavior = Chewy.config.import_scope_cleanup_behavior

if behavior != :ignore && (@default_scope.arel.orders.present? ||
@default_scope.arel.limit.present? || @default_scope.arel.offset.present?)
Chewy.logger.warn('Default type scope order, limit and offset are ignored and will be nullified')
if behavior == :warn && Chewy.logger
gem_dir = File.realpath('../..', __dir__)
source = caller.grep_v(Regexp.new(gem_dir)).first
Chewy.logger.warn(
"Default type scope order, limit and offset are ignored and will be nullified (called from: #{source})"
)
elsif behavior == :raise
raise ImportScopeCleanupError, 'Default type scope order, limit and offset are ignored and will be nullified'
end
end

@default_scope = @default_scope.reorder(nil).limit(nil).offset(nil)
Expand Down
62 changes: 62 additions & 0 deletions spec/chewy/index/adapter/active_record_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,68 @@ def rating
specify { expect(described_class.new(City.where(rating: 10)).default_scope).to eq(City.where(rating: 10)) }
end

describe '.new' do
context 'with logger' do
let(:test_logger) { Logger.new('/dev/null') }
let(:default_scope_behavior) { :warn }

around do |example|
previous_logger = Chewy.logger
Chewy.logger = test_logger

previous_default_scope_behavior = Chewy.config.import_scope_cleanup_behavior
Chewy.config.import_scope_cleanup_behavior = default_scope_behavior

example.run
ensure
Chewy.logger = previous_logger
Chewy.config.import_scope_cleanup_behavior = previous_default_scope_behavior
end

specify do
expect(test_logger).to receive(:warn)
described_class.new(City.order(:id))
end

specify do
expect(test_logger).to receive(:warn)
described_class.new(City.offset(10))
end

specify do
expect(test_logger).to receive(:warn)
described_class.new(City.limit(10))
end

context 'ignore import scope warning' do
let(:default_scope_behavior) { :ignore }

specify do
expect(test_logger).not_to receive(:warn)
described_class.new(City.order(:id))
end

specify do
expect(test_logger).not_to receive(:warn)
described_class.new(City.offset(10))
end

specify do
expect(test_logger).not_to receive(:warn)
described_class.new(City.limit(10))
end
end

context 'raise exception on import scope with order/limit/offset' do
let(:default_scope_behavior) { :raise }

specify { expect { described_class.new(City.order(:id)) }.to raise_error(Chewy::ImportScopeCleanupError) }
specify { expect { described_class.new(City.limit(10)) }.to raise_error(Chewy::ImportScopeCleanupError) }
specify { expect { described_class.new(City.offset(10)) }.to raise_error(Chewy::ImportScopeCleanupError) }
end
end
end

describe '#type_name' do
specify { expect(described_class.new(City).type_name).to eq('city') }
specify { expect(described_class.new(City.order(:id)).type_name).to eq('city') }
Expand Down