Skip to content

Mongoid criteria refactor #20

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

Merged
merged 19 commits into from
Mar 14, 2018
Merged
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
13 changes: 6 additions & 7 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-03-11 13:14:54 +0100 using RuboCop version 0.49.1.
# on 2018-03-13 23:29:51 +0100 using RuboCop version 0.49.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -20,9 +20,9 @@ Metrics/AbcSize:
# Offense count: 14
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/BlockLength:
Max: 202
Max: 216

# Offense count: 6
# Offense count: 5
Metrics/CyclomaticComplexity:
Max: 11

@@ -37,7 +37,7 @@ Metrics/LineLength:
Metrics/MethodLength:
Max: 25

# Offense count: 4
# Offense count: 3
Metrics/PerceivedComplexity:
Max: 11

@@ -48,7 +48,7 @@ Style/Documentation:
- 'test/**/*'
- 'examples/mongoid_scroll_feed.rb'
- 'lib/mongo/scrollable.rb'
- 'lib/mongoid/criterion/scrollable.rb'
- 'lib/mongoid/criteria/scrollable.rb'
- 'lib/mongoid/scroll/cursor.rb'
- 'lib/mongoid/scroll/errors/base.rb'
- 'lib/mongoid/scroll/errors/invalid_cursor_error.rb'
@@ -64,11 +64,10 @@ Style/FileName:
Exclude:
- 'lib/mongoid-scroll.rb'

# Offense count: 2
# Offense count: 1
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Exclude:
- 'lib/mongoid/criterion/scrollable.rb'
- 'lib/moped/scrollable.rb'

# Offense count: 1
2 changes: 1 addition & 1 deletion lib/mongoid-scroll.rb
Original file line number Diff line number Diff line change
@@ -9,4 +9,4 @@
require 'mongoid/scroll/cursor'
require 'moped/scrollable' if Object.const_defined?(:Moped)
require 'mongo/scrollable' if Object.const_defined?(:Mongo)
require 'mongoid/criterion/scrollable'
require 'mongoid/criteria/scrollable'
81 changes: 81 additions & 0 deletions lib/mongoid/criteria/scrollable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
module Mongoid
class Criteria
module Scrollable
def scroll(cursor = nil, &_block)
raise_multiple_sort_fields_error if multiple_sort_fields?
criteria = dup
criteria.merge!(default_sort) if no_sort_option?
cursor_options = build_cursor_options(criteria)
cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : new_cursor(cursor, cursor_options)
cursor_criteria = build_cursor_criteria(criteria, cursor)
if block_given?
cursor_criteria.order_by(_id: scroll_direction(criteria)).each do |record|
yield record, cursor_from_record(record, cursor_options)
end
else
cursor_criteria
end
end

private

def raise_multiple_sort_fields_error
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be a bang method I think, so raise_multiple_sort_fields_error!, for clarity that it fails loudly.

raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: criteria.options.sort)
end

def multiple_sort_fields?
options.sort && options.sort.keys.size != 1
end

def no_sort_option?
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe flip it to sort_option??

options.sort.blank? || options.sort.empty?
end

def default_sort
asc(:_id)
end

def scroll_field(criteria)
criteria.options.sort.keys.first
end

def scroll_direction(criteria)
criteria.options.sort.values.first.to_i
end

def build_cursor_options(criteria)
{
field_type: scroll_field_type(criteria),
field_name: scroll_field(criteria),
direction: scroll_direction(criteria)
}
end

def new_cursor(cursor, cursor_options)
Mongoid::Scroll::Cursor.new(cursor, cursor_options)
end

def build_cursor_criteria(criteria, cursor)
cursor_criteria = criteria.dup
cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
cursor_criteria
end

def cursor_from_record(record, cursor_options)
Mongoid::Scroll::Cursor.from_record(record, cursor_options)
end

def scroll_field_type(criteria)
scroll_field = scroll_field(criteria)
field = criteria.klass.fields[scroll_field.to_s]
field.foreign_key? && field.object_id_field? ? bson_type : field.type
end

def bson_type
Copy link
Collaborator

Choose a reason for hiding this comment

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

You should add this to mongoid-compatibility, maybe Mongoid::Compatibility::ObjectId#bson_type. Obviously fine for now here.

Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
end
end
end
end

Mongoid::Criteria.send(:include, Mongoid::Criteria::Scrollable)
40 changes: 0 additions & 40 deletions lib/mongoid/criterion/scrollable.rb

This file was deleted.

14 changes: 14 additions & 0 deletions spec/mongoid/criteria_spec.rb
Original file line number Diff line number Diff line change
@@ -43,6 +43,20 @@
expect(records.size).to eq 10
expect(records).to eq Feed::Item.all.to_a
end
it 'does not change original criteria' do
criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
original_criteria = criteria.dup
criteria.limit(2).scroll
expect(criteria).to eq original_criteria
cursor = nil
criteria.limit(2).scroll(cursor) do |_record, next_cursor|
cursor = next_cursor
end
criteria.scroll(cursor) do |_record, next_cursor|
cursor = next_cursor
end
expect(criteria).to eq original_criteria
end
end

context 'with a foreign key' do