mini_sql 0.1.5 → 0.1.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 +4 -4
- data/.gitignore +1 -0
- data/README.md +32 -7
- data/bench/topic_perf.rb +63 -20
- data/lib/mini_sql/builder.rb +23 -24
- data/lib/mini_sql/connection.rb +2 -3
- data/lib/mini_sql/version.rb +1 -1
- metadata +2 -3
- data/Gemfile.lock +0 -73
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fe7bfcf37c73b216a8532cd6b17957733213610c73924e241ba36619ae4ce04
|
4
|
+
data.tar.gz: 21e2f615add1039d3cd6363ce1bdea501dc2b9bc08d17565cb8b6378a508e04e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c8de4d35f5d332dd53925502b3d696782a90862b47e75b28e7402b85f7735c675c64ffd6027e419328396114dd9e1d8fcd62760ceda42e58576f52727da0411
|
7
|
+
data.tar.gz: 23e73177710c4ac500bf2a6d96de4c0b9d191526c9e68cd7fcd29d39a3fd686e39a59ade520bc35f60279b3daf78bd3365b1be06b33642f42ee932946734ed98
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -27,19 +27,40 @@ conn = MiniSql::Connection.new(pg_conn)
|
|
27
27
|
puts conn.exec('update table set column = 1 where id in (1,2)')
|
28
28
|
# returns 2 if 2 rows changed
|
29
29
|
|
30
|
-
conn.query("select 1 id, 'bob' name") do |user|
|
30
|
+
conn.query("select 1 id, 'bob' name").each do |user|
|
31
31
|
puts user.name # bob
|
32
32
|
puts user.id # 1
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
p conn.query_single('select 1 union select 2')
|
36
36
|
# [1,2]
|
37
37
|
|
38
|
+
p conn.query_hash('select 1 as a, 2 as b union select 3, 4')
|
39
|
+
# [{"a" => 1, "b"=> 1},{"a" => 3, "b" => 4}
|
40
|
+
```
|
41
|
+
|
42
|
+
## The query builder
|
43
|
+
|
44
|
+
You can use the simple query builder interface to compose queries.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
builder = conn.build("select * from topics /*where*/ /*limit*/")
|
48
|
+
|
49
|
+
if look_for_something
|
50
|
+
builder.where("title = :title", title: 'something')
|
51
|
+
end
|
52
|
+
|
53
|
+
builder.limit(20)
|
54
|
+
|
55
|
+
builder.query.each do |t|
|
56
|
+
puts t.id
|
57
|
+
puts t.title
|
58
|
+
end
|
38
59
|
```
|
39
60
|
|
40
61
|
## Is it fast?
|
41
62
|
|
42
|
-
Yes, it is very fast
|
63
|
+
Yes, it is very fast. See benchmarks in [the bench directory](https://github.com/discourse/mini_sql/tree/master/bench).
|
43
64
|
|
44
65
|
As a rule it will outperform similar naive PG code while remaining safe.
|
45
66
|
|
@@ -47,14 +68,18 @@ As a rule it will outperform similar naive PG code while remaining safe.
|
|
47
68
|
pg_conn = PG.connect(db_name: 'my_db')
|
48
69
|
|
49
70
|
# this is slower, and less safe
|
50
|
-
pg_conn.async_exec('select * from table')
|
71
|
+
result = pg_conn.async_exec('select * from table')
|
72
|
+
result.each do |r|
|
51
73
|
name = r['name']
|
52
74
|
end
|
75
|
+
# ideally you want to remember to run r.clear here
|
53
76
|
|
54
77
|
# this is faster and safer
|
55
78
|
conn = MiniSql::Connection.new(pg_conn)
|
56
|
-
conn.query('select * from table')
|
57
|
-
|
79
|
+
r = conn.query('select * from table')
|
80
|
+
|
81
|
+
r.each do |row|
|
82
|
+
name = row.name
|
58
83
|
end
|
59
84
|
```
|
60
85
|
|
@@ -79,4 +104,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
79
104
|
|
80
105
|
## Code of Conduct
|
81
106
|
|
82
|
-
Everyone interacting in the MiniSql project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
107
|
+
Everyone interacting in the MiniSql project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/discourse/mini_sql/blob/master/CODE_OF_CONDUCT.md).
|
data/bench/topic_perf.rb
CHANGED
@@ -168,7 +168,28 @@ def sequel_pluck_title_id
|
|
168
168
|
s
|
169
169
|
end
|
170
170
|
|
171
|
-
|
171
|
+
# usage is not really recommended but just to compare to pluck lets have it
|
172
|
+
def mini_sql_title_id_query_single
|
173
|
+
s = +""
|
174
|
+
i = 0
|
175
|
+
r = $mini_sql.query_single(-"select id, title from topics order by id limit 1000")
|
176
|
+
while i < r.length
|
177
|
+
s << r[i].to_s
|
178
|
+
s << r[i+1]
|
179
|
+
i += 2
|
180
|
+
end
|
181
|
+
s
|
182
|
+
end
|
183
|
+
|
184
|
+
results = [
|
185
|
+
ar_title_id,
|
186
|
+
ar_title_id_pluck,
|
187
|
+
pg_title_id,
|
188
|
+
mini_sql_title_id,
|
189
|
+
sequel_pluck_title_id,
|
190
|
+
sequel_select_title_id,
|
191
|
+
mini_sql_title_id_query_single
|
192
|
+
]
|
172
193
|
|
173
194
|
exit(-1) unless results.uniq.length == 1
|
174
195
|
|
@@ -241,12 +262,6 @@ Benchmark.ips do |r|
|
|
241
262
|
n -= 1
|
242
263
|
end
|
243
264
|
end
|
244
|
-
r.report("sequel title id pluck") do |n|
|
245
|
-
while n > 0
|
246
|
-
sequel_pluck_title_id
|
247
|
-
n -= 1
|
248
|
-
end
|
249
|
-
end
|
250
265
|
r.report("pg select title id") do |n|
|
251
266
|
while n > 0
|
252
267
|
pg_title_id
|
@@ -259,30 +274,58 @@ Benchmark.ips do |r|
|
|
259
274
|
n -= 1
|
260
275
|
end
|
261
276
|
end
|
277
|
+
r.report("sequel title id pluck") do |n|
|
278
|
+
while n > 0
|
279
|
+
sequel_pluck_title_id
|
280
|
+
n -= 1
|
281
|
+
end
|
282
|
+
end
|
283
|
+
r.report("mini_sql query_single title id") do |n|
|
284
|
+
while n > 0
|
285
|
+
mini_sql_title_id_query_single
|
286
|
+
n -= 1
|
287
|
+
end
|
288
|
+
end
|
262
289
|
r.compare!
|
263
290
|
end
|
264
291
|
|
265
292
|
|
266
293
|
# Calculating -------------------------------------
|
267
|
-
#
|
294
|
+
# wide topic ar 2.383k (± 4.9%) i/s - 12.005k in 5.050490s
|
295
|
+
# wide topic sequel 3.449k (± 3.2%) i/s - 17.591k in 5.104951s
|
296
|
+
# wide topic pg 7.345k (± 1.2%) i/s - 37.352k in 5.086015s
|
297
|
+
# wide topic mini sql 7.536k (± 1.4%) i/s - 38.220k in 5.072834s
|
298
|
+
#
|
299
|
+
# Comparison:
|
300
|
+
# wide topic mini sql: 7535.8 i/s
|
301
|
+
# wide topic pg: 7345.1 i/s - same-ish: difference falls within error
|
302
|
+
# wide topic sequel: 3449.4 i/s - 2.18x slower
|
303
|
+
# wide topic ar: 2382.9 i/s - 3.16x slower
|
304
|
+
#
|
305
|
+
# Calculating -------------------------------------
|
306
|
+
# ar select title id 131.572 (± 3.8%) i/s - 658.000 in 5.008231s
|
268
307
|
# ar select title id pluck
|
269
|
-
#
|
308
|
+
# 696.233 (± 3.7%) i/s - 3.519k in 5.061335s
|
270
309
|
# sequel title id select
|
271
|
-
#
|
272
|
-
#
|
273
|
-
# 1.183k (± 3.2%) i/s - 5.967k in 5.048635s
|
274
|
-
# pg select title id 1.040k (± 1.4%) i/s - 5.253k in 5.051679s
|
310
|
+
# 916.841 (± 3.7%) i/s - 4.655k in 5.084499s
|
311
|
+
# pg select title id 1.002k (± 4.0%) i/s - 5.044k in 5.040584s
|
275
312
|
# mini_sql select title id
|
276
|
-
# 1.
|
313
|
+
# 1.106k (± 2.4%) i/s - 5.618k in 5.084423s
|
314
|
+
# sequel title id pluck
|
315
|
+
# 1.181k (± 3.5%) i/s - 5.980k in 5.069815s
|
316
|
+
# mini_sql query_single title id
|
317
|
+
# 1.171k (± 3.1%) i/s - 5.880k in 5.025793s
|
277
318
|
#
|
278
319
|
# Comparison:
|
279
|
-
# sequel title id pluck:
|
280
|
-
# mini_sql
|
281
|
-
#
|
282
|
-
#
|
283
|
-
#
|
284
|
-
#
|
320
|
+
# sequel title id pluck: 1181.0 i/s
|
321
|
+
# mini_sql query_single title id: 1171.1 i/s - same-ish: difference falls within error
|
322
|
+
# mini_sql select title id: 1105.6 i/s - 1.07x slower
|
323
|
+
# pg select title id: 1002.2 i/s - 1.18x slower
|
324
|
+
# sequel title id select: 916.8 i/s - 1.29x slower
|
325
|
+
# ar select title id pluck: 696.2 i/s - 1.70x slower
|
326
|
+
# ar select title id: 131.6 i/s - 8.98x slower
|
285
327
|
#
|
328
|
+
|
286
329
|
# to run deep analysis run
|
287
330
|
# MemoryProfiler.report do
|
288
331
|
# ar
|
data/lib/mini_sql/builder.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class MiniSql::Builder
|
2
4
|
|
3
5
|
def initialize(connection, template)
|
@@ -8,9 +10,13 @@ class MiniSql::Builder
|
|
8
10
|
end
|
9
11
|
|
10
12
|
[:set, :where2, :where, :order_by, :limit, :left_join, :join, :offset, :select].each do |k|
|
11
|
-
define_method k do |data, args
|
13
|
+
define_method k do |data, *args|
|
12
14
|
@args ||= {}
|
13
|
-
|
15
|
+
if Hash === args
|
16
|
+
@args.merge!(args)
|
17
|
+
elsif args && args.length > 0
|
18
|
+
data = @connection.param_encoder.encode(data, *args)
|
19
|
+
end
|
14
20
|
@sections[k] ||= []
|
15
21
|
@sections[k] << data
|
16
22
|
self
|
@@ -24,21 +30,21 @@ class MiniSql::Builder
|
|
24
30
|
joined = nil
|
25
31
|
case k
|
26
32
|
when :select
|
27
|
-
joined = "SELECT " << v.join(" , ")
|
33
|
+
joined = (+"SELECT ") << v.join(" , ")
|
28
34
|
when :where, :where2
|
29
|
-
joined = "WHERE " << v.map { |c| "(" << c << ")" }.join(" AND ")
|
35
|
+
joined = (+"WHERE ") << v.map { |c| (+"(") << c << ")" }.join(" AND ")
|
30
36
|
when :join
|
31
|
-
joined = v.map { |item| "JOIN " << item }.join("\n")
|
37
|
+
joined = v.map { |item| (+"JOIN ") << item }.join("\n")
|
32
38
|
when :left_join
|
33
|
-
joined = v.map { |item| "LEFT JOIN " << item }.join("\n")
|
39
|
+
joined = v.map { |item| (+"LEFT JOIN ") << item }.join("\n")
|
34
40
|
when :limit
|
35
|
-
joined = "LIMIT " << v.last.to_s
|
41
|
+
joined = (+"LIMIT ") << v.last.to_i.to_s
|
36
42
|
when :offset
|
37
|
-
joined = "OFFSET " << v.last.to_s
|
43
|
+
joined = (+"OFFSET ") << v.last.to_i.to_s
|
38
44
|
when :order_by
|
39
|
-
joined = "ORDER BY " << v.join(" , ")
|
45
|
+
joined = (+"ORDER BY ") << v.join(" , ")
|
40
46
|
when :set
|
41
|
-
joined = "SET " << v.join(" , ")
|
47
|
+
joined = (+"SET ") << v.join(" , ")
|
42
48
|
end
|
43
49
|
|
44
50
|
sql.sub!("/*#{k}*/", joined)
|
@@ -46,20 +52,13 @@ class MiniSql::Builder
|
|
46
52
|
sql
|
47
53
|
end
|
48
54
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def exec(args = nil)
|
58
|
-
if args
|
59
|
-
@args.merge!(args)
|
60
|
-
end
|
61
|
-
sql = to_sql
|
62
|
-
@connection.exec(sql, @args)
|
55
|
+
[:query, :query_single, :query_hash, :exec].each do |m|
|
56
|
+
class_eval <<~RUBY
|
57
|
+
def #{m}(hash_args = nil)
|
58
|
+
hash_args = @args.merge(hash_args) if hash_args
|
59
|
+
@connection.#{m}(to_sql, hash_args || @args)
|
60
|
+
end
|
61
|
+
RUBY
|
63
62
|
end
|
64
63
|
|
65
64
|
end
|
data/lib/mini_sql/connection.rb
CHANGED
@@ -2,8 +2,7 @@
|
|
2
2
|
|
3
3
|
module MiniSql
|
4
4
|
class Connection
|
5
|
-
attr_reader :raw_connection
|
6
|
-
attr_reader :type_map
|
5
|
+
attr_reader :raw_connection, :type_map, :param_encoder
|
7
6
|
|
8
7
|
def self.default_deserializer_cache
|
9
8
|
@deserializer_cache ||= DeserializerCache.new
|
@@ -100,7 +99,7 @@ module MiniSql
|
|
100
99
|
|
101
100
|
def run(sql, params)
|
102
101
|
if params && params.length > 0
|
103
|
-
sql =
|
102
|
+
sql = param_encoder.encode(sql, *params)
|
104
103
|
end
|
105
104
|
raw_connection.async_exec(sql)
|
106
105
|
end
|
data/lib/mini_sql/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_sql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -119,7 +119,6 @@ files:
|
|
119
119
|
- ".travis.yml"
|
120
120
|
- CODE_OF_CONDUCT.md
|
121
121
|
- Gemfile
|
122
|
-
- Gemfile.lock
|
123
122
|
- Guardfile
|
124
123
|
- LICENSE.txt
|
125
124
|
- README.md
|
data/Gemfile.lock
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
mini_sql (0.1.5)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
activesupport (5.2.0)
|
10
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
-
i18n (>= 0.7, < 2)
|
12
|
-
minitest (~> 5.1)
|
13
|
-
tzinfo (~> 1.1)
|
14
|
-
coderay (1.1.2)
|
15
|
-
concurrent-ruby (1.0.5)
|
16
|
-
ffi (1.9.25)
|
17
|
-
formatador (0.2.5)
|
18
|
-
guard (2.14.2)
|
19
|
-
formatador (>= 0.2.4)
|
20
|
-
listen (>= 2.7, < 4.0)
|
21
|
-
lumberjack (>= 1.0.12, < 2.0)
|
22
|
-
nenv (~> 0.1)
|
23
|
-
notiffany (~> 0.0)
|
24
|
-
pry (>= 0.9.12)
|
25
|
-
shellany (~> 0.0)
|
26
|
-
thor (>= 0.18.1)
|
27
|
-
guard-compat (1.2.1)
|
28
|
-
guard-minitest (2.4.6)
|
29
|
-
guard-compat (~> 1.2)
|
30
|
-
minitest (>= 3.0)
|
31
|
-
i18n (1.0.1)
|
32
|
-
concurrent-ruby (~> 1.0)
|
33
|
-
listen (3.1.5)
|
34
|
-
rb-fsevent (~> 0.9, >= 0.9.4)
|
35
|
-
rb-inotify (~> 0.9, >= 0.9.7)
|
36
|
-
ruby_dep (~> 1.2)
|
37
|
-
lumberjack (1.0.13)
|
38
|
-
method_source (0.9.0)
|
39
|
-
minitest (5.11.3)
|
40
|
-
nenv (0.3.0)
|
41
|
-
notiffany (0.1.1)
|
42
|
-
nenv (~> 0.1)
|
43
|
-
shellany (~> 0.0)
|
44
|
-
pg (1.0.0)
|
45
|
-
pry (0.11.3)
|
46
|
-
coderay (~> 1.1.0)
|
47
|
-
method_source (~> 0.9.0)
|
48
|
-
rake (10.5.0)
|
49
|
-
rb-fsevent (0.10.3)
|
50
|
-
rb-inotify (0.9.10)
|
51
|
-
ffi (>= 0.5.0, < 2)
|
52
|
-
ruby_dep (1.5.0)
|
53
|
-
shellany (0.0.1)
|
54
|
-
thor (0.20.0)
|
55
|
-
thread_safe (0.3.6)
|
56
|
-
tzinfo (1.2.5)
|
57
|
-
thread_safe (~> 0.1)
|
58
|
-
|
59
|
-
PLATFORMS
|
60
|
-
ruby
|
61
|
-
|
62
|
-
DEPENDENCIES
|
63
|
-
activesupport (~> 5.2)
|
64
|
-
bundler (~> 1.16)
|
65
|
-
guard (~> 2.14)
|
66
|
-
guard-minitest (~> 2.4)
|
67
|
-
mini_sql!
|
68
|
-
minitest (~> 5.0)
|
69
|
-
pg (~> 1.0.0)
|
70
|
-
rake (~> 10.0)
|
71
|
-
|
72
|
-
BUNDLED WITH
|
73
|
-
1.16.2
|