Method: SQLite3::Database#create_aggregate_handler

Defined in:
lib/sqlite3/database.rb

#create_aggregate_handler(handler) ⇒ Object

This is another approach to creating an aggregate function (see #create_aggregate). Instead of explicitly specifying the name, callbacks, arity, and type, you specify a factory object (the “handler”) that knows how to obtain all of that information. The handler should respond to the following messages:

arity

corresponds to the arity parameter of #create_aggregate. This message is optional, and if the handler does not respond to it, the function will have an arity of -1.

name

this is the name of the function. The handler must implement this message.

new

this must be implemented by the handler. It should return a new instance of the object that will handle a specific invocation of the function.

The handler instance (the object returned by the new message, described above), must respond to the following messages:

step

this is the method that will be called for each step of the aggregate function’s evaluation. It should implement the same signature as the step callback for #create_aggregate.

finalize

this is the method that will be called to finalize the aggregate function’s evaluation. It should implement the same signature as the finalize callback for #create_aggregate.

Example:

class LengthsAggregateHandler
  def self.arity; 1; end
  def self.name; 'lengths'; end

  def initialize
    @total = 0
  end

  def step( ctx, name )
    @total += ( name ? name.length : 0 )
  end

  def finalize( ctx )
    ctx.result = @total
  end
end

db.create_aggregate_handler( LengthsAggregateHandler )
puts db.get_first_value( "select lengths(name) from A" )


543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/sqlite3/database.rb', line 543

def create_aggregate_handler( handler )
  # This is a compatibility shim so the (basically pointless) FunctionProxy
  # "ctx" object is passed as first argument to both step() and finalize().
  # Now its up to the library user whether he prefers to store his
  # temporaries as instance variables or fields in the FunctionProxy.
  # The library user still must set the result value with
  # FunctionProxy.result= as there is no backwards compatible way to
  # change this.
  proxy = Class.new(handler) do
    def initialize
      super
      @fp = FunctionProxy.new
    end

    def step( *args )
      super(@fp, *args)
    end

    def finalize
      super(@fp)
      @fp.result
    end
  end
  define_aggregator2(proxy, proxy.name)
  self
end