occams-record 1.0.0.rc9 → 1.0.0.rc10

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
  SHA256:
3
- metadata.gz: dffcac805f1cbe701d082c2b965aeaa98c89c289fbb1d5bf3e164e5ce5ad8af1
4
- data.tar.gz: a94cda603a6c408c77f751e2d9358a1f52decb34464bbd8967af9f16fd978712
3
+ metadata.gz: c0cdafe04c023de8a937ebef5fb1c274459e11b10c06f7fec38cf5632b93c969
4
+ data.tar.gz: f98a82b06655ddaf71bcc68f171b3aa077b08f64bdfca9f35725e8fe2ad0c4f3
5
5
  SHA512:
6
- metadata.gz: afeb27a07b31d12257161618ea4d9a17088963014d354691de035b3e0e423d7f8d5d1c62991f4c9256282ec7ab4afecf32806ba4f56182cdb9d36a91e4436bf0
7
- data.tar.gz: aecefa1ddbcb7179b5b24805d1ffcadbd71a25a1f4888c8bb89a433f7900f39dd576885a4e85e33502f568cef82b9da04eccdcaa3f4d9c44964ac59631595442
6
+ metadata.gz: dfe0c1a6f0c18be9e37c17b5928a4911e62615cc95e5399b3d181b75d769bdf803c13823773d285daab4602f526c397d15f3d0f9dfa62fa9970539e07028a9e7
7
+ data.tar.gz: e606aee2bae1577a3d77649979efa76c32b30b40614d0bbd4acb5f19ea1f453c16175e466a9afbad6997112c1cb12a64b6b890dd929cafbee039d2e1cbdb665d
data/README.md CHANGED
@@ -55,9 +55,9 @@ orders = OccamsRecord.
55
55
  run
56
56
  ````
57
57
 
58
- `each`, `map`, `reduce`, and other Enumerable methods may be used instead of *run*. `find_each` and `find_in_batches` are also supported. Occams Record has great support for raw SQL queries too, but we'll get to those later.
58
+ `each`, `map`, `reduce`, and other Enumerable methods may be used instead of *run*. `find_each` and `find_in_batches` are also supported, and unlike in ActiveRecord, `ORDER BY` works as you'd expect.
59
59
 
60
- NOTE Unlike in Active Record, `find_each` and `find_in_batches` respect *ORDER BY*. However, to ensure consistency, it's strongly recomended to use `find_each`/`find_in_batches` inside of a transaction.
60
+ Occams Record has great support for raw SQL queries too, but we'll get to those later.
61
61
 
62
62
  ## Basic eager loading
63
63
 
@@ -4,22 +4,21 @@ module OccamsRecord
4
4
  #
5
5
  module Batches
6
6
  #
7
- # Load records in batches of N and yield each record to a block if given.
8
- # If no block is given, returns an Enumerator.
7
+ # Load records in batches of N and yield each record to a block if given. If no block is given,
8
+ # returns an Enumerator.
9
9
  #
10
- # NOTE Unlike ActiveRecord's find_each, order is respected. The primary key will be appended
11
- # to the ORDER BY clause to help ensure consistent batches. HOWEVER, it's still possible for
12
- # batches to be "corrupted" (miss records or repeat records) if table data changes out from
13
- # enderneath them. To prevent this, it's strongly recomended to always run find_each inside
10
+ # NOTE Unlike ActiveRecord's find_each, ORDER BY is respected. The primary key will be appended
11
+ # to the ORDER BY clause to help ensure consistent batches. Additionally, it will be run inside
14
12
  # of a transaction.
15
13
  #
16
14
  # @param batch_size [Integer]
15
+ # @param use_transaction [Boolean] Ensure it runs inside of a database transaction
17
16
  # @yield [OccamsRecord::Results::Row]
18
17
  # @return [Enumerator] will yield each record
19
18
  #
