yesql 0.1.8 → 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 +4 -4
- data/README.md +6 -22
- data/lib/.rbnext/2.3/yesql/errors/file_path_does_not_exist_error.rb +40 -0
- data/lib/.rbnext/2.3/yesql/errors/no_bindings_provided_error.rb +38 -0
- data/lib/.rbnext/2.3/yesql/errors/output_argument_error.rb +31 -0
- data/lib/.rbnext/2.3/yesql/query/transform_result.rb +48 -0
- data/lib/.rbnext/2.7/yesql/bindings/extract.rb +71 -0
- data/lib/.rbnext/2.7/yesql/bindings/extractor.rb +38 -0
- data/lib/.rbnext/2.7/yesql/bindings/transformed.rb +58 -0
- data/lib/.rbnext/2.7/yesql/bindings/utils.rb +16 -0
- data/lib/.rbnext/2.7/yesql/errors/file_path_does_not_exist_error.rb +43 -0
- data/lib/.rbnext/2.7/yesql/errors/no_bindings_provided_error.rb +41 -0
- data/lib/.rbnext/2.7/yesql/query/transform_result.rb +48 -0
- data/lib/.rbnext/2.7/yesql/statement.rb +44 -0
- data/lib/.rbnext/2.7/yesql/utils/read.rb +20 -0
- data/lib/.rbnext/3.0/yesql/bindings/extract.rb +71 -0
- data/lib/.rbnext/3.0/yesql/bindings/transformed.rb +58 -0
- data/lib/.rbnext/3.0/yesql/common/adapter.rb +18 -0
- data/lib/.rbnext/3.0/yesql/config/configuration.rb +32 -0
- data/lib/.rbnext/3.0/yesql/errors/file_path_does_not_exist_error.rb +43 -0
- data/lib/.rbnext/3.0/yesql/errors/no_bindings_provided_error.rb +41 -0
- data/lib/.rbnext/3.0/yesql/params/output.rb +26 -0
- data/lib/.rbnext/3.0/yesql/query/performer.rb +44 -0
- data/lib/.rbnext/3.0/yesql/query/result.rb +41 -0
- data/lib/.rbnext/3.0/yesql/query/transform_result.rb +48 -0
- data/lib/.rbnext/3.0/yesql/statement.rb +44 -0
- data/lib/.rbnext/3.0/yesql/utils/read.rb +20 -0
- data/lib/yesql.rb +25 -31
- data/lib/yesql/bindings/extract.rb +15 -21
- data/lib/yesql/bindings/extractor.rb +21 -21
- data/lib/yesql/bindings/transformed.rb +8 -11
- data/lib/yesql/bindings/utils.rb +7 -5
- data/lib/yesql/common/adapter.rb +6 -13
- data/lib/yesql/config/configuration.rb +4 -5
- data/lib/yesql/errors/file_path_does_not_exist_error.rb +22 -17
- data/lib/yesql/errors/no_bindings_provided_error.rb +18 -19
- data/lib/yesql/errors/output_argument_error.rb +13 -4
- data/lib/yesql/params/output.rb +6 -14
- data/lib/yesql/query/performer.rb +13 -42
- data/lib/yesql/query/result.rb +12 -17
- data/lib/yesql/query/transform_result.rb +11 -21
- data/lib/yesql/statement.rb +19 -24
- data/lib/yesql/utils/read.rb +11 -8
- data/lib/yesql/version.rb +1 -1
- metadata +47 -17
- data/.gitignore +0 -4
- data/.rubocop.yml +0 -20
- data/Gemfile +0 -9
- data/Gemfile.lock +0 -167
- data/Rakefile +0 -1
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/yesql/errors/cache_expiration_error.rb +0 -18
- data/yesql.gemspec +0 -28
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yesql"
|
4
|
+
require "yesql/bindings/utils"
|
5
|
+
require "yesql/common/adapter"
|
6
|
+
require "yesql/bindings/transformed"
|
7
|
+
require "yesql/query/result"
|
8
|
+
require "yesql/query/transform_result"
|
9
|
+
require "yesql/params/output"
|
10
|
+
|
11
|
+
module ::YeSQL
|
12
|
+
module Query
|
13
|
+
class Performer
|
14
|
+
include ::YeSQL::Bindings::Utils
|
15
|
+
|
16
|
+
def initialize(bind_statement:, file_path:, bindings: {}, output: :rows, prepare: false)
|
17
|
+
@bind_statement = bind_statement
|
18
|
+
@file_path = file_path
|
19
|
+
@named_bindings = bindings.transform_keys(&:to_sym)
|
20
|
+
@output = ::YeSQL::Params::Output.new(output)
|
21
|
+
@prepare = prepare
|
22
|
+
end
|
23
|
+
|
24
|
+
def call ; ::YeSQL::Query::TransformResult.new(output: output, result: query_result).call; end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :bind_statement, :file_path, :named_bindings, :output, :prepare
|
29
|
+
|
30
|
+
def query_result
|
31
|
+
@query_result ||= ::YeSQL::Query::Result.new(binds: binds,
|
32
|
+
bind_statement: bind_statement,
|
33
|
+
file_path: file_path,
|
34
|
+
prepare: prepare).call
|
35
|
+
end
|
36
|
+
|
37
|
+
def binds
|
38
|
+
::YeSQL::Bindings::Transformed.new(statement_binds: statement_binds(extractor)).call
|
39
|
+
end
|
40
|
+
|
41
|
+
def extractor ; ::YeSQL::Bindings::Extractor.new(bindings: named_bindings).call; end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yesql"
|
4
|
+
require "forwardable"
|
5
|
+
require "yesql/common/adapter"
|
6
|
+
|
7
|
+
module ::YeSQL
|
8
|
+
module Query
|
9
|
+
class Result
|
10
|
+
extend ::Forwardable
|
11
|
+
|
12
|
+
include ::YeSQL::Common::Adapter
|
13
|
+
|
14
|
+
def initialize(bind_statement:, file_path:, prepare:, binds: [])
|
15
|
+
@binds = binds
|
16
|
+
@bind_statement = bind_statement
|
17
|
+
@file_path = file_path
|
18
|
+
@prepare_option = prepare
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
return view_result if view?
|
23
|
+
return rails5_result if ::ActiveRecord::VERSION::MAJOR == 5 && mysql?
|
24
|
+
|
25
|
+
exec_query(bound, file_path, binds, prepare: prepare_option)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :binds, :bind_statement, :file_path, :prepare_option
|
31
|
+
|
32
|
+
def_delegators(:bind_statement, :bound, :to_s, :view?)
|
33
|
+
def_delegators(:connection, :exec_query, :raw_connection)
|
34
|
+
def_delegators(:raw_connection, :prepare)
|
35
|
+
|
36
|
+
def view_result ; exec_query(bound); end
|
37
|
+
def rails5_result ; prepare(bound).execute(*binds); end
|
38
|
+
def connection ; @connection ||= ActiveRecord::Base.connection; end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "yesql"
|
4
|
+
require "yesql/common/adapter"
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
module ::YeSQL
|
8
|
+
module Query
|
9
|
+
class TransformResult
|
10
|
+
extend ::Forwardable
|
11
|
+
|
12
|
+
include ::YeSQL::Common::Adapter
|
13
|
+
|
14
|
+
def initialize(output:, result:)
|
15
|
+
@output = output
|
16
|
+
@result = result
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
if rails_5? && mysql?
|
21
|
+
return columns if columns?
|
22
|
+
return rows_values if rows?
|
23
|
+
return array_of_symbol_hashes if hash?
|
24
|
+
end
|
25
|
+
|
26
|
+
return result.public_send(output.to_sym) if columns? || rows?
|
27
|
+
|
28
|
+
to_a.map(&:symbolize_keys)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :output, :result
|
34
|
+
|
35
|
+
def_delegators(:result, :fields, :rows, :to_a)
|
36
|
+
def_delegators(:output, :columns?, :hash?, :rows?)
|
37
|
+
|
38
|
+
def array_of_symbol_hashes
|
39
|
+
to_a.tap { break hashed_rows(_1) if rails_5? }.map { _1&.symbolize_keys || _1 }
|
40
|
+
end
|
41
|
+
|
42
|
+
def columns ; fields || result.columns; end
|
43
|
+
def rows_values ; to_a.map { _1.respond_to?(:values) ? _1.values : _1 }; end
|
44
|
+
def hashed_rows(rows) ; rows.map { columns.zip(_1).to_h }; end
|
45
|
+
def rails_5? ; ::ActiveRecord::VERSION::MAJOR == 5; end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_record"
|
4
|
+
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
require "yesql/utils/read"
|
8
|
+
require "yesql/bindings/extractor"
|
9
|
+
require "yesql/common/adapter"
|
10
|
+
|
11
|
+
module ::YeSQL
|
12
|
+
class Statement
|
13
|
+
extend ::Forwardable
|
14
|
+
|
15
|
+
include ::YeSQL::Common::Adapter
|
16
|
+
include ::YeSQL::Utils::Read
|
17
|
+
# Give access to the quote method.
|
18
|
+
include ::ActiveRecord::ConnectionAdapters::Quoting
|
19
|
+
|
20
|
+
def initialize(bindings = {}, file_path)
|
21
|
+
@bindings = bindings
|
22
|
+
@file_path = file_path
|
23
|
+
end
|
24
|
+
|
25
|
+
def bound
|
26
|
+
to_s.gsub(::YeSQL::BIND_REGEX) { extract_bind_values(extractor[_1[/(\w+)/].to_sym]) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s ; @to_s ||= statement(readable: true); end
|
30
|
+
def view? ; to_s =~ /^create\s.*view\s/i; end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :bindings, :file_path
|
35
|
+
|
36
|
+
def extract_bind_values(match)
|
37
|
+
return quote(match[:value]) if view?
|
38
|
+
|
39
|
+
match[:bind][:vars]
|
40
|
+
end
|
41
|
+
|
42
|
+
def extractor ; @extractor ||= ::YeSQL::Bindings::Extractor.new(bindings: bindings).call; end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ::YeSQL
|
4
|
+
module Utils
|
5
|
+
module Read
|
6
|
+
def statement(readable: false) ; read_file(found_file, readable); end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def read_file(file, readable)
|
11
|
+
return File.readlines(file, chomp: true).join(" ") if readable == true
|
12
|
+
|
13
|
+
File.read(file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def found_file ; dir_sql_files.find { _1.include?("#{file_path}.sql") }; end
|
17
|
+
def dir_sql_files ; Dir["./#{::YeSQL.config.path}/**/*.sql"]; end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/yesql.rb
CHANGED
@@ -1,50 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
|
12
|
-
|
3
|
+
require "ruby-next/language/setup"
|
4
|
+
|
5
|
+
RubyNext::Language.setup_gem_load_path
|
6
|
+
|
7
|
+
require "yesql/statement"
|
8
|
+
require "yesql/version"
|
9
|
+
require "yesql/config/configuration"
|
10
|
+
require "yesql/query/performer"
|
11
|
+
require "yesql/errors/file_path_does_not_exist_error"
|
12
|
+
require "yesql/errors/no_bindings_provided_error"
|
13
|
+
require "yesql/errors/output_argument_error"
|
14
|
+
|
15
|
+
module ::YeSQL
|
13
16
|
include ::YeSQL::Config
|
14
|
-
include ::YeSQL::Errors::CacheExpirationError
|
15
|
-
include ::YeSQL::Errors::FilePathDoesNotExistError
|
16
|
-
include ::YeSQL::Errors::NoBindingsProvidedError
|
17
|
-
include ::YeSQL::Errors::OutputArgumentError
|
18
17
|
|
19
|
-
BIND_REGEX = /(?<!:):(\w+)(?=\b)
|
18
|
+
BIND_REGEX = /(?<!:):(\w+)(?=\b)/
|
20
19
|
|
21
|
-
|
22
|
-
def YeSQL(file_path, bindings = {}, options = {})
|
20
|
+
def YeSQL(file_path, binds = {}, options = {})
|
23
21
|
output = options[:output] || :rows
|
24
|
-
cache = options[:cache] || {}
|
25
22
|
|
26
|
-
validate(
|
27
|
-
execute(
|
23
|
+
validate(binds, file_path, output)
|
24
|
+
execute(binds, file_path, output, options[:prepare])
|
28
25
|
end
|
29
|
-
# rubocop:enable Naming/MethodName
|
30
26
|
|
31
27
|
private
|
32
28
|
|
33
|
-
def validate(
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
validate_cache_expiration(cache[:expires_in]) unless cache.empty?
|
29
|
+
def validate(binds, file_path, output)
|
30
|
+
::YeSQL::Errors::FilePathDoesNotExistError.new(file_path).validate_file_path_existence
|
31
|
+
::YeSQL::Errors::NoBindingsProvidedError.new(binds, file_path).validate_statement_bindings
|
32
|
+
::YeSQL::Errors::OutputArgumentError.new(output).validate_output_options
|
38
33
|
end
|
39
34
|
|
40
|
-
def execute(
|
35
|
+
def execute(binds, file_path, output, prepare)
|
41
36
|
::YeSQL::Query::Performer.new(
|
42
|
-
bindings:
|
43
|
-
bind_statement: ::YeSQL::Statement.new(
|
44
|
-
cache: cache,
|
37
|
+
bindings: binds,
|
38
|
+
bind_statement: ::YeSQL::Statement.new(binds, file_path),
|
45
39
|
file_path: file_path,
|
46
40
|
output: output,
|
47
|
-
prepare:
|
41
|
+
prepare: prepare
|
48
42
|
).call
|
49
43
|
end
|
50
44
|
end
|
@@ -1,54 +1,52 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "yesql"
|
4
|
+
require "yesql/common/adapter"
|
5
5
|
|
6
6
|
module ::YeSQL
|
7
7
|
module Bindings
|
8
8
|
class Extract
|
9
9
|
include ::YeSQL::Common::Adapter
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@indexed_bindings = indexed_bindings
|
11
|
+
def initialize(hash, indexed_bindings, index, value)
|
13
12
|
@hash = hash
|
14
13
|
@index = index
|
14
|
+
@indexed_bindings = indexed_bindings
|
15
15
|
@value = value
|
16
16
|
end
|
17
17
|
|
18
18
|
def bind_vals
|
19
19
|
return [nil, value] unless array?
|
20
20
|
|
21
|
-
value.map {
|
21
|
+
value.map { [nil, _1] }
|
22
22
|
end
|
23
23
|
|
24
24
|
def bind_vars
|
25
25
|
if mysql?
|
26
|
-
return
|
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
|
|
32
|
-
value.map.with_index(bind_index) {
|
32
|
+
value.map.with_index(bind_index) { "$#{_2}" }.join(", ")
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
def last_val
|
37
|
-
prev_last_val + current_val_size
|
38
|
-
end
|
39
|
-
|
40
36
|
def prev
|
41
37
|
return if first?
|
42
38
|
|
43
39
|
indexed_bindings[index - 2].first
|
44
40
|
end
|
45
41
|
|
42
|
+
def last_val = prev_last_val + current_val_size
|
43
|
+
|
46
44
|
private
|
47
45
|
|
48
46
|
attr_reader :hash, :index, :indexed_bindings, :value
|
49
47
|
|
50
48
|
def current_val_size
|
51
|
-
return
|
49
|
+
return size if array?
|
52
50
|
|
53
51
|
1
|
54
52
|
end
|
@@ -59,19 +57,15 @@ module ::YeSQL
|
|
59
57
|
hash[prev][:last_val]
|
60
58
|
end
|
61
59
|
|
62
|
-
def first?
|
63
|
-
index == 1
|
64
|
-
end
|
65
|
-
|
66
|
-
def array?
|
67
|
-
value.is_a?(Array)
|
68
|
-
end
|
69
|
-
|
70
60
|
def bind_index
|
71
61
|
return 1 if first?
|
72
62
|
|
73
63
|
prev_last_val + 1
|
74
64
|
end
|
65
|
+
|
66
|
+
def size = value.size
|
67
|
+
def first? = index == 1
|
68
|
+
def array? = value.is_a?(Array)
|
75
69
|
end
|
76
70
|
end
|
77
71
|
end
|
@@ -1,38 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
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
|
-
# rubocop:disable Metrics/MethodLength
|
14
13
|
def call
|
15
|
-
bindings
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
vals: extract.bind_vals,
|
21
|
-
vars: extract.bind_vars
|
22
|
-
},
|
23
|
-
last_val: extract.last_val,
|
24
|
-
match: key,
|
25
|
-
prev: extract.prev,
|
26
|
-
value: value
|
27
|
-
}
|
28
|
-
end
|
29
|
-
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
|
30
19
|
end
|
31
|
-
# rubocop:enable Metrics/MethodLength
|
32
20
|
|
33
21
|
private
|
34
22
|
|
35
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
|
27
|
+
break {
|
28
|
+
bind: { vals: _1.bind_vals, vars: _1.bind_vars },
|
29
|
+
last_val: _1.last_val,
|
30
|
+
match: key,
|
31
|
+
prev: _1.prev,
|
32
|
+
value: value
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "yesql"
|
4
|
+
require "yesql/common/adapter"
|
5
5
|
|
6
6
|
module ::YeSQL
|
7
7
|
module Bindings
|
@@ -23,19 +23,16 @@ module ::YeSQL
|
|
23
23
|
|
24
24
|
attr_reader :statement_binds
|
25
25
|
|
26
|
-
def rails5?
|
27
|
-
::Rails::VERSION::MAJOR == 5
|
28
|
-
end
|
26
|
+
def rails5? = ::ActiveRecord::VERSION::MAJOR == 5
|
29
27
|
|
30
28
|
def mysql_rails5_binds
|
31
29
|
statement_binds
|
32
|
-
.
|
33
|
-
.flatten(1)
|
30
|
+
.flat_map(&:first)
|
34
31
|
.each_slice(2)
|
35
|
-
.flat_map do
|
36
|
-
next [
|
32
|
+
.flat_map do
|
33
|
+
next [_1, _2].compact.map(&:last) if _1.is_a?(Array)
|
37
34
|
|
38
|
-
|
35
|
+
_2
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
@@ -49,7 +46,7 @@ module ::YeSQL
|
|
49
46
|
|
50
47
|
def pg_binds
|
51
48
|
statement_binds
|
52
|
-
.sort_by {
|
49
|
+
.sort_by { _2.to_s.tr("$", "").to_i }
|
53
50
|
.uniq
|
54
51
|
.map(&:first)
|
55
52
|
.flatten
|