##// END OF EJS Templates
Replaces find(:all) calls....
Jean-Philippe Lang -
r10693:5cb56fd1e423
parent child
Show More
@@ -1,133 +1,130
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module Redmine
18 module Redmine
19 module Acts
19 module Acts
20 module Searchable
20 module Searchable
21 def self.included(base)
21 def self.included(base)
22 base.extend ClassMethods
22 base.extend ClassMethods
23 end
23 end
24
24
25 module ClassMethods
25 module ClassMethods
26 # Options:
26 # Options:
27 # * :columns - a column or an array of columns to search
27 # * :columns - a column or an array of columns to search
28 # * :project_key - project foreign key (default to project_id)
28 # * :project_key - project foreign key (default to project_id)
29 # * :date_column - name of the datetime column (default to created_on)
29 # * :date_column - name of the datetime column (default to created_on)
30 # * :sort_order - name of the column used to sort results (default to :date_column or created_on)
30 # * :sort_order - name of the column used to sort results (default to :date_column or created_on)
31 # * :permission - permission required to search the model (default to :view_"objects")
31 # * :permission - permission required to search the model (default to :view_"objects")
32 def acts_as_searchable(options = {})
32 def acts_as_searchable(options = {})
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
34
34
35 cattr_accessor :searchable_options
35 cattr_accessor :searchable_options
36 self.searchable_options = options
36 self.searchable_options = options
37
37
38 if searchable_options[:columns].nil?
38 if searchable_options[:columns].nil?
39 raise 'No searchable column defined.'
39 raise 'No searchable column defined.'
40 elsif !searchable_options[:columns].is_a?(Array)
40 elsif !searchable_options[:columns].is_a?(Array)
41 searchable_options[:columns] = [] << searchable_options[:columns]
41 searchable_options[:columns] = [] << searchable_options[:columns]
42 end
42 end
43
43
44 searchable_options[:project_key] ||= "#{table_name}.project_id"
44 searchable_options[:project_key] ||= "#{table_name}.project_id"
45 searchable_options[:date_column] ||= "#{table_name}.created_on"
45 searchable_options[:date_column] ||= "#{table_name}.created_on"
46 searchable_options[:order_column] ||= searchable_options[:date_column]
46 searchable_options[:order_column] ||= searchable_options[:date_column]
47
47
48 # Should we search custom fields on this model ?
48 # Should we search custom fields on this model ?
49 searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?
49 searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?
50
50
51 send :include, Redmine::Acts::Searchable::InstanceMethods
51 send :include, Redmine::Acts::Searchable::InstanceMethods
52 end
52 end
53 end
53 end
54
54
55 module InstanceMethods
55 module InstanceMethods
56 def self.included(base)
56 def self.included(base)
57 base.extend ClassMethods
57 base.extend ClassMethods
58 end
58 end
59
59
60 module ClassMethods
60 module ClassMethods
61 # Searches the model for the given tokens
61 # Searches the model for the given tokens
62 # projects argument can be either nil (will search all projects), a project or an array of projects
62 # projects argument can be either nil (will search all projects), a project or an array of projects
63 # Returns the results and the results count
63 # Returns the results and the results count
64 def search(tokens, projects=nil, options={})
64 def search(tokens, projects=nil, options={})
65 if projects.is_a?(Array) && projects.empty?
65 if projects.is_a?(Array) && projects.empty?
66 # no results
66 # no results
67 return [[], 0]
67 return [[], 0]
68 end
68 end
69
69
70 # TODO: make user an argument
70 # TODO: make user an argument
71 user = User.current
71 user = User.current
72 tokens = [] << tokens unless tokens.is_a?(Array)
72 tokens = [] << tokens unless tokens.is_a?(Array)
73 projects = [] << projects unless projects.nil? || projects.is_a?(Array)
73 projects = [] << projects unless projects.nil? || projects.is_a?(Array)
74
74
75 find_options = {:include => searchable_options[:include]}
75 find_options = {:include => searchable_options[:include]}
76 find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
76 find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
77
77
78 limit_options = {}
78 limit_options = {}
79 limit_options[:limit] = options[:limit] if options[:limit]
79 limit_options[:limit] = options[:limit] if options[:limit]
80 if options[:offset]
80 if options[:offset]
81 limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
81 limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
82 end
82 end
83
83
84 columns = searchable_options[:columns]
84 columns = searchable_options[:columns]
85 columns = columns[0..0] if options[:titles_only]
85 columns = columns[0..0] if options[:titles_only]
86
86
87 token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
87 token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
88
88
89 if !options[:titles_only] && searchable_options[:search_custom_fields]
89 if !options[:titles_only] && searchable_options[:search_custom_fields]
90 searchable_custom_field_ids = CustomField.find(:all,
90 searchable_custom_field_ids = CustomField.where(:type => "#{self.name}CustomField", :searchable => true).pluck(:id)
91 :select => 'id',
92 :conditions => { :type => "#{self.name}CustomField",
93 :searchable => true }).collect(&:id)
94 if searchable_custom_field_ids.any?
91 if searchable_custom_field_ids.any?
95 custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
92 custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
96 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
93 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
97 " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
94 " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
98 token_clauses << custom_field_sql
95 token_clauses << custom_field_sql
99 end
96 end
100 end
97 end
101
98
102 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
99 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
103
100
104 find_options[:conditions] = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
101 find_options[:conditions] = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
105
102
106 scope = self
103 scope = self
107 project_conditions = []
104 project_conditions = []
108 if searchable_options.has_key?(:permission)
105 if searchable_options.has_key?(:permission)
109 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project)
106 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project)
110 elsif respond_to?(:visible)
107 elsif respond_to?(:visible)
111 scope = scope.visible(user)
108 scope = scope.visible(user)
112 else
109 else
113 ActiveSupport::Deprecation.warn "acts_as_searchable with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option."
110 ActiveSupport::Deprecation.warn "acts_as_searchable with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option."
114 project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym)
111 project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym)
115 end
112 end
116 # TODO: use visible scope options instead
113 # TODO: use visible scope options instead
117 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
114 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
118 project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ')
115 project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ')
119
116
120 results = []
117 results = []
121 results_count = 0
118 results_count = 0
122
119
123 scope = scope.scoped({:conditions => project_conditions}).scoped(find_options)
120 scope = scope.scoped({:conditions => project_conditions}).scoped(find_options)
124 results_count = scope.count(:all)
121 results_count = scope.count(:all)
125 results = scope.find(:all, limit_options)
122 results = scope.find(:all, limit_options)
126
123
127 [results, results_count]
124 [results, results_count]
128 end
125 end
129 end
126 end
130 end
127 end
131 end
128 end
132 end
129 end
133 end
130 end
General Comments 0
You need to be logged in to leave comments. Login now