2013-02-05 13:16:51 -06:00
class SqlBuilder
2013-02-10 06:37:24 -06:00
def initialize ( template , klass = nil )
2013-02-05 13:16:51 -06:00
@args = { }
@sql = template
@sections = { }
2013-02-10 06:37:24 -06:00
@klass = klass
2013-02-05 13:16:51 -06:00
end
2013-05-12 19:48:32 -05:00
[ :set , :where2 , :where , :order_by , :limit , :left_join , :join , :offset , :select ] . each do | k |
2013-02-05 13:16:51 -06:00
define_method k do | data , args = { } |
@args . merge! ( args )
@sections [ k ] || = [ ]
@sections [ k ] << data
self
end
end
2013-06-05 01:10:26 -05:00
def secure_category ( secure_category_ids , category_alias = 'c' )
if secure_category_ids . present?
2013-07-13 20:24:16 -05:00
where ( " NOT COALESCE( " << category_alias << " .read_restricted, false) OR " << category_alias << " .id IN (:secure_category_ids) " , secure_category_ids : secure_category_ids )
2013-06-05 01:10:26 -05:00
else
2013-07-13 20:24:16 -05:00
where ( " NOT COALESCE( " << category_alias << " .read_restricted, false) " )
2013-06-05 01:10:26 -05:00
end
self
end
2013-05-12 19:48:32 -05:00
def to_sql
2013-02-05 13:16:51 -06:00
sql = @sql . dup
@sections . each do | k , v |
joined = nil
2013-02-25 10:42:20 -06:00
case k
2013-05-12 19:48:32 -05:00
when :select
joined = " SELECT " << v . join ( " , " )
2013-02-05 13:16:51 -06:00
when :where , :where2
2013-05-23 00:21:07 -05:00
joined = " WHERE " << v . map { | c | " ( " << c << " ) " } . join ( " AND " )
2013-02-05 13:16:51 -06:00
when :join
joined = v . map { | v | " JOIN " << v } . join ( " \n " )
when :left_join
joined = v . map { | v | " LEFT JOIN " << v } . join ( " \n " )
when :limit
joined = " LIMIT " << v . last . to_s
when :offset
joined = " OFFSET " << v . last . to_s
when :order_by
joined = " ORDER BY " << v . join ( " , " )
when :set
joined = " SET " << v . join ( " , " )
end
sql . sub! ( " /* #{ k } */ " , joined )
end
2013-05-12 19:48:32 -05:00
sql
end
def exec ( args = { } )
@args . merge! ( args )
2013-02-25 10:42:20 -06:00
2013-05-12 19:48:32 -05:00
sql = to_sql
2013-02-10 06:37:24 -06:00
if @klass
@klass . find_by_sql ( ActiveRecord :: Base . send ( :sanitize_sql_array , [ sql , @args ] ) )
else
2013-10-09 21:33:52 -05:00
if @args == { }
ActiveRecord :: Base . exec_sql ( sql )
else
ActiveRecord :: Base . exec_sql ( sql , @args )
end
2013-02-10 06:37:24 -06:00
end
2013-02-05 13:16:51 -06:00
end
2013-05-23 00:21:07 -05:00
2013-06-11 20:14:08 -05:00
#AS reloads this on tests
remove_const :FTYPE_MAP if defined? FTYPE_MAP
2014-08-17 20:46:53 -05:00
if rails_master?
FTYPE_MAP = {
23 = > ActiveRecord :: Type :: Integer . new ,
1114 = > ActiveRecord :: Type :: DateTime . new ,
16 = > ActiveRecord :: Type :: Boolean . new
}
else
FTYPE_MAP = {
23 = > :value_to_integer ,
1114 = > :string_to_time ,
16 = > :value_to_boolean
}
end
2013-05-23 00:21:07 -05:00
2014-06-24 02:10:56 -05:00
def self . map_exec ( klass , sql , args = { } )
self . new ( sql ) . map_exec ( klass , args )
end
2013-10-16 21:23:38 -05:00
def map_exec ( klass = OpenStruct , args = { } )
2013-05-23 00:21:07 -05:00
results = exec ( args )
setters = results . fields . each_with_index . map do | f , index |
[ ( f . dup << " = " ) . to_sym , FTYPE_MAP [ results . ftype ( index ) ] ]
end
values = results . values
values . map! do | row |
mapped = klass . new
setters . each_with_index do | mapper , index |
translated = row [ index ]
if mapper [ 1 ] && ! translated . nil?
2014-08-17 20:46:53 -05:00
if rails_master?
translated = mapper [ 1 ] . type_cast_from_database ( translated )
else
translated = ActiveRecord :: ConnectionAdapters :: Column . send mapper [ 1 ] , translated
end
2013-05-23 00:21:07 -05:00
end
mapped . send mapper [ 0 ] , translated
end
mapped
end
end
2013-02-10 06:37:24 -06:00
end
2013-02-05 13:16:51 -06:00
2013-02-25 10:42:20 -06:00
class ActiveRecord :: Base
2013-02-10 06:37:24 -06:00
def self . sql_builder ( template )
SqlBuilder . new ( template , self )
end
2013-02-05 13:16:51 -06:00
end