Module: DbMod::Statements::Params

Included in:
Prepared
Defined in:
lib/db_mod/statements/params.rb

Overview

Parsing and validation of query parameters for prepared SQL statements

Constant Summary collapse

NUMBERED_PARAM =

Regex matching a numbered parameter

/\$\d+/
NAMED_PARAM =

Regex matching a named parameter

/\$[a-z]+(?:_[a-z]+)*/
NAMED_OR_NUMBERED =

For validation, named or numbered parameter

/^\$(?:\d+|[a-z]+(?:_[a-z]+)*)$/

Class Method Summary collapse

Class Method Details

.parse_named_params!(sql, params) ⇒ Array<Symbol>

Replaces the given list of named parameters in the query string with numbered parameters, and returns an array of symbols giving the order the parameters should be fed into the prepared statement for execution.


97
98
99
100
101
102
103
104
105
# File 'lib/db_mod/statements/params.rb', line 97

def self.parse_named_params!(sql, params)
  unique_params = params.uniq
  params.each do |param|
    index = unique_params.index(param)
    sql[param] = "$#{index + 1}"
  end

  unique_params.map { |p| p[1..-1].to_sym }
end

.parse_numbered_params!(params) ⇒ Fixnum

Validates the numbered parameters given (i.e. no gaps), and returns the parameter count.


78
79
80
81
82
83
84
85
86
87
# File 'lib/db_mod/statements/params.rb', line 78

def self.parse_numbered_params!(params)
  params.sort!
  params.uniq!
  if params.last[1..-1].to_i != params.length ||
     params.first[1..-1].to_i != 1
    fail ArgumentError, 'Invalid parameter list'
  end

  params.length
end

.parse_params!(sql) ⇒ Fixnum, Array<Symbol>

Parses parameters, named or numbered, from an SQL statement. See the DbMod::Statements::Prepared module documentation for more. This method may modify the sql statement to change named parameters to numbered parameters. If the query uses numbered parameters, an integer will be returned that is the arity of the statement. If the query uses named parameters, an array of symbols will be returned, giving the order in which the named parameters should be fed into the statement.


49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/db_mod/statements/params.rb', line 49

def self.parse_params!(sql)
  Params.valid_sql_params! sql
  numbered = sql.scan NUMBERED_PARAM
  named = sql.scan NAMED_PARAM

  if numbered.any?
    fail ArgumentError, 'mixed named and numbered params' if named.any?
    Params.parse_numbered_params! numbered
  else
    Params.parse_named_params! sql, named
  end
end

.valid_named_args!(expected, args) ⇒ Array

Assert that the named arguments given for the prepared statement with the given name satisfy expectations.


12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/db_mod/statements/params.rb', line 12

def self.valid_named_args!(expected, args)
  unless args.is_a? Hash
    fail ArgumentError, "invalid argument: #{args.inspect}"
  end

  if args.size != expected.size
    fail ArgumentError, "#{args.size} args given, #{expected.size} needed"
  end

  expected.map do |arg|
    args[arg] || fail(ArgumentError, "missing arg #{arg}")
  end
end

.valid_sql_params!(sql) ⇒ Object

Fails if any parameters in an sql query aren't in the expected format. They must either be lower_case_a_to_z or digits only.


65
66
67
68
69
70
71
# File 'lib/db_mod/statements/params.rb', line 65

def self.valid_sql_params!(sql)
  sql.scan(/\$\S+/) do |param|
    unless param =~ NAMED_OR_NUMBERED
      fail ArgumentError, "Invalid parameter #{param}"
    end
  end
end