simple-sql 0.4.23 → 0.4.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/simple/sql/connection_adapter.rb +44 -29
- data/lib/simple/sql/version.rb +1 -1
- data/simple-sql.gemspec +2 -0
- data/spec/simple/sql/all_into_spec.rb +0 -17
- data/spec/simple/sql/each_spec.rb +148 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11f161fabbc3c7a0079e8e82288ed819bd75ac07f37a0c8a378032c9a9ca0b4c
|
4
|
+
data.tar.gz: 1792494b7417826ef4fe16523d3afb1bbd670d23db69be55ffeebc00adbcee6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df9ac5a0c455dc17fc20e36c79e5905667f37c9dfe3a3b11debdbcd612ff4d64c84b8ebcf1a4e1a2c0e585a83623ca052c92a2e22dfb042a19be4bf553a7e40b
|
7
|
+
data.tar.gz: fcfe42ddfad18c3d0a019a07b3bd124595d0db5e64ac16e3c8244ac00ae3faad4e851915c74fd5418fb8b8285045c0338cf548638ad4446b8d3f683d3c87f180
|
@@ -32,29 +32,36 @@ module Simple::SQL::ConnectionAdapter
|
|
32
32
|
# end
|
33
33
|
|
34
34
|
def all(sql, *args, into: nil, &block)
|
35
|
-
|
35
|
+
raise ArgumentError, "all no longer support blocks, use each instead." if block
|
36
|
+
rows = []
|
37
|
+
my_pg_source_oid = nil
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# each row into a Hash initially, and only later convert it to the final
|
42
|
-
# target type (via RowConverter.convert_ary). This is to allow to fill in
|
43
|
-
# more entries later on.
|
44
|
-
records = enumerate(pg_result, into: into)
|
39
|
+
each_without_conversion(sql, *args, into: into) do |row, pg_source_oid|
|
40
|
+
rows << row
|
41
|
+
my_pg_source_oid = pg_source_oid
|
42
|
+
end
|
45
43
|
|
46
|
-
|
47
|
-
pg_result.clear unless pg_result.autoclear?
|
44
|
+
record_set = convert_rows_to_result rows, into: into, pg_source_oid: my_pg_source_oid
|
48
45
|
|
49
46
|
# [TODO] - resolve associations. Note that this is only possible if the type
|
50
47
|
# is not an Array (i.e. into is nil)
|
51
48
|
|
52
49
|
if sql.is_a?(Scope) && sql.paginated?
|
53
|
-
|
50
|
+
record_set.send(:set_pagination_info, sql)
|
54
51
|
end
|
55
52
|
|
56
|
-
|
57
|
-
|
53
|
+
record_set
|
54
|
+
end
|
55
|
+
|
56
|
+
def each(sql, *args, into: nil)
|
57
|
+
raise ArgumentError, "Missing block" unless block_given?
|
58
|
+
|
59
|
+
each_without_conversion sql, *args, into: into do |row, pg_source_oid|
|
60
|
+
record = convert_row_to_record row, into: into, pg_source_oid: pg_source_oid
|
61
|
+
yield record
|
62
|
+
end
|
63
|
+
|
64
|
+
self
|
58
65
|
end
|
59
66
|
|
60
67
|
# Runs a query and prints the results via "table_print"
|
@@ -76,7 +83,7 @@ module Simple::SQL::ConnectionAdapter
|
|
76
83
|
# returns an array <tt>[ <id>, <email> ]</tt> (or +nil+)
|
77
84
|
def ask(sql, *args, into: nil)
|
78
85
|
catch(:ok) do
|
79
|
-
|
86
|
+
each(sql, *args, into: into) { |row| throw :ok, row }
|
80
87
|
nil
|
81
88
|
end
|
82
89
|
end
|
@@ -88,16 +95,16 @@ module Simple::SQL::ConnectionAdapter
|
|
88
95
|
#
|
89
96
|
# - <tt>Simple::SQL.locked(4711) { puts 'do work while locked' }
|
90
97
|
def locked(lock_id)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
ask("SELECT pg_advisory_unlock(#{lock_id})")
|
96
|
-
end
|
98
|
+
ask("SELECT pg_advisory_lock(#{lock_id})")
|
99
|
+
yield
|
100
|
+
ensure
|
101
|
+
ask("SELECT pg_advisory_unlock(#{lock_id})")
|
97
102
|
end
|
98
103
|
|
99
104
|
private
|
100
105
|
|
106
|
+
Result = ::Simple::SQL::Result
|
107
|
+
Decoder = ::Simple::SQL::Helpers::Decoder
|
101
108
|
Encoder = ::Simple::SQL::Helpers::Encoder
|
102
109
|
|
103
110
|
def exec_logged(sql_or_scope, *args)
|
@@ -115,20 +122,28 @@ module Simple::SQL::ConnectionAdapter
|
|
115
122
|
end
|
116
123
|
end
|
117
124
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
def enumerate(pg_result, into:)
|
122
|
-
records = []
|
123
|
-
pg_source_oid = nil
|
125
|
+
def each_without_conversion(sql, *args, into: nil)
|
126
|
+
pg_result = exec_logged(sql, *args)
|
124
127
|
|
125
128
|
if pg_result.ntuples > 0 && pg_result.nfields > 0
|
126
129
|
decoder = Decoder.new(self, pg_result, into: (into ? Hash : nil))
|
127
|
-
pg_result.each_row { |row| records << decoder.decode(row) }
|
128
130
|
pg_source_oid = pg_result.ftable(0)
|
131
|
+
|
132
|
+
pg_result.each_row do |row|
|
133
|
+
yield decoder.decode(row), pg_source_oid
|
134
|
+
end
|
129
135
|
end
|
130
136
|
|
131
|
-
|
137
|
+
# optimization: If we wouldn't clear here the GC would do this later.
|
138
|
+
pg_result.clear unless pg_result.autoclear?
|
139
|
+
end
|
140
|
+
|
141
|
+
def convert_row_to_record(row, into:, pg_source_oid:)
|
142
|
+
convert_rows_to_result([row], into: into, pg_source_oid: pg_source_oid).first
|
143
|
+
end
|
144
|
+
|
145
|
+
def convert_rows_to_result(rows, into:, pg_source_oid:)
|
146
|
+
Result.build(rows, target_type: into, pg_source_oid: pg_source_oid)
|
132
147
|
end
|
133
148
|
|
134
149
|
public
|
data/lib/simple/sql/version.rb
CHANGED
data/simple-sql.gemspec
CHANGED
@@ -42,4 +42,6 @@ Gem::Specification.new do |gem|
|
|
42
42
|
gem.add_development_dependency 'database_cleaner', '~> 1'
|
43
43
|
gem.add_development_dependency 'simplecov', '~> 0'
|
44
44
|
gem.add_development_dependency 'awesome_print', '~> 0'
|
45
|
+
|
46
|
+
gem.add_development_dependency 'memory_profiler', '~> 0.9.12'
|
45
47
|
end
|
@@ -15,23 +15,6 @@ describe "Simple::SQL.ask into: :struct" do
|
|
15
15
|
r = SQL.all("SELECT * FROM users WHERE FALSE", into: Hash)
|
16
16
|
expect(r).to eq([])
|
17
17
|
end
|
18
|
-
|
19
|
-
it "yields the results into a block" do
|
20
|
-
received = []
|
21
|
-
SQL.all("SELECT id FROM users", into: Hash) do |hsh|
|
22
|
-
received << hsh
|
23
|
-
end
|
24
|
-
expect(received.length).to eq(USER_COUNT)
|
25
|
-
expect(received.map(&:class).uniq).to eq([Hash])
|
26
|
-
end
|
27
|
-
|
28
|
-
it "does not yield if there is no match" do
|
29
|
-
received = []
|
30
|
-
SQL.all("SELECT id FROM users WHERE FALSE", into: Hash) do |hsh|
|
31
|
-
received << hsh
|
32
|
-
end
|
33
|
-
expect(received.length).to eq(0)
|
34
|
-
end
|
35
18
|
end
|
36
19
|
|
37
20
|
describe "into: :struct" do
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Simple::SQL.each" do
|
4
|
+
context "when called without a block " do
|
5
|
+
it "raises an ArgumentError" do
|
6
|
+
expect {
|
7
|
+
SQL.each("SELECT id FROM users", into: Hash)
|
8
|
+
}.to raise_error(ArgumentError)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_users!
|
13
|
+
1.upto(USER_COUNT).map { create(:user) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def each!(sql, into: nil)
|
17
|
+
@received = nil
|
18
|
+
SQL.each(sql, into: into) do |id|
|
19
|
+
@received ||= []
|
20
|
+
@received << id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:received) { @received }
|
25
|
+
|
26
|
+
describe "each into: nil" do
|
27
|
+
before { generate_users! }
|
28
|
+
context "when called with matches" do
|
29
|
+
it "receives rows as arrays" do
|
30
|
+
each! "SELECT id, id FROM users ORDER BY id"
|
31
|
+
|
32
|
+
expect(received).to eq(1.upto(USER_COUNT).map { |i| [ i,i ]})
|
33
|
+
end
|
34
|
+
|
35
|
+
it "receives single item row as individual objects" do
|
36
|
+
each! "SELECT id FROM users ORDER BY id"
|
37
|
+
|
38
|
+
expect(received).to eq(1.upto(USER_COUNT).to_a)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when called with no matches' do
|
43
|
+
it "does not yield" do
|
44
|
+
each! "SELECT id FROM users WHERE FALSE"
|
45
|
+
expect(received).to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "each into: <something>" do
|
51
|
+
before { generate_users! }
|
52
|
+
|
53
|
+
it "receives rows as Hashes" do
|
54
|
+
each! "SELECT id, id AS dupe FROM users ORDER BY id", into: Hash
|
55
|
+
|
56
|
+
expect(received).to eq(1.upto(USER_COUNT).map { |i| { id: i, dupe: i }})
|
57
|
+
end
|
58
|
+
|
59
|
+
it "receives rows as immutable" do
|
60
|
+
each! "SELECT id, id AS dupe FROM users ORDER BY id", into: :immutable
|
61
|
+
|
62
|
+
expect(received.first.id).to eq(1)
|
63
|
+
expect(received[1].dupe).to eq(2)
|
64
|
+
expect(received.map(&:class).uniq).to eq([Simple::SQL::Helpers::Immutable])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
xdescribe "memory usage: pending due to inconclusive results" do
|
69
|
+
it "generates a series" do
|
70
|
+
each! "SELECT a.n from generate_series(1, 100) as a(n)"
|
71
|
+
expect(received).to eq((1..100).to_a)
|
72
|
+
end
|
73
|
+
|
74
|
+
require 'memory_profiler'
|
75
|
+
|
76
|
+
def measure_retained_objects(msg, &block)
|
77
|
+
r = nil
|
78
|
+
report = MemoryProfiler.report do
|
79
|
+
r = yield
|
80
|
+
end
|
81
|
+
|
82
|
+
STDERR.puts "#{msg} Total allocated: #{report.total_allocated_memsize} bytes (#{report.total_allocated} objects)"
|
83
|
+
STDERR.puts "#{msg} Total retained: #{report.total_retained_memsize} bytes (#{report.total_retained} objects)"
|
84
|
+
|
85
|
+
report.total_retained_memsize
|
86
|
+
end
|
87
|
+
|
88
|
+
it "is using less memory than .all" do
|
89
|
+
sql_warmup = "SELECT a.n from generate_series(10000, 100) as a(n)"
|
90
|
+
|
91
|
+
SQL.all(sql_warmup, into: Hash)
|
92
|
+
|
93
|
+
SQL.each(sql_warmup) do |id|
|
94
|
+
:nop
|
95
|
+
end
|
96
|
+
|
97
|
+
cnt = 1000000
|
98
|
+
sql = "SELECT a.n from generate_series(#{cnt}, #{cnt}) as a(n)"
|
99
|
+
|
100
|
+
r = nil
|
101
|
+
retained_objects_all = measure_retained_objects "all" do
|
102
|
+
r = SQL.all(sql, into: Hash)
|
103
|
+
end
|
104
|
+
|
105
|
+
retained_objects_each = measure_retained_objects "each" do
|
106
|
+
r = SQL.each(sql) do |id|
|
107
|
+
:nop
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
expect(0).to eq "one"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
__END__
|
117
|
+
|
118
|
+
describe "each into: X" do
|
119
|
+
it "calls the database" do
|
120
|
+
r = SQL.all("SELECT id FROM users", into: Hash)
|
121
|
+
expect(r).to be_a(Array)
|
122
|
+
expect(r.length).to eq(USER_COUNT)
|
123
|
+
expect(r.map(&:class).uniq).to eq([Hash])
|
124
|
+
end
|
125
|
+
|
126
|
+
it "returns an empty array when there is no match" do
|
127
|
+
r = SQL.all("SELECT * FROM users WHERE FALSE", into: Hash)
|
128
|
+
expect(r).to eq([])
|
129
|
+
end
|
130
|
+
|
131
|
+
it "yields the results into a block" do
|
132
|
+
received = []
|
133
|
+
SQL.all("SELECT id FROM users", into: Hash) do |hsh|
|
134
|
+
received << hsh
|
135
|
+
end
|
136
|
+
expect(received.length).to eq(USER_COUNT)
|
137
|
+
expect(received.map(&:class).uniq).to eq([Hash])
|
138
|
+
end
|
139
|
+
|
140
|
+
it "does not yield if there is no match" do
|
141
|
+
received = []
|
142
|
+
SQL.all("SELECT id FROM users WHERE FALSE", into: Hash) do |hsh|
|
143
|
+
received << hsh
|
144
|
+
end
|
145
|
+
expect(received.length).to eq(0)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple-sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.24
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-11
|
12
|
+
date: 2018-12-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pg_array_parser
|
@@ -165,6 +165,20 @@ dependencies:
|
|
165
165
|
- - "~>"
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: memory_profiler
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 0.9.12
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "~>"
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: 0.9.12
|
168
182
|
description: SQL with a simple interface. Postgres only.
|
169
183
|
email: eno@radiospiel.org
|
170
184
|
executables: []
|
@@ -218,6 +232,7 @@ files:
|
|
218
232
|
- spec/simple/sql/conversion_spec.rb
|
219
233
|
- spec/simple/sql/duplicate_spec.rb
|
220
234
|
- spec/simple/sql/duplicate_unique_spec.rb
|
235
|
+
- spec/simple/sql/each_spec.rb
|
221
236
|
- spec/simple/sql/insert_spec.rb
|
222
237
|
- spec/simple/sql/reflection_spec.rb
|
223
238
|
- spec/simple/sql/scope_spec.rb
|
@@ -262,6 +277,7 @@ test_files:
|
|
262
277
|
- spec/simple/sql/conversion_spec.rb
|
263
278
|
- spec/simple/sql/duplicate_spec.rb
|
264
279
|
- spec/simple/sql/duplicate_unique_spec.rb
|
280
|
+
- spec/simple/sql/each_spec.rb
|
265
281
|
- spec/simple/sql/insert_spec.rb
|
266
282
|
- spec/simple/sql/reflection_spec.rb
|
267
283
|
- spec/simple/sql/scope_spec.rb
|