mini_sql 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b4a853f294d878decdf635afbfe2ef4029fe994ec710172038ec2a9ac664980
4
- data.tar.gz: 278a68ac45dda9070d30fd08d98ca9bb93ea6c8e5b378d7ebe7f085620797c77
3
+ metadata.gz: e88eaeeb85de88eed3c83b12481b9682a1de4327ee433098a46932866884c1d3
4
+ data.tar.gz: eac737d3b6281392099675b6d3bcd25d6493d836d66204fa7de229583c2a3be8
5
5
  SHA512:
6
- metadata.gz: ae6b7f73423e5001d80f0fc027fe0f2c557ac4961c1868e642087c50b8147bf2fca8b3431f8bec2603c33d762c533be57bb742d1ea5983481b4c3045ca348e73
7
- data.tar.gz: c6628d1b1ce3b9c2d0f6f553370f705f649d643c25ec1a524415fb5f3c871a9c93f80834698d6df8b82b04012917baaf3ada442bea585ddce3692bcc7af40870
6
+ metadata.gz: 166faf87640bb2a07fe7d2f4e146274f7229f8c56f61e4160c1296a7f5d9587a5e11be09168abd792807f3bc5a08cec21b835e2ae81dc978c175bec6e155d607
7
+ data.tar.gz: d43a73fa9abb29de17005b4e361c607509c7a34a82b88e07ad2a344820c3c1efe7bfced0358310c2286d1bf9cc63977c2159c8bbdc3df6233d028a3ca45dadec
data/.travis.yml CHANGED
@@ -1,5 +1,21 @@
1
- sudo: false
2
1
  language: ruby
3
2
  rvm:
4
3
  - 2.5.1
