yesql 0.2.2 → 0.2.3

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: d4cad8cd91b4afba6c7a8722f9f0dfd6092552d2f4ce735c6880425241122b43
4
- data.tar.gz: b8be652b46ee03e081ec2d8bc3bcc2321e26e2b7fcd55dcbf2a2bb288ddac139
3
+ metadata.gz: f38a878a124272c8ed8f51d723cba49704d2e7b60b28920c562fdbc8e1d68836
4
+ data.tar.gz: dbfa7776c1eb0eeae767023504cb741dd05052fd992b3b01a218f849917d7696
5
5
  SHA512:
6
- metadata.gz: 4dc794c44484b4fcc8815fa866023c6cf5d2f4b82d4f2c45c6de7e86082eaa3ba838c55e750e3f2fd53b0312b4be699c7ddc900400c8445c377fd7c6d1139190
7
- data.tar.gz: 88b860a5ce91655366f9d73336b522678a8f709938881e1ff150a13565b57cd12b65c753531ecfb886528d162405c36ca9036c1c3cba52a62aa2e3e3993e76fb
6
+ metadata.gz: b781599e0e8d5f6a84bec509737595269f28e6347284046f2a7d767ff14256b79a8658643b0e077a453ce08bf4d23766e2eebbd1bcc19b952b43f3eeda94b87b
7
+ data.tar.gz: 6ac1827d64222972e9fd70bbdb216576581c86dd54a93824d20236e451720ae035ee54ad47912270faa823d8ff30d471353e9a69d123fa1d2544315067683481
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- yesql (0.2.2)
4
+ yesql (0.1.8)
5
5
  activerecord (>= 4.0.0.beta1)
6
6
 
7
7
  GEM
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, bindings = {}, options = {})
16
+ def YeSQL(file_path, binds = {}, options = {})
20
17
  output = options[:output] || :rows
21
18
 
