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,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "yesql/utils/read"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ::YeSQL
         | 
| 6 | 
            +
              module Errors
         | 
| 7 | 
            +
                class NoBindingsProvidedError
         | 
| 8 | 
            +
                  include ::YeSQL::Utils::Read
         | 
| 9 | 
            +
             | 
| 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, format(MESSAGE, renderable_statement_binds)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  attr_reader :binds, :file_path
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  MESSAGE = <<~MSG
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    YeSQL invoked without bindings.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    Expected bindings are:
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    %s
         | 
| 33 | 
            +
                  MSG
         | 
| 34 | 
            +
                  private_constant :MESSAGE
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def statement_binds ;  statement.scan(::YeSQL::BIND_REGEX).tap { |_1| break (_1 || []).sort }; end
         | 
| 37 | 
            +
                  def renderable_statement_binds ;  statement_binds.flatten.map { |_1| "- `#{_1}`\n" }.join; end
         | 
| 38 | 
            +
                  def expected_binds? ;  binds.is_a?(::Hash) && !binds.empty?; 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| _1&.symbolize_keys || _1 }
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def columns ;  fields || result.columns; end
         | 
| 43 | 
            +
                  def rows_values ;  to_a.map { |_1| _1.respond_to?(:values) ? _1.values : _1 }; end
         | 
| 44 | 
            +
                  def hashed_rows(rows) ;  rows.map { |_1| 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) { |_1| 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| _1.include?("#{file_path}.sql") }; end
         | 
| 17 | 
            +
                  def dir_sql_files ;  Dir["./#{::YeSQL.config.path}/**/*.sql"]; end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "yesql"
         | 
| 4 | 
            +
            require "yesql/common/adapter"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module ::YeSQL
         | 
| 7 | 
            +
              module Bindings
         | 
| 8 | 
            +
                class Extract
         | 
| 9 | 
            +
                  include ::YeSQL::Common::Adapter
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(hash, indexed_bindings, index, value)
         | 
| 12 | 
            +
                    @hash = hash
         | 
| 13 | 
            +
                    @index = index
         | 
| 14 | 
            +
                    @indexed_bindings = indexed_bindings
         | 
| 15 | 
            +
                    @value = value
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def bind_vals
         | 
| 19 | 
            +
                    return [nil, value] unless array?
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    value.map { [nil, _1] }
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def bind_vars
         | 
| 25 | 
            +
                    if mysql?
         | 
| 26 | 
            +
                      return "?" unless array?
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                      Array.new(size, "?").join(", ")
         | 
| 29 | 
            +
                    elsif pg?
         | 
| 30 | 
            +
                      return "$#{last_val}" unless array?
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      value.map.with_index(bind_index) { "$#{_2}" }.join(", ")
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def prev
         | 
| 37 | 
            +
                    return if first?
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    indexed_bindings[index - 2].first
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def last_val ;  prev_last_val + current_val_size; end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  private
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  attr_reader :hash, :index, :indexed_bindings, :value
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def current_val_size
         | 
| 49 | 
            +
                    return size if array?
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    1
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  def prev_last_val
         | 
| 55 | 
            +
                    return 0 if first?
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    hash[prev][:last_val]
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def bind_index
         | 
| 61 | 
            +
                    return 1 if first?
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    prev_last_val + 1
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def size ;  value.size; end
         | 
| 67 | 
            +
                  def first? ;  index == 1; end
         | 
| 68 | 
            +
                  def array? ;  value.is_a?(Array); end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "yesql"
         | 
| 4 | 
            +
            require "yesql/common/adapter"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module ::YeSQL
         | 
| 7 | 
            +
              module Bindings
         | 
| 8 | 
            +
                class Transformed
         | 
| 9 | 
            +
                  include ::YeSQL::Common::Adapter
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(statement_binds:)
         | 
| 12 | 
            +
                    @statement_binds = statement_binds
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def call
         | 
| 16 | 
            +
                    return mysql_rails5_binds if rails5? && mysql?
         | 
| 17 | 
            +
                    return mysql_binds if !rails5? && mysql?
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    pg_binds
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  attr_reader :statement_binds
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def rails5? ;  ::ActiveRecord::VERSION::MAJOR == 5; end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def mysql_rails5_binds
         | 
| 29 | 
            +
                    statement_binds
         | 
| 30 | 
            +
                      .flat_map(&:first)
         | 
| 31 | 
            +
                      .each_slice(2)
         | 
| 32 | 
            +
                      .flat_map do
         | 
| 33 | 
            +
                        next [_1, _2].compact.map(&:last) if _1.is_a?(Array)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                        _2
         | 
| 36 | 
            +
                      end
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def mysql_binds
         | 
| 40 | 
            +
                    statement_binds
         | 
| 41 | 
            +
                      .map(&:first)
         | 
