2019-05-03 08:17:27 +10:00
# frozen_string_literal: true
2013-02-05 14:16:51 -05:00
class SqlBuilder
2017-07-28 10:20:09 +09:00
def initialize ( template , klass = nil )
2018-06-20 17:48:02 +10:00
Discourse . deprecate ( "SqlBuilder is deprecated and will be removed, please use DB.build instead!" )
2013-02-05 14:16:51 -05:00
@args = {}
@sql = template
@sections = {}
2013-02-10 23:37:24 +11:00
@klass = klass
2013-02-05 14:16:51 -05:00
end
2017-07-28 10:20:09 +09:00
[ :set , :where2 , :where , :order_by , :limit , :left_join , :join , :offset , :select ]. each do | k |
2013-02-05 14:16:51 -05:00
define_method k do | data , args = {} |
@args . merge! ( args )
@sections [ k ] ||= []
@sections [ k ] << data
self
end
end
2013-06-05 16:10:26 +10:00
def secure_category ( secure_category_ids , category_alias = 'c' )
if secure_category_ids . present?
2017-07-28 10:20:09 +09: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 16:10:26 +10:00
else
2013-07-14 11:24:16 +10:00
where ( "NOT COALESCE(" << category_alias << ".read_restricted, false)" )
2013-06-05 16:10:26 +10:00
end
self
end
2013-05-13 10:48:32 +10:00
def to_sql
2013-02-05 14:16:51 -05:00
sql = @sql . dup
2017-07-28 10:20:09 +09:00
@sections . each do | k , v |
2013-02-05 14:16:51 -05:00
joined = nil
2013-02-25 19:42:20 +03:00
case k
2013-05-13 10:48:32 +10:00
when :select
joined = "SELECT " << v . join ( " , " )
2013-02-05 14:16:51 -05:00
when :where , :where2
2017-07-28 10:20:09 +09:00
joined = "WHERE " << v . map { | c | "(" << c << ")" } . join ( " AND " )
2013-02-05 14:16:51 -05:00
when :join
2017-07-28 10:20:09 +09:00
joined = v . map { | item | "JOIN " << item } . join ( " \n " )
2013-02-05 14:16:51 -05:00
when :left_join
2017-07-28 10:20:09 +09:00
joined = v . map { | item | "LEFT JOIN " << item } . join ( " \n " )
2013-02-05 14:16:51 -05:00
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-13 10:48:32 +10:00
sql
end
def exec ( args = {})
@args . merge! ( args )
2013-02-25 19:42:20 +03:00
2013-05-13 10:48:32 +10:00
sql = to_sql
2013-02-10 23:37:24 +11:00
if @klass
2019-05-07 09:27:05 +08:00
@klass . find_by_sql ( ActiveRecord :: Base . public_send ( :sanitize_sql_array , [ sql , @args ] ))
2013-02-10 23:37:24 +11:00
else
2013-10-10 13:33:52 +11:00
if @args == {}
ActiveRecord :: Base . exec_sql ( sql )
else
2017-07-28 10:20:09 +09:00
ActiveRecord :: Base . exec_sql ( sql , @args )
2013-10-10 13:33:52 +11:00
end
2013-02-10 23:37:24 +11:00
end
2013-02-05 14:16:51 -05:00
end
2013-05-23 15:21:07 +10:00
2014-06-24 17:10:56 +10:00
def self . map_exec ( klass , sql , args = {})
self . new ( sql ) . map_exec ( klass , args )
end
2015-05-13 16:45:59 +10:00
class RailsDateTimeDecoder < PG :: SimpleDecoder
2017-07-28 10:20:09 +09:00
def decode ( string , tuple = nil , field = nil )
2018-06-20 17:48:02 +10:00
@caster ||= ActiveRecord :: Type :: DateTime . new
@caster . cast ( string )
2015-05-13 16:45:59 +10:00
end
end
class ActiveRecordTypeMap < PG :: BasicTypeMapForResults
def initialize ( connection )
super ( connection )
rm_coder 0 , 1114
add_coder RailsDateTimeDecoder . new ( name : "timestamp" , oid : 1114 , format : 0 )
2017-07-28 10:20:09 +09:00
# we don't need deprecations
self . default_type_map = PG :: TypeMapInRuby . new
2015-05-13 16:45:59 +10:00
end
end
def self . pg_type_map
conn = ActiveRecord :: Base . connection . raw_connection
@typemap ||= ActiveRecordTypeMap . new ( conn )
end
2013-10-17 13:23:38 +11:00
def map_exec ( klass = OpenStruct , args = {})
2013-05-23 15:21:07 +10:00
results = exec ( args )
2015-05-13 16:45:59 +10:00
results . type_map = SqlBuilder . pg_type_map
2013-05-23 15:21:07 +10:00
setters = results . fields . each_with_index . map do | f , index |
2015-05-13 16:45:59 +10:00
f . dup << "="
2013-05-23 15:21:07 +10:00
end
2015-05-13 16:45:59 +10:00
2013-05-23 15:21:07 +10:00
values = results . values
values . map! do | row |
mapped = klass . new
2015-05-13 16:45:59 +10:00
setters . each_with_index do | name , index |
2019-05-07 12:22:37 +10:00
mapped . public_send name , row [ index ]
2013-05-23 15:21:07 +10:00
end
mapped
end
end
2013-02-10 23:37:24 +11:00
end