sql_runner 0.1.0 → 0.2.0
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 +5 -5
- data/.gitignore +1 -1
- data/.rubocop.yml +6 -0
- data/.travis.yml +20 -4
- data/Gemfile +2 -0
- data/README.md +6 -3
- data/Rakefile +4 -2
- data/bin/console +1 -0
- data/examples/bench.rb +21 -5
- data/examples/profiling.rb +2 -0
- data/examples/test.rb +13 -9
- data/lib/sql_runner.rb +6 -2
- data/lib/sql_runner/adapters.rb +14 -7
- data/lib/sql_runner/adapters/mysql.rb +99 -0
- data/lib/sql_runner/adapters/postgresql.rb +18 -19
- data/lib/sql_runner/configuration.rb +2 -0
- data/lib/sql_runner/connection.rb +3 -1
- data/lib/sql_runner/query.rb +25 -8
- data/lib/sql_runner/query/many.rb +2 -0
- data/lib/sql_runner/query/model.rb +3 -1
- data/lib/sql_runner/query/one.rb +10 -1
- data/lib/sql_runner/runner.rb +2 -0
- data/lib/sql_runner/version.rb +3 -1
- data/sql_runner.gemspec +17 -8
- metadata +28 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 7a50f9a5b18f7be9951324422fdeaeccc9c730bd4d65fcb4d35549ef1ce74fee
|
|
4
|
+
data.tar.gz: a4f6d679838c59c469cf456965d8e76bddc96b0a5747c3c9b7ce1a40ce6747c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 98aacdc458f23e6a47c462e5665c7c20dd9fc966af5d597e20aa1e572bf33b589407b415fe2e326c224c641103b3f4aba60ef5f720a2902dda1c5ab74249e5ef
|
|
7
|
+
data.tar.gz: 3972eba432a3cb7aa5f67796b80db01206e82f56770350054bb6c544f1ed5af93c198486f6bf520765ccf8b26e166b9a5fea82140da72c7f93064b922d6877a5
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
data/.travis.yml
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
|
+
---
|
|
1
2
|
language: ruby
|
|
2
3
|
cache: bundler
|
|
3
4
|
sudo: false
|
|
4
5
|
rvm:
|
|
5
|
-
- 2.
|
|
6
|
+
- 2.7.0
|
|
7
|
+
services:
|
|
8
|
+
- mysql
|
|
9
|
+
addons:
|
|
10
|
+
postgresql: "10"
|
|
11
|
+
apt:
|
|
12
|
+
packages:
|
|
13
|
+
- postgresql-10
|
|
14
|
+
- postgresql-client-10
|
|
15
|
+
before_script:
|
|
16
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
17
|
+
- chmod +x ./cc-test-reporter
|
|
18
|
+
- "./cc-test-reporter before-build"
|
|
19
|
+
after_script:
|
|
20
|
+
- "./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT"
|
|
6
21
|
before_install:
|
|
7
|
-
- gem install bundler
|
|
8
|
-
- createdb test
|
|
22
|
+
- gem install bundler
|
|
23
|
+
- createdb test
|
|
24
|
+
- mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
|
|
9
25
|
notifications:
|
|
10
26
|
email: false
|
|
11
27
|
env:
|
|
12
28
|
global:
|
|
13
|
-
secure:
|
|
29
|
+
secure: 4dDrl8nCItKPRKpoA2KJVWsDm3o7U0pIsdY8t19pJXbziteT3zw5pEmFh+/qWGB1VszzFFZzXcZCIoKv3NX/x24g+LU+qvL7vLYLyhUR8ZjR4rGzGkwBCgEYBWgVtqg9ncYTbYsdbAqryt6f+HvpFj8EFvGSjIWVqJyh59qHdwAVT+BUKjllEH+t5Dbjd2knIQw83af+0A5ljP2uMziNcuHD7MUBIKY1DfFnBYQ5YA50o/mZe8sG5h6bZU/sf0pdoa+z2xDIJOPO7qaCwANACetDtsfs1DN39DsubvlFLg0s2z0XCuYyWSsJQ4zhRipHgnqYn+Rmpql17t0WmhVPA1xvLyk0/4X8rjRcYyYHMM3ryga5bnrpvSiPsqG+JFNhDczpN394KGa7o+/jCuNA0MVFcCzsvW2AMkYpUbPtADY7/Tl4iUJWmFbl0nO1n1wh5dDJ7Wo7mdkPAmdV7hNmMUmHbPeh8mSjMnuS2gcMc11wDgmR56TEMu/B7LUM31og7L+JouEJAOWtzThtpdYLpqDQ3Xe1G5uMl1oZ0lNOqag5Bg+AQCAIGr1N4G2m8fI74M9lUQUfhu87L+zycYMHInOH+Czc+RamlkH3vLl9Fu6aOKoXA0+zh85sVDj3Er+X2NEHaoRe4PSkOHOBNYSkAUd36TYMt8J5MgAD0w7HqmY=
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# SQLRunner
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/fnando/sql_runner)
|
|
4
4
|
[](https://codeclimate.com/github/fnando/sql_runner)
|
|
5
5
|
[](https://codeclimate.com/github/fnando/sql_runner/coverage)
|
|
6
6
|
[](https://rubygems.org/gems/sql_runner)
|
|
7
7
|
[](https://rubygems.org/gems/sql_runner)
|
|
8
8
|
|
|
9
|
-
SQLRunner allows you to load your queries out of SQL files, without using ORMs. Available
|
|
9
|
+
SQLRunner allows you to load your queries out of SQL files, without using ORMs. Available for PostgreSQL and MySQL.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -145,8 +145,11 @@ module ReverseRecords
|
|
|
145
145
|
super(**bind_vars).to_a.reverse
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
|
+
```
|
|
148
149
|
|
|
149
150
|
# Register the plugin.
|
|
151
|
+
|
|
152
|
+
```ruby
|
|
150
153
|
SQLRunner::Query.register_plugin :reverse, ReverseRecords
|
|
151
154
|
|
|
152
155
|
class Users < SQLRunner::Query
|
|
@@ -157,7 +160,7 @@ end
|
|
|
157
160
|
Users.call
|
|
158
161
|
```
|
|
159
162
|
|
|
160
|
-
If
|
|
163
|
+
If your plugin can receive options, you can call it as `plugin reverse: options`, where `options` can be anything (e.g. `Hash`, `Array`, `Object`, etc).
|
|
161
164
|
|
|
162
165
|
## Benchmarks
|
|
163
166
|
|
data/Rakefile
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "bundler/gem_tasks"
|
|
2
4
|
require "rake/testtask"
|
|
3
5
|
|
|
4
6
|
Rake::TestTask.new(:test) do |t|
|
|
5
7
|
t.libs << "test"
|
|
6
8
|
t.libs << "lib"
|
|
7
|
-
t.test_files = FileList[
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
8
10
|
t.warning = false
|
|
9
11
|
end
|
|
10
12
|
|
|
11
|
-
task :
|
|
13
|
+
task default: :test
|
data/bin/console
CHANGED
data/examples/bench.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
$LOAD_PATH.push File.expand_path("#{__dir__}/../lib")
|
|
2
4
|
require "sql_runner"
|
|
3
5
|
require "virtus"
|
|
@@ -13,7 +15,9 @@ SQLRunner.pool = 25
|
|
|
13
15
|
SQLRunner.timeout = 10
|
|
14
16
|
SQLRunner.root_dir = "#{__dir__}/sql"
|
|
15
17
|
|
|
16
|
-
ActiveRecord::Base.establish_connection(
|
|
18
|
+
ActiveRecord::Base.establish_connection(
|
|
19
|
+
"#{connection_string}&prepared_statements=false&pool=25"
|
|
20
|
+
)
|
|
17
21
|
|
|
18
22
|
module Types
|
|
19
23
|
include Dry::Types.module
|
|
@@ -77,10 +81,22 @@ class Users < SQLRunner::Query
|
|
|
77
81
|
end
|
|
78
82
|
|
|
79
83
|
Benchmark.ips do |x|
|
|
80
|
-
x.report("activerecord - find one
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
x.report("activerecord - find one") do
|
|
85
|
+
User.find_by_email("me@fnando.com")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
x.report(" sql_runner - find one (dry-types)") do
|
|
89
|
+
FindUserDry.call(email: "me@fnando.com")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
x.report(" sql_runner - find one (virtus)") do
|
|
93
|
+
FindUserVirtus.call(email: "me@fnando.com")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
x.report(" sql_runner - find one (raw)") do
|
|
97
|
+
FindUser.call(email: "me@fnando.com")
|
|
98
|
+
end
|
|
99
|
+
|
|
84
100
|
x.compare!
|
|
85
101
|
end
|
|
86
102
|
|
data/examples/profiling.rb
CHANGED
data/examples/test.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
$LOAD_PATH.push File.expand_path("#{__dir__}/../lib")
|
|
2
4
|
require "sql_runner"
|
|
3
5
|
require "virtus"
|
|
@@ -7,15 +9,17 @@ SQLRunner.pool = 25
|
|
|
7
9
|
SQLRunner.timeout = 10
|
|
8
10
|
SQLRunner.root_dir = "#{__dir__}/sql"
|
|
9
11
|
|
|
10
|
-
result = SQLRunner.execute
|
|
12
|
+
result = SQLRunner.execute(
|
|
13
|
+
"select application_name from pg_stat_activity where pid = pg_backend_pid();"
|
|
14
|
+
)
|
|
11
15
|
p result.to_a
|
|
12
16
|
|
|
13
|
-
result = SQLRunner.execute
|
|
14
|
-
select
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
result = SQLRunner.execute <<~SQL, name: "john", age: 18
|
|
18
|
+
select
|
|
19
|
+
'hello'::text as message,
|
|
20
|
+
:name::text as name,
|
|
21
|
+
:age::integer as age,
|
|
22
|
+
:name::text as name2
|
|
19
23
|
SQL
|
|
20
24
|
p result.to_a
|
|
21
25
|
|
|
@@ -86,8 +90,8 @@ p FindCustomer.call!(email: "me@fnando.com")
|
|
|
86
90
|
|
|
87
91
|
begin
|
|
88
92
|
FindUser.call!(email: "me@fnando.coms")
|
|
89
|
-
rescue SQLRunner::RecordNotFound =>
|
|
90
|
-
p
|
|
93
|
+
rescue SQLRunner::RecordNotFound => e
|
|
94
|
+
p e
|
|
91
95
|
end
|
|
92
96
|
|
|
93
97
|
SQLRunner.disconnect
|
data/lib/sql_runner.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "uri"
|
|
2
4
|
require "connection_pool"
|
|
3
5
|
|
|
@@ -17,11 +19,13 @@ module SQLRunner
|
|
|
17
19
|
|
|
18
20
|
Adapters.register("postgres", Adapters::PostgreSQL)
|
|
19
21
|
Adapters.register("postgresql", Adapters::PostgreSQL)
|
|
22
|
+
Adapters.register("mysql", Adapters::MySQL)
|
|
23
|
+
Adapters.register("mysql2", Adapters::MySQL)
|
|
20
24
|
|
|
21
25
|
Query.register_plugin :one, Query::One
|
|
22
26
|
Query.register_plugin :many, Query::Many
|
|
23
27
|
Query.register_plugin :model, Query::Model
|
|
24
28
|
|
|
25
|
-
self.timeout = ENV.fetch("SQL_CONNECTION_TIMEOUT", 5)
|
|
26
|
-
self.pool
|
|
29
|
+
self.timeout = Integer(ENV.fetch("SQL_CONNECTION_TIMEOUT", 5))
|
|
30
|
+
self.pool = Integer(ENV.fetch("SQL_CONNECTION_POOL", 5))
|
|
27
31
|
end
|
data/lib/sql_runner/adapters.rb
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
4
|
UnsupportedDatabase = Class.new(StandardError)
|
|
3
|
-
MissingDependency
|
|
5
|
+
MissingDependency = Class.new(StandardError)
|
|
6
|
+
|
|
7
|
+
def self.adapter_registry
|
|
8
|
+
@adapter_registry ||= {}
|
|
9
|
+
end
|
|
4
10
|
|
|
5
11
|
module Adapters
|
|
6
12
|
require "sql_runner/adapters/postgresql"
|
|
7
|
-
|
|
8
|
-
ADAPTERS = {}
|
|
13
|
+
require "sql_runner/adapters/mysql"
|
|
9
14
|
|
|
10
15
|
def self.register(name, adapter)
|
|
11
|
-
|
|
16
|
+
SQLRunner.adapter_registry[name] = adapter
|
|
12
17
|
end
|
|
13
18
|
|
|
14
19
|
def self.find(name)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
adapter = SQLRunner.adapter_registry.fetch(name) do
|
|
21
|
+
raise UnsupportedDatabase, "#{name} is not supported by SQLRunner"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
adapter.tap(&:load)
|
|
18
25
|
end
|
|
19
26
|
end
|
|
20
27
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SQLRunner
|
|
4
|
+
module Adapters
|
|
5
|
+
class MySQL
|
|
6
|
+
InvalidPreparedStatement = Class.new(StandardError)
|
|
7
|
+
|
|
8
|
+
def self.load
|
|
9
|
+
require "mysql2"
|
|
10
|
+
rescue LoadError
|
|
11
|
+
raise MissingDependency, "make sure the `mysql2` gem is available"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(connection_string)
|
|
15
|
+
@connection_string = connection_string
|
|
16
|
+
@uri = URI.parse(@connection_string)
|
|
17
|
+
connect
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def connect(started = Process.clock_gettime(Process::CLOCK_MONOTONIC))
|
|
21
|
+
@connection = Mysql2::Client.new(
|
|
22
|
+
host: @uri.host,
|
|
23
|
+
port: @uri.port,
|
|
24
|
+
username: @uri.user,
|
|
25
|
+
password: @uri.password,
|
|
26
|
+
database: @uri.path[1..-1]
|
|
27
|
+
)
|
|
28
|
+
rescue Mysql2::Error
|
|
29
|
+
ended = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
30
|
+
|
|
31
|
+
raise unless ended - started < SQLRunner.timeout
|
|
32
|
+
|
|
33
|
+
sleep 0.1
|
|
34
|
+
connect(started)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def disconnect
|
|
38
|
+
@connection&.close && (@connection = nil)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reconnect
|
|
42
|
+
disconnect
|
|
43
|
+
connect
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def execute(query, **bind_vars)
|
|
47
|
+
bound_query, bindings, names = parse(query, bind_vars)
|
|
48
|
+
validate_bindings(query, bind_vars, names)
|
|
49
|
+
|
|
50
|
+
statement = @connection.prepare(bound_query)
|
|
51
|
+
statement.execute(*bindings, cast: true)
|
|
52
|
+
rescue Mysql2::Error
|
|
53
|
+
reconnect
|
|
54
|
+
execute(query, **bind_vars)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def active?
|
|
58
|
+
!@connection&.closed?
|
|
59
|
+
rescue Mysql2::Error
|
|
60
|
+
false
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def to_s
|
|
64
|
+
%[#<#{self.class.name} #{format('0x00%x', (object_id << 1))}>]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def inspect
|
|
68
|
+
to_s
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse(query, bind_vars)
|
|
72
|
+
bindings = []
|
|
73
|
+
names = []
|
|
74
|
+
|
|
75
|
+
parsed_query = query.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
|
|
76
|
+
next match if Regexp.last_match(1) == ":" # skip type casting
|
|
77
|
+
|
|
78
|
+
name = match[1..-1]
|
|
79
|
+
sym_name = name.to_sym
|
|
80
|
+
names << sym_name
|
|
81
|
+
bindings << bind_vars[sym_name]
|
|
82
|
+
|
|
83
|
+
"?"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
[parsed_query, bindings, names]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private def validate_bindings(query, bind_vars, names)
|
|
90
|
+
names.each do |name|
|
|
91
|
+
next if bind_vars.key?(name)
|
|
92
|
+
|
|
93
|
+
raise InvalidPreparedStatement,
|
|
94
|
+
"missing value for :#{name} in #{query}"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
4
|
module Adapters
|
|
3
5
|
class PostgreSQL
|
|
@@ -6,7 +8,7 @@ module SQLRunner
|
|
|
6
8
|
def self.load
|
|
7
9
|
require "pg"
|
|
8
10
|
rescue LoadError
|
|
9
|
-
|
|
11
|
+
raise MissingDependency, "make sure the `pg` gem is available"
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def initialize(connection_string)
|
|
@@ -19,16 +21,14 @@ module SQLRunner
|
|
|
19
21
|
rescue PG::ConnectionBad
|
|
20
22
|
ended = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
raise
|
|
27
|
-
end
|
|
24
|
+
raise unless ended - started < SQLRunner.timeout
|
|
25
|
+
|
|
26
|
+
sleep 0.1
|
|
27
|
+
connect(started)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def disconnect
|
|
31
|
-
@connection
|
|
31
|
+
@connection&.close && (@connection = nil)
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def reconnect
|
|
@@ -36,14 +36,10 @@ module SQLRunner
|
|
|
36
36
|
connect
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def connection
|
|
40
|
-
@connection
|
|
41
|
-
end
|
|
42
|
-
|
|
43
39
|
def execute(query, **bind_vars)
|
|
44
|
-
|
|
40
|
+
bound_query, bindings = parse(query)
|
|
45
41
|
args = extract_args(query, bindings, bind_vars)
|
|
46
|
-
@connection.exec_params(
|
|
42
|
+
@connection.exec_params(bound_query, args)
|
|
47
43
|
rescue PG::ConnectionBad
|
|
48
44
|
reconnect
|
|
49
45
|
execute(query, **bind_vars)
|
|
@@ -56,24 +52,24 @@ module SQLRunner
|
|
|
56
52
|
end
|
|
57
53
|
|
|
58
54
|
def to_s
|
|
59
|
-
%[#<#{self.class.name} #{
|
|
55
|
+
%[#<#{self.class.name} #{format('0x00%x', (object_id << 1))}>]
|
|
60
56
|
end
|
|
61
57
|
|
|
62
58
|
def inspect
|
|
63
59
|
to_s
|
|
64
60
|
end
|
|
65
61
|
|
|
66
|
-
def parse(query)
|
|
62
|
+
def parse(query) # rubocop:disable Metrics/MethodLength
|
|
67
63
|
bindings = {}
|
|
68
64
|
count = 0
|
|
69
65
|
|
|
70
66
|
parsed_query = query.gsub(/(:?):([a-zA-Z]\w*)/) do |match|
|
|
71
|
-
next match if
|
|
67
|
+
next match if Regexp.last_match(1) == ":" # skip type casting
|
|
72
68
|
|
|
73
69
|
name = match[1..-1]
|
|
74
70
|
sym_name = name.to_sym
|
|
75
71
|
|
|
76
|
-
|
|
72
|
+
unless (index = bindings[sym_name])
|
|
77
73
|
index = (count += 1)
|
|
78
74
|
bindings[sym_name] = index
|
|
79
75
|
end
|
|
@@ -86,7 +82,10 @@ module SQLRunner
|
|
|
86
82
|
|
|
87
83
|
private def extract_args(query, bindings, bind_vars)
|
|
88
84
|
bindings.each_with_object([]) do |(name, position), buffer|
|
|
89
|
-
buffer[position - 1] = bind_vars.fetch(name)
|
|
85
|
+
buffer[position - 1] = bind_vars.fetch(name) do
|
|
86
|
+
raise InvalidPreparedStatement,
|
|
87
|
+
"missing value for :#{name} in #{query}"
|
|
88
|
+
end
|
|
90
89
|
end
|
|
91
90
|
end
|
|
92
91
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
4
|
module Connection
|
|
3
5
|
def self.call(connection_string)
|
|
@@ -18,7 +20,7 @@ module SQLRunner
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def disconnect
|
|
21
|
-
connection_pool
|
|
23
|
+
connection_pool&.shutdown(&:disconnect) && (@connection_pool = nil)
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
def connection_pool
|
data/lib/sql_runner/query.rb
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
|
-
RecordNotFound
|
|
3
|
-
PluginNotFound
|
|
4
|
+
RecordNotFound = Class.new(StandardError)
|
|
5
|
+
PluginNotFound = Class.new(StandardError)
|
|
4
6
|
InvalidPluginOrder = Class.new(StandardError)
|
|
7
|
+
NotImplemented = Class.new(StandardError)
|
|
8
|
+
|
|
9
|
+
def self.plugin_registry
|
|
10
|
+
@plugin_registry ||= {}
|
|
11
|
+
end
|
|
5
12
|
|
|
6
13
|
class Query
|
|
7
14
|
extend Runner
|
|
8
15
|
|
|
9
|
-
|
|
16
|
+
def self.inherited(subclass)
|
|
17
|
+
subclass.instance_variable_set(:@connection_pool, @connection_pool)
|
|
18
|
+
subclass.instance_variable_set(:@root_dir, @root_dir)
|
|
19
|
+
end
|
|
10
20
|
|
|
11
21
|
def self.query_name(*values)
|
|
12
22
|
@query_name = values.first if values.any?
|
|
@@ -14,9 +24,13 @@ module SQLRunner
|
|
|
14
24
|
end
|
|
15
25
|
|
|
16
26
|
def self.query_name_from_class
|
|
27
|
+
replacer = proc do
|
|
28
|
+
"#{Regexp.last_match(1)}_#{Regexp.last_match(2).downcase}"
|
|
29
|
+
end
|
|
30
|
+
|
|
17
31
|
name
|
|
18
32
|
.gsub("::", "/")
|
|
19
|
-
.gsub(/([a-z0-9])([A-Z])
|
|
33
|
+
.gsub(/([a-z0-9])([A-Z])/, &replacer)
|
|
20
34
|
.downcase
|
|
21
35
|
end
|
|
22
36
|
|
|
@@ -39,24 +53,27 @@ module SQLRunner
|
|
|
39
53
|
end
|
|
40
54
|
|
|
41
55
|
def self.register_plugin(name, mod)
|
|
42
|
-
|
|
56
|
+
SQLRunner.plugin_registry[name] = mod
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
def self.plugin(*names)
|
|
46
|
-
plugins
|
|
60
|
+
plugins(*names)
|
|
47
61
|
end
|
|
48
62
|
|
|
49
63
|
def self.plugins(*names)
|
|
50
64
|
names = prepare_plugins_with_options(names)
|
|
51
65
|
|
|
52
66
|
names.each do |name, options|
|
|
53
|
-
plugin =
|
|
67
|
+
plugin = SQLRunner.plugin_registry.fetch(name) do
|
|
68
|
+
raise PluginNotFound, "#{name.inspect} wasn't found"
|
|
69
|
+
end
|
|
70
|
+
|
|
54
71
|
plugin.activate(self, options)
|
|
55
72
|
end
|
|
56
73
|
end
|
|
57
74
|
|
|
58
75
|
def self.prepare_plugins_with_options(plugins)
|
|
59
|
-
return plugins unless plugins.last.
|
|
76
|
+
return plugins unless plugins.last.is_a?(Hash)
|
|
60
77
|
|
|
61
78
|
plugins_with_options = plugins.pop
|
|
62
79
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
4
|
class Query
|
|
3
5
|
module Model
|
|
@@ -13,7 +15,7 @@ module SQLRunner
|
|
|
13
15
|
def call(**bind_vars)
|
|
14
16
|
result = super(**bind_vars)
|
|
15
17
|
return unless result
|
|
16
|
-
return model.new(result) if result.
|
|
18
|
+
return model.new(result) if result.is_a?(Hash)
|
|
17
19
|
|
|
18
20
|
result.to_a.map do |attrs|
|
|
19
21
|
model.new(attrs)
|
data/lib/sql_runner/query/one.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module SQLRunner
|
|
2
4
|
class Query
|
|
3
5
|
module One
|
|
@@ -11,7 +13,14 @@ module SQLRunner
|
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def call!(**bind_vars)
|
|
14
|
-
call(**bind_vars)
|
|
16
|
+
result = call(**bind_vars)
|
|
17
|
+
|
|
18
|
+
return if result
|
|
19
|
+
|
|
20
|
+
raise(
|
|
21
|
+
SQLRunner::RecordNotFound,
|
|
22
|
+
"#{name}: record was not found with #{bind_vars.inspect} arguments"
|
|
23
|
+
)
|
|
15
24
|
end
|
|
16
25
|
end
|
|
17
26
|
end
|
data/lib/sql_runner/runner.rb
CHANGED
data/lib/sql_runner/version.rb
CHANGED
data/sql_runner.gemspec
CHANGED
|
@@ -1,28 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "./lib/sql_runner/version"
|
|
2
4
|
|
|
3
5
|
Gem::Specification.new do |spec|
|
|
4
6
|
spec.name = "sql_runner"
|
|
5
7
|
spec.version = SQLRunner::VERSION
|
|
6
8
|
spec.authors = ["Nando Vieira"]
|
|
7
|
-
spec.email = ["fnando.
|
|
9
|
+
spec.email = ["me@fnando.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = <<~TEXT.gsub(/\n/, " ")
|
|
12
|
+
SQLRunner allows you to load your queries out of SQL files, without using
|
|
13
|
+
ORMs.
|
|
14
|
+
TEXT
|
|
8
15
|
|
|
9
|
-
spec.summary = "SQLRunner allows you to load your queries out of SQL files, without using ORMs. Available only for PostgreSQL."
|
|
10
16
|
spec.description = spec.summary
|
|
11
17
|
spec.homepage = "https://github.com/fnando/sql_runner"
|
|
12
18
|
spec.license = "MIT"
|
|
13
19
|
|
|
14
|
-
spec.files = `git ls-files -z
|
|
20
|
+
spec.files = `git ls-files -z`
|
|
21
|
+
.split("\x0")
|
|
22
|
+
.reject {|f| f.match(%r{^(test|spec|features)/}) }
|
|
15
23
|
spec.bindir = "exe"
|
|
16
|
-
spec.executables = spec.files.grep(%r{^exe/}) {
|
|
24
|
+
spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
|
|
17
25
|
spec.require_paths = ["lib"]
|
|
18
26
|
|
|
19
27
|
spec.add_dependency "connection_pool"
|
|
20
28
|
|
|
21
29
|
spec.add_development_dependency "bundler"
|
|
22
|
-
spec.add_development_dependency "rake"
|
|
23
30
|
spec.add_development_dependency "minitest-utils"
|
|
24
|
-
spec.add_development_dependency "pry-meta"
|
|
25
|
-
spec.add_development_dependency "pg"
|
|
26
31
|
spec.add_development_dependency "mocha"
|
|
27
|
-
spec.add_development_dependency "
|
|
32
|
+
spec.add_development_dependency "mysql2"
|
|
33
|
+
spec.add_development_dependency "pg"
|
|
34
|
+
spec.add_development_dependency "pry-meta"
|
|
35
|
+
spec.add_development_dependency "rake"
|
|
36
|
+
spec.add_development_dependency "simplecov"
|
|
28
37
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sql_runner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nando Vieira
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-01-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: connection_pool
|
|
@@ -39,7 +39,7 @@ dependencies:
|
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: minitest-utils
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
@@ -53,7 +53,7 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: mocha
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - ">="
|
|
@@ -67,7 +67,7 @@ dependencies:
|
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: mysql2
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - ">="
|
|
@@ -95,7 +95,21 @@ dependencies:
|
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: pry-meta
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rake
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
100
114
|
requirements:
|
|
101
115
|
- - ">="
|
|
@@ -109,7 +123,7 @@ dependencies:
|
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
124
|
version: '0'
|
|
111
125
|
- !ruby/object:Gem::Dependency
|
|
112
|
-
name:
|
|
126
|
+
name: simplecov
|
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
|
114
128
|
requirements:
|
|
115
129
|
- - ">="
|
|
@@ -123,17 +137,19 @@ dependencies:
|
|
|
123
137
|
- !ruby/object:Gem::Version
|
|
124
138
|
version: '0'
|
|
125
139
|
description: SQLRunner allows you to load your queries out of SQL files, without using
|
|
126
|
-
ORMs.
|
|
140
|
+
ORMs.
|
|
127
141
|
email:
|
|
128
|
-
- fnando.
|
|
142
|
+
- me@fnando.com
|
|
129
143
|
executables: []
|
|
130
144
|
extensions: []
|
|
131
145
|
extra_rdoc_files: []
|
|
132
146
|
files:
|
|
133
147
|
- ".gitignore"
|
|
148
|
+
- ".rubocop.yml"
|
|
134
149
|
- ".travis.yml"
|
|
135
150
|
- CODE_OF_CONDUCT.md
|
|
136
151
|
- Gemfile
|
|
152
|
+
- Gemfile.lock
|
|
137
153
|
- LICENSE.txt
|
|
138
154
|
- README.md
|
|
139
155
|
- Rakefile
|
|
@@ -148,6 +164,7 @@ files:
|
|
|
148
164
|
- examples/test.rb
|
|
149
165
|
- lib/sql_runner.rb
|
|
150
166
|
- lib/sql_runner/adapters.rb
|
|
167
|
+
- lib/sql_runner/adapters/mysql.rb
|
|
151
168
|
- lib/sql_runner/adapters/postgresql.rb
|
|
152
169
|
- lib/sql_runner/configuration.rb
|
|
153
170
|
- lib/sql_runner/connection.rb
|
|
@@ -177,10 +194,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
177
194
|
- !ruby/object:Gem::Version
|
|
178
195
|
version: '0'
|
|
179
196
|
requirements: []
|
|
180
|
-
|
|
181
|
-
rubygems_version: 2.5.1
|
|
197
|
+
rubygems_version: 3.1.2
|
|
182
198
|
signing_key:
|
|
183
199
|
specification_version: 4
|
|
184
200
|
summary: SQLRunner allows you to load your queries out of SQL files, without using
|
|
185
|
-
ORMs.
|
|
201
|
+
ORMs.
|
|
186
202
|
test_files: []
|