| 42 | 
            +
                      .flatten
         | 
| 43 | 
            +
                      .each_slice(2)
         | 
| 44 | 
            +
                      .to_a
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def pg_binds
         | 
| 48 | 
            +
                    statement_binds
         | 
| 49 | 
            +
                      .sort_by { _2.to_s.tr("$", "").to_i }
         | 
| 50 | 
            +
                      .uniq
         | 
| 51 | 
            +
                      .map(&:first)
         | 
| 52 | 
            +
                      .flatten
         | 
| 53 | 
            +
                      .each_slice(2)
         | 
| 54 | 
            +
                      .to_a
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "forwardable"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ::YeSQL
         | 
| 6 | 
            +
              module Common
         | 
| 7 | 
            +
                module Adapter
         | 
| 8 | 
            +
                  extend ::Forwardable
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def mysql? ;  adapter == "Mysql2"; end
         | 
| 11 | 
            +
                  def pg? ;  adapter == "PostgreSQL"; end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  private
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def adapter ;  ::ActiveRecord::Base.connection.adapter_name; end
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ::YeSQL
         | 
| 4 | 
            +
              module Config
         | 
| 5 | 
            +
                class Configuration
         | 
| 6 | 
            +
                  attr_accessor :connection, :path
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  DEFAULT_PATH = "app/yesql"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def initialize
         | 
| 11 | 
            +
                    @connection = ""
         | 
| 12 | 
            +
                    @path = DEFAULT_PATH
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              class << self
         | 
| 18 | 
            +
                def config ;  @config ||= ::YeSQL::Configuration.new; end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def configure
         | 
| 21 | 
            +
                  yield config if block_given?
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def reset_config
         | 
| 25 | 
            +
                  tap do |conf|
         | 
| 26 | 
            +
                    conf.configure do |configuration|
         | 
| 27 | 
            +
                      configuration.path = ::YeSQL::Configuration::DEFAULT_PATH
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module ::YeSQL
         | 
| 4 | 
            +
              module Errors
         | 
| 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?
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    raise(
         | 
| 14 | 
            +
                      ::NotImplementedError,
         | 
| 15 | 
            +
                      format(
         | 
| 16 | 
            +
                        MESSAGE,
         | 
| 17 | 
            +
                        available_files: available_files,
         | 
| 18 | 
            +
                        file_path: file_path,
         | 
| 19 | 
            +
                        path: ::YeSQL.config.path
         | 
| 20 | 
            +
                      )
         | 
| 21 | 
            +
                    )
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  private
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  attr_reader :file_path
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  MESSAGE = <<~MSG
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    SQL file "%<file_path>s" does not exist in %<path>s.
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    Available SQL files are:
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    %<available_files>s
         | 
| 35 | 
            +
                  MSG
         | 
| 36 | 
            +
                  private_constant :MESSAGE
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def file_exists? ;  path_files.any? { _1.include?("#{file_path}.sql") }; end
         | 
| 39 | 
            +
                  def path_files ;  @path_files ||= Dir["#{::YeSQL.config.path}/**/*.sql"]; end
         | 
| 40 | 
            +
                  def available_files ;  path_files.map { "- #{_1}\n" }.join; end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "yesql/utils/read"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module ::YeSQL
         | 
| 6 | 
            +
              module Errors
         | 
| 7 | 
            +
                class NoBindingsProvidedError
         | 
| 8 | 
            +
                  include ::YeSQL::Utils::Read
         | 
| 9 | 
            +
             | 
| 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, format(MESSAGE, renderable_statement_binds)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  attr_reader :binds, :file_path
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  MESSAGE = <<~MSG
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    YeSQL invoked without bindings.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    Expected bindings are:
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    %s
         | 
| 33 | 
            +
                  MSG
         | 
| 34 | 
            +
                  private_constant :MESSAGE
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def statement_binds ;  statement.scan(::YeSQL::BIND_REGEX).tap { break (_1 || []).sort }; end
         | 
| 37 | 
            +
                  def renderable_statement_binds ;  statement_binds.flatten.map { "- `#{_1}`\n" }.join; end
         | 
| 38 | 
            +
                  def expected_binds? ;  binds.is_a?(::Hash) && !binds.empty?; end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "yesql"
         | 
| 4 | 
            +
            require "forwardable"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module ::YeSQL
         | 
| 7 | 
            +
              module Params
         | 
| 8 | 
            +
                class Output
         | 
| 9 | 
            +
                  extend ::Forwardable
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(output)
         | 
| 12 | 
            +
                    @output = output.to_s
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def columns? ;  output == "columns"; end
         | 
| 16 | 
            +
                  def rows? ;  output == "rows"; end
         | 
| 17 | 
            +
                  def hash? ;  output == "hash"; end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def_delegator(:output, :to_sym)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  private
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  attr_reader :output
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         |