mirror of
https://github.com/discourse/discourse.git
synced 2025-05-21 18:12:32 +08:00
PERF: Active Record #pluck is twice faster
PERF: SqlBuilder bypasses AR converters and uses PG directly
This commit is contained in:
@ -36,9 +36,9 @@ class SqlBuilder
|
||||
when :where, :where2
|
||||
joined = "WHERE " << v.map{|c| "(" << c << ")" }.join(" AND ")
|
||||
when :join
|
||||
joined = v.map{|v| "JOIN " << v }.join("\n")
|
||||
joined = v.map{|item| "JOIN " << item }.join("\n")
|
||||
when :left_join
|
||||
joined = v.map{|v| "LEFT JOIN " << v }.join("\n")
|
||||
joined = v.map{|item| "LEFT JOIN " << item }.join("\n")
|
||||
when :limit
|
||||
joined = "LIMIT " << v.last.to_s
|
||||
when :offset
|
||||
@ -69,46 +69,50 @@ class SqlBuilder
|
||||
end
|
||||
end
|
||||
|
||||
#AS reloads this on tests
|
||||
remove_const :FTYPE_MAP if defined? FTYPE_MAP
|
||||
|
||||
if Rails.version >= "4.2.0"
|
||||
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
|
||||
|
||||
def self.map_exec(klass, sql, args = {})
|
||||
self.new(sql).map_exec(klass, args)
|
||||
end
|
||||
|
||||
class RailsDateTimeDecoder < PG::SimpleDecoder
|
||||
def decode(string, tuple=nil, field=nil)
|
||||
if Rails.version >= "4.2.0"
|
||||
@caster ||= ActiveRecord::Type::DateTime.new
|
||||
@caster.type_cast_from_database(string)
|
||||
else
|
||||
ActiveRecord::ConnectionAdapters::Column.string_to_time string
|
||||
end
|
||||
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)
|
||||
# we don't need deprecations
|
||||
self.default_type_map = PG::TypeMapInRuby.new
|
||||
end
|
||||
end
|
||||
|
||||
def self.pg_type_map
|
||||
conn = ActiveRecord::Base.connection.raw_connection
|
||||
@typemap ||= ActiveRecordTypeMap.new(conn)
|
||||
end
|
||||
|
||||
def map_exec(klass = OpenStruct, args = {})
|
||||
results = exec(args)
|
||||
results.type_map = SqlBuilder.pg_type_map
|
||||
|
||||
setters = results.fields.each_with_index.map do |f, index|
|
||||
[(f.dup << "=").to_sym, FTYPE_MAP[results.ftype(index)]]
|
||||
f.dup << "="
|
||||
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?
|
||||
if Rails.version >= "4.2.0"
|
||||
translated = mapper[1].type_cast_from_database(translated)
|
||||
else
|
||||
translated = ActiveRecord::ConnectionAdapters::Column.send mapper[1], translated
|
||||
end
|
||||
end
|
||||
mapped.send mapper[0], translated
|
||||
setters.each_with_index do |name, index|
|
||||
mapped.send name, row[index]
|
||||
end
|
||||
mapped
|
||||
end
|
||||
|
Reference in New Issue
Block a user