Class: IssuableFinder
- Inherits:
-
Object
- Object
- IssuableFinder
- Includes:
- CreatedAtFilter, FinderMethods, FinderWithCrossProjectAccess, Gitlab::Utils::StrongMemoize, UpdatedAtFilter
- Defined in:
- app/finders/issuable_finder.rb,
app/finders/issuable_finder/params.rb
Overview
IssuableFinder
Used to filter Issues and MergeRequests collections by set of params
Note: This class is NOT meant to be instantiated. Instead you should
look at IssuesFinder or EpicsFinder, which inherit from this.
Arguments:
klass - actual class like Issue or MergeRequest
current_user - which user use
params:
scope: 'created_by_me' or 'assigned_to_me' or 'all'
state: 'opened' or 'closed' or 'locked' or 'all'
group_id: integer
project_id: integer
milestone_title: string (cannot be simultaneously used with milestone_wildcard_id)
milestone_wildcard_id: 'none', 'any', 'upcoming', 'started' (cannot be simultaneously used with milestone_title)
release_tag: string
author_id: integer
author_username: string
assignee_id: integer or 'None' or 'Any'
closed_by_id: integer
assignee_username: string
search: string
in: 'title', 'description', or a string joining them with comma
label_name: string
sort: string
non_archived: boolean
iids: integer[]
my_reaction_emoji: string
created_after: datetime
created_before: datetime
updated_after: datetime
updated_before: datetime
attempt_group_search_optimizations: boolean
attempt_project_search_optimizations: boolean
crm_contact_id: integer
crm_organization_id: integer
Direct Known Subclasses
Defined Under Namespace
Classes: Params
Constant Summary collapse
- FULL_TEXT_SEARCH_TERM_PATTERN =
'[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'
- FULL_TEXT_SEARCH_TERM_REGEX =
/\A#{FULL_TEXT_SEARCH_TERM_PATTERN}\z/
- NEGATABLE_PARAMS_HELPER_KEYS =
%i[project_id scope status include_subgroups].freeze
Instance Attribute Summary collapse
-
#current_user ⇒ Object
Returns the value of attribute current_user.
-
#original_params ⇒ Object
readonly
Returns the value of attribute original_params.
-
#params ⇒ Object
Returns the value of attribute params.
-
#parent ⇒ Object
writeonly
Sets the attribute parent.
Attributes included from FinderWithCrossProjectAccess
#should_skip_cross_project_check
Class Method Summary collapse
- .array_params ⇒ Object
-
.negatable_array_params ⇒ Object
This should not be used in controller strong params!.
-
.negatable_params ⇒ Object
This should not be used in controller strong params!.
-
.negatable_scalar_params ⇒ Object
This should not be used in controller strong params!.
- .scalar_params ⇒ Object
- .valid_params ⇒ Object
Instance Method Summary collapse
-
#count_by_state ⇒ Object
We often get counts for each state by running a query per state, and counting those results.
- #execute ⇒ Object
- #filter_items(items) ⇒ Object
-
#filter_negated_items(items) ⇒ Object
Negates all params found in ‘negatable_params`.
-
#initialize(current_user, params = {}) ⇒ IssuableFinder
constructor
A new instance of IssuableFinder.
- #klass ⇒ Object
- #params_class ⇒ Object
- #parent_param ⇒ Object
- #parent_param=(obj) ⇒ Object
- #row_count ⇒ Object
-
#search ⇒ Object
rubocop: enable CodeReuse/ActiveRecord.
- #should_filter_negated_args? ⇒ Boolean
- #use_cte_for_search? ⇒ Boolean
Methods included from UpdatedAtFilter
Methods included from CreatedAtFilter
Methods included from FinderMethods
Methods included from FinderWithCrossProjectAccess
#can_read_cross_project?, #can_read_project?, #find, #find_by, #find_by!, #skip_cross_project_check
Methods included from Gitlab::Utils::Override
#extended, extensions, #included, #method_added, #override, #prepended, #queue_verification, verify!
Constructor Details
#initialize(current_user, params = {}) ⇒ IssuableFinder
Returns a new instance of IssuableFinder.
113 114 115 116 117 |
# File 'app/finders/issuable_finder.rb', line 113 def initialize(current_user, params = {}) @current_user = current_user @original_params = params @params = params_class.new(params, current_user, klass) end |
Instance Attribute Details
#current_user ⇒ Object
Returns the value of attribute current_user.
55 56 57 |
# File 'app/finders/issuable_finder.rb', line 55 def current_user @current_user end |
#original_params ⇒ Object (readonly)
Returns the value of attribute original_params.
56 57 58 |
# File 'app/finders/issuable_finder.rb', line 56 def original_params @original_params end |
#params ⇒ Object
Returns the value of attribute params.
55 56 57 |
# File 'app/finders/issuable_finder.rb', line 55 def params @params end |
#parent=(value) ⇒ Object
Sets the attribute parent
57 58 59 |
# File 'app/finders/issuable_finder.rb', line 57 def parent=(value) @parent = value end |
Class Method Details
.array_params ⇒ Object
81 82 83 |
# File 'app/finders/issuable_finder.rb', line 81 def array_params @array_params ||= { label_name: [], assignee_username: [] } end |
.negatable_array_params ⇒ Object
This should not be used in controller strong params!
91 92 93 |
# File 'app/finders/issuable_finder.rb', line 91 def negatable_array_params @negatable_array_params ||= array_params.keys.append(:iids) end |
.negatable_params ⇒ Object
This should not be used in controller strong params!
96 97 98 |
# File 'app/finders/issuable_finder.rb', line 96 def negatable_params @negatable_params ||= negatable_scalar_params + negatable_array_params end |
.negatable_scalar_params ⇒ Object
This should not be used in controller strong params!
86 87 88 |
# File 'app/finders/issuable_finder.rb', line 86 def negatable_scalar_params @negatable_scalar_params ||= scalar_params - %i[search in] end |
.scalar_params ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'app/finders/issuable_finder.rb', line 62 def scalar_params @scalar_params ||= %i[ assignee_id closed_by_id assignee_username author_id author_username crm_contact_id crm_organization_id in label_name milestone_title release_tag my_reaction_emoji search subscribed ] end |
.valid_params ⇒ Object
100 101 102 |
# File 'app/finders/issuable_finder.rb', line 100 def valid_params @valid_params ||= scalar_params + [array_params.merge(or: {}, not: {})] end |
Instance Method Details
#count_by_state ⇒ Object
We often get counts for each state by running a query per state, and counting those results. This is typically slower than running one query (even if that query is slower than any of the individual state queries) and grouping and counting within that query.
rubocop: disable CodeReuse/ActiveRecord
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'app/finders/issuable_finder.rb', line 181 def count_by_state count_params = params.merge(state: nil, sort: nil, force_cte: true) finder = self.class.new(current_user, count_params) state_counts = finder .execute .reorder(nil) .group(:state_id) .count counts = Hash.new(0) state_counts.each do |key, value| counts[count_key(key)] += value end counts[:all] = counts.values.sum counts.with_indifferent_access end |
#execute ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'app/finders/issuable_finder.rb', line 119 def execute items = init_collection items = filter_items(items) # Let's see if we have to negate anything items = filter_negated_items(items) if should_filter_negated_args? # This has to be last as we use a CTE as an optimization fence # for counts by passing the force_cte param and passing the # attempt_group_search_optimizations param # https://www.postgresql.org/docs/current/static/queries-with.html items = by_search(items) sort(items) end |
#filter_items(items) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'app/finders/issuable_finder.rb', line 135 def filter_items(items) items = by_parent(items) items = by_scope(items) items = by_created_at(items) items = by_updated_at(items) items = by_closed_at(items) items = by_state(items) items = by_assignee(items) items = by_closed_by(items) items = (items) items = by_non_archived(items) items = by_iids(items) items = by_milestone(items) items = by_release(items) items = by_label(items) items = by_my_reaction_emoji(items) items = by_crm_contact(items) items = by_subscribed(items) by_crm_organization(items) end |
#filter_negated_items(items) ⇒ Object
Negates all params found in ‘negatable_params`
162 163 164 165 166 167 |
# File 'app/finders/issuable_finder.rb', line 162 def filter_negated_items(items) items = by_negated_milestone(items) items = by_negated_release(items) items = by_negated_my_reaction_emoji(items) by_negated_iids(items) end |
#klass ⇒ Object
109 110 111 |
# File 'app/finders/issuable_finder.rb', line 109 def klass raise NotImplementedError end |
#params_class ⇒ Object
105 106 107 |
# File 'app/finders/issuable_finder.rb', line 105 def params_class IssuableFinder::Params end |
#parent_param ⇒ Object
220 221 222 223 224 225 226 227 228 229 |
# File 'app/finders/issuable_finder.rb', line 220 def parent_param case parent when Project :project_id when Group :group_id else raise "Unexpected parent: #{parent.class}" end end |
#parent_param=(obj) ⇒ Object
215 216 217 218 |
# File 'app/finders/issuable_finder.rb', line 215 def parent_param=(obj) @parent = obj params[parent_param] = parent if parent end |
#row_count ⇒ Object
169 170 171 172 173 |
# File 'app/finders/issuable_finder.rb', line 169 def row_count Gitlab::IssuablesCountForState .new(self, nil, fast_fail: true) .for_state_or_opened(params[:state]) end |
#search ⇒ Object
rubocop: enable CodeReuse/ActiveRecord
202 203 204 |
# File 'app/finders/issuable_finder.rb', line 202 def search params[:search].presence end |
#should_filter_negated_args? ⇒ Boolean
156 157 158 159 |
# File 'app/finders/issuable_finder.rb', line 156 def should_filter_negated_args? # API endpoints send in `nil` values so we test if there are any non-nil not_params.present? && not_params.values.any? end |
#use_cte_for_search? ⇒ Boolean
206 207 208 209 210 211 212 213 |
# File 'app/finders/issuable_finder.rb', line 206 def use_cte_for_search? strong_memoize(:use_cte_for_search) do next false unless search next false unless default_or_simple_sort? attempt_group_search_optimizations? || attempt_project_search_optimizations? end end |