Created
August 4, 2015 11:24
-
-
Save dreyks/13182f572c7ed38b7d4e to your computer and use it in GitHub Desktop.
Thinking Sphinx monkeypatches
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# fixing incorrect quoting of full table names | |
# e.g. db_name.table_name has to be quoted as | |
# `db_name`.`table_name` not `db_name.table_name` | |
ThinkingSphinx::ActiveRecord::ColumnSQLPresenter.class_eval do | |
def with_table | |
return __name if string? | |
return nil unless exists? | |
# original code does this wrong. See +properly_quoted_table+ | |
quoted_table = escape_table? ? properly_quoted_table : table | |
"#{quoted_table}.#{adapter.quote __name}" | |
end | |
private | |
def properly_quoted_table | |
table.split('.').map { |t| adapter.quote(t) }.join('.') | |
end | |
end | |
# original code acts weird when sql_options[:order] is passed | |
ThinkingSphinx::Middlewares::ActiveRecordTranslator::Inner.class_eval do | |
def call | |
results_for_models | |
# original code | |
# context[:results] = if sql_options[:order] | |
# # this produces *nil* if nothing found which leads to crash when checking for stale ids | |
# results_for_models.values.first | |
# else | |
# context[:results].collect { |row| result_for(row) } | |
# end | |
context[:results].collect! { |row| result_for(row) } | |
end | |
end | |
# Storing each STI class under it;s own name leads to multiple identical queries | |
# when populating results. | |
# ActiveRecord::Inheritance#base_class returns correct parent class for both STI | |
# parent and children. Also correct for non-STI classes | |
ThinkingSphinx::RealTime::Index::Template.class_eval do | |
def class_column | |
[:class, :base_class, :name] | |
end | |
end | |
# this allows searching on scopes | |
# Article.select(:id, :user_id).includes(:tags, :users).search('sometext') | |
# becomes | |
# Article.search('sometext', sql: {select: [:id, :user_id], includes: [:tags, :users]}) | |
ThinkingSphinx::ActiveRecord::Base::ClassMethods.class_eval do | |
private | |
def merge_search(search, query, options) | |
merger = ThinkingSphinx::Search::Merger.new search | |
merger.merge! *default_sphinx_scope_response if default_sphinx_scope? | |
if current_scope && !merger.search.options[:ignore_scopes] | |
merger.merge! query, scope_to_sql_options(options) | |
else | |
merger.merge! query, options | |
end | |
result = merger.merge! nil, :classes => [self] | |
result.populate if result.options[:populate] | |
result | |
end | |
def scope_to_sql_options(options) | |
sql_options = [:includes, :joins, :order, :select, :group].map do |method| | |
[method, current_scope.send("#{method}_values")] | |
end.to_h | |
options.merge(sql: sql_options) | |
end | |
end | |
# sql_options[:include] should really be sql_options[:includes] to allow nice | |
# scoped searching code | |
ThinkingSphinx::Middlewares::ActiveRecordTranslator::Inner.class_eval do | |
private | |
def model_relation_with_sql_options(relation) | |
# sql_options[:includes], not sql_options[:include] | |
relation = relation.includes sql_options[:includes] if sql_options[:includes] | |
relation = relation.joins sql_options[:joins] if sql_options[:joins] | |
relation = relation.order sql_options[:order] if sql_options[:order] | |
relation = relation.select sql_options[:select] if sql_options[:select] | |
relation = relation.group sql_options[:group] if sql_options[:group] | |
# for backwards compatibility | |
relation = relation.includes sql_options[:include] if sql_options[:include] | |
relation | |
end | |
end | |
# Article.facets(with: {user_id: 123}).for(date: 20150707) | |
# resulted in losing user_id = 123 in sphinx query | |
ThinkingSphinx::FacetSearch.class_eval do | |
def for(facet_values = {}) | |
filter_facets = facet_values.keys.collect { |key| | |
facets.detect { |facet| facet.name == key.to_s } | |
} | |
tmp_options = options.merge(:indices => index_names_for(*filter_facets)) | |
# poor man's Hash#deep_merge | |
# (const_get because we're in class eval) | |
self.class.const_get(:Filter).new(facets, facet_values).to_hash.each do |filter_type, filter_value| | |
if tmp_options[filter_type] | |
tmp_options[filter_type].merge! filter_value | |
else | |
tmp_options[filter_type] = filter_value | |
end | |
end | |
ThinkingSphinx::Search.new query, tmp_options | |
# original code overwrites options[:with] while merging | |
# ThinkingSphinx::Search.new query, options.merge( | |
# :indices => index_names_for(*filter_facets) | |
# ).merge(Filter.new(facets, facet_values).to_hash) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment