lib/baza/sql_queries/select.rb
class Baza::SqlQueries::Select
def initialize(args)
@db = args.fetch(:db)
@selects = []
@froms = []
@joins = []
@wheres = []
@groups = []
@orders = []
end
def count
@count = true
query.fetch.fetch(:count).to_i
ensure
@count = false
end
def current_page
@page || 1
end
def select(arg)
@selects << arg
self
end
def from(arg)
@froms << arg
self
end
def join(arg)
@joins << arg
self
end
def where(*args)
@wheres << args
self
end
def group(arg)
@groups << arg
self
end
def order(arg)
@orders << arg
self
end
def page(number)
@page = number.try(:to_i) || 1
self
end
def per_page(number)
@per_page = number
self
end
def limit(limit)
@limit = limit
self
end
def offset(offset)
@offset = offset
self
end
def to_sql
"#{select_sql} #{from_sql} #{where_sql} #{group_sql} #{limit_sql}"
end
def to_a
each.to_a
end
def total_pages
@per_page ||= 30
per_page_value = @per_page
(count.to_f / per_page_value.to_f).ceil
end
def each(&blk)
query(&blk)
end
def each_row
query do |data|
yield Baza::Row.new(
db: @db,
table: first_from,
data: data
)
end
end
def to_enum
Enumerator.new do |yielder|
query do |data|
yielder << data
end
end
end
def query(&blk)
@db.query(to_sql, &blk)
end
private
def select_sql
sql = "SELECT"
if @count
sql << " COUNT(*) AS count"
elsif @selects.empty?
sql << " *"
else
first = true
@selects.each do |select|
sql << "," unless first
first = false if first
if select.is_a?(Symbol)
select << " #{@db.quote_column(select)}"
else
select << @db.quote_value(select)
end
end
end
sql
end
def from_sql
sql = "FROM"
first = true
@froms.each do |from|
sql << "," unless first
first = false if first
sql << " #{@db.quote_table(from)}"
end
sql
end
def first_from
@first_from ||= @froms.first
end
def where_sql
return if @wheres.empty?
sql = " WHERE"
first = true
@wheres.each do |args|
where = args.shift
sql << " AND " unless first
first = false if first
if where.is_a?(Hash)
where.each do |key, value|
sql << "#{@db.quote_column(key)} = #{@db.quote_value(value)}"
end
elsif where.is_a?(String)
sql_arg = where.clone
args.each do |arg|
sql_arg.sub!("?", @db.quote_value(arg))
end
sql << sql_arg
else
raise "Dont know what to do with that argument: #{where}"
end
end
sql
end
def group_sql
return if @groups.empty?
end
def limit_sql
unless @count
if @page
@per_page ||= 30
sql = "LIMIT #{@db.quote_value(@per_page)} OFFSET #{@per_page * (current_page - 1)}"
elsif @limit
sql = "LIMIT #{@db.quote_value(@limit)}"
sql << ", #{@db.quote_value(@offset)}" if @offset
end
end
sql
end
end