yesql 0.2.2 → 0.2.3
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/Gemfile.lock +1 -1
- data/lib/yesql.rb +12 -15
- data/lib/yesql/bindings/extract.rb +7 -3
- data/lib/yesql/bindings/extractor.rb +23 -18
- data/lib/yesql/bindings/utils.rb +7 -6
- data/lib/yesql/errors/file_path_does_not_exist_error.rb +16 -13
- data/lib/yesql/errors/no_bindings_provided_error.rb +27 -20
- data/lib/yesql/errors/output_argument_error.rb +21 -11
- data/lib/yesql/params/output.rb +1 -1
- data/lib/yesql/query/performer.rb +2 -2
- data/lib/yesql/query/result.rb +6 -4
- data/lib/yesql/query/transform_result.rb +7 -5
- data/lib/yesql/statement.rb +9 -6
- data/lib/yesql/utils/read.rb +18 -8
- data/lib/yesql/version.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f38a878a124272c8ed8f51d723cba49704d2e7b60b28920c562fdbc8e1d68836
|
4
|
+
data.tar.gz: dbfa7776c1eb0eeae767023504cb741dd05052fd992b3b01a218f849917d7696
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b781599e0e8d5f6a84bec509737595269f28e6347284046f2a7d767ff14256b79a8658643b0e077a453ce08bf4d23766e2eebbd1bcc19b952b43f3eeda94b87b
|
7
|
+
data.tar.gz: 6ac1827d64222972e9fd70bbdb216576581c86dd54a93824d20236e451720ae035ee54ad47912270faa823d8ff30d471353e9a69d123fa1d2544315067683481
|
data/Gemfile.lock
CHANGED
data/lib/yesql.rb
CHANGED
@@ -8,36 +8,33 @@ require "yesql/errors/file_path_does_not_exist_error"
|
|
8
8
|
require "yesql/errors/no_bindings_provided_error"
|
9
9
|
require "yesql/errors/output_argument_error"
|
10
10
|
|
11
|
-
module YeSQL
|
11
|
+
module ::YeSQL
|
12
12
|
include ::YeSQL::Config
|
13
|
-
include ::YeSQL::Errors::FilePathDoesNotExistError
|
14
|
-
include ::YeSQL::Errors::NoBindingsProvidedError
|
15
|
-
include ::YeSQL::Errors::OutputArgumentError
|
16
13
|
|
17
14
|
BIND_REGEX = /(?<!:):(\w+)(?=\b)/
|
18
15
|
|
19
|
-
def YeSQL(file_path,
|
16
|
+
def YeSQL(file_path, binds = {}, options = {})
|
20
17
|
output = options[:output] || :rows
|
21
18
|
|
22
|
-
validate(
|
23
|
-
execute(
|
19
|
+
validate(binds, file_path, output)
|
20
|
+
execute(binds, file_path, output, options[:prepare])
|
24
21
|
end
|
25
22
|
|
26
23
|
private
|
27
24
|
|
28
|
-
def validate(
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
def validate(binds, file_path, output)
|
26
|
+
::YeSQL::Errors::FilePathDoesNotExistError.new(file_path).validate_file_path_existence
|
27
|
+
::YeSQL::Errors::NoBindingsProvidedError.new(binds, file_path).validate_statement_bindings
|
28
|
+
::YeSQL::Errors::OutputArgumentError.new(output).validate_output_options
|
32
29
|
end
|
33
30
|
|
34
|
-
def execute(
|
31
|
+
def execute(binds, file_path, output, prepare)
|
35
32
|
::YeSQL::Query::Performer.new(
|
36
|
-
bindings:
|
37
|
-
bind_statement: ::YeSQL::Statement.new(
|
33
|
+
bindings: binds,
|
34
|
+
bind_statement: ::YeSQL::Statement.new(binds, file_path),
|
38
35
|
file_path: file_path,
|
39
36
|
output: output,
|
40
|
-
prepare:
|
37
|
+
prepare: prepare
|
41
38
|
).call
|
42
39
|
end
|
43
40
|
end
|
@@ -8,7 +8,7 @@ module ::YeSQL
|
|
8
8
|
class Extract
|
9
9
|
include ::YeSQL::Common::Adapter
|
10
10
|
|
11
|
-
def initialize(
|
11
|
+
def initialize(hash, indexed_bindings, index, value)
|
12
12
|
@hash = hash
|
13
13
|
@index = index
|
14
14
|
@indexed_bindings = indexed_bindings
|
@@ -25,7 +25,7 @@ module ::YeSQL
|
|
25
25
|
if mysql?
|
26
26
|
return "?" unless array?
|
27
27
|
|
28
|
-
Array.new(
|
28
|
+
Array.new(size, "?").join(", ")
|
29
29
|
elsif pg?
|
30
30
|
return "$#{last_val}" unless array?
|
31
31
|
|
@@ -48,7 +48,7 @@ module ::YeSQL
|
|
48
48
|
attr_reader :hash, :index, :indexed_bindings, :value
|
49
49
|
|
50
50
|
def current_val_size
|
51
|
-
return
|
51
|
+
return size if array?
|
52
52
|
|
53
53
|
1
|
54
54
|
end
|
@@ -72,6 +72,10 @@ module ::YeSQL
|
|
72
72
|
|
73
73
|
prev_last_val + 1
|
74
74
|
end
|
75
|
+
|
76
|
+
def size
|
77
|
+
value.size
|
78
|
+
end
|
75
79
|
end
|
76
80
|
end
|
77
81
|
end
|
@@ -2,35 +2,40 @@
|
|
2
2
|
|
3
3
|
require "yesql/bindings/extract"
|
4
4
|
|
5
|
-
module YeSQL
|
5
|
+
module ::YeSQL
|
6
6
|
module Bindings
|
7
7
|
class Extractor
|
8
|
-
def initialize(bindings:)
|
8
|
+
def initialize(bindings: {})
|
9
9
|
@bindings = bindings
|
10
|
-
@indexed_bindings =
|
10
|
+
@indexed_bindings = bindings.to_a
|
11
11
|
end
|
12
12
|
|
13
13
|
def call
|
14
|
-
bindings
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
vals: extract.bind_vals,
|
20
|
-
vars: extract.bind_vars
|
21
|
-
},
|
22
|
-
last_val: extract.last_val,
|
23
|
-
match: key,
|
24
|
-
prev: extract.prev,
|
25
|
-
value: value
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
14
|
+
bindings
|
15
|
+
.each_with_object({})
|
16
|
+
.with_index(1) do |((key, value), hash), index|
|
17
|
+
hash[key] = binding_extracts(hash, indexed_bindings, index, key, value)
|
18
|
+
end
|
29
19
|
end
|
30
20
|
|
31
21
|
private
|
32
22
|
|
33
23
|
attr_reader :bindings, :indexed_bindings
|
24
|
+
|
25
|
+
def binding_extracts(hash, indexed_bindings, index, key, value)
|
26
|
+
::YeSQL::Bindings::Extract.new(hash, indexed_bindings, index, value).tap do |extract|
|
27
|
+
break {
|
28
|
+
bind: {
|
29
|
+
vals: extract.bind_vals,
|
30
|
+
vars: extract.bind_vars
|
31
|
+
},
|
32
|
+
last_val: extract.last_val,
|
33
|
+
match: key,
|
34
|
+
prev: extract.prev,
|
35
|
+
value: value
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
data/lib/yesql/bindings/utils.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module YeSQL
|
3
|
+
module ::YeSQL
|
4
4
|
module Bindings
|
5
5
|
module Utils
|
6
|
+
include ::YeSQL::Utils::Read
|
7
|
+
|
6
8
|
def statement_binds(extractor)
|
7
|
-
|
8
|
-
.
|
9
|
-
.
|
10
|
-
|
11
|
-
end
|
9
|
+
statement(readable: true)
|
10
|
+
.scan(::YeSQL::BIND_REGEX)
|
11
|
+
.map(&:first)
|
12
|
+
.map { extractor[_1.to_sym][:bind].values_at(:vals, :vars) }
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -1,28 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module YeSQL
|
3
|
+
module ::YeSQL
|
4
4
|
module Errors
|
5
|
-
|
6
|
-
def
|
7
|
-
|
5
|
+
class FilePathDoesNotExistError
|
6
|
+
def initialize(file_path)
|
7
|
+
@file_path = file_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_file_path_existence
|
11
|
+
return if file_exists?
|
8
12
|
|
9
|
-
raise NotImplementedError,
|
10
|
-
file_path: file_path, path: ::YeSQL.config.path)
|
13
|
+
raise ::NotImplementedError, message
|
11
14
|
end
|
12
15
|
|
13
16
|
private
|
14
17
|
|
15
|
-
|
18
|
+
attr_reader :file_path
|
16
19
|
|
17
|
-
|
20
|
+
def message
|
21
|
+
"\nSQL file \"#{file_path}\" does not exist in #{::YeSQL.config.path}.
|
18
22
|
|
19
|
-
|
23
|
+
Available SQL files are:
|
20
24
|
|
21
|
-
|
22
|
-
|
23
|
-
private_constant :MESSAGE
|
25
|
+
#{available_files}\n"
|
26
|
+
end
|
24
27
|
|
25
|
-
def file_exists?
|
28
|
+
def file_exists?
|
26
29
|
path_files.any? { |filename| filename.include?("#{file_path}.sql") }
|
27
30
|
end
|
28
31
|
|
@@ -4,38 +4,45 @@ require "yesql/utils/read"
|
|
4
4
|
|
5
5
|
module ::YeSQL
|
6
6
|
module Errors
|
7
|
-
|
8
|
-
|
9
|
-
return unless statement_binds(file_path).size.positive?
|
7
|
+
class NoBindingsProvidedError
|
8
|
+
include ::YeSQL::Utils::Read
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def initialize(binds, file_path)
|
11
|
+
@binds = binds
|
12
|
+
@file_path = file_path
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate_statement_bindings
|
16
|
+
return unless statement_binds.size.positive?
|
17
|
+
return if expected_binds?
|
18
|
+
|
19
|
+
raise ::ArgumentError, message
|
14
20
|
end
|
15
21
|
|
16
22
|
private
|
17
23
|
|
18
|
-
|
24
|
+
attr_reader :binds, :file_path
|
19
25
|
|
20
|
-
|
26
|
+
def message
|
27
|
+
"\nYeSQL invoked without bindings.
|
21
28
|
|
22
|
-
|
29
|
+
Expected bindings are:
|
23
30
|
|
24
|
-
|
25
|
-
|
26
|
-
private_constant :MESSAGE
|
31
|
+
#{renderable_statement_binds}\n"
|
32
|
+
end
|
27
33
|
|
28
|
-
def statement_binds
|
29
|
-
|
30
|
-
.scan(::YeSQL::BIND_REGEX)
|
31
|
-
break []
|
34
|
+
def statement_binds
|
35
|
+
statement
|
36
|
+
.scan(::YeSQL::BIND_REGEX)
|
37
|
+
.tap { |scanned_binds| break (scanned_binds || []).sort }
|
38
|
+
end
|
32
39
|
|
33
|
-
|
34
|
-
|
40
|
+
def renderable_statement_binds
|
41
|
+
statement_binds.flatten.map { |bind| "- `#{bind}`\n" }.join
|
35
42
|
end
|
36
43
|
|
37
|
-
def
|
38
|
-
|
44
|
+
def expected_binds?
|
45
|
+
binds.is_a?(::Hash) && !binds.empty?
|
39
46
|
end
|
40
47
|
end
|
41
48
|
end
|
@@ -1,22 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module YeSQL
|
3
|
+
module ::YeSQL
|
4
4
|
module Errors
|
5
|
-
|
6
|
-
def
|
5
|
+
class OutputArgumentError
|
6
|
+
def initialize(output)
|
7
|
+
@output = output
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_output_options
|
7
11
|
return if output.nil?
|
12
|
+
return if OPTIONS.include?(output.to_sym)
|
8
13
|
|
9
|
-
raise ArgumentError,
|
14
|
+
raise ArgumentError, message
|
10
15
|
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
- `rows`: returns an array of arrays for each row from the given SQL statement.
|
17
|
-
MSG
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :output
|
20
|
+
|
18
21
|
OPTIONS = %i[columns hash rows].freeze
|
19
|
-
private_constant :
|
22
|
+
private_constant :OPTIONS
|
23
|
+
|
24
|
+
def message
|
25
|
+
"Unsupported `output` option given `#{output}`. Possible values are:
|
26
|
+
- `columns`: returns an array with the columns from the result.
|
27
|
+
- `hash`: returns an array of hashes combining both, the columns and rows from the statement result.
|
28
|
+
- `rows`: returns an array of arrays for each row from the given SQL statement.\n"
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
32
|
end
|
data/lib/yesql/params/output.rb
CHANGED
@@ -8,7 +8,7 @@ require "yesql/query/result"
|
|
8
8
|
require "yesql/query/transform_result"
|
9
9
|
require "yesql/params/output"
|
10
10
|
|
11
|
-
module YeSQL
|
11
|
+
module ::YeSQL
|
12
12
|
module Query
|
13
13
|
class Performer
|
14
14
|
include ::YeSQL::Bindings::Utils
|
@@ -27,7 +27,7 @@ module YeSQL
|
|
27
27
|
|
28
28
|
private
|
29
29
|
|
30
|
-
attr_reader :bind_statement, :file_path, :named_bindings, :output, :prepare
|
30
|
+
attr_reader :bind_statement, :file_path, :named_bindings, :output, :prepare
|
31
31
|
|
32
32
|
def query_result
|
33
33
|
@query_result ||= ::YeSQL::Query::Result.new(binds: binds,
|
data/lib/yesql/query/result.rb
CHANGED
@@ -7,14 +7,13 @@ require "yesql/common/adapter"
|
|
7
7
|
module ::YeSQL
|
8
8
|
module Query
|
9
9
|
class Result
|
10
|
-
extend Forwardable
|
10
|
+
extend ::Forwardable
|
11
11
|
|
12
12
|
include ::YeSQL::Common::Adapter
|
13
13
|
|
14
14
|
def initialize(bind_statement:, file_path:, prepare:, binds: [])
|
15
15
|
@binds = binds
|
16
16
|
@bind_statement = bind_statement
|
17
|
-
@connection = ActiveRecord::Base.connection
|
18
17
|
@file_path = file_path
|
19
18
|
@prepare_option = prepare
|
20
19
|
end
|
@@ -28,7 +27,7 @@ module ::YeSQL
|
|
28
27
|
|
29
28
|
private
|
30
29
|
|
31
|
-
attr_reader :binds, :bind_statement, :
|
30
|
+
attr_reader :binds, :bind_statement, :file_path, :prepare_option
|
32
31
|
|
33
32
|
def_delegators(:bind_statement, :bound, :to_s, :view?)
|
34
33
|
def_delegators(:connection, :exec_query, :raw_connection)
|
@@ -38,10 +37,13 @@ module ::YeSQL
|
|
38
37
|
exec_query(bound)
|
39
38
|
end
|
40
39
|
|
41
|
-
# TODO: recheck this case
|
42
40
|
def rails5_result
|
43
41
|
prepare(bound).execute(*binds)
|
44
42
|
end
|
43
|
+
|
44
|
+
def connection
|
45
|
+
@connection ||= ActiveRecord::Base.connection
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
49
|
end
|
@@ -7,7 +7,7 @@ require "forwardable"
|
|
7
7
|
module ::YeSQL
|
8
8
|
module Query
|
9
9
|
class TransformResult
|
10
|
-
extend Forwardable
|
10
|
+
extend ::Forwardable
|
11
11
|
|
12
12
|
include ::YeSQL::Common::Adapter
|
13
13
|
|
@@ -17,7 +17,7 @@ module ::YeSQL
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def call
|
20
|
-
if
|
20
|
+
if rails_5? && mysql?
|
21
21
|
return columns if columns?
|
22
22
|
return rows_values if rows?
|
23
23
|
return array_of_symbol_hashes if hash?
|
@@ -32,7 +32,7 @@ module ::YeSQL
|
|
32
32
|
|
33
33
|
attr_reader :output, :result
|
34
34
|
|
35
|
-
def_delegators(:result, :rows, :to_a)
|
35
|
+
def_delegators(:result, :fields, :rows, :to_a)
|
36
36
|
def_delegators(:output, :columns?, :hash?, :rows?)
|
37
37
|
|
38
38
|
def rows_values
|
@@ -50,9 +50,11 @@ module ::YeSQL
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def columns
|
53
|
-
|
53
|
+
fields || result.columns
|
54
|
+
end
|
54
55
|
|
55
|
-
|
56
|
+
def rails_5?
|
57
|
+
::ActiveRecord::VERSION::MAJOR == 5
|
56
58
|
end
|
57
59
|
end
|
58
60
|
end
|
data/lib/yesql/statement.rb
CHANGED
@@ -13,6 +13,7 @@ module ::YeSQL
|
|
13
13
|
extend ::Forwardable
|
14
14
|
|
15
15
|
include ::YeSQL::Common::Adapter
|
16
|
+
include ::YeSQL::Utils::Read
|
16
17
|
# Give access to the quote method.
|
17
18
|
include ::ActiveRecord::ConnectionAdapters::Quoting
|
18
19
|
|
@@ -23,16 +24,12 @@ module ::YeSQL
|
|
23
24
|
|
24
25
|
def bound
|
25
26
|
to_s.gsub(::YeSQL::BIND_REGEX) do |match|
|
26
|
-
extractor[match[/(\w+)/].to_sym]
|
27
|
-
break quote(extract[:value]) if view?
|
28
|
-
|
29
|
-
break extract[:bind][:vars]
|
30
|
-
end
|
27
|
+
extract_bind_values(extractor[match[/(\w+)/].to_sym])
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
34
31
|
def to_s
|
35
|
-
@to_s ||=
|
32
|
+
@to_s ||= statement(readable: true)
|
36
33
|
end
|
37
34
|
|
38
35
|
def view?
|
@@ -43,6 +40,12 @@ module ::YeSQL
|
|
43
40
|
|
44
41
|
attr_reader :bindings, :file_path
|
45
42
|
|
43
|
+
def extract_bind_values(match)
|
44
|
+
return quote(match[:value]) if view?
|
45
|
+
|
46
|
+
match[:bind][:vars]
|
47
|
+
end
|
48
|
+
|
46
49
|
def extractor
|
47
50
|
::YeSQL::Bindings::Extractor.new(bindings: bindings).call
|
48
51
|
end
|
data/lib/yesql/utils/read.rb
CHANGED
@@ -1,16 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module YeSQL
|
3
|
+
module ::YeSQL
|
4
4
|
module Utils
|
5
5
|
module Read
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
def statement(readable: false)
|
7
|
+
read_file(found_file, readable)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
def read_file(file, readable)
|
13
|
+
return File.readlines(file, chomp: true).join(" ") if readable == true
|
14
|
+
|
15
|
+
File.read(file)
|
16
|
+
end
|
17
|
+
|
18
|
+
def found_file
|
19
|
+
dir_sql_files.find { |dir_file_path| dir_file_path.include?("#{file_path}.sql") }
|
20
|
+
end
|
21
|
+
|
22
|
+
def dir_sql_files
|
23
|
+
Dir["./#{::YeSQL.config.path}/**/*.sql"]
|
14
24
|
end
|
15
25
|
end
|
16
26
|
end
|
data/lib/yesql/version.rb
CHANGED