summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2019-02-05 09:52:40 +0000
committerSean McGivern <sean@gitlab.com>2019-02-05 09:52:40 +0000
commit068b41275f6f142acfddca273ace68d03a6c0730 (patch)
treec3f4c927ede7a09242f16771481a0cb7f627fc91
parenta34d6abd3b2ee98b0a68b4571c7de61321b4a3ce (diff)
parent40198f81843b315f2eb1c1a1a65292b6fc61f9d7 (diff)
downloadgitlab-ce-068b41275f6f142acfddca273ace68d03a6c0730.tar.gz
Merge branch 'search-title' into 'master'
Add 'in' filter that modifies scope of 'search' filter to issues and merge requests API See merge request gitlab-org/gitlab-ce!24350
-rw-r--r--app/finders/issuable_finder.rb4
-rw-r--r--app/finders/issues_finder.rb1
-rw-r--r--app/finders/merge_requests_finder.rb1
-rw-r--r--app/models/concerns/issuable.rb12
-rw-r--r--changelogs/unreleased/search-title.yml5
-rw-r--r--doc/api/issues.md2
-rw-r--r--doc/api/merge_requests.md2
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/merge_requests.rb3
-rw-r--r--spec/finders/issues_finder_spec.rb8
-rw-r--r--spec/models/concerns/issuable_spec.rb72
-rw-r--r--spec/requests/api/issues_spec.rb12
-rw-r--r--spec/requests/api/merge_requests_spec.rb12
13 files changed, 132 insertions, 5 deletions
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 1a69ec85d18..3e08c0ccd8f 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -18,6 +18,7 @@
# 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
@@ -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
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 45e494725d7..a0504ca0879 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -14,6 +14,7 @@
# milestone_title: string
# assignee_id: integer
# search: string
+# in: 'title', 'description', or a string joining them with comma
# label_name: string
# sort: string
# my_reaction_emoji: string
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index e190d5d90c9..b645011a3c5 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -15,6 +15,7 @@
# author_id: integer
# assignee_id: integer
# search: string
+# in: 'title', 'description', or a string joining them with comma
# label_name: string
# sort: string
# non_archived: boolean
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index b1cf03551f6..0a77fbeba08 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -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: [])
diff --git a/changelogs/unreleased/search-title.yml b/changelogs/unreleased/search-title.yml
new file mode 100644
index 00000000000..ff0933ed0b2
--- /dev/null
+++ b/changelogs/unreleased/search-title.yml
@@ -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
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 6d8683601f6..ed3165d95df 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -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 joining 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 |
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index b3548391228..802ff1d1df9 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -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 joining 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
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index afa3ac80121..b3636c98550 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -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 joining 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'
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 132b19164d0..4179aaa93a0 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -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 joining them with comma'
optional :wip, type: String, values: %w[yes no], desc: 'Search merge requests for WIP in the title'
use :pagination
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 682fae06434..34cb09942be 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -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 } }
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 5753c646106..41159348e04 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -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 matching 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 matching 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 matching 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 matching 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 matching 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 matching 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
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index e0f1e303e96..04908378a24 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -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 }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 4d42bc39ac3..51343287a13 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -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 }