ref: master
plugins/pg_search/lib/pg_search_plugin.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
require 'noosfero/friendly_mime' class PgSearchPlugin < Noosfero::Plugin def self.plugin_name "Postgres Full-Text Search" end def self.plugin_description _("Search engine that uses Postgres Full-Text Search.") end def stylesheet? true end def search_facets? true end def js_files 'search.js' end def find_by_contents(asset, scope, query, paginate_options={}, options={}) facets = options[:facets] || {} periods = options[:periods] || {:created_at => nil, :updated_at => nil} @base_scope = scope @asset = asset scope = scope.send(options[:filter]) if options[:filter] && options[:filter] != 'more_relevant' scope = filter_by_periods(scope, periods) if options[:periods].present? scope = filter_by_facets(scope, facets) if options[:facets].present? if query.present? query_scope = @base_scope.pg_search_plugin_search(query) #TODO The reorder is necessary to avoid crashes with core scopes chain scope = query_scope.where(:id => scope.map(&:id)).reorder("") end facets_params = facets.present? ? facets_options(asset, scope, facets) : {} {:results => scope.paginate(paginate_options), :facets => facets_params, :periods => periods} end private def filter_by_periods(scope, periods) periods.each do |attribute, period| next if period.blank? scope = scope.send(attribute, period['start_date'], period['end_date']) end scope end def filter_by_facets(scope, facets) queries = [] facets.each do |term, values| kind, klass = term.split('-') if kind == 'attribute' || kind == 'relation' arguments = values.map {|value, check| value if check == '1'}.compact arguments.map! {|argument| argument == ' ' ? nil : argument} else next end facet_slug = klass.split('/').last arguments.each do |argument| if kind == 'attribute' queries << scope.base_class.send('pg_search_plugin_by_attribute', facet_slug, argument).to_sql elsif kind == 'relation' queries << scope.base_class.send("pg_search_plugin_by_#{facet_slug}", argument).to_sql end register_search_facet_occurrence(environment, @asset, kind, facet_slug, argument) end end queries.blank? ? scope : scope.where(:id => scope.base_class.find_by_sql(queries.join(' INTERSECT '))) end def facets_options(asset, scope, selected_facets) self.send("#{asset}_facets", scope, selected_facets).compact end def articles_facets(scope, selected_facets) [ attribute_facet(Article, scope, selected_facets, {:attribute => :type}), attribute_facet(Article, scope, selected_facets, {:attribute => :content_type}), relation_facet(Tag, scope, selected_facets), relation_facet(Category, scope, selected_facets, {:filter => :pg_search_plugin_articles_facets}) ] end def profiles_facets(scope, selected_facets) [ relation_facet(Kind, scope, selected_facets), relation_facet(Tag, scope, selected_facets), relation_facet(Category, scope, selected_facets, {:filter => :pg_search_plugin_profiles_facets}), relation_facet(Region, scope, selected_facets), ] end alias :people_facets :profiles_facets alias :communities_facets :profiles_facets alias :enterprises_facets :profiles_facets def events_facets(scope, selected_facets) [] end def attribute_facet(klass, scope, selected_facets, params = {}) generic_facet(klass, scope, selected_facets, :attribute, params) end def relation_facet(klass, scope, selected_facets, params = {:filter => :pg_search_plugin_facets}) generic_facet(klass, scope, selected_facets, :relation, params) end def generic_facet(klass, scope, selected_facets, kind, params = {}) no_results = false results = self.send("#{kind}_results", klass, scope, params) if results.blank? no_results = true results = self.send("#{kind}_results", klass, @base_scope, params) end identifier = self.send("#{kind}_identifier", klass, params) options = results.map do |result| value = result[:value].blank? ? ' ' : result[:value].to_s name = self.send("#{kind}_option_name", result[:name], klass, params) enabled = selected_facets[identifier] && selected_facets[identifier][value] == '1' count = no_results ? 0 : result[:count] {:label => name, :value => value, :count => count, :enabled => enabled, :identifier => identifier} end.compact return if options.blank? {:name => self.send("#{kind}_label", klass, params), :options => options} end def attribute_identifier(klass, params) "attribute-#{params[:attribute]}" end def attribute_label(klass, params) params[:attribute].to_s.humanize.pluralize end def attribute_option_name(name, klass, params) return nil if name.blank? if params[:attribute].to_s == 'content_type' Noosfero::FriendlyMIME.find(name)[1..-1].upcase else name end end def attribute_results(klass, scope, params) results = klass.pg_search_plugin_attribute_facets(scope, params[:attribute]).count results.map do |name, count| {:name => name, :value => name, :count => count} end end def relation_identifier(klass, params) "relation-#{klass.name.underscore}" end def relation_label(klass, params) klass.name.split('::').last.pluralize end def relation_option_name(name, klass, params) name end def relation_results(klass, scope, params) results = klass.send(params[:filter], scope). select("#{klass.table_name}.*, count(#{klass.table_name}.*) as counts"). order("counts DESC") results.map do |result| {:name => relation_result_label(result), :value => result.id, :count => result.counts} end end def relation_result_label_for_category(result) result.full_name(' → ').html_safe end def relation_result_label(result) klass = result.class loop do method_name = "relation_result_label_for_#{klass.name.demodulize.underscore}" begin return self.send(method_name, result) rescue NoMethodError klass = klass.superclass return result.name if klass == ActiveRecord::Base end end end def register_search_facet_occurrence(environment, asset, kind, facet_slug, argument) occurrence = PgSearchPlugin::SearchFacetOccurrence.new(:environment => environment, :asset => asset) case kind when 'attribute' occurrence.attribute_name = facet_slug occurrence.value = argument when 'relation' klass_name = facet_slug.classify occurrence.target = klass_name.constantize.find(argument) else return end occurrence.save! occurrence end def translations _('Created at') _('Updated at') _('Types') _('TextArticle') _('UploadedFile') _('RSSFeed') _('Content types') _('Tags') end end |