simple-sql 0.4.23 → 0.4.24
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 +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
|