5
- before_install: gem install bundler -v 1.16.2
4
+ - ruby-head
5
+
6
+ before_install:
7
+ - gem install bundler
8
+
9
+ cache: bundler
10
+ sudo: false
11
+
12
+ addons:
13
+ postgresql: 9.6
14
+
15
+ install:
16
+ - createdb test_mini_sql
17
+ - bundle install
18
+
19
+ matrix:
20
+ allow_failures:
21
+ - rvm: ruby-head
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mini_sql (0.1.1)
4
+ mini_sql (0.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -37,6 +37,34 @@ puts conn.query_single('select 1 union select 2')
37
37
 
38
38
  ```
39
39
 
40
+ ## Is it fast?
41
+
42
+ Yes, it is very fast, see benchmarks [the bench directory](https://github.com/discourse/mini_sql/tree/master/bench)
43
+
44
+ As a rule it will outperform similar naive PG code while remaining safe.
45
+
46
+ ```ruby
47
+ pg_conn = PG.connect(db_name: 'my_db')
48
+
49
+ # this is slower, and less safe
50
+ pg_conn.async_exec('select * from table') do |r|
51
+ name = r['name']
52
+ end
53
+
54
+ # this is faster and safer
55
+ conn = MiniSql::Connection.new(pg_conn)
56
+ conn.query('select * from table') do |r|
57
+ name = r.name
58
+ end
59
+ ```
60
+
61
+ ## Safety
62
+
63
+ In current version of the PG gem you should be careful to clear results. If you do not you risk memory bloat.
64
+ See: [Sam's blog post](https://samsaffron.com/archive/2018/06/13/ruby-x27-s-external-malloc-problem).
65
+
66
+ MiniSql is careful to always clear results as soon as possible.
67
+
40
68
  ## Development
41
69
 
42
70
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
data/bench/topic_perf.rb CHANGED
@@ -34,7 +34,7 @@ SQL
34
34
 
35
35
  pg.async_exec <<SQL
36
36
  CREATE TABLE topics (
37
- id integer NOT NULL,
37
+ id integer NOT NULL PRIMARY KEY,
38
38
  title character varying NOT NULL,
39
39
  last_posted_at timestamp without time zone,
40
40
  created_at timestamp without time zone NOT NULL,
@@ -172,6 +172,56 @@ results = [ar_title_id, ar_title_id_pluck, pg_title_id, mini_sql_title_id, seque
172
172
 
173
173
  exit(-1) unless results.uniq.length == 1
174
174
 
175
+
176
+ def wide_topic_ar
177
+ Topic.first
178
+ end
179
+
180
+ def wide_topic_pg
181
+ r = $conn.async_exec("select * from topics limit 1")
182
+ row = r.first
183
+ r.clear
184
+ row
185
+ end
186
+
187
+ def wide_topic_sequel
188
+ TopicSequel.first
189
+ end
190
+
191
+ def wide_topic_mini_sql
192
+ $conn.query("select * from topics limit 1").first
193
+ end
194
+
195
+ Benchmark.ips do |r|
196
+ r.report("wide topic ar") do |n|
197
+ while n > 0
198
+ wide_topic_ar
199
+ n -= 1
200
+ end
201
+ end
202
+ r.report("wide topic sequel") do |n|
203
+ while n > 0
204
+ wide_topic_sequel
205
+ n -= 1
206
+ end
207
+ end
208
+ r.report("wide topic pg") do |n|
209
+ while n > 0
210
+ wide_topic_pg
211
+ n -= 1
212
+ end
213
+ end
214
+ r.report("wide topic mini sql") do |n|
215
+ while n > 0
216
+ wide_topic_mini_sql
217
+ n -= 1
218
+ end
219
+ end
220
+ r.compare!
221
+ end
222
+
223
+
224
+
175
225
  Benchmark.ips do |r|
176
226
  r.report("ar select title id") do |n|
177
227
  while n > 0
data/lib/mini_sql.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require_relative "mini_sql/version"
2
2
  require_relative "mini_sql/connection"
3
3
  require_relative "mini_sql/deserializer_cache"
4
+ require_relative "mini_sql/builder"
4
5
 
5
6
  module MiniSql
6
7
  autoload :Coders, "mini_sql/coders"
@@ -0,0 +1,65 @@
1
+ class MiniSql::Builder
2
+
3
+ def initialize(connection, template)
4
+ @args = {}
5
+ @sql = template
6
+ @sections = {}
7
+ @connection = connection
8
+ end
9
+
10
+ [:set, :where2, :where, :order_by, :limit, :left_join, :join, :offset, :select].each do |k|
11
+ define_method k do |data, args = {}|
12
+ @args.merge!(args)
13
+ @sections[k] ||= []
14
+ @sections[k] << data
15
+ self
16
+ end
17
+ end
18
+
19
+ def to_sql
20
+ sql = @sql.dup
21
+
22
+ @sections.each do |k, v|
23
+ joined = nil
24
+ case k
25
+ when :select
26
+ joined = "SELECT " << v.join(" , ")
27
+ when :where, :where2
28
+ joined = "WHERE " << v.map { |c| "(" << c << ")" }.join(" AND ")
29
+ when :join
30
+ joined = v.map { |item| "JOIN " << item }.join("\n")
31
+ when :left_join
32
+ joined = v.map { |item| "LEFT JOIN " << item }.join("\n")
33
+ when :limit
34
+ joined = "LIMIT " << v.last.to_s
35
+ when :offset
36
+ joined = "OFFSET " << v.last.to_s
37
+ when :order_by
38
+ joined = "ORDER BY " << v.join(" , ")
39
+ when :set
40
+ joined = "SET " << v.join(" , ")
41
+ end
42
+
43
+ sql.sub!("/*#{k}*/", joined)
44
+ end
45
+ sql
46
+ end
47
+
48
+ def query(args = nil)
49
+ if args
50
+ @args.merge!(args)
51
+ end
52
+ sql = to_sql
53
+ @connection.query(sql, args)
54
+ end
55
+
56
+ def exec(args = nil)
57
+ if args
58
+ @args.merge!(args)
59
+ end
60
+ sql = to_sql
61
+ @connection.query(sql, args)
62
+ end
63
+
64
+ end
65
+
@@ -5,5 +5,10 @@ module MiniSql
5
5
  string.to_f
6
6
  end
7
7
  end
8
+ class IPAddrCoder < PG::SimpleDecoder
9
+ def decode(string, tuple = nil, field = nil)
10
+ IPAddr.new(string)
11
+ end
12
+ end
8
13
  end
9
14
  end
@@ -10,6 +10,7 @@ module MiniSql
10
10
  begin
11
11
  map = PG::BasicTypeMapForResults.new(conn)
12
12
  map.add_coder(MiniSql::Coders::NumericCoder.new(name: "numeric", oid: 1700, format: 0))
13
+ map.add_coder(MiniSql::Coders::IPAddrCoder.new(name: "inet", oid: 869, format: 0))
13
14
  end
14
15
  end
15
16
 
@@ -43,6 +44,10 @@ module MiniSql
43
44
  result.clear if result
44
45
  end
45
46
 
47
+ def build(sql)
48
+ Builder.new(self, sql)
49
+ end
50
+
46
51
  private
47
52
 
48
53
  def run(sql, params)
@@ -55,11 +60,26 @@ module MiniSql
55
60
 
56
61
  def process_params(sql, params)
57
62
  sql = sql.dup
58
- param_array = []
63
+ param_array = nil
59
64
 
60
- params.each do |k, v|
61
- sql.gsub!(":#{k.to_s}", "$#{param_array.length + 1}")
62
- param_array << v
65
+ if Hash === params
66
+ param_array = []
67
+ params.each do |k, v|
68
+ sql.gsub!(":#{k.to_s}", "$#{param_array.length + 1}")
69
+ param_array << v
70
+ end
71
+ elsif Array === params
72
+ i = 0
73
+ sql.gsub!("?") do
74
+ i += 1
75
+ case params[i-1]
76
+ when Integer then "$#{i}::bigint"
77
+ when Float then "$#{i}::float8"
78
+ when String then "$#{i}::text"
79
+ else "$#{i}::unknown"
80
+ end
81
+ end
82
+ param_array = params
63
83
  end
64
84
 
65
85
  [sql, param_array]
@@ -1,3 +1,3 @@
1
1
  module MiniSql
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
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.1
4
+ version: 0.1.2
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-15 00:00:00.000000000 Z
11
+ date: 2018-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler