Add 'in' filter that modifies scope of 'search' filter to issues and merge requests API
This commit is contained in:
parent
1161c99e5c
commit
d32aec06fe
13 changed files with 132 additions and 5 deletions
|
@ -18,6 +18,7 @@
|
|||
# assignee_id: integer or 'None' or 'Any'
|
||||
# assignee_username: string
|
||||
# search: string
|
||||
# in: 'title', 'description' or a string joined them with comma
|
||||
# label_name: string
|
||||
# sort: string
|
||||
# non_archived: boolean
|
||||
|
@ -56,6 +57,7 @@ class IssuableFinder
|
|||
milestone_title
|
||||
my_reaction_emoji
|
||||
search
|
||||
in
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -408,7 +410,7 @@ class IssuableFinder
|
|||
items = klass.with(cte.to_arel).from(klass.table_name)
|
||||
end
|
||||
|
||||
items.full_search(search)
|
||||
items.full_search(search, matched_columns: params[:in])
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# milestone_title: string
|
||||
# assignee_id: integer
|
||||
# search: string
|
||||
# in: 'title', 'description' or a string joined them with comma
|
||||
# label_name: string
|
||||
# sort: string
|
||||
# my_reaction_emoji: string
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# author_id: integer
|
||||
# assignee_id: integer
|
||||
# search: string
|
||||
# in: 'title', 'description' or a string joined them with comma
|
||||
# label_name: string
|
||||
# sort: string
|
||||
# non_archived: boolean
|
||||
|
|
|
@ -136,10 +136,18 @@ module Issuable
|
|||
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.
|
||||
#
|
||||
# query - The search query as a String
|
||||
# matched_columns - Modify the scope of the query. 'title', 'description' or joining them with a comma.
|
||||
#
|
||||
# Returns an ActiveRecord::Relation.
|
||||
def full_search(query)
|
||||
fuzzy_search(query, [:title, :description])
|
||||
def full_search(query, matched_columns: 'title,description')
|
||||
allowed_columns = [:title, :description]
|
||||
matched_columns = matched_columns.to_s.split(',').map(&:to_sym)
|
||||
matched_columns &= allowed_columns
|
||||
|
||||
# Matching title or description if the matched_columns did not contain any allowed columns.
|
||||
matched_columns = [:title, :description] if matched_columns.empty?
|
||||
|
||||
fuzzy_search(query, matched_columns)
|
||||
end
|
||||
|
||||
def sort_by_attribute(method, excluded_labels: [])
|
||||
|
|
5
changelogs/unreleased/search-title.yml
Normal file
5
changelogs/unreleased/search-title.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add 'in' filter that modifies scope of 'search' filter to issues and merge requests API
|
||||
merge_request: 24350
|
||||
author: Hiroyuki Sato
|
||||
type: added
|
|
@ -31,6 +31,7 @@ GET /issues?iids[]=42&iids[]=43
|
|||
GET /issues?author_id=5
|
||||
GET /issues?assignee_id=5
|
||||
GET /issues?my_reaction_emoji=star
|
||||
GET /issues?search=foo&in=title
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|
@ -46,6 +47,7 @@ GET /issues?my_reaction_emoji=star
|
|||
| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` |
|
||||
| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` |
|
||||
| `search` | string | no | Search issues against their `title` and `description` |
|
||||
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joined them with comma. Default is `title,description` |
|
||||
| `created_after` | datetime | no | Return issues created on or after the given time |
|
||||
| `created_before` | datetime | no | Return issues created on or before the given time |
|
||||
| `updated_after` | datetime | no | Return issues updated on or after the given time |
|
||||
|
|
|
@ -24,6 +24,7 @@ GET /merge_requests?labels=bug,reproduced
|
|||
GET /merge_requests?author_id=5
|
||||
GET /merge_requests?my_reaction_emoji=star
|
||||
GET /merge_requests?scope=assigned_to_me
|
||||
GET /merge_requests?search=foo&in=title
|
||||
```
|
||||
|
||||
Parameters:
|
||||
|
@ -47,6 +48,7 @@ Parameters:
|
|||
| `source_branch` | string | no | Return merge requests with the given source branch |
|
||||
| `target_branch` | string | no | Return merge requests with the given target branch |
|
||||
| `search` | string | no | Search merge requests against their `title` and `description` |
|
||||
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joined them with comma. Default is `title,description` |
|
||||
| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests |
|
||||
|
||||
```json
|
||||
|
|
|
@ -43,7 +43,8 @@ module API
|
|||
desc: 'Return issues sorted in `asc` or `desc` order.'
|
||||
optional :milestone, type: String, desc: 'Return issues for a specific milestone'
|
||||
optional :iids, type: Array[Integer], desc: 'The IID array of issues'
|
||||
optional :search, type: String, desc: 'Search issues for text present in the title or description'
|
||||
optional :search, type: String, desc: 'Search issues for text present in the title, description or any combination of these'
|
||||
optional :in, type: String, desc: '`title`, `description` or a string joined them with comma'
|
||||
optional :created_after, type: DateTime, desc: 'Return issues created after the specified time'
|
||||
optional :created_before, type: DateTime, desc: 'Return issues created before the specified time'
|
||||
optional :updated_after, type: DateTime, desc: 'Return issues updated after the specified time'
|
||||
|
|
|
@ -109,7 +109,8 @@ module API
|
|||
optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji'
|
||||
optional :source_branch, type: String, desc: 'Return merge requests with the given source branch'
|
||||
optional :target_branch, type: String, desc: 'Return merge requests with the given target branch'
|
||||
optional :search, type: String, desc: 'Search merge requests for text present in the title or description'
|
||||
optional :search, type: String, desc: 'Search merge requests for text present in the title, description or any combination of these'
|
||||
optional :in, type: String, desc: '`title`, `description` or a string joined them with comma'
|
||||
optional :wip, type: String, values: %w[yes no], desc: 'Search merge requests for WIP in the title'
|
||||
use :pagination
|
||||
end
|
||||
|
|
|
@ -314,6 +314,14 @@ describe IssuesFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'filtering by issue term in title' do
|
||||
let(:params) { { search: 'git', in: 'title' } }
|
||||
|
||||
it 'returns issues with title match for search term' do
|
||||
expect(issues).to contain_exactly(issue1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering by issues iids' do
|
||||
let(:params) { { iids: issue3.iid } }
|
||||
|
||||
|
|
|
@ -139,6 +139,78 @@ describe Issuable do
|
|||
it 'returns issues with a matching description for a query shorter than 3 chars' do
|
||||
expect(issuable_class.full_search(searchable_issue2.description.downcase)).to eq([searchable_issue2])
|
||||
end
|
||||
|
||||
context 'when mathing columns is "title"' do
|
||||
it 'returns issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
|
||||
it 'returns no issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title'))
|
||||
.to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mathing columns is "description"' do
|
||||
it 'returns no issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'description'))
|
||||
.to be_empty
|
||||
end
|
||||
|
||||
it 'returns issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'description'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mathing columns is "title,description"' do
|
||||
it 'returns issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title,description'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
|
||||
it 'returns issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title,description'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mathing columns is nil"' do
|
||||
it 'returns issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: nil))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
|
||||
it 'returns issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: nil))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mathing columns is "invalid"' do
|
||||
it 'returns issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'invalid'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
|
||||
it 'returns issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'invalid'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when mathing columns is "title,invalid"' do
|
||||
it 'returns issues with a matching title' do
|
||||
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title,invalid'))
|
||||
.to eq([searchable_issue])
|
||||
end
|
||||
|
||||
it 'returns no issues with a matching description' do
|
||||
expect(issuable_class.full_search(searchable_issue.description, matched_columns: 'title,invalid'))
|
||||
.to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.to_ability_name' do
|
||||
|
|
|
@ -208,6 +208,18 @@ describe API::Issues do
|
|||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns issues matching given search string for title and scoped in title' do
|
||||
get api("/issues", user), params: { search: issue.title, in: 'title' }
|
||||
|
||||
expect_paginated_array_response(issue.id)
|
||||
end
|
||||
|
||||
it 'returns an empty array if no issue matches given search string for title and scoped in description' do
|
||||
get api("/issues", user), params: { search: issue.title, in: 'description' }
|
||||
|
||||
expect_paginated_array_response([])
|
||||
end
|
||||
|
||||
it 'returns issues matching given search string for description' do
|
||||
get api("/issues", user), params: { search: issue.description }
|
||||
|
||||
|
|
|
@ -260,6 +260,18 @@ describe API::MergeRequests do
|
|||
expect_response_ordered_exactly(merge_request)
|
||||
end
|
||||
|
||||
it 'returns merge requests matching given search string for title and scoped in title' do
|
||||
get api("/merge_requests", user), params: { search: merge_request.title, in: 'title' }
|
||||
|
||||
expect_response_ordered_exactly(merge_request)
|
||||
end
|
||||
|
||||
it 'returns an empty array if no merge reques matches given search string for description and scoped in title' do
|
||||
get api("/merge_requests", user), params: { search: merge_request.description, in: 'title' }
|
||||
|
||||
expect_response_contain_exactly
|
||||
end
|
||||
|
||||
it 'returns merge requests for project matching given search string for description' do
|
||||
get api("/merge_requests", user), params: { project_id: project.id, search: merge_request.description }
|
||||
|
||||
|
|
Loading…
Reference in a new issue