22
- validate(bindings, file_path, output)
23
- execute(bindings, file_path, output, options)
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(bindings, file_path, output)
29
- validate_file_path_existence(file_path)
30
- validate_statement_bindings(bindings, file_path)
31
- validate_output_options(output)
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(bindings, file_path, output, options)
31
+ def execute(binds, file_path, output, prepare)
35
32
  ::YeSQL::Query::Performer.new(
36
- bindings: bindings,
37
- bind_statement: ::YeSQL::Statement.new(bindings, file_path),
33
+ bindings: binds,
34
+ bind_statement: ::YeSQL::Statement.new(binds, file_path),
38
35
  file_path: file_path,
39
36
  output: output,
40
- prepare: options[: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(indexed_bindings, hash, index, value)
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(value.size, "?").join(", ")
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 value.size if array?
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 = (bindings || {}).to_a
10
+ @indexed_bindings = bindings.to_a
11
11
  end
12
12
 
13
13
  def call
14
- bindings.each_with_object({}).with_index(1) do |((key, value), hash), index|
15
- hash[key] =
16
- ::YeSQL::Bindings::Extract.new(indexed_bindings, hash, index, value).tap do |extract|
17
- break {
18
- bind: {
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
@@ -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
- ::YeSQL::Utils::Read
8
- .statement(file_path, readable: true)
9
- .scan(::YeSQL::BIND_REGEX).map do |(bind)|
10
- extractor[bind.to_sym][:bind].values_at(:vals, :vars)
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
- module FilePathDoesNotExistError
6
- def validate_file_path_existence(file_path)
7
- return if file_exists?(file_path)
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, format(MESSAGE, available_files: available_files,
10
- file_path: file_path, path: ::YeSQL.config.path)
13
+ raise ::NotImplementedError, message
11
14
  end
12
15
 
13
16
  private
14
17
 
15
- MESSAGE = <<~MSG
18
+ attr_reader :file_path
16
19
 
17
- SQL file "%<file_path>s" does not exist in %<path>s.
20
+ def message
21
+ "\nSQL file \"#{file_path}\" does not exist in #{::YeSQL.config.path}.
18
22
 
19
- Available SQL files are:
23
+ Available SQL files are:
20
24
 
21
- %<available_files>s
22
- MSG
23
- private_constant :MESSAGE
25
+ #{available_files}\n"
26
+ end
24
27
 
25
- def file_exists?(file_path)
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
- module NoBindingsProvidedError
8
- def validate_statement_bindings(binds, file_path)
9
- return unless statement_binds(file_path).size.positive?
7
+ class NoBindingsProvidedError
8
+ include ::YeSQL::Utils::Read
10
9
 
11
- format(MESSAGE, renderable_statement_binds(file_path)).tap do |message|
12
- raise ::ArgumentError, message unless binds.is_a?(::Hash) && !binds.empty?
13
- end
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
- MESSAGE = <<~MSG
24
+ attr_reader :binds, :file_path
19
25
 
20
- YeSQL invoked without bindings.
26
+ def message
27
+ "\nYeSQL invoked without bindings.
21
28
 
22
- Expected bindings are:
29
+ Expected bindings are:
23
30
 
24
- %s
25
- MSG
26
- private_constant :MESSAGE
31
+ #{renderable_statement_binds}\n"
32
+ end
27
33
 
28
- def statement_binds(file_path)
29
- ::YeSQL::Utils::Read.statement(file_path)
30
- .scan(::YeSQL::BIND_REGEX).tap do |scanned_binds|
31
- break [] if scanned_binds.size.zero?
34
+ def statement_binds
35
+ statement
36
+ .scan(::YeSQL::BIND_REGEX)
37
+ .tap { |scanned_binds| break (scanned_binds || []).sort }
38
+ end
32
39
 
33
- break scanned_binds.sort
34
- end
40
+ def renderable_statement_binds
41
+ statement_binds.flatten.map { |bind| "- `#{bind}`\n" }.join
35
42
  end
36
43
 
37
- def renderable_statement_binds(file_path)
38
- statement_binds(file_path).flatten.map { |bind| "- `#{bind}`\n" }.join
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
- module OutputArgumentError
6
- def validate_output_options(output)
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, format(MESSAGE, output) unless OPTIONS.include?(output.to_sym)
14
+ raise ArgumentError, message
10
15
  end
11
16
 
12
- MESSAGE = <<~MSG
13
- Unsupported `output` option given `%s`. Possible values are:
14
- - `columns`: returns an array with the columns from the result.
15
- - `hash`: returns an array of hashes combining both, the columns and rows from the statement result.
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 :MESSAGE, :OPTIONS
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
@@ -6,7 +6,7 @@ require "forwardable"
6
6
  module ::YeSQL
7
7
  module Params
8
8
  class Output
9
- extend Forwardable
9
+ extend ::Forwardable
10
10
 
11
11
  def initialize(output)
12
12
  @output = output.to_s
@@ -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, :rows
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,
@@ -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, :connection, :file_path, :prepare_option
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 ::ActiveRecord::VERSION::MAJOR == 5 && mysql?
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
- return result.fields if result.respond_to?(:fields)
53
+ fields || result.columns
54
+ end
54
55
 
55
- result.columns
56
+ def rails_5?
57
+ ::ActiveRecord::VERSION::MAJOR == 5
56
58
  end
57
59
  end
58
60
  end
@@ -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].tap do |extract|
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 ||= ::YeSQL::Utils::Read.statement(file_path, readable: true)
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
@@ -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 self.statement(file_path, readable: false)
7
- Dir["./#{::YeSQL.config.path}/**/*.sql"]
8
- .find { |dir_file_path| dir_file_path.include?("#{file_path}.sql") }
9
- .tap do |sql_file_path|
10
- break File.readlines(sql_file_path, chomp: true).join(" ") if readable == true
6
+ def statement(readable: false)
7
+ read_file(found_file, readable)
8
+ end
9
+
10
+ private
11
11
 
12
- break File.read(sql_file_path)
13
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module YeSQL
4
- VERSION = "0.2.2"
3
+ module ::YeSQL
4
+ VERSION = "0.2.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yesql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastián Palma