query_string_search 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +61 -75
- data/lib/query_string_search/matchers/match_attribute.rb +4 -1
- data/lib/query_string_search/matchers/match_no_attribute.rb +4 -1
- data/lib/query_string_search/version.rb +1 -1
- data/spec/features/find_records_by_searching_a_attribute_that_returns_a_collection_spec.rb +16 -0
- data/spec/fixtures/movie.rb +1 -1
- data/spec/lib/query_string_search/matchers/match_attribute_spec.rb +11 -1
- data/spec/lib/query_string_search/matchers/match_no_attribute_spec.rb +10 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ac9f7da9d9c53692c3ccb4e3c7fab60ba524d1f
|
4
|
+
data.tar.gz: 865d14548d4ed0aa2129b759f127b8b808d7121d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 502464cf14160e106a69ccaa6b671db44650980c6db6e91acba6b5fe39f7e11aa28d70e1b04b0d657829ddf8c90df858aef79703e9f5c0148ea5478034f73407
|
7
|
+
data.tar.gz: fe7f411d65369fb73ec21f2cd15883149a47ae357fdb74d74eaf182f26c9988402f8ba5b453f7cbbe3032fe504842431a8aa12dfd3dbb217367ac41d6134264a
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,84 +1,59 @@
|
|
1
|
-
# Query String Search
|
1
|
+
# Query String Search
|
2
|
+
[![Build Status](https://api.travis-ci.org/umn-asr/query_string_search.svg?branch=master)](https://travis-ci.org/umn-asr/query_string_search)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/umn-asr/query_string_search/badges/gpa.svg)](https://codeclimate.com/github/umn-asr/query_string_search)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/query_string_search.svg)](http://badge.fury.io/rb/query_string_search)
|
2
5
|
|
3
|
-
Provides an easy way to implement searching in your API endpoints
|
6
|
+
Provides an easy way to implement searching in your API endpoints.
|
4
7
|
|
5
8
|
## Searches it supports
|
6
9
|
|
7
|
-
Say you have a `movies` endpoint and people want to be able to search your huge collection of movie data.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
`movies?q=rating=none`
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
`movies?q=
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
### Return all data that matches one of many attributes
|
32
|
-
|
33
|
-
`movies?q=year=1994|1995`
|
34
|
-
|
35
|
-
Returns all movies with a year of 1994 or 1995
|
36
|
-
|
37
|
-
### Return all data with values greater than or less than an attribute
|
38
|
-
|
39
|
-
`movies?q=star_rating>1`
|
40
|
-
Returns all movies with a star rating greater than one
|
41
|
-
|
42
|
-
`movies?q=star_rating<3`
|
43
|
-
Returns all movies with a star rating less than three
|
44
|
-
|
45
|
-
`movies?q=star_rating>=2`
|
46
|
-
Returns all movies with a star rating greater than or equal to 2
|
47
|
-
|
48
|
-
`movies?q=star_rating<=4`
|
49
|
-
Returns all movies with a star rating less than or equal to 4
|
50
|
-
|
51
|
-
### Search an attribute that returns a collection
|
52
|
-
|
53
|
-
If your `movie` has a `home_formats` method that retuns an array like `["DVD", "BD"]` you can filter that too.
|
54
|
-
|
55
|
-
`movies?q=home_formats=DVD`
|
56
|
-
Returns all movies whose `home_formats` includes "DVD"
|
57
|
-
|
58
|
-
or
|
59
|
-
|
60
|
-
`movies?q=home_formats=BD|DVD`
|
61
|
-
Returns all movies whose `home_formats` includes "DVD" or "BD"
|
10
|
+
Say you have a `movies` endpoint and people want to be able to search your huge collection of movie data. Each of your movies have these properties
|
11
|
+
|
12
|
+
- Rating: returns "PG", "R", etc. Can also return nil
|
13
|
+
- Year: returns the year the film was released
|
14
|
+
- Title: The movie's title
|
15
|
+
- Star Rating: returns a number 1 to 5
|
16
|
+
- Home Formats: returns an array of available home formats. `["DVD", "BD"]`, for example.
|
17
|
+
|
18
|
+
The API Search gem will give you the following search functionality:
|
19
|
+
|
20
|
+
Query String Example | What Data is Returned
|
21
|
+
------------- | -------------
|
22
|
+
`movies` | All data in your data set
|
23
|
+
`movies?q=rating=all` | Movies with a non-nil rating
|
24
|
+
`movies?q=rating=none` | Movies with a nil rating
|
25
|
+
`movies?q=year=1994` | Movies with a year of 1994
|
26
|
+
`movies?q=year=1994|1995` | Movies with a year of 1994 or 1995
|
27
|
+
`movies?q=title=Dunston%20Checks%20In` | Movies with the title Dunston Checks In
|
28
|
+
`movies?q=star_rating>1` | Movies with a star rating greater than one
|
29
|
+
`movies?q=star_rating<3` | Movies with a star rating less than three
|
30
|
+
`movies?q=star_rating>=2` | Movies with a star rating greater than or equal to 2
|
31
|
+
`movies?q=star_rating<=4` | Movies with a star rating less than or equal to 4
|
32
|
+
`movies?q=home_formats=DVD` | Movies that are available on DVD.
|
33
|
+
`movies?q=home_formats=DVD|BD` | Movies that are available on DVD or Blu Ray
|
62
34
|
|
63
35
|
### Combining Searches
|
64
36
|
|
65
|
-
|
37
|
+
Any of the above critera can be combined.
|
38
|
+
Just separate criteria with commas.
|
39
|
+
Records that match **all** the criteria will be returned.
|
40
|
+
Some examples!
|
66
41
|
|
67
|
-
`movie?q=year=1994,country=US,rated=none
|
42
|
+
`movie?q=year=1994,country=US,rated=none`<br />
|
43
|
+
All un-rated movies made in the US in 1994.
|
68
44
|
|
69
|
-
|
45
|
+
`movie?q=home_formats=BD|DVD,rated=R|PG,star_rating>3`<br />
|
46
|
+
All movies available on BD or DVD, that are rated R or PG, and that have a star rating greater than 3
|
70
47
|
|
71
|
-
##
|
48
|
+
## Use Cases
|
72
49
|
|
73
|
-
|
50
|
+
This gem fits best when you're trying to provide very flexible searching on a relatively small and flat set of data. Because it filters a data set that you provide, the speed at which it works is wholly dependent on the size of your data set.
|
74
51
|
|
75
|
-
|
76
|
-
gem 'query_string_search'
|
77
|
-
```
|
52
|
+
We currently use this gem on a small (~2000 rows) data set which is cached in memory. Response times using Rails/Passenger/Apache are always under 100ms, usually under 50ms. That's plenty fast! But if your initial data set is massive, or you can't cache it, your response times will be slower. Such is life. Gems like [Periscope](https://rubygems.org/gems/periscope) or [has_scope](https://rubygems.org/gems/has_scope) may be more your speed.
|
78
53
|
|
79
|
-
|
54
|
+
A downside of gems like those, though, is that you end up defining all of your filtering methods in advance. This is not the case with Query String Search. If the elements in your data set respond to a method, then the data can be filtered by the return value of that method. It is possible that this is not what you want. In which case, check out those other gems. Or, you could also wrap your object instances in a wrapper that only responds to the methods that you want to filter on.
|
80
55
|
|
81
|
-
|
56
|
+
Also, this gem is platform and persistence agnostic. Rails? Sinatra? Cuba? Redis? Postgres? Doesn't matter. You pass it objects, it filters them down based on the query string.
|
82
57
|
|
83
58
|
## Usage
|
84
59
|
|
@@ -90,20 +65,20 @@ Movie.all
|
|
90
65
|
|
91
66
|
Or something similar. As long as it returns a collection of objects, you should be good.
|
92
67
|
|
93
|
-
The objects must respond to the
|
68
|
+
The objects must respond to the methods you want to search on. Say you want to allow a search string like this:
|
94
69
|
|
95
|
-
```
|
96
70
|
`movies?q=year=1994`
|
97
|
-
```
|
98
71
|
|
99
72
|
Then every object in your data collection needs to respond to `year`.
|
100
73
|
|
101
|
-
Again, with ActiveRecord this is pretty straightforward. But if you're building your data source from raw SQL then you're going to have to convert that data into objects that respond to the attributes you want to search on.
|
102
|
-
|
103
74
|
Second, search! In Rails you can do something like this in a Controller method.
|
104
75
|
|
105
76
|
```ruby
|
106
|
-
|
77
|
+
def index
|
78
|
+
query_string = params[:q]
|
79
|
+
QueryStringSearch.new(Movie.all, query_string).results
|
80
|
+
#....
|
81
|
+
end
|
107
82
|
```
|
108
83
|
|
109
84
|
This returns a collection of the objects that matched the search criteria.
|
@@ -111,12 +86,23 @@ This returns a collection of the objects that matched the search criteria.
|
|
111
86
|
Or you can do it not in the controller. This will work:
|
112
87
|
|
113
88
|
```ruby
|
114
|
-
|
115
|
-
QueryStringSearch.new(Movie.all, test_query).results
|
89
|
+
QueryStringSearch.new(Movie.all, "country=us").results
|
116
90
|
```
|
117
91
|
|
118
92
|
You get the idea. Pass in a data set and a query-stringish string and you'll get results back.
|
119
93
|
|
94
|
+
## Installation
|
95
|
+
|
96
|
+
Add this line to your application's Gemfile:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
gem 'query_string_search'
|
100
|
+
```
|
101
|
+
|
102
|
+
And then execute:
|
103
|
+
|
104
|
+
$ bundle
|
105
|
+
|
120
106
|
|
121
107
|
## Contributing
|
122
108
|
|
@@ -1,6 +1,9 @@
|
|
1
1
|
class MatchNoAttribute < QueryStringSearch::AbstractMatcher
|
2
2
|
def match?(data)
|
3
|
-
match_with_contingency
|
3
|
+
match_with_contingency do
|
4
|
+
actual_value(data) == false ||
|
5
|
+
Array(actual_value(data)).empty?
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
6
9
|
def self.reserved_words
|
@@ -6,6 +6,8 @@ RSpec.describe "Finding data based on an attribute that returns a collection" do
|
|
6
6
|
|
7
7
|
let(:movies_on_dvd) { data_set.select { |d| d.home_formats.include?("DVD") } }
|
8
8
|
let(:movies_on_dvd_or_bd) { data_set.select { |d| d.home_formats.include?("DVD") || d.home_formats.include?("BD") } }
|
9
|
+
let(:movies_with_home_format) { data_set.select { |d| d.home_formats.any? } }
|
10
|
+
let(:movies_without_home_format) { data_set.select { |d| d.home_formats.none? } }
|
9
11
|
|
10
12
|
it "Returns the correct records when searching for one value" do
|
11
13
|
query_string = "home_formats=DVD"
|
@@ -20,4 +22,18 @@ RSpec.describe "Finding data based on an attribute that returns a collection" do
|
|
20
22
|
|
21
23
|
expect(results).to eq(movies_on_dvd_or_bd)
|
22
24
|
end
|
25
|
+
|
26
|
+
it "Returns the correct records when searching for all" do
|
27
|
+
query_string = "home_formats=#{ %w(all true).sample }"
|
28
|
+
results = QueryStringSearch.new(data_set, query_string).results
|
29
|
+
|
30
|
+
expect(results).to eq(movies_with_home_format)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "Returns the correct records when searching for none" do
|
34
|
+
query_string = "home_formats=#{ %w(none false).sample }"
|
35
|
+
results = QueryStringSearch.new(data_set, query_string).results
|
36
|
+
|
37
|
+
expect(results).to eq(movies_without_home_format)
|
38
|
+
end
|
23
39
|
end
|
data/spec/fixtures/movie.rb
CHANGED
@@ -16,7 +16,7 @@ class Movie
|
|
16
16
|
self.country = random_country
|
17
17
|
self.seen = [true, false].sample
|
18
18
|
self.star_rating = [1, 2, 3, 4, 5].sample
|
19
|
-
self.home_formats = %w(BD DVD Hulu Amazon Netflix).sample(2)
|
19
|
+
self.home_formats = %w(BD DVD Hulu Amazon Netflix).sample(rand(2))
|
20
20
|
end
|
21
21
|
|
22
22
|
def seen?
|
@@ -23,6 +23,16 @@ RSpec.describe MatchAttribute do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
describe "if the target's attribute returns a collection" do
|
27
|
+
let(:target) { SearchTarget.new(property: %w(a b c)) }
|
28
|
+
|
29
|
+
it "is true" do
|
30
|
+
matcher = MatchAttribute.new
|
31
|
+
matcher.attribute = :property
|
32
|
+
expect(matcher.match?(target)).to be_truthy
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
26
36
|
describe "if the target's attribute is nil" do
|
27
37
|
let(:target) { SearchTarget.new(property: nil) }
|
28
38
|
|
@@ -36,7 +46,7 @@ RSpec.describe MatchAttribute do
|
|
36
46
|
describe "if the target's attribute is false" do
|
37
47
|
let(:target) { SearchTarget.new(property: false) }
|
38
48
|
|
39
|
-
it "is
|
49
|
+
it "is false" do
|
40
50
|
matcher = MatchAttribute.new
|
41
51
|
matcher.attribute = :property
|
42
52
|
expect(matcher.match?(target)).to be_falsey
|
@@ -23,6 +23,16 @@ RSpec.describe MatchNoAttribute do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
describe "if the target's attribute returns a collection" do
|
27
|
+
let(:target) { SearchTarget.new(property: %w(a b c)) }
|
28
|
+
|
29
|
+
it "is false" do
|
30
|
+
matcher = MatchNoAttribute.new
|
31
|
+
matcher.attribute = :property
|
32
|
+
expect(matcher.match?(target)).to be_falsey
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
26
36
|
describe "if the target's attribute is false" do
|
27
37
|
let(:target) { SearchTarget.new(property: false) }
|
28
38
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: query_string_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Whitney
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-04-06 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|