module StaticRecord::QueryBuildingConcern

Helps building SQL queries

Public Instance Methods

build_query() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 6
def build_query
  sql = sql_select_from
  sql += sql_joins unless @joins_clauses.empty?
  sql += sql_where unless @where_clauses.empty?
  sql += sql_order unless @order_by.empty?
  sql += sql_limit_offset if @sql_limit
  sql
end

Private Instance Methods

cast(value) click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 112
def cast(value)
  return escape(value.class.name) if value.class < StaticRecord::Base
  return value.to_s if value =~ /^[+|-]?\d+\.?\d*$/
  escape(value)
end
escape(value) click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 118
def escape(value)
  return "'#{value}'" unless value.to_s.include?('\'')
  "\"#{value}\""
end
get_column_for_static_table(table) click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 123
def get_column_for_static_table(table)
  klass = @klass.constantize
  klass.bound_static_tables[table.to_sym]
end
sql_joins() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 21
def sql_joins
  @joins_clauses.map do |joint|
    " INNER JOIN #{joint} ON "\
    "#{@store}.#{get_column_for_static_table(joint)} = #{joint}.klass"
  end.join
end
sql_limit_offset() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 50
def sql_limit_offset
  sql = " LIMIT #{@sql_limit}"
  sql += " OFFSET #{@sql_offset}" if @sql_offset
  sql
end
sql_order() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 32
def sql_order
  ord_sql = ''
  @order_by.each do |ord|
    ord_sql += ord_sql.empty? ? ' ORDER BY' : ', '
    case ord.class.name
    when Hash.name
      ord_sql += ord.map { |k, v| " #{@table}.#{k} #{v.to_s.upcase}" }.join(',')
    when Array.name
      ord_sql += ord.map { |sym| " #{@table}.#{sym} ASC" }.join(',')
    when Symbol.name
      ord_sql += " #{@table}.#{ord} ASC"
    when String.name
      ord_sql += " #{ord}"
    end
  end
  ord_sql
end
sql_select_from() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 17
def sql_select_from
  "SELECT #{@columns} FROM #{@table}"
end
sql_where() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 28
def sql_where
  " WHERE #{where_clause_builder}"
end
where_clause_builder() click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 56
def where_clause_builder
  params = []
  @where_clauses.map do |clause|
    subquery = clause[:q]
    if subquery.is_a?(Hash)
      params << where_clause_from_hash(clause, subquery)
    elsif subquery.is_a?(String)
      params << where_clause_from_string(clause, subquery)
    end

    if params.size > 1
      joint = clause[:chain] == :or ? 'OR' : 'AND'
      params = [params.join(" #{joint} ")]
    end
  end

  params.first
end
where_clause_from_hash(clause, subquery) click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 75
def where_clause_from_hash(clause, subquery)
  parts = subquery.keys.map do |key|
    value = subquery[key]
    if value.is_a?(Array)
      # ex: where(name: ['John', 'Jack'])
      # use IN operator
      value.map! { |v| cast(v) }
      inverse = 'NOT ' if clause[:operator] == :not_eq
      "#{key} #{inverse}IN (#{value.join(',')})"
    else
      # ex: where(name: 'John')
      # use = operator
      inverse = '!' if clause[:operator] == :not_eq
      "#{key} #{inverse}= #{cast(value)}"
    end
  end
  parts.join(' AND ')
end
where_clause_from_string(clause, subquery) click to toggle source
# File lib/static_record/concerns/query_building_concern.rb, line 94
def where_clause_from_string(clause, subquery)
  final_string = subquery
  if clause[:parameters].is_a?(Array)
    # Anon parameters
    # ex: where("name = ? OR name = ?", 'John', 'Jack')
    clause[:parameters].each do |param|
      final_string.sub!(/\?/, cast(param))
    end
  elsif clause[:parameters].is_a?(Hash)
    # Named parameters (placeholder condition)
    # ex: where("name = :one OR name = :two", one: 'John', two: 'Smith')
    clause[:parameters].each do |key, value|
      final_string.sub!(":#{key}", cast(value))
    end
  end
  final_string
end