Class: IssuableFinder
- Inherits:
-
Object
- Object
- IssuableFinder
- Includes:
- CreatedAtFilter, FinderMethods, FinderWithCrossProjectAccess, Gitlab::Utils::StrongMemoize
- 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'
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_REGEX =
/\A[\p{ASCII}|\p{Latin}]+\z/.freeze
- 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 Gitlab::Utils::StrongMemoize
#clear_memoization, #strong_memoize, #strong_memoized?
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.
108 109 110 111 112 |
# File 'app/finders/issuable_finder.rb', line 108 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.
52 53 54 |
# File 'app/finders/issuable_finder.rb', line 52 def current_user @current_user end |
#original_params ⇒ Object (readonly)
Returns the value of attribute original_params.
53 54 55 |
# File 'app/finders/issuable_finder.rb', line 53 def original_params @original_params end |
#params ⇒ Object
Returns the value of attribute params.
52 53 54 |
# File 'app/finders/issuable_finder.rb', line 52 def params @params end |
#parent=(value) ⇒ Object
Sets the attribute parent
54 55 56 |
# File 'app/finders/issuable_finder.rb', line 54 def parent=(value) @parent = value end |
Class Method Details
.array_params ⇒ Object
76 77 78 |
# File 'app/finders/issuable_finder.rb', line 76 def array_params @array_params ||= { label_name: [], assignee_username: [] } end |
.negatable_array_params ⇒ Object
This should not be used in controller strong params!
86 87 88 |
# File 'app/finders/issuable_finder.rb', line 86 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!
91 92 93 |
# File 'app/finders/issuable_finder.rb', line 91 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!
81 82 83 |
# File 'app/finders/issuable_finder.rb', line 81 def negatable_scalar_params @negatable_scalar_params ||= scalar_params - %i[search in] end |
.scalar_params ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'app/finders/issuable_finder.rb', line 59 def scalar_params @scalar_params ||= %i[ assignee_id assignee_username author_id author_username crm_contact_id crm_organization_id label_name milestone_title release_tag my_reaction_emoji search in ] end |
.valid_params ⇒ Object
95 96 97 |
# File 'app/finders/issuable_finder.rb', line 95 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
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'app/finders/issuable_finder.rb', line 176 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
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'app/finders/issuable_finder.rb', line 114 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
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'app/finders/issuable_finder.rb', line 130 def filter_items(items) # Selection by group is already covered by `by_project` and `projects` for project-based issuables # Group-based issuables have their own group filter methods items = by_project(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 = (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) by_crm_organization(items) end |
#filter_negated_items(items) ⇒ Object
Negates all params found in `negatable_params`
157 158 159 160 161 162 |
# File 'app/finders/issuable_finder.rb', line 157 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
104 105 106 |
# File 'app/finders/issuable_finder.rb', line 104 def klass raise NotImplementedError end |
#params_class ⇒ Object
100 101 102 |
# File 'app/finders/issuable_finder.rb', line 100 def params_class IssuableFinder::Params end |
#parent_param ⇒ Object
215 216 217 218 219 220 221 222 223 224 |
# File 'app/finders/issuable_finder.rb', line 215 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
210 211 212 213 |
# File 'app/finders/issuable_finder.rb', line 210 def parent_param=(obj) @parent = obj params[parent_param] = parent if parent end |
#row_count ⇒ Object
164 165 166 167 168 |
# File 'app/finders/issuable_finder.rb', line 164 def row_count Gitlab::IssuablesCountForState .new(self, nil, fast_fail: true) .for_state_or_opened(params[:state]) end |
#search ⇒ Object
rubocop: enable CodeReuse/ActiveRecord
197 198 199 |
# File 'app/finders/issuable_finder.rb', line 197 def search params[:search].presence end |
#should_filter_negated_args? ⇒ Boolean
151 152 153 154 |
# File 'app/finders/issuable_finder.rb', line 151 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
201 202 203 204 205 206 207 208 |
# File 'app/finders/issuable_finder.rb', line 201 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 |