20
- def find_each(batch_size: 1000)
19
+ def find_each(batch_size: 1000, use_transaction: true)
21
20
  enum = Enumerator.new { |y|
22
- batches(of: batch_size).each { |batch|
21
+ batches(of: batch_size, use_transaction: use_transaction).each { |batch|
23
22
  batch.each { |record| y.yield record }
24
23
  }
25
24
  }
@@ -34,18 +33,17 @@ module OccamsRecord
34
33
  # Load records in batches of N and yield each batch to a block if given.
35
34
  # If no block is given, returns an Enumerator.
36
35
  #
37
- # NOTE Unlike ActiveRecord's find_in_batches, order is respected. The primary key will be appended
38
- # to the ORDER BY clause to help ensure consistent batches. HOWEVER, it's still possible for
39
- # batches to be "corrupted" (miss records or repeat records) if table data changes out from
40
- # enderneath them. To prevent this, it's strongly recomended to always run find_in_batches inside
36
+ # NOTE Unlike ActiveRecord's find_each, ORDER BY is respected. The primary key will be appended
37
+ # to the ORDER BY clause to help ensure consistent batches. Additionally, it will be run inside
41
38
  # of a transaction.
42
39
  #
43
40
  # @param batch_size [Integer]
41
+ # @param use_transaction [Boolean] Ensure it runs inside of a database transaction
44
42
  # @yield [OccamsRecord::Results::Row]
45
43
  # @return [Enumerator] will yield each batch
46
44
  #
47
- def find_in_batches(batch_size: 1000)
48
- enum = batches(of: batch_size)
45
+ def find_in_batches(batch_size: 1000, use_transaction: true)
46
+ enum = batches(of: batch_size, use_transaction: use_transaction)
49
47
  if block_given?
50
48
  enum.each { |batch| yield batch }
51
49
  else
@@ -62,29 +60,37 @@ module OccamsRecord
62
60
  # whereas this does.
63
61
  #
64
62
  # @param of [Integer] batch size
63
+ # @param use_transaction [Boolean] Ensure it runs inside of a database transaction
65
64
  # @return [Enumerator] yields batches
66
65
  #
67
- def batches(of:)
68
- if model.connection.open_transactions == 0
69
- $stderr.puts "Occams Record Warning: find_each or find_in_batches is being run outside of transaction. Batch consistency can only be ensured within a transaction."
66
+ def batches(of:, use_transaction: true)
67
+ Enumerator.new do |y|
68
+ if use_transaction and model.connection.open_transactions == 0
69
+ model.connection.transaction {
70
+ run_batches y, of
71
+ }
72
+ else
73
+ run_batches y, of
74
+ end
70
75
  end
76
+ end
71
77
 
78
+ def run_batches(y, of)
72
79
  limit = scope.limit_value
73
80
  batch_size = limit && limit < of ? limit : of
74
- Enumerator.new do |y|
75
- offset = scope.offset_value || 0
76
- out_of_records, count = false, 0
77
81
 
78
- until out_of_records
79
- l = limit && batch_size > limit - count ? limit - count : batch_size
80
- q = scope.order(model.primary_key.to_sym).offset(offset).limit(l)
81
- results = Query.new(q, use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders).run
82
+ offset = scope.offset_value || 0
83
+ out_of_records, count = false, 0
82
84
 
83
- y.yield results if results.any?
84
- count += results.size
85
- offset += results.size
86
- out_of_records = results.size < batch_size || (limit && count >= limit)
87
- end
85
+ until out_of_records
86
+ l = limit && batch_size > limit - count ? limit - count : batch_size
87
+ q = scope.order(model.primary_key.to_sym).offset(offset).limit(l)
88
+ results = Query.new(q, use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders).run
89
+
90
+ y.yield results if results.any?
91
+ count += results.size
92
+ offset += results.size
93
+ out_of_records = results.size < batch_size || (limit && count >= limit)
88
94
  end
89
95
  end
90
96
  end
@@ -139,26 +139,37 @@ module OccamsRecord
139
139
  # The bind values will be provided by OccamsRecord.
140
140
  #
141
141
  # @param of [Integer] batch size
142
+ # @param use_transaction [Boolean] Ensure it runs inside of a database transaction
142
143
  # @return [Enumerator] yields batches
143
144
  #
144
- def batches(of:)
145
+ def batches(of:, use_transaction: true)
145
146
  unless @sql =~ /LIMIT\s+%\{batch_limit\}/i and @sql =~ /OFFSET\s+%\{batch_offset\}/i
146
147
  raise ArgumentError, "When using find_each/find_in_batches you must specify 'LIMIT %{batch_limit} OFFSET %{batch_offset}'. SQL statement: #{@sql}"
147
148
  end
148
149
 
149
150
  Enumerator.new do |y|
150
- offset = 0
151
- loop do
152
- results = RawQuery.new(@sql, @binds.merge({
153
- batch_limit: of,
154
- batch_offset: offset,
155
- }), use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders).run
156
-
157
- y.yield results if results.any?
158
- break if results.size < of
159
- offset += results.size
151
+ if use_transaction and @conn.open_transactions == 0
152
+ @conn.transaction {
153
+ run_batches y, of
154
+ }
155
+ else
156
+ run_batches y, of
160
157
  end
161
158
  end
162
159
  end
160
+
161
+ def run_batches(y, of)
162
+ offset = 0
163
+ loop do
164
+ results = RawQuery.new(@sql, @binds.merge({
165
+ batch_limit: of,
166
+ batch_offset: offset,
167
+ }), use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders).run
168
+
169
+ y.yield results if results.any?
170
+ break if results.size < of
171
+ offset += results.size
172
+ end
173
+ end
163
174
  end
164
175
  end
@@ -3,5 +3,5 @@
3
3
  #
4
4
  module OccamsRecord
5
5
  # Library version
6
- VERSION = '1.0.0.rc9'.freeze
6
+ VERSION = '1.0.0.rc10'.freeze
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: occams-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.rc9
4
+ version: 1.0.0.rc10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-22 00:00:00.000000000 Z
11
+ date: 2019-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord