Commit d32aec06 authored by Hiroyuki Sato's avatar Hiroyuki Sato

Add 'in' filter that modifies scope of 'search' filter to issues and merge requests API

parent 1161c99e
......@@ -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: [])
......
---
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 }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment