sql_runner 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Travis-CI](https://travis-ci.org/fnando/sql_runner.
|
3
|
+
[![Travis-CI](https://travis-ci.org/fnando/sql_runner.svg)](https://travis-ci.org/fnando/sql_runner)
|
4
4
|
[![Code Climate](https://codeclimate.com/github/fnando/sql_runner/badges/gpa.svg)](https://codeclimate.com/github/fnando/sql_runner)
|
5
5
|
[![Test Coverage](https://codeclimate.com/github/fnando/sql_runner/badges/coverage.svg)](https://codeclimate.com/github/fnando/sql_runner/coverage)
|
6
6
|
[![Gem](https://img.shields.io/gem/v/sql_runner.svg)](https://rubygems.org/gems/sql_runner)
|
7
7
|
[![Gem](https://img.shields.io/gem/dt/sql_runner.svg)](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: []
|