class Ferret::Expression

Attributes

exemplars[R]
multicolumn[RW]
selectees[R]
stages[R]
type[RW]

Public Class Methods

new() click to toggle source
Calls superclass method
# File lib/sql-ferret.rb, line 929
def initialize
  super()
  @stages = [Ferret::Stage.new(nil, nil, :left)]
  @selectees = []
  @exemplars = []
  @multicolumn = false
  @type = :select # the default
  return
end

Public Instance Methods

assign_stage_qualifiers(ag) click to toggle source
# File lib/sql-ferret.rb, line 939
def assign_stage_qualifiers ag
  raise 'type mismatch' \
      unless ag.is_a? Ferret::Alias_Generator
  table_visit_counts = Hash.new 0 # name => count
  @stages.each_with_index do |stage, i|
    table_visit_counts[stage.table.name] += 1
  end

  # The tables that we visited more than once need
  # distinguishing names.
  @stages.each do |stage|
    stage.qualifier =
        if table_visit_counts[stage.table.name] > 1 then
          ag.create stage.table.name[0]
        else
          stage.table.name
        end
  end
  return
end
from_clause() click to toggle source
# File lib/sql-ferret.rb, line 960
def from_clause
  clause = "from "
  @stages.each_with_index do |stage, i|
    # In case of a non-query expression -- a modification --,
    # the last stage is empty and mustn't be joined.  It then
    # serves only the purpose of holding the last stalk.
    break if i == @stages.length - 1 and modification?

    unless i.zero? then
      clause << " #{stage.join_type} join "
    end

    clause << stage.table.name << " as " << stage.qualifier

    unless i.zero? then
      clause << " on %s.%s = %s.%s" % [
          stage.parent.qualifier,
              (stage.stalk.haunt || stage.stalk).name,
          stage.qualifier, stage.stalk.ref.name,
      ]
    end
  end
  return clause
end
modification?() click to toggle source
# File lib/sql-ferret.rb, line 1046
def modification?
  case @type
    when :select, :select_distinct then
      return false
    when :update, :insert, :delete then
      return true
    else
      raise 'assertion failed'
  end
end
select() click to toggle source

Prepare a [[select]] statement as an [[Annotated_SQL_Template]]. If this expression represents a query statement, the result will cover the whole query. If it represents an update statement, the result will cover the subquery that determines key value(s) of records in the last table to update.

# File lib/sql-ferret.rb, line 1008
def select
  qualifiers_needed =
      @stages.length != (modification? ? 2 : 1)
  sql_selectees = @selectees.map do |selectee|
    (qualifiers_needed ?
            selectee.stage.qualifier + "." : "") +
        (selectee.field.haunt || selectee.field).name
  end.join(', ')

  outputs = {}
  @selectees.each do |selectee|
    outputs[selectee.output_name.to_sym] =
        selectee.interpretation
  end

  sql = "select"
  sql << " distinct" if @type == :select_distinct
  sql << " " << sql_selectees << " " << from_clause

  sql << " " << where_clause unless @exemplars.empty?

  # Determine the shape of the table
  shape = 0
  shape |= QSF_MULTICOL if @multicolumn
  # If no [[unique]] exemplar field is specified or if any of
  # the joins is performed along a ghost field (i.e.,
  # possibly a 1->n reference), our result will have multiple
  # rows.
  shape |= QSF_MULTIROW \
      unless @exemplars.any?{|ex| ex.column.unique?} and
          !@stages[1 .. -1].any?{|stage| stage.stalk.ghost?}

  return Ferret::Annotated_SQL_Template.new(sql,
      outputs, shape)
end
where_clause() click to toggle source
# File lib/sql-ferret.rb, line 985
def where_clause
  raise 'assertion failed' if @exemplars.empty?
  clause = "where "
  @exemplars.each_with_index do |exemplar, i|
    clause << " and " unless i.zero?
    # The qualifier is only necessary if the clause has more
    # than one stage.
    if @stages.length > 1 then
      # In the navigational model, the (primary) filter always
      # lives in the zeroth stage.
      clause << @stages[0].qualifier << "."
    end
    clause << exemplar.column.name << " [test #{i}]"
  end
  return clause
end