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 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