Module: DbMod::Statements::Prepared

Defined in:
lib/db_mod/statements/prepared.rb

Overview

Provides the def_prepared function which allows DbMod modules to declare prepared SQL statements that will be added to the database connection when DbMod#db_connect is called.

For statements that are not prepared ahead of execution, see def_statement in Statement.

def_prepared accepts two parameters:

  • name [Symbol]: The name that will be given to the prepared statement. A method will also be defined on the module with the same name which will call the statement and return the result.

  • sql [String]: The SQL statement to be prepared. Parameters may be declared using the $ symbol followed by a number ($1, $2, $3) or a name ($one, $two, $a_b). The two styles may not be mixed in the same statement. The defined function can then be passed parameters that will be used when the statement is executed.

module MyModule
  include DbMod

  def_prepared :my_prepared, "    SELECT *\n      FROM stuff\n     WHERE a = $1 AND b = $2\n  SQL\n\n  def_prepared :my_named_prepared, <<-SQL\n    SELECT *\n      FROM stuff\n     WHERE a = $a AND b = $b\n  SQL\nend\n\ninclude MyModule\ndb_connect db: 'mydb'\nmy_prepared(1,2)\nmy_named_prepared(a: 1, b: 2)\n"

Class Method Summary collapse

Class Method Details

.define_def_prepared(mod) ⇒ Object (private)

Add a def_prepared method definition to a module. This method allows modules to declare named SQL statements that will be prepared when the database connection is established, and that can be accessed via an instance method with the same name.

Parameters:

  • mod (Module)

    a module with DbMod included



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/db_mod/statements/prepared.rb', line 66

def self.define_def_prepared(mod)
  mod.class.instance_eval do
    define_method(:def_prepared) do |name, sql|
      sql = sql.dup
      name = name.to_sym

      params = Parameters.parse_params! sql
      prepared_statements[name] = sql
      Prepared.define_prepared_method(mod, name, params)
    end
  end
end

.define_fixed_args_prepared_method(mod, name, count) ⇒ Object (private)

Define a method with the given name that accepts a fixed number of arguments, that will call the prepared statement with the same name.

Parameters:

  • mod (Module)

    DbMod enabled module where the method will be defined

  • name (Symbol)

    name of the method to be defined and the prepared query to be called.

  • count (Fixnum)

    arity of the defined method, the number of parameters that the prepared statement requires



176
177
178
179
180
181
182
183
184
# File 'lib/db_mod/statements/prepared.rb', line 176

def self.define_fixed_args_prepared_method(mod, name, count)
  method = lambda do |*args|
    Parameters.valid_fixed_args!(count, args)

    conn.exec_prepared(name.to_s, args)
  end

  Configuration.def_configurable(mod, name, method)
end

.define_inherited_prepared_statements(mod) ⇒ Object (private)

Adds inherited_prepared_statements to a module. This list of named prepared statements declared on this module and all included modules will be added to the connection when DbMod#db_connect is called.



203
204
205
206
207
208
209
210
211
212
213
# File 'lib/db_mod/statements/prepared.rb', line 203

def self.define_inherited_prepared_statements(mod)
  mod.class.instance_eval do
    define_method(:inherited_prepared_statements) do
      inherited = {}
      ancestors.each do |klass|
        Prepared.merge_statements(inherited, klass)
      end
      inherited
    end
  end
end

.define_named_args_prepared_method(mod, name, params) ⇒ Object (private)

Define a method with the given name that accepts the given set of named parameters, that will call the prepared statement with the same name.

Parameters:

  • mod (Module)

    DbMod enabled module where the method will be defined

  • name (Symbol)

    name of the method to be defined and the prepared query to be called.

  • params (Array<Symbol>)

    list of parameter names



156
157
158
159
160
161
162
163
# File 'lib/db_mod/statements/prepared.rb', line 156

def self.define_named_args_prepared_method(mod, name, params)
  method = lambda do |*args|
    args = Parameters.valid_named_args! params, args
    conn.exec_prepared(name.to_s, args)
  end

  Configuration.def_configurable mod, name, method
end

.define_no_args_prepared_method(mod, name) ⇒ Object (private)

Define a no-argument method with the given name that will call the prepared statement with the same name.

Parameters:

  • mod (Module)

    DbMod enabled module where the method will be defined

  • name (Symbol)

    name of the method to be defined and the prepared query to be called.



142
143
144
145
# File 'lib/db_mod/statements/prepared.rb', line 142

def self.define_no_args_prepared_method(mod, name)
  method = ->() { conn.exec_prepared(name.to_s) }
  Configuration.def_configurable mod, name, method
end

.define_prepare_all_statements(mod) ⇒ Object (private)

Defines prepare_all_statements, a module method which accepts a connection object and will prepare on it all of the prepared statements that have been declared on the module or any of its included modules.

Parameters:

  • mod (Module)

    module that has DbMod included



85
86
87
88
89
90
91
92
93
# File 'lib/db_mod/statements/prepared.rb', line 85

def self.define_prepare_all_statements(mod)
  mod.class.instance_eval do
    define_method(:prepare_all_statements) do |conn|
      inherited_prepared_statements.each do |name, sql|
        conn.prepare(name.to_s, sql)
      end
    end
  end
end

.define_prepared_method(mod, name, params) ⇒ Object (private)

Define a method in the given module with the given name and parameters, that will call the prepared statement with the same name.

Parameters:

  • mod (Module)

    module declaring the method

  • name (Symbol)

    method name

  • params (Fixnum, Array<Symbol>)

    expected parameter count, or a list of argument names. An empty array produces a no-argument method.



122
123
124
125
126
127
128
129
130
131
132
# File 'lib/db_mod/statements/prepared.rb', line 122

def self.define_prepared_method(mod, name, params)
  if params.is_a?(Array)
    if params.empty?
      define_no_args_prepared_method(mod, name)
    else
      define_named_args_prepared_method(mod, name, params)
    end
  else
    define_fixed_args_prepared_method(mod, name, params)
  end
end

.define_prepared_statements(mod) ⇒ Object (private)

Adds prepared_statements to a module. This list of named prepared statements will be added to the connection when DbMod#db_connect is called.

Parameters:

  • mod (Module)


191
192
193
194
195
196
197
# File 'lib/db_mod/statements/prepared.rb', line 191

def self.define_prepared_statements(mod)
  mod.class.instance_eval do
    define_method(:prepared_statements) do
      @prepared_statements ||= {}
    end
  end
end

.merge_statements(statements, klass) ⇒ Object (private)

Merge the prepared statements from a module into a given hash. Fails if there are any duplicates.

Parameters:

  • statements (Hash)

    named list of prepared statements

  • klass (Class, Module)

    ancestor (hopefully a DbMod module) to collect prepared statements from



102
103
104
105
106
107
108
109
110
111
# File 'lib/db_mod/statements/prepared.rb', line 102

def self.merge_statements(statements, klass)
  return unless klass.respond_to? :prepared_statements
  return if klass.prepared_statements.nil?

  klass.prepared_statements.each do |name, sql|
    fail DbMod::Exceptions::DuplicateStatementName if statements.key? name

    statements[name] = sql
  end
end

.setup(mod) ⇒ Object

Defines a module-specific def_prepared function for a module that has just had DbMod included.

Parameters:

  • mod (Module)


50
51
52
53
54
55
# File 'lib/db_mod/statements/prepared.rb', line 50

def self.setup(mod)
  Prepared.define_def_prepared(mod)
  Prepared.define_prepared_statements(mod)
  Prepared.define_inherited_prepared_statements(mod)
  Prepared.define_prepare_all_statements(mod)
end