Skip to content

Commit

Permalink
Add excluding tag to API
Browse files Browse the repository at this point in the history
  • Loading branch information
nikolai-b committed Jan 8, 2016
1 parent 9497cca commit 8ec629c
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 10 deletions.
2 changes: 2 additions & 0 deletions app/api/issue_api.rb
Expand Up @@ -46,6 +46,7 @@ def bbox_from_string(string, factory)
params do
optional :bbox, type: String, desc: 'Four comma-separated coordinates making up the boundary of interest, e.g. "0.11905,52.20791,0.11907,52.20793"'
optional :tags, type: Array, desc: 'An array of tags all the issues must have, e.g. ["taga","tagb"]', coerce_with: JSON
optional :excluding_tags, type: Array, desc: 'An array of tags that the issues must not have, e.g. ["taga","tagb"]', coerce_with: JSON
optional :group, type: String, desc: 'Return only issues from area of group given by its short name, e.g. "london"'
optional :order, type: String, desc: 'Order of returned issues. Current working parameters are: "vote_count", "created_at", "start_at", "size"'
optional :end_date, type: Date, desc: 'No issues after the end date are returned'
Expand All @@ -69,6 +70,7 @@ def bbox_from_string(string, factory)
end
scope = scope.intersects_not_covered(bbox_from_string(params[:bbox], Issue.rgeo_factory).to_geometry) if params[:bbox].present?
scope = scope.where_tag_names_in(params[:tags]) if params[:tags]
scope = scope.where_tag_names_not_in(params[:excluding_tags]) if params[:excluding_tags]
scope = scope.before_date(params[:end_date]) if params[:end_date]
scope = scope.after_date(params[:start_date]) if params[:start_date]
scope = paginate scope
Expand Down
19 changes: 16 additions & 3 deletions lib/taggable.rb
Expand Up @@ -15,13 +15,26 @@ def find_by_tag(tag)
end

def where_tag_names_in(tag_names)
if tag_names.present? &&
ids = joins(:tags).where(tags: {name: tag_names}).group('issues.id').having('COUNT(tags.id)=?', tag_names.size)
where(id: ids)
if tag_names.present?
where(id: ids_with_all(tag_names))
else
none
end
end

def where_tag_names_not_in(tag_names)
if tag_names.present?
where.not(id: ids_with_all(tag_names))
else
all
end
end

private

def ids_with_all(tag_names)
joins(:tags).where(tags: {name: tag_names}).group('issues.id').having('COUNT(tags.id)=?', tag_names.size)
end
end

def tags_string
Expand Down
22 changes: 15 additions & 7 deletions spec/models/issue_spec.rb
Expand Up @@ -375,13 +375,21 @@
end
end

describe 'where_tag_names_in' do
it 'should return the issues which have all of the tags' do
tag1 = create :tag, name: 'tag1'
tag2 = create :tag, name: 'tag2'
tag3 = create :tag, name: 'tag3'
with_tags = create :issue, tags: [tag1, tag2]
with_other_tags = create :issue, tags: [tag1, tag3]
describe 'where_tag_names' do
let(:tag1) { create :tag, name: 'tag1' }
let(:tag2) { create :tag, name: 'tag2' }
let(:tag3) { create :tag, name: 'tag3' }
let!(:with_tags) { create :issue, tags: [tag1, tag2] }
let!(:with_other_tags) { create :issue, tags: [tag1, tag3] }

it 'not in should return the issues which do not have the tags' do
no_tag = create :issue
expect(described_class.all.where_tag_names_not_in([])).to match_array([no_tag, with_tags, with_other_tags])
expect(described_class.all.where_tag_names_not_in(['tag2'])).to match_array([no_tag, with_other_tags])
expect(described_class.all.where_tag_names_not_in(['tag1'])).to match_array([no_tag])
end

it 'in should return the issues which have all of the tags' do
create :issue

expect(described_class.where_tag_names_in(['tag1'])).to match_array([with_tags, with_other_tags])
Expand Down

0 comments on commit 8ec629c

Please sign in to comment.