mongoid-scroll 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57a1e903af68213f7d6552ca5dc91515ef599fcd
4
- data.tar.gz: f957cb76b0556ba653b2a56d030850c07ed995c6
3
+ metadata.gz: 3c6aed40600433d3619cdc8839f6a2ad2da3b9c7
4
+ data.tar.gz: fbe2257d54b98c8aff1d8163f2a4dc15071c7d92
5
5
  SHA512:
6
- metadata.gz: e4df4fa326bfb87fa7cb41e577e4cf22010415e2cedaa74f52a7b789f72143bcc2f5c6074f3823f95705c3090fef4a75d7b365d3274a8ff640105d429918b08f
7
- data.tar.gz: cacbb8b7577052c47fac14aa4401117dfb6c05a788e900d252fac0c565d49c24b6512deb87c02f69ab3803ce4348820bdfe78e6f99309516be5d45cc9bf66229
6
+ metadata.gz: 4936c9a792ec9950a4bbd5c02c8fcc89cedc44cd1900737d6e20106ad3810f1d27b7aa9bbb230f58177a2dd10ac251bfbaec4674a5e31855c5f5bf450fd7dfbf
7
+ data.tar.gz: 5f087846be5d4870975de8841872320a6e0ce441b568e4db28526a2bb715264b92b7089aa70df9adb615d3f735b8079847472e55e9c8cd75cd0eca4b33cd01ca
@@ -4,5 +4,3 @@ AllCops:
4
4
  Exclude:
5
5
  - vendor/**/*
6
6
  - gemfiles/vendor/**/*
7
-
8
-
@@ -1,31 +1,43 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2016-09-27 11:32:40 -0700 using RuboCop version 0.43.0.
3
+ # on 2018-03-13 23:29:51 +0100 using RuboCop version 0.49.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
+ # Offense count: 6
10
+ # Configuration parameters: Include.
11
+ # Include: **/Gemfile, **/gems.rb
12
+ Bundler/DuplicatedGem:
13
+ Exclude:
14
+ - 'Gemfile'
15
+
9
16
  # Offense count: 6
10
17
  Metrics/AbcSize:
11
18
  Max: 67
12
19
 
13
- # Offense count: 6
20
+ # Offense count: 14
21
+ # Configuration parameters: CountComments, ExcludedMethods.
22
+ Metrics/BlockLength:
23
+ Max: 216
24
+
25
+ # Offense count: 5
14
26
  Metrics/CyclomaticComplexity:
15
27
  Max: 11
16
28
 
17
- # Offense count: 114
18
- # Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
29
+ # Offense count: 121
30
+ # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
19
31
  # URISchemes: http, https
20
32
  Metrics/LineLength:
21
- Max: 170
33
+ Max: 172
22
34
 
23
35
  # Offense count: 6
24
36
  # Configuration parameters: CountComments.
25
37
  Metrics/MethodLength:
26
38
  Max: 25
27
39
 
28
- # Offense count: 4
40
+ # Offense count: 3
29
41
  Metrics/PerceivedComplexity:
30
42
  Max: 11
31
43
 
@@ -36,7 +48,7 @@ Style/Documentation:
36
48
  - 'test/**/*'
37
49
  - 'examples/mongoid_scroll_feed.rb'
38
50
  - 'lib/mongo/scrollable.rb'
39
- - 'lib/mongoid/criterion/scrollable.rb'
51
+ - 'lib/mongoid/criteria/scrollable.rb'
40
52
  - 'lib/mongoid/scroll/cursor.rb'
41
53
  - 'lib/mongoid/scroll/errors/base.rb'
42
54
  - 'lib/mongoid/scroll/errors/invalid_cursor_error.rb'
@@ -46,27 +58,21 @@ Style/Documentation:
46
58
  - 'lib/moped/scrollable.rb'
47
59
 
48
60
  # Offense count: 1
49
- # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts.
61
+ # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
62
+ # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
50
63
  Style/FileName:
51
64
  Exclude:
52
65
  - 'lib/mongoid-scroll.rb'
53
66
 
54
- # Offense count: 2
67
+ # Offense count: 1
55
68
  # Configuration parameters: MinBodyLength.
56
69
  Style/GuardClause:
57
70
  Exclude:
58
- - 'lib/mongoid/criterion/scrollable.rb'
59
71
  - 'lib/moped/scrollable.rb'
60
72
 
61
- # Offense count: 7
73
+ # Offense count: 1
62
74
  # Cop supports --auto-correct.
63
75
  # Configuration parameters: SupportedStyles.
64
76
  # SupportedStyles: compact, exploded
65
77
  Style/RaiseArgs:
66
78
  EnforcedStyle: compact
67
-
68
- # Offense count: 1
69
- # Configuration parameters: SupportedStyles.
70
- # SupportedStyles: snake_case, normalcase, non_integer
71
- Style/VariableNumber:
72
- EnforcedStyle: normalcase
@@ -26,3 +26,10 @@ matrix:
26
26
  - bundle exec danger
27
27
 
28
28
  bundler_args: --without development
