activerecord-postgresql-cursors 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +18 -0
- data/Gemfile +4 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +15 -10
- data/Rakefile +3 -1
- data/lib/active_record/postgresql_cursors/cursors.rb +14 -51
- data/lib/active_record/postgresql_cursors/version.rb +1 -1
- data/lib/activerecord-postgresql-cursors.rb +19 -41
- data/test/cursor_tests.rb +24 -35
- data/test/test_helper.rb +20 -26
- metadata +4 -4
- data/lib/active_record/postgresql_cursors/cursors_2.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4664b822d630c82374f56ca318d69c736c9ad819
|
4
|
+
data.tar.gz: 7318a45c89b1b76dcb8d79fecb6a499bac1a7a48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '053952a5bcc975b0bc7652e652d0f8029fda8a1dd470adbfc0a081d1095f0a0ec601ee4c633250930b16c7e089e8f175d4753d2580d3bb4c796f6f0ff67671b0'
|
7
|
+
data.tar.gz: a67bb236338e87143a8d0827edbbb847371b132f9fbc7dae09c9b39ce5a02129ece6fa8b809b2b8ca4a9cd989994203935c79a1d0b73a4a705d7cfc5b07afdd3
|
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.5.0
|
4
|
+
- 2.4.3
|
5
|
+
- 2.3.6
|
6
|
+
- 2.2.9
|
7
|
+
- jruby
|
8
|
+
env:
|
9
|
+
- RAILS_VERSION=5.1
|
10
|
+
- RAILS_VERSION=4.2
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: jruby
|
14
|
+
before_install:
|
15
|
+
- gem update --system
|
16
|
+
- gem install bundler
|
17
|
+
before_script:
|
18
|
+
- psql -c 'create database postgresql_cursors_unit_tests;' -U postgres
|
data/Gemfile
CHANGED
@@ -5,12 +5,12 @@ gemspec
|
|
5
5
|
if RUBY_PLATFORM == "java"
|
6
6
|
gem "activerecord-jdbcpostgresql-adapter"
|
7
7
|
else
|
8
|
-
gem "pg"
|
8
|
+
gem "pg", '~> 0.21'
|
9
9
|
end
|
10
10
|
|
11
|
-
gem "rdoc"
|
12
|
-
gem "rake"
|
13
|
-
gem "minitest"
|
11
|
+
gem "rdoc"
|
12
|
+
gem "rake"
|
13
|
+
gem "minitest"
|
14
14
|
gem "minitest-reporters"
|
15
15
|
gem "guard-minitest"
|
16
16
|
gem "simplecov"
|
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
= ActiveRecord PostgreSQL Cursors
|
2
2
|
|
3
3
|
This extension allows you to loop through record sets using cursors in an
|
4
4
|
Enumerable fashion. This allows you to cut down memory usage by only pulling
|
@@ -9,21 +9,22 @@ To use a cursor, just change the first parameter to an
|
|
9
9
|
ActiveRecord::Base.find to :cursor instead of :first or :all or
|
10
10
|
whatever or use the ActiveRecord::Base.cursor method directly.
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
MyModel.find(:cursor, :conditions => 'some_column = true').each do |r|
|
13
|
+
puts r.inspect
|
14
|
+
end
|
15
15
|
|
16
|
-
|
16
|
+
MyModel.find(:cursor).collect { |r| r.foo / PI }.avg
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
MyModel.cursor.each do |r|
|
19
|
+
puts r.inspect
|
20
|
+
end
|
21
21
|
|
22
22
|
All ActiveRecord::Base.find options are available and should work as-is.
|
23
23
|
As a bonus, the PostgreSQLCursor object returned includes Enumerable,
|
24
24
|
so you can iterate to your heart's content.
|
25
25
|
|
26
|
-
This extension should work
|
26
|
+
This extension should work with Rails 4.2+. For older versions of Rails, try
|
27
|
+
out older versions of the gem.
|
27
28
|
|
28
29
|
At the moment, this is a non-scrollable cursor -- it will only fetch
|
29
30
|
forward. Also note that these cursors are non-updateable/insensitive to
|
@@ -48,5 +49,9 @@ while the first query is just used to build the larger joined query. This
|
|
48
49
|
allows for a brief window between the point that the cursor query is
|
49
50
|
created and the time it is executed. In these cases, it may be wise to wrap
|
50
51
|
your use or cursors in your own transaction to ensure that changes made to
|
51
|
-
the underlying data don't interfere with your cursor's
|
52
|
+
the underlying data don't interfere with your cursor's visibility.
|
52
53
|
|
54
|
+
== License
|
55
|
+
|
56
|
+
This gem is licensed under an MIT-style license. See the +MIT-LICENSE+ file for
|
57
|
+
details.
|
data/Rakefile
CHANGED
@@ -13,11 +13,14 @@ version = ActiveRecord::PostgreSQLCursors::VERSION
|
|
13
13
|
|
14
14
|
desc 'Test PostgreSQL extensions'
|
15
15
|
Rake::TestTask.new(:test) do |t|
|
16
|
+
t.libs << "#{File.dirname(__FILE__)}/test"
|
16
17
|
t.test_files = FileList['test/**/*_tests.rb']
|
17
18
|
t.verbose = !!ENV['VERBOSE_TESTS']
|
18
19
|
t.warning = !!ENV['WARNINGS']
|
19
20
|
end
|
20
21
|
|
22
|
+
task :default => :test
|
23
|
+
|
21
24
|
desc 'Build docs'
|
22
25
|
Rake::RDocTask.new do |t|
|
23
26
|
t.title = "ActiveRecord PostgreSQL Cursors #{version}"
|
@@ -25,4 +28,3 @@ Rake::RDocTask.new do |t|
|
|
25
28
|
t.rdoc_dir = 'doc'
|
26
29
|
t.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb')
|
27
30
|
end
|
28
|
-
|
@@ -3,13 +3,7 @@ module ActiveRecord
|
|
3
3
|
module CursorExtensions
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
|
7
|
-
alias_method_chain :find, :cursors
|
8
|
-
end
|
9
|
-
|
10
|
-
# Override ActiveRecord::Base#find to allow for cursors in
|
11
|
-
# PostgreSQL. To use a cursor, set the first argument of
|
12
|
-
# find to :cursor. A PostgreSQLCursor object will be returned,
|
6
|
+
# Find using cursors. A PostgreSQLCursor object will be returned,
|
13
7
|
# which can then be used as an Enumerable to loop through the
|
14
8
|
# results.
|
15
9
|
#
|
@@ -18,21 +12,18 @@ module ActiveRecord
|
|
18
12
|
# is pretty unlikely to clash if you're using nested cursors.
|
19
13
|
# Alternatively, you can supply a specific cursor name by
|
20
14
|
# supplying a :cursor_name option.
|
21
|
-
def
|
22
|
-
|
15
|
+
def cursor(*args)
|
16
|
+
find_with_cursor('cursor', *args)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def find_with_cursor(*args)
|
23
22
|
options = args.extract_options!
|
24
23
|
cursor_name = options.delete(:cursor_name)
|
25
24
|
find_cursor(cursor_name, options)
|
26
|
-
else
|
27
|
-
find_without_cursors(*args)
|
28
25
|
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def cursor(*args)
|
32
|
-
find_with_cursors('cursor', *args)
|
33
|
-
end
|
34
26
|
|
35
|
-
private
|
36
27
|
# Find method for using cursors. This works just like the regular
|
37
28
|
# ActiveRecord::Base#find_every method, except it returns a
|
38
29
|
# PostgreSQLCursor object that can be used to loop through records.
|
@@ -41,22 +32,15 @@ module ActiveRecord
|
|
41
32
|
raise CursorsNotSupported, "#{connection.class} doesn't support cursors"
|
42
33
|
end
|
43
34
|
|
44
|
-
relation =
|
45
|
-
apply_finder_options(options, silence_deprecation = true)
|
46
|
-
else
|
47
|
-
apply_finder_options(options)
|
48
|
-
end
|
49
|
-
|
35
|
+
relation = merge(options.slice(:readonly, :references, :order, :limit, :joins, :group, :having, :offset, :select, :uniq))
|
50
36
|
including = (relation.eager_load_values + relation.includes_values).uniq
|
51
37
|
|
52
38
|
if including.present?
|
53
|
-
join_dependency =
|
54
|
-
ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
|
55
|
-
else
|
56
|
-
ActiveRecord::Associations::ClassMethods::JoinDependency.new(@klass, including, nil)
|
57
|
-
end
|
39
|
+
join_dependency = construct_join_dependency(joins_values)
|
58
40
|
|
59
|
-
|
41
|
+
aliases = join_dependency.aliases
|
42
|
+
join_relation = select(aliases.columns)
|
43
|
+
join_relation = apply_join_dependency(join_relation, join_dependency)
|
60
44
|
|
61
45
|
ActiveRecord::PostgreSQLCursor.new(self, cursor_name, join_relation, join_dependency)
|
62
46
|
else
|
@@ -64,23 +48,6 @@ module ActiveRecord
|
|
64
48
|
end
|
65
49
|
end
|
66
50
|
end
|
67
|
-
|
68
|
-
class PostgreSQLCursor
|
69
|
-
def initialize_with_rails(model, cursor_name, relation, join_dependency = nil)
|
70
|
-
@relation = relation
|
71
|
-
|
72
|
-
query = if ActiveRecord::VERSION::MAJOR >= 4
|
73
|
-
model.connection.unprepared_statement do
|
74
|
-
relation.to_sql
|
75
|
-
end
|
76
|
-
else
|
77
|
-
relation.to_sql
|
78
|
-
end
|
79
|
-
|
80
|
-
initialize_without_rails(model, cursor_name, query, join_dependency)
|
81
|
-
end
|
82
|
-
alias_method_chain :initialize, :rails
|
83
|
-
end
|
84
51
|
end
|
85
52
|
|
86
53
|
class ActiveRecord::Relation
|
@@ -89,10 +56,6 @@ end
|
|
89
56
|
|
90
57
|
class ActiveRecord::Base
|
91
58
|
class << self
|
92
|
-
|
93
|
-
delegate :cursor, :to => :all
|
94
|
-
else
|
95
|
-
delegate :cursor, :to => :scoped
|
96
|
-
end
|
59
|
+
delegate :cursor, to: :all
|
97
60
|
end
|
98
61
|
end
|
@@ -4,37 +4,26 @@ module ActiveRecord
|
|
4
4
|
# absolutely should be in our app.
|
5
5
|
class CursorsNotSupported < ActiveRecordError; end
|
6
6
|
|
7
|
-
module PostgreSQLCursors
|
8
|
-
module JoinDependency
|
9
|
-
# Extra method we can use to clear out a couple of things in
|
10
|
-
# JoinDependency so we can use some of the methods for our
|
11
|
-
# cursors code.
|
12
|
-
def clear_with_cursor
|
13
|
-
@reflections = []
|
14
|
-
@base_records_hash = {}
|
15
|
-
@base_records_in_order = []
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
7
|
# PostgreSQLCursor is an Enumerable class so you can use each, map,
|
21
8
|
# any? and all of those nice Enumerable methods.
|
22
9
|
#
|
23
10
|
# At the moment, cursors aren't scrollable and are fetch forward-only
|
24
11
|
# and read-only.
|
25
|
-
#
|
26
|
-
# This class isn't really meant to be used outside of the
|
27
|
-
# ActiveRecord::Base#find method.
|
28
12
|
class PostgreSQLCursor
|
29
13
|
include Enumerable
|
30
14
|
|
31
|
-
def initialize(model, cursor_name,
|
15
|
+
def initialize(model, cursor_name, relation, join_dependency = nil)
|
32
16
|
@model = model
|
17
|
+
@relation = relation
|
18
|
+
@join_dependency = join_dependency
|
19
|
+
|
33
20
|
@cursor_name = if cursor_name
|
34
21
|
@model.connection.quote_table_name(cursor_name.gsub(/"/, '\"'))
|
35
22
|
end
|
36
|
-
|
37
|
-
@
|
23
|
+
|
24
|
+
@query = model.connection.unprepared_statement do
|
25
|
+
relation.to_sql
|
26
|
+
end
|
38
27
|
end
|
39
28
|
|
40
29
|
def inspect
|
@@ -50,26 +39,28 @@ module ActiveRecord
|
|
50
39
|
if @join_dependency
|
51
40
|
rows = Array.new
|
52
41
|
last_id = nil
|
42
|
+
|
53
43
|
while row = fetch_forward
|
54
|
-
|
44
|
+
instantiated_row = @join_dependency.instantiate([row], @join_dependency.aliases).first
|
45
|
+
|
46
|
+
current_id = instantiated_row[@join_dependency.join_root.primary_key]
|
55
47
|
last_id ||= current_id
|
56
48
|
if last_id == current_id
|
57
49
|
rows << row
|
58
50
|
last_id = current_id
|
59
51
|
else
|
60
|
-
yield @join_dependency.instantiate(rows).first
|
61
|
-
@join_dependency.clear_with_cursor
|
52
|
+
yield @join_dependency.instantiate(rows, @join_dependency.aliases).first
|
62
53
|
rows = [ row ]
|
63
54
|
end
|
64
55
|
last_id = current_id
|
65
56
|
end
|
66
57
|
|
67
58
|
if !rows.empty?
|
68
|
-
yield @join_dependency.instantiate(rows).first
|
59
|
+
yield @join_dependency.instantiate(rows, @join_dependency.aliases).first
|
69
60
|
end
|
70
61
|
else
|
71
62
|
while row = fetch_forward
|
72
|
-
yield row
|
63
|
+
yield @model.instantiate(row)
|
73
64
|
end
|
74
65
|
end
|
75
66
|
ensure
|
@@ -80,12 +71,13 @@ module ActiveRecord
|
|
80
71
|
end
|
81
72
|
|
82
73
|
private
|
74
|
+
|
83
75
|
def cursor_name
|
84
|
-
@cursor_name ||= "cursor_#{(rand *
|
76
|
+
@cursor_name ||= "cursor_#{(rand * 1_000_000).ceil}"
|
85
77
|
end
|
86
78
|
|
87
79
|
def fetch_forward #:nodoc:
|
88
|
-
@
|
80
|
+
@relation.connection.select_all(%{FETCH FORWARD FROM #{cursor_name}}).first
|
89
81
|
end
|
90
82
|
|
91
83
|
def declare_cursor #:nodoc:
|
@@ -98,18 +90,4 @@ module ActiveRecord
|
|
98
90
|
end
|
99
91
|
end
|
100
92
|
|
101
|
-
|
102
|
-
class ActiveRecord::Associations::JoinDependency
|
103
|
-
include ActiveRecord::PostgreSQLCursors::JoinDependency
|
104
|
-
end
|
105
|
-
else
|
106
|
-
class ActiveRecord::Associations::ClassMethods::JoinDependency
|
107
|
-
include ActiveRecord::PostgreSQLCursors::JoinDependency
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
if ActiveRecord::VERSION::MAJOR >= 3
|
112
|
-
require File.join(File.dirname(__FILE__), *%w{ active_record postgresql_cursors cursors })
|
113
|
-
else
|
114
|
-
require File.join(File.dirname(__FILE__), *%w{ active_record postgresql_cursors cursors_2 })
|
115
|
-
end
|
93
|
+
require File.join(File.dirname(__FILE__), *%w{ active_record postgresql_cursors cursors })
|
data/test/cursor_tests.rb
CHANGED
@@ -1,20 +1,11 @@
|
|
1
1
|
|
2
|
-
$: << File.dirname(__FILE__)
|
3
2
|
require 'test_helper'
|
4
3
|
|
5
|
-
class PostgreSQLCursorTests <
|
4
|
+
class PostgreSQLCursorTests < Minitest::Test
|
6
5
|
include PostgreSQLCursorTestHelper
|
7
6
|
|
8
|
-
def test_find_cursor
|
9
|
-
cursor = Foo.find(:cursor, :order => 'id')
|
10
|
-
|
11
|
-
assert(cursor.is_a?(ActiveRecord::PostgreSQLCursor))
|
12
|
-
|
13
|
-
assert_equal(%w{ one two three four five }, cursor.collect(&:name))
|
14
|
-
end
|
15
|
-
|
16
7
|
def test_cursor_scoped
|
17
|
-
cursor = Foo.cursor(:
|
8
|
+
cursor = Foo.cursor(order: 'id')
|
18
9
|
|
19
10
|
assert(cursor.is_a?(ActiveRecord::PostgreSQLCursor))
|
20
11
|
|
@@ -22,7 +13,7 @@ class PostgreSQLCursorTests < MiniTest::Unit::TestCase
|
|
22
13
|
end
|
23
14
|
|
24
15
|
def test_cursor_while_updating
|
25
|
-
cursor = Foo.cursor(:
|
16
|
+
cursor = Foo.cursor(order: 'id')
|
26
17
|
|
27
18
|
cursor.each do |row|
|
28
19
|
row.name = "#{row.name}_updated"
|
@@ -33,7 +24,7 @@ class PostgreSQLCursorTests < MiniTest::Unit::TestCase
|
|
33
24
|
end
|
34
25
|
|
35
26
|
def test_with_associations
|
36
|
-
cursor = Foo.cursor(:
|
27
|
+
cursor = Foo.cursor(order: 'id')
|
37
28
|
|
38
29
|
cursor.each do |row|
|
39
30
|
assert(row.is_a?(Foo))
|
@@ -44,7 +35,7 @@ class PostgreSQLCursorTests < MiniTest::Unit::TestCase
|
|
44
35
|
end
|
45
36
|
|
46
37
|
def test_with_associations_eager_loading
|
47
|
-
cursor = Foo.cursor(:
|
38
|
+
cursor = Foo.cursor(order: 'foos.id', include: :bars)
|
48
39
|
|
49
40
|
cursor.each do |row|
|
50
41
|
assert(row.is_a?(Foo))
|
@@ -55,7 +46,7 @@ class PostgreSQLCursorTests < MiniTest::Unit::TestCase
|
|
55
46
|
end
|
56
47
|
|
57
48
|
def test_nested_cursors
|
58
|
-
cursor = Foo.cursor(:
|
49
|
+
cursor = Foo.cursor(order: 'foos.id')
|
59
50
|
|
60
51
|
cursor.each do |row|
|
61
52
|
bars_cursor = row.bars.cursor
|
@@ -67,30 +58,28 @@ class PostgreSQLCursorTests < MiniTest::Unit::TestCase
|
|
67
58
|
end
|
68
59
|
end
|
69
60
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
assert(bar.is_a?(Bar))
|
80
|
-
end
|
61
|
+
def test_as_relation
|
62
|
+
cursor = Foo.order('foos.id').where('foos.id >= 3').cursor
|
63
|
+
assert_equal(3, cursor.to_a.length)
|
64
|
+
|
65
|
+
cursor.each do |row|
|
66
|
+
assert(row.is_a?(Foo))
|
67
|
+
assert_equal(2, row.bars.length)
|
68
|
+
row.bars.each do |bar|
|
69
|
+
assert(bar.is_a?(Bar))
|
81
70
|
end
|
82
71
|
end
|
72
|
+
end
|
83
73
|
|
84
|
-
|
85
|
-
|
86
|
-
|
74
|
+
def test_as_relation_with_associations
|
75
|
+
cursor = Foo.includes(:bars).order('foos.id').where('foos.id >= 3').cursor
|
76
|
+
assert_equal(3, cursor.to_a.length)
|
87
77
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
78
|
+
cursor.each do |row|
|
79
|
+
assert(row.is_a?(Foo))
|
80
|
+
assert_equal(2, row.bars.length)
|
81
|
+
row.bars.each do |bar|
|
82
|
+
assert(bar.is_a?(Bar))
|
94
83
|
end
|
95
84
|
end
|
96
85
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
require 'simplecov'
|
2
|
+
require 'simplecov'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
4
|
+
SimpleCov.command_name('Unit Tests')
|
5
|
+
SimpleCov.start do
|
6
|
+
add_filter '/test/'
|
9
7
|
end
|
10
8
|
|
11
9
|
require 'rubygems'
|
@@ -14,14 +12,11 @@ require 'active_support/core_ext/module/aliasing'
|
|
14
12
|
require 'active_record'
|
15
13
|
require 'logger'
|
16
14
|
require 'minitest/autorun'
|
17
|
-
|
18
|
-
if RUBY_VERSION >= '1.9'
|
19
|
-
require 'minitest/reporters'
|
20
|
-
end
|
15
|
+
require 'minitest/reporters'
|
21
16
|
|
22
17
|
require File.join(File.dirname(__FILE__), *%w{ .. lib activerecord-postgresql-cursors })
|
23
18
|
|
24
|
-
ActiveRecord::Base.logger = Logger.new(
|
19
|
+
ActiveRecord::Base.logger = Logger.new('debug.log') if ENV['ENABLE_LOGGER']
|
25
20
|
ActiveRecord::Base.configurations = {
|
26
21
|
'arunit' => {}
|
27
22
|
}
|
@@ -32,12 +27,12 @@ ActiveRecord::Base.configurations = {
|
|
32
27
|
}.each do |file|
|
33
28
|
file = File.join('test', file)
|
34
29
|
|
35
|
-
next unless File.
|
30
|
+
next unless File.exist?(file)
|
36
31
|
|
37
|
-
configuration = YAML.
|
32
|
+
configuration = YAML.safe_load(File.read(file))
|
38
33
|
|
39
34
|
if configuration['arunit']
|
40
|
-
ActiveRecord::Base.configurations['arunit']
|
35
|
+
ActiveRecord::Base.configurations['arunit'] = configuration['arunit']
|
41
36
|
end
|
42
37
|
|
43
38
|
if defined?(JRUBY_VERSION) && configuration['jdbc']
|
@@ -45,29 +40,31 @@ ActiveRecord::Base.configurations = {
|
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
48
|
-
ActiveRecord::Base.establish_connection
|
43
|
+
ActiveRecord::Base.establish_connection :arunit
|
49
44
|
ARBC = ActiveRecord::Base.connection
|
50
45
|
|
51
46
|
puts "Ruby version #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} - #{RbConfig::CONFIG['RUBY_INSTALL_NAME']}"
|
52
|
-
puts "Testing against ActiveRecord #{Gem.loaded_specs['activerecord'].version
|
53
|
-
|
47
|
+
puts "Testing against ActiveRecord #{Gem.loaded_specs['activerecord'].version}"
|
48
|
+
|
49
|
+
postgresql_version = ARBC.select_rows('SELECT version()').flatten.to_s
|
50
|
+
|
51
|
+
if postgresql_version
|
54
52
|
puts "PostgreSQL info from version(): #{postgresql_version}"
|
55
53
|
end
|
56
54
|
|
57
|
-
|
55
|
+
unless ARBC.data_source_exists?('foos')
|
58
56
|
ActiveRecord::Migration.create_table(:foos) do |t|
|
59
57
|
t.text :name
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
63
|
-
|
61
|
+
unless ARBC.data_source_exists?('bars')
|
64
62
|
ActiveRecord::Migration.create_table(:bars) do |t|
|
65
63
|
t.text :name
|
66
64
|
t.integer :foo_id
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
70
|
-
|
71
68
|
class Bar < ActiveRecord::Base
|
72
69
|
belongs_to :foo
|
73
70
|
end
|
@@ -84,18 +81,15 @@ module PostgreSQLCursorTestHelper
|
|
84
81
|
ARBC.execute(%{select setval('bars_id_seq', 1, false)})
|
85
82
|
|
86
83
|
%w{ six seven eight nine ten eleven twelve thirteen fourteen fifteen }.each do |name|
|
87
|
-
Bar.create(:
|
84
|
+
Bar.create(name: name)
|
88
85
|
end
|
89
86
|
|
90
87
|
%w{ one two three four five }.each_with_index do |name, i|
|
91
|
-
foo = Foo.new(:
|
88
|
+
foo = Foo.new(name: name)
|
92
89
|
foo.bar_ids = [ i + 1, i + 6 ]
|
93
90
|
foo.save
|
94
91
|
end
|
95
92
|
end
|
96
93
|
end
|
97
94
|
|
98
|
-
|
99
|
-
MiniTest::Reporters.use!(MiniTest::Reporters::SpecReporter.new)
|
100
|
-
end
|
101
|
-
|
95
|
+
Minitest::Reporters.use!(MiniTest::Reporters::SpecReporter.new)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-postgresql-cursors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -32,6 +32,7 @@ extra_rdoc_files:
|
|
32
32
|
- README.rdoc
|
33
33
|
files:
|
34
34
|
- ".gitignore"
|
35
|
+
- ".travis.yml"
|
35
36
|
- Gemfile
|
36
37
|
- Guardfile
|
37
38
|
- MIT-LICENSE
|
@@ -39,7 +40,6 @@ files:
|
|
39
40
|
- Rakefile
|
40
41
|
- activerecord-postgresql-cursors.gemspec
|
41
42
|
- lib/active_record/postgresql_cursors/cursors.rb
|
42
|
-
- lib/active_record/postgresql_cursors/cursors_2.rb
|
43
43
|
- lib/active_record/postgresql_cursors/version.rb
|
44
44
|
- lib/activerecord-postgresql-cursors.rb
|
45
45
|
- test/cursor_tests.rb
|
@@ -65,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
65
65
|
version: '0'
|
66
66
|
requirements: []
|
67
67
|
rubyforge_project:
|
68
|
-
rubygems_version: 2.
|
68
|
+
rubygems_version: 2.6.13
|
69
69
|
signing_key:
|
70
70
|
specification_version: 4
|
71
71
|
summary: Provides some support for PostgreSQL cursors in ActiveRecord.
|
@@ -1,75 +0,0 @@
|
|
1
|
-
|
2
|
-
module ActiveRecord
|
3
|
-
class Base
|
4
|
-
class << self
|
5
|
-
# Override ActiveRecord::Base#find to allow for cursors in
|
6
|
-
# PostgreSQL. To use a cursor, set the first argument of
|
7
|
-
# find to :cursor. A PostgreSQLCursor object will be returned,
|
8
|
-
# which can then be used as an Enumerable to loop through the
|
9
|
-
# results.
|
10
|
-
#
|
11
|
-
# By default, cursor names are generated automatically using
|
12
|
-
# "cursor_#{rand}", where rand is a big ol' random number that
|
13
|
-
# is pretty unlikely to clash if you're using nested cursors.
|
14
|
-
# Alternatively, you can supply a specific cursor name by
|
15
|
-
# supplying a :cursor_name option.
|
16
|
-
def find_with_cursors *args
|
17
|
-
if args.first.to_s == 'cursor'
|
18
|
-
options = args.extract_options!
|
19
|
-
cursor_name = options.delete(:cursor_name)
|
20
|
-
validate_find_options(options)
|
21
|
-
set_readonly_option!(options)
|
22
|
-
find_cursor(cursor_name, options)
|
23
|
-
else
|
24
|
-
find_without_cursors(*args)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
alias_method_chain :find, :cursors
|
28
|
-
|
29
|
-
def cursor(*args)
|
30
|
-
find(:cursor, *args)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
# Find method for using cursors. This works just like the regular
|
36
|
-
# ActiveRecord::Base#find_every method, except it returns a
|
37
|
-
# PostgreSQLCursor object that can be used to loop through records.
|
38
|
-
def self.find_cursor(cursor_name, options)
|
39
|
-
unless connection.is_a? ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
40
|
-
raise CursorsNotSupported, "#{connection.class} doesn't support cursors"
|
41
|
-
end
|
42
|
-
|
43
|
-
catch :invalid_query do
|
44
|
-
if options[:include]
|
45
|
-
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
|
46
|
-
return ActiveRecord::PostgreSQLCursor.new(
|
47
|
-
self,
|
48
|
-
cursor_name,
|
49
|
-
construct_finder_sql_with_included_associations(
|
50
|
-
options,
|
51
|
-
join_dependency
|
52
|
-
),
|
53
|
-
join_dependency
|
54
|
-
)
|
55
|
-
else
|
56
|
-
return ActiveRecord::PostgreSQLCursor.new(
|
57
|
-
self,
|
58
|
-
cursor_name,
|
59
|
-
construct_finder_sql(
|
60
|
-
options
|
61
|
-
)
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
nil
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class PostgreSQLCursor
|
70
|
-
def initialize_with_rails_2(model, cursor_name, query, join_dependency = nil)
|
71
|
-
initialize_without_rails_2(model, cursor_name, query, join_dependency)
|
72
|
-
end
|
73
|
-
alias_method_chain :initialize, :rails_2
|
74
|
-
end
|
75
|
-
end
|