29
+
30
+ addons:
31
+ apt:
32
+ sources:
33
+ - mongodb-3.4-precise
34
+ packages:
35
+ - mongodb-org-server
@@ -1,50 +1,46 @@
1
- 0.3.5 (2016/09/27)
2
- ------------------
1
+ ### 0.3.6 (2018/05/01)
2
+
3
+ * [#18](https://github.com/mongoid/mongoid-scroll/pull/18): Fix mongoid scroll without block returning wrong criteria - [@asgerb](https://github.com/asgerb).
4
+ * [#15](https://github.com/mongoid/mongoid-scroll/pull/15): Use MongoDB 3.4 in testing and fix tests w/ WiredTiger storage engine - [@dblock](https://github.com/dblock).
5
+ * [#14](https://github.com/mongoid/mongoid-scroll/pull/14): Allow scrolling by foreign key - [@joeyAghion](https://github.com/joeyAghion).
6
+
7
+ ### 0.3.5 (2016/09/27)
3
8
 
4
9
  * [#11](https://github.com/mongoid/mongoid-scroll/pull/11): Compatibility with Mongoid 6 - [@dblock](https://github.com/dblock).
5
10
  * [#12](https://github.com/mongoid/mongoid-scroll/pull/12): Added Danger, PR linter - [@dblock](https://github.com/dblock).
6
11
 
7
- 0.3.4 (2015/10/22)
8
- ------------------
12
+ ### 0.3.4 (2015/10/22)
9
13
 
10
14
  * Added support for [mongo-ruby-driver](https://github.com/mongodb/mongo-ruby-driver), `Mongo::Collection::View` - [@dblock](https://github.com/dblock).
11
15
 
12
- 0.3.3 (2015/09/17)
13
- ------------------
16
+ ### 0.3.3 (2015/09/17)
14
17
 
15
18
  * Compatibility with Mongoid 5 - [@dblock](https://github.com/dblock).
16
19
 
17
- 0.3.2 (2015/8/8)
18
- ----------------
20
+ ### 0.3.2 (2015/8/8)
19
21
 
20
22
  * [#7](https://github.com/mongoid/mongoid-scroll/pull/7): Fix: pre-merge cursor criteria fields - [@sweir27](https://github.com/sweir27).
21
23
 
22
- 0.3.1 (2015/7/27)
23
- -----------------
24
+ ### 0.3.1 (2015/7/27)
24
25
 
25
26
  * Compatibility with Mongoid 5.x beta - [@dblock](https://github.com/dblock).
26
27
  * [#4](https://github.com/mongoid/mongoid-scroll/pull/4): Fix: support chaining `$or` criteria - [@sweir27](https://github.com/sweir27).
27
28
  * [#5](https://github.com/mongoid/mongoid-scroll/pull/5): Fix: embeddable objects now returned in pagination - [@sweir27](https://github.com/sweir27).
28
29
 
29
- 0.3.0 (2014/1/7)
30
- ----------------
30
+ ### 0.3.0 (2014/1/7)
31
31
 
32
32
  * Compatibility with Mongoid 4.x - [@dblock](https://github.com/dblock).
33
33
  * Implemeneted Rubocop, Ruby linter - [@dblock](https://github.com/dblock).
34
34
 
35
- 0.2.1 (2013/3/21)
36
- -----------------
35
+ ### 0.2.1 (2013/3/21)
37
36
 
38
37
  * Fix: scroll over a collection that has duplicate values while data is being modified in a way that causes a change in the natural sort order - [@dblock](https://github.com/dblock).
39
38
 
40
- 0.2.0 (2013/3/14)
41
- -----------------
39
+ ### 0.2.0 (2013/3/14)
42
40
 
43
41
  * Extended `Moped::Query` with `scroll` - [@dblock](https://github.com/dblock).
44
42
  * `Mongoid::Scroll::Cursor.from_record` can now be called with either a Mongoid field or `field_type` and `field_name` in the `options` hash - [@dblock](https://github.com/dblock).
45
43
 
46
- 0.1.0 (2013/2/14)
47
- -----------------
44
+ ### 0.1.0 (2013/2/14)
48
45
 
49
46
  * Initial public release, extends `Mongoid::Criteria` with `scroll` - [@dblock](https://github.com/dblock).
50
-
data/Gemfile CHANGED
@@ -5,6 +5,8 @@ gemspec
5
5
  case version = ENV['MONGOID_VERSION'] || '~> 6.0'
6
6
  when 'HEAD'
7
7
  gem 'mongoid', github: 'mongodb/mongoid'
8
+ when /7/
9
+ gem 'mongoid', github: 'mongodb/mongoid', branch: '7.0-dev'
8
10
  when /6/
9
11
  gem 'mongoid', '~> 6.0'
10
12
  when /5/
@@ -18,11 +20,12 @@ else
18
20
  end
19
21
 
20
22
  group :development, :test do
21
- gem 'rake'
22
23
  gem 'bundler'
23
- gem 'rspec', '~> 3.0'
24
- gem 'rspec-its'
24
+ gem 'database_cleaner'
25
25
  gem 'faker'
26
- gem 'rubocop', '0.43.0'
27
26
  gem 'mongoid-danger', '~> 0.1.0', require: false
27
+ gem 'rake'
28
+ gem 'rspec', '~> 3.0'
29
+ gem 'rspec-its'
30
+ gem 'rubocop', '0.49.1'
28
31
  end
@@ -1,7 +1,7 @@
1
1
  Releasing Mongoid::Scroll
2
2
  =========================
3
3
 
4
- There're no particular rules about when to release mongoid-scroll. Release bug fixes frequenty, features not so frequently and breaking API changes rarely.
4
+ There're no particular rules about when to release mongoid-scroll. Release bug fixes frequently, features not so frequently and breaking API changes rarely.
5
5
 
6
6
  ### Release
7
7
 
@@ -22,11 +22,10 @@ Increment the version, modify [lib/mongoid/scroll/version.rb](lib/mongoid/scroll
22
22
  Change "Next Release" in [CHANGELOG.md](CHANGELOG.md) to the new version.
23
23
 
24
24
  ```
25
- 0.4.0 (2014-01-27)
26
- ==================
25
+ ### 0.4.0 (2018/12/24)
27
26
  ```
28
27
 
29
- Remove the line with "Your contribution here.", since there will be no more contributions to this release.
28
+ Remove the line with "* Your contribution here.", since there will be no more contributions to this release.
30
29
 
31
30
  Commit your changes.
32
31
 
@@ -52,15 +51,14 @@ Pushed mongoid-scroll 0.4.0 to rubygems.org.
52
51
  Add the next release to [CHANGELOG.md](CHANGELOG.md).
53
52
 
54
53
  ```
55
- Next Release
56
- ============
54
+ ### Next Release
57
55
 
58
56
  * Your contribution here.
59
57
  ```
60
58
 
61
59
  Increment the minor version, modify [lib/mongoid-scroll/version.rb](lib/mongoid-scroll/version.rb).
62
60
 
63
- Comit your changes.
61
+ Commit your changes.
64
62
 
65
63
  ```
66
64
  git add CHANGELOG.md lib/mongoid-scroll/version.rb
data/Rakefile CHANGED
@@ -24,4 +24,4 @@ task :spec
24
24
  require 'rubocop/rake_task'
25
25
  RuboCop::RakeTask.new(:rubocop)
26
26
 
27
- task default: [:rubocop, :spec]
27
+ task default: %i[rubocop spec]
@@ -9,4 +9,4 @@ require 'mongoid/scroll/errors'
9
9
  require 'mongoid/scroll/cursor'
10
10
  require 'moped/scrollable' if Object.const_defined?(:Moped)
11
11
  require 'mongo/scrollable' if Object.const_defined?(:Mongo)
12
- require 'mongoid/criterion/scrollable'
12
+ require 'mongoid/criteria/scrollable'
@@ -0,0 +1,81 @@
1
+ module Mongoid
2
+ class Criteria
3
+ module Scrollable
4
+ def scroll(cursor = nil, &_block)
5
+ raise_multiple_sort_fields_error if multiple_sort_fields?
6
+ criteria = dup
7
+ criteria.merge!(default_sort) if no_sort_option?
8
+ cursor_options = build_cursor_options(criteria)
9
+ cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : new_cursor(cursor, cursor_options)
10
+ cursor_criteria = build_cursor_criteria(criteria, cursor)
11
+ if block_given?
12
+ cursor_criteria.order_by(_id: scroll_direction(criteria)).each do |record|
13
+ yield record, cursor_from_record(record, cursor_options)
14
+ end
15
+ else
16
+ cursor_criteria
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def raise_multiple_sort_fields_error
23
+ raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: criteria.options.sort)
24
+ end
25
+
26
+ def multiple_sort_fields?
27
+ options.sort && options.sort.keys.size != 1
28
+ end
29
+
30
+ def no_sort_option?
31
+ options.sort.blank? || options.sort.empty?
32
+ end
33
+
34
+ def default_sort
35
+ asc(:_id)
36
+ end
37
+
38
+ def scroll_field(criteria)
39
+ criteria.options.sort.keys.first
40
+ end
41
+
42
+ def scroll_direction(criteria)
43
+ criteria.options.sort.values.first.to_i
44
+ end
45
+
46
+ def build_cursor_options(criteria)
47
+ {
48
+ field_type: scroll_field_type(criteria),
49
+ field_name: scroll_field(criteria),
50
+ direction: scroll_direction(criteria)
51
+ }
52
+ end
53
+
54
+ def new_cursor(cursor, cursor_options)
55
+ Mongoid::Scroll::Cursor.new(cursor, cursor_options)
56
+ end
57
+
58
+ def build_cursor_criteria(criteria, cursor)
59
+ cursor_criteria = criteria.dup
60
+ cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
61
+ cursor_criteria
62
+ end
63
+
64
+ def cursor_from_record(record, cursor_options)
65
+ Mongoid::Scroll::Cursor.from_record(record, cursor_options)
66
+ end
67
+
68
+ def scroll_field_type(criteria)
69
+ scroll_field = scroll_field(criteria)
70
+ field = criteria.klass.fields[scroll_field.to_s]
71
+ field.foreign_key? && field.object_id_field? ? bson_type : field.type
72
+ end
73
+
74
+ def bson_type
75
+ Mongoid::Compatibility::Version.mongoid3? ? Moped::BSON::ObjectId : BSON::ObjectId
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ Mongoid::Criteria.send(:include, Mongoid::Criteria::Scrollable)
@@ -14,7 +14,7 @@ module Mongoid
14
14
  compare_direction = direction == 1 ? '$gt' : '$lt'
15
15
  cursor_criteria = { field_name => { compare_direction => mongo_value } } if mongo_value
16
16
  tiebreak_criteria = { field_name => mongo_value, :_id => { compare_direction => tiebreak_id } } if mongo_value && tiebreak_id
17
- cursor_selector = if Mongoid::Compatibility::Version.mongoid6?
17
+ cursor_selector = if Mongoid::Compatibility::Version.mongoid6? || Mongoid::Compatibility::Version.mongoid7?
18
18
  Mongoid::Criteria::Queryable::Selector.new
19
19
  else
20
20
  Origin::Selector.new
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Scroll
3
- VERSION = '0.3.5'.freeze
3
+ VERSION = '0.3.6'.freeze
4
4
  end
5
5
  end
@@ -1,124 +1,126 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Mongo::Collection::View do
4
- context 'scrollable' do
5
- subject do
6
- Mongoid.default_client['feed_items'].find
7
- end
8
- it ':scroll' do
9
- expect(subject).to respond_to(:scroll)
10
- end
11
- end
12
- context 'with multiple sort fields' do
13
- subject do
14
- Mongoid.default_client['feed_items'].find.sort(name: 1, value: -1)
15
- end
16
- it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
17
- expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
18
- /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
19
- end
20
- end
21
- context 'with no sort' do
22
- subject do
23
- Mongoid.default_client['feed_items'].find
3
+ if Object.const_defined?(:Mongo)
4
+ describe Mongo::Collection::View do
5
+ context 'scrollable' do
6
+ subject do
7
+ Mongoid.default_client['feed_items'].find
8
+ end
9
+ it ':scroll' do
10
+ expect(subject).to respond_to(:scroll)
11
+ end
24
12
  end
25
- it 'adds a default sort by _id' do
26
- expect(subject.scroll.sort).to eq('_id' => 1)
13
+ context 'with multiple sort fields' do
14
+ subject do
15
+ Mongoid.default_client['feed_items'].find.sort(name: 1, value: -1)
16
+ end
17
+ it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
18
+ expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
19
+ /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
20
+ end
27
21
  end
28
- end
29
- context 'with data' do
30
- before :each do
31
- 10.times do |i|
32
- Mongoid.default_client['feed_items'].insert_one(
33
- a_string: i.to_s,
34
- a_integer: i,
35
- a_datetime: DateTime.mongoize(DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC')),
36
- a_date: Date.mongoize(Date.new(2013, i + 1, 21)),
37
- a_time: Time.mongoize(Time.at(Time.now.to_i + i))
38
- )
22
+ context 'with no sort' do
23
+ subject do
24
+ Mongoid.default_client['feed_items'].find
25
+ end
26
+ it 'adds a default sort by _id' do
27
+ expect(subject.scroll.sort).to eq('_id' => 1)
39
28
  end
40
29
  end
41
- context 'default' do
42
- it 'scrolls all' do
43
- records = []
44
- Mongoid.default_client['feed_items'].find.scroll do |record, _next_cursor|
45
- records << record
30
+ context 'with data' do
31
+ before :each do
32
+ 10.times do |i|
33
+ Mongoid.default_client['feed_items'].insert_one(
34
+ a_string: i.to_s,
35
+ a_integer: i,
36
+ a_datetime: DateTime.mongoize(DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC')),
37
+ a_date: Date.mongoize(Date.new(2013, i + 1, 21)),
38
+ a_time: Time.mongoize(Time.at(Time.now.to_i + i))
39
+ )
46
40
  end
47
- expect(records.size).to eq 10
48
- expect(records).to eq Mongoid.default_client['feed_items'].find.to_a
49
41
  end
50
- end
51
- { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
52
- context field_type do
53
- it 'scrolls all with a block' do
42
+ context 'default' do
43
+ it 'scrolls all' do
54
44
  records = []
55
- Mongoid.default_client['feed_items'].find.sort(field_name => 1).scroll(nil, field_type: field_type) do |record, _next_cursor|
45
+ Mongoid.default_client['feed_items'].find.scroll do |record, _next_cursor|
56
46
  records << record
57
47
  end
58
48
  expect(records.size).to eq 10
59
49
  expect(records).to eq Mongoid.default_client['feed_items'].find.to_a
60
50
  end
61
- it 'scrolls all with a break' do
51
+ end
52
+ { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
53
+ context field_type do
54
+ it 'scrolls all with a block' do
55
+ records = []
56
+ Mongoid.default_client['feed_items'].find.sort(field_name => 1).scroll(nil, field_type: field_type) do |record, _next_cursor|
57
+ records << record
58
+ end
59
+ expect(records.size).to eq 10
60
+ expect(records).to eq Mongoid.default_client['feed_items'].find.to_a
61
+ end
62
+ it 'scrolls all with a break' do
63
+ records = []
64
+ cursor = nil
65
+ Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(5).scroll(nil, field_type: field_type) do |record, next_cursor|
66
+ records << record
67
+ cursor = next_cursor
68
+ end
69
+ expect(records.size).to eq 5
70
+ Mongoid.default_client['feed_items'].find.sort(field_name => 1).scroll(cursor, field_type: field_type) do |record, next_cursor|
71
+ records << record
72
+ cursor = next_cursor
73
+ end
74
+ expect(records.size).to eq 10
75
+ expect(records).to eq Mongoid.default_client['feed_items'].find.to_a
76
+ end
77
+ it 'scrolls in descending order' do
78
+ records = []
79
+ Mongoid.default_client['feed_items'].find.sort(field_name => -1).limit(3).scroll(nil, field_type: field_type, field_name: field_name) do |record, _next_cursor|
80
+ records << record
81
+ end
82
+ expect(records.size).to eq 3
83
+ expect(records).to eq Mongoid.default_client['feed_items'].find.sort(field_name => -1).limit(3).to_a
84
+ end
85
+ it 'map' do
86
+ record = Mongoid.default_client['feed_items'].find.limit(3).scroll(nil, field_type: field_type, field_name: field_name).map { |r| r }.last
87
+ cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
88
+ expect(cursor).to_not be nil
89
+ expect(cursor.to_s.split(':')).to eq [
90
+ Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record[field_name.to_s]).to_s,
91
+ record['_id'].to_s
92
+ ]
93
+ end
94
+ end
95
+ end
96
+ end
97
+ context 'with overlapping data', if: MongoDB.mmapv1? do
98
+ before :each do
99
+ 3.times { Feed::Item.create! a_integer: 5 }
100
+ Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
101
+ end
102
+ it 'natural order is different from order by id' do
103
+ # natural order isn't necessarily going to be the same as _id order
104
+ # if a document is updated and grows in size, it may need to be relocated and
105
+ # thus cause the natural order to change
106
+ expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq Feed::Item.order_by(_id: 1).to_a
107
+ end
108
+ [{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
109
+ it "scrolls by #{sort_order}" do
62
110
  records = []
63
111
  cursor = nil
64
- Mongoid.default_client['feed_items'].find.sort(field_name => 1).limit(5).scroll(nil, field_type: field_type) do |record, next_cursor|
112
+ Mongoid.default_client['feed_items'].find.sort(sort_order).limit(2).scroll do |record, next_cursor|
65
113
  records << record
66
114
  cursor = next_cursor
67
115
  end
68
- expect(records.size).to eq 5
69
- Mongoid.default_client['feed_items'].find.sort(field_name => 1).scroll(cursor, field_type: field_type) do |record, next_cursor|
70
- records << record
71
- cursor = next_cursor
72
- end
73
- expect(records.size).to eq 10
74
- expect(records).to eq Mongoid.default_client['feed_items'].find.to_a
75
- end
76
- it 'scrolls in descending order' do
77
- records = []
78
- Mongoid.default_client['feed_items'].find.sort(field_name => -1).limit(3).scroll(nil, field_type: field_type, field_name: field_name) do |record, _next_cursor|
116
+ expect(records.size).to eq 2
117
+ Mongoid.default_client['feed_items'].find.sort(sort_order).scroll(cursor) do |record, _next_cursor|
79
118
  records << record
80
119
  end
81
120
  expect(records.size).to eq 3
82
- expect(records).to eq Mongoid.default_client['feed_items'].find.sort(field_name => -1).limit(3).to_a
83
- end
84
- it 'map' do
85
- record = Mongoid.default_client['feed_items'].find.limit(3).scroll(nil, field_type: field_type, field_name: field_name).map { |r| r }.last
86
- cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
87
- expect(cursor).to_not be nil
88
- expect(cursor.to_s.split(':')).to eq [
89
- Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record[field_name.to_s]).to_s,
90
- record['_id'].to_s
91
- ]
92
- end
93
- end
94
- end
95
- end
96
- context 'with overlapping data' do
97
- before :each do
98
- 3.times { Feed::Item.create! a_integer: 5 }
99
- Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
100
- end
101
- it 'natural order is different from order by id' do
102
- # natural order isn't necessarily going to be the same as _id order
103
- # if a document is updated and grows in size, it may need to be relocated and
104
- # thus cause the natural order to change
105
- expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq Feed::Item.order_by(_id: 1).to_a
106
- end
107
- [{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
108
- it "scrolls by #{sort_order}" do
109
- records = []
110
- cursor = nil
111
- Mongoid.default_client['feed_items'].find.sort(sort_order).limit(2).scroll do |record, next_cursor|
112
- records << record
113
- cursor = next_cursor
114
- end
115
- expect(records.size).to eq 2
116
- Mongoid.default_client['feed_items'].find.sort(sort_order).scroll(cursor) do |record, _next_cursor|
117
- records << record
121
+ expect(records).to eq Mongoid.default_client['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
118
122
  end
119
- expect(records.size).to eq 3
120
- expect(records).to eq Mongoid.default_client['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
121
123
  end
122
124
  end
123
125
  end
124
- end if Object.const_defined?(:Mongo)
126
+ end
@@ -13,6 +13,7 @@ describe Mongoid::Criteria do
13
13
  /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
14
14
  end
15
15
  end
16
+
16
17
  context 'with no sort' do
17
18
  subject do
18
19
  Feed::Item.all
@@ -42,7 +43,30 @@ describe Mongoid::Criteria do
42
43
  expect(records.size).to eq 10
43
44
  expect(records).to eq Feed::Item.all.to_a
44
45
  end
46
+ it 'does not change original criteria' do
47
+ criteria = Feed::Item.where(:a_time.gt => Time.new(2013, 7, 22, 1, 2, 3))
48
+ original_criteria = criteria.dup
49
+ criteria.limit(2).scroll
50
+ expect(criteria).to eq original_criteria
51
+ cursor = nil
52
+ criteria.limit(2).scroll(cursor) do |_record, next_cursor|
53
+ cursor = next_cursor
54
+ end
55
+ criteria.scroll(cursor) do |_record, next_cursor|
56
+ cursor = next_cursor
57
+ end
58
+ expect(criteria).to eq original_criteria
59
+ end
45
60
  end
61
+
62
+ context 'with a foreign key' do
63
+ it 'sorts by object id' do
64
+ records = []
65
+ Feed::Item.asc('publisher_id').scroll { |r, _| records << r }
66
+ expect(records).not_to be_empty
67
+ end
68
+ end
69
+
46
70
  { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
47
71
  context field_type do
48
72
  it 'scrolls all with a block' do
@@ -68,6 +92,17 @@ describe Mongoid::Criteria do
68
92
  expect(records.size).to eq 10
69
93
  expect(records).to eq Feed::Item.all.to_a
70
94
  end
95
+ it 'scrolls from a cursor' do
96
+ last_record = nil
97
+ cursor = nil
98
+ Feed::Item.asc(field_name).limit(5).scroll do |record, next_cursor|
99
+ last_record = record
100
+ cursor = next_cursor
101
+ end
102
+ sixth_item = Feed::Item.asc(field_name).to_a[5]
103
+ from_item = Feed::Item.asc(field_name).scroll(cursor).to_a.first
104
+ expect(from_item).to eq sixth_item
105
+ end
71
106
  it 'scrolls in descending order' do
72
107
  records = []
73
108
  Feed::Item.desc(field_name).limit(3).scroll do |record, _next_cursor|
@@ -160,7 +195,7 @@ describe Mongoid::Criteria do
160
195
  expect(records.map(&:name)).to eq ['embedded']
161
196
  end
162
197
  end
163
- context 'with overlapping data' do
198
+ context 'with overlapping data', if: MongoDB.mmapv1? do
164
199
  before :each do
165
200
  3.times { Feed::Item.create! a_integer: 5 }
166
201
  Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
@@ -124,7 +124,7 @@ describe Mongoid::Scroll::Cursor do
124
124
  end
125
125
  end
126
126
  context 'an array field cursor' do
127
- let(:feed_item) { Feed::Item.create!(a_array: %w(x y)) }
127
+ let(:feed_item) { Feed::Item.create!(a_array: %w[x y]) }
128
128
  it 'is not supported' do
129
129
  expect do
130
130
  Mongoid::Scroll::Cursor.from_record feed_item, field_name: 'a_array', field_type: Array
@@ -1,124 +1,126 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Moped::Query do
4
- context 'scrollable' do
5
- subject do
6
- Mongoid.default_session['feed_items'].find
7
- end
8
- it ':scroll' do
9
- expect(subject).to respond_to(:scroll)
10
- end
11
- end
12
- context 'with multiple sort fields' do
13
- subject do
14
- Mongoid.default_session['feed_items'].find.sort(name: 1, value: -1)
15
- end
16
- it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
17
- expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
18
- /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
19
- end
20
- end
21
- context 'with no sort' do
22
- subject do
23
- Mongoid.default_session['feed_items'].find
3
+ if Object.const_defined?(:Moped)
4
+ describe Moped::Query do
5
+ context 'scrollable' do
6
+ subject do
7
+ Mongoid.default_session['feed_items'].find
8
+ end
9
+ it ':scroll' do
10
+ expect(subject).to respond_to(:scroll)
11
+ end
24
12
  end
25
- it 'adds a default sort by _id' do
26
- expect(subject.scroll.operation.selector['$orderby']).to eq(_id: 1)
13
+ context 'with multiple sort fields' do
14
+ subject do
15
+ Mongoid.default_session['feed_items'].find.sort(name: 1, value: -1)
16
+ end
17
+ it 'raises Mongoid::Scroll::Errors::MultipleSortFieldsError' do
18
+ expect { subject.scroll }.to raise_error Mongoid::Scroll::Errors::MultipleSortFieldsError,
19
+ /You're attempting to scroll over data with a sort order that includes multiple fields: name, value./
20
+ end
27
21
  end
28
- end
29
- context 'with data' do
30
- before :each do
31
- 10.times do |i|
32
- Mongoid.default_session['feed_items'].insert(
33
- a_string: i.to_s,
34
- a_integer: i,
35
- a_datetime: DateTime.mongoize(DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC')),
36
- a_date: Date.mongoize(Date.new(2013, i + 1, 21)),
37
- a_time: Time.mongoize(Time.at(Time.now.to_i + i))
38
- )
22
+ context 'with no sort' do
23
+ subject do
24
+ Mongoid.default_session['feed_items'].find
25
+ end
26
+ it 'adds a default sort by _id' do
27
+ expect(subject.scroll.operation.selector['$orderby']).to eq(_id: 1)
39
28
  end
40
29
  end
41
- context 'default' do
42
- it 'scrolls all' do
43
- records = []
44
- Mongoid.default_session['feed_items'].find.scroll do |record, _next_cursor|
45
- records << record
30
+ context 'with data' do
31
+ before :each do
32
+ 10.times do |i|
33
+ Mongoid.default_session['feed_items'].insert(
34
+ a_string: i.to_s,
35
+ a_integer: i,
36
+ a_datetime: DateTime.mongoize(DateTime.new(2013, i + 1, 21, 1, 42, 3, 'UTC')),
37
+ a_date: Date.mongoize(Date.new(2013, i + 1, 21)),
38
+ a_time: Time.mongoize(Time.at(Time.now.to_i + i))
39
+ )
46
40
  end
47
- expect(records.size).to eq 10
48
- expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
49
41
  end
50
- end
51
- { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
52
- context field_type do
53
- it 'scrolls all with a block' do
42
+ context 'default' do
43
+ it 'scrolls all' do
54
44
  records = []
55
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(nil, field_type: field_type) do |record, _next_cursor|
45
+ Mongoid.default_session['feed_items'].find.scroll do |record, _next_cursor|
56
46
  records << record
57
47
  end
58
48
  expect(records.size).to eq 10
59
49
  expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
60
50
  end
61
- it 'scrolls all with a break' do
51
+ end
52
+ { a_string: String, a_integer: Integer, a_date: Date, a_datetime: DateTime }.each_pair do |field_name, field_type|
53
+ context field_type do
54
+ it 'scrolls all with a block' do
55
+ records = []
56
+ Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(nil, field_type: field_type) do |record, _next_cursor|
57
+ records << record
58
+ end
59
+ expect(records.size).to eq 10
60
+ expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
61
+ end
62
+ it 'scrolls all with a break' do
63
+ records = []
64
+ cursor = nil
65
+ Mongoid.default_session['feed_items'].find.sort(field_name => 1).limit(5).scroll(nil, field_type: field_type) do |record, next_cursor|
66
+ records << record
67
+ cursor = next_cursor
68
+ end
69
+ expect(records.size).to eq 5
70
+ Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(cursor, field_type: field_type) do |record, next_cursor|
71
+ records << record
72
+ cursor = next_cursor
73
+ end
74
+ expect(records.size).to eq 10
75
+ expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
76
+ end
77
+ it 'scrolls in descending order' do
78
+ records = []
79
+ Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).scroll(nil, field_type: field_type, field_name: field_name) do |record, _next_cursor|
80
+ records << record
81
+ end
82
+ expect(records.size).to eq 3
83
+ expect(records).to eq Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).to_a
84
+ end
85
+ it 'map' do
86
+ record = Mongoid.default_session['feed_items'].find.limit(3).scroll(nil, field_type: field_type, field_name: field_name).map { |r| r }.last
87
+ cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
88
+ expect(cursor).to_not be nil
89
+ expect(cursor.to_s.split(':')).to eq [
90
+ Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record[field_name.to_s]).to_s,
91
+ record['_id'].to_s
92
+ ]
93
+ end
94
+ end
95
+ end
96
+ end
97
+ context 'with overlapping data', if: MongoDB.mmapv1? do
98
+ before :each do
99
+ 3.times { Feed::Item.create! a_integer: 5 }
100
+ Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
101
+ end
102
+ it 'natural order is different from order by id' do
103
+ # natural order isn't necessarily going to be the same as _id order
104
+ # if a document is updated and grows in size, it may need to be relocated and
105
+ # thus cause the natural order to change
106
+ expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq Feed::Item.order_by(_id: 1).to_a
107
+ end
108
+ [{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
109
+ it "scrolls by #{sort_order}" do
62
110
  records = []
63
111
  cursor = nil
64
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).limit(5).scroll(nil, field_type: field_type) do |record, next_cursor|
112
+ Mongoid.default_session['feed_items'].find.sort(sort_order).limit(2).scroll do |record, next_cursor|
65
113
  records << record
66
114
  cursor = next_cursor
67
115
  end
68
- expect(records.size).to eq 5
69
- Mongoid.default_session['feed_items'].find.sort(field_name => 1).scroll(cursor, field_type: field_type) do |record, next_cursor|
70
- records << record
71
- cursor = next_cursor
72
- end
73
- expect(records.size).to eq 10
74
- expect(records).to eq Mongoid.default_session['feed_items'].find.to_a
75
- end
76
- it 'scrolls in descending order' do
77
- records = []
78
- Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).scroll(nil, field_type: field_type, field_name: field_name) do |record, _next_cursor|
116
+ expect(records.size).to eq 2
117
+ Mongoid.default_session['feed_items'].find.sort(sort_order).scroll(cursor) do |record, _next_cursor|
79
118
  records << record
80
119
  end
81
120
  expect(records.size).to eq 3
82
- expect(records).to eq Mongoid.default_session['feed_items'].find.sort(field_name => -1).limit(3).to_a
83
- end
84
- it 'map' do
85
- record = Mongoid.default_session['feed_items'].find.limit(3).scroll(nil, field_type: field_type, field_name: field_name).map { |r| r }.last
86
- cursor = Mongoid::Scroll::Cursor.from_record(record, field_type: field_type, field_name: field_name)
87
- expect(cursor).to_not be nil
88
- expect(cursor.to_s.split(':')).to eq [
89
- Mongoid::Scroll::Cursor.transform_field_value(field_type, field_name, record[field_name.to_s]).to_s,
90
- record['_id'].to_s
91
- ]
92
- end
93
- end
94
- end
95
- end
96
- context 'with overlapping data' do
97
- before :each do
98
- 3.times { Feed::Item.create! a_integer: 5 }
99
- Feed::Item.first.update_attributes!(name: Array(1000).join('a'))
100
- end
101
- it 'natural order is different from order by id' do
102
- # natural order isn't necessarily going to be the same as _id order
103
- # if a document is updated and grows in size, it may need to be relocated and
104
- # thus cause the natural order to change
105
- expect(Feed::Item.order_by('$natural' => 1).to_a).to_not eq Feed::Item.order_by(_id: 1).to_a
106
- end
107
- [{ a_integer: 1 }, { a_integer: -1 }].each do |sort_order|
108
- it "scrolls by #{sort_order}" do
109
- records = []
110
- cursor = nil
111
- Mongoid.default_session['feed_items'].find.sort(sort_order).limit(2).scroll do |record, next_cursor|
112
- records << record
113
- cursor = next_cursor
114
- end
115
- expect(records.size).to eq 2
116
- Mongoid.default_session['feed_items'].find.sort(sort_order).scroll(cursor) do |record, _next_cursor|
117
- records << record
121
+ expect(records).to eq Mongoid.default_session['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
118
122
  end
119
- expect(records.size).to eq 3
120
- expect(records).to eq Mongoid.default_session['feed_items'].find.sort(sort_order.merge(_id: sort_order[:a_integer])).to_a
121
123
  end
122
124
  end
123
125
  end
124
- end if Object.const_defined?(:Moped)
126
+ end
@@ -4,6 +4,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
4
  require 'rubygems'
5
5
  require 'rspec'
6
6
  require 'rspec/its'
7
+ require 'database_cleaner'
7
8
  require 'mongoid-scroll'
8
9
 
9
10
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
@@ -17,9 +18,9 @@ end
17
18
  RSpec.configure do |config|
18
19
  config.before :all do
19
20
  Mongoid.logger.level = Logger::INFO
20
- Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5?
21
+ Mongo::Logger.logger.level = Logger::INFO if Mongoid::Compatibility::Version.mongoid5? || Mongoid::Compatibility::Version.mongoid6?
21
22
  end
22
23
  config.before :each do
23
- Mongoid.purge!
24
+ DatabaseCleaner.clean
24
25
  end
25
26
  end
@@ -10,6 +10,10 @@ module Feed
10
10
  field :a_time, type: Time
11
11
  field :a_array, type: Array
12
12
 
13
- embeds_many :embedded_items
13
+ embeds_many :embedded_items, class_name: 'Feed::EmbeddedItem'
14
+
15
+ publisher_options = { class_name: 'Feed::Publisher' }
16
+ publisher_options[:optional] = true if Mongoid::Compatibility::Version.mongoid6? || Mongoid::Compatibility::Version.mongoid7?
17
+ belongs_to :publisher, publisher_options
14
18
  end
15
19
  end
@@ -0,0 +1,9 @@
1
+ module Feed
2
+ class Publisher
3
+ include Mongoid::Document
4
+
5
+ field :name, type: String
6
+
7
+ has_many :items
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module MongoDB
2
+ def self.mmapv1?
3
+ if Mongoid.respond_to?(:default_session)
4
+ Mongoid.default_session.command(serverStatus: 1)['storageEngine']['name'] == 'mmapv1'
5
+ else
6
+ Mongoid.default_client.command(serverStatus: 1).first['storageEngine']['name'] == 'mmapv1'
7
+ end
8
+ end
9
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-scroll
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Doubrovkine
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-09-27 00:00:00.000000000 Z
12
+ date: 2018-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongoid
@@ -77,7 +77,7 @@ files:
77
77
  - lib/config/locales/en.yml
78
78
  - lib/mongo/scrollable.rb
79
79
  - lib/mongoid-scroll.rb
80
- - lib/mongoid/criterion/scrollable.rb
80
+ - lib/mongoid/criteria/scrollable.rb
81
81
  - lib/mongoid/scroll/cursor.rb
82
82
  - lib/mongoid/scroll/errors.rb
83
83
  - lib/mongoid/scroll/errors/base.rb
@@ -97,6 +97,8 @@ files:
97
97
  - spec/spec_helper.rb
98
98
  - spec/support/feed/embedded_item.rb
99
99
  - spec/support/feed/item.rb
100
+ - spec/support/feed/publisher.rb
101
+ - spec/support/mongodb.rb
100
102
  homepage: http://github.com/mongoid/mongoid-scroll
101
103
  licenses:
102
104
  - MIT
@@ -117,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
119
  version: 1.3.6
118
120
  requirements: []
119
121
  rubyforge_project:
120
- rubygems_version: 2.5.1
122
+ rubygems_version: 2.6.12
121
123
  signing_key:
122
124
  specification_version: 4
123
125
  summary: Mongoid extensions to enable infinite scroll.
@@ -1,35 +0,0 @@
1
- module Mongoid
2
- module Criterion
3
- module Scrollable
4
- def scroll(cursor = nil, &_block)
5
- criteria = self
6
- # we don't support scrolling over a criteria with multiple fields
7
- if criteria.options[:sort] && criteria.options[:sort].keys.size != 1
8
- raise Mongoid::Scroll::Errors::MultipleSortFieldsError.new(sort: criteria.options[:sort])
9
- elsif !criteria.options.key?(:sort) || criteria.options[:sort].empty?
10
- # introduce a default sort order if there's none
11
- criteria = criteria.asc(:_id)
12
- end
13
- # scroll field and direction
14
- scroll_field = criteria.options[:sort].keys.first
15
- scroll_direction = criteria.options[:sort].values.first.to_i
16
- # scroll cursor from the parameter, with value and tiebreak_id
17
- field = criteria.klass.fields[scroll_field.to_s]
18
- cursor_options = { field_type: field.type, field_name: scroll_field, direction: scroll_direction }
19
- cursor = cursor.is_a?(Mongoid::Scroll::Cursor) ? cursor : Mongoid::Scroll::Cursor.new(cursor, cursor_options)
20
- # scroll
21
- if block_given?
22
- cursor_criteria = criteria.dup
23
- cursor_criteria.selector = { '$and' => [criteria.selector, cursor.criteria] }
24
- cursor_criteria.order_by(_id: scroll_direction).each do |record|
25
- yield record, Mongoid::Scroll::Cursor.from_record(record, cursor_options)
26
- end
27
- else
28
- criteria
29
- end
30
- end
31
- end
32
- end
33
- end
34
-
35
- Mongoid::Criteria.send(:include, Mongoid::Criterion::Scrollable)