minidusen 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21b9abdca5644bbe2c9d7266988f8a0a22927435
4
+ data.tar.gz: 8fde451ba5ee361aa2c7ee3377ac195edd641d0e
5
+ SHA512:
6
+ metadata.gz: fbd3c16faed08b0ec651898c609f78da008688701513dbfa372f495327540d14d283f031d9723d75a8425069499aab945129ee794b0bd1aa85699bc9bcd36e6c
7
+ data.tar.gz: fc869ed7bd8b21f1babd9c433bf6c5c31383188a6d9672e3a43680591bde2989dbd61ce4678d9ff525a1ef2d266935fd3da245a288eb3b110ba0c00846d01812
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ pkg
2
+ tags
3
+ *.gem
4
+ .idea
5
+ tmp
6
+ spec/support/database.yml
7
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1,2 @@
1
+ 2.2.4
2
+
data/.travis.yml ADDED
@@ -0,0 +1,30 @@
1
+ language: ruby
2
+ rvm:
3
+ - "2.1.8"
4
+ - "2.3.1"
5
+ gemfile:
6
+ - gemfiles/Gemfile.3.2.mysql2
7
+ - gemfiles/Gemfile.4.2.mysql2
8
+ - gemfiles/Gemfile.4.2.pg
9
+ - gemfiles/Gemfile.5.0.mysql2
10
+ - gemfiles/Gemfile.5.0.pg
11
+ before_script:
12
+ - psql -c 'create database minidusen_test;' -U postgres
13
+ - mysql -e 'create database IF NOT EXISTS minidusen_test;'
14
+ script: bundle exec rspec spec
15
+ sudo: false
16
+ cache: bundler
17
+ notifications:
18
+ email:
19
+ - fail@makandra.de
20
+ branches:
21
+ only:
22
+ - master
23
+ matrix:
24
+ exclude:
25
+ - rvm: "2.3.1"
26
+ gemfile: gemfiles/Gemfile.3.2.mysql2
27
+ - rvm: "2.1.8"
28
+ gemfile: gemfiles/Gemfile.5.0.mysql2
29
+ - rvm: "2.1.8"
30
+ gemfile: gemfiles/Gemfile.5.0.pg
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Henning Koch
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,209 @@
1
+ Minidusen [![Build Status](https://secure.travis-ci.org/makandra/minidusen.png?branch=master)](https://travis-ci.org/makandra/minidusen)
2
+ =========
3
+
4
+ Low-tech search solution for ActiveRecord with MySQL or PostgreSQL
5
+ ------------------------------------------------------------------
6
+
7
+ Minidusen lets you filter ActiveRecord models with a single query string.
8
+ It works with your existing MySQL or PostgreSQL schema by mostly relying on simple `LIKE` queries. No additional indexes, tables or indexing databases are required.
9
+
10
+ Minidusen accepts a single, Google-like query string and converts it into `WHERE` conditions for [an ActiveRecord scope](http://guides.rubyonrails.org/active_record_querying.html#conditions).
11
+
12
+ The following type of queries are supported:
13
+
14
+ - `foo` (case-insensitive search for `foo` in developer-defined columns)
15
+ - `foo bar` (rows must include both `foo` and `bar`)
16
+ - `"foo bar"` (rows must include the phrase `"foo bar"`)
17
+ - `-bar` (rows must not include the word `bar`)
18
+ - `filetype:pdf` (developer-defined filter for file type)
19
+ - `some words 'a phrase' filetype:pdf -excluded -'excluded phrase' -filetype:pdf` (combination of the above)
20
+
21
+ Minidusen is a quick way to implement find-as-you-type filters for index views:
22
+
23
+ ![A list of records filtered by a query](https://raw.githubusercontent.com/makandra/minidusen/master/doc/filtered_index_view.cropped.png)
24
+
25
+ We have found it to scale well for many thousand records. It's probably not a good idea to use Minidusen for hundreds of thousands of records or very long text columns. For this we recommend to use PostgreSQL with [pg_search](https://github.com/Casecommons/pg_search) or full-text databases like [Solr](https://github.com/sunspot/sunspot).
26
+
27
+
28
+ Installation
29
+ ------------
30
+
31
+ In your `Gemfile` say:
32
+
33
+ ```ruby
34
+ gem 'minidusen'
35
+ ```
36
+
37
+ Now run `bundle install` and restart your server.
38
+
39
+
40
+ Basic Usage
41
+ -----------
42
+
43
+ Our example will be a simple address book:
44
+
45
+ ```ruby
46
+ class Contact < ActiveRecord::Base
47
+ validates_presence_of :name, :street, :city, :email
48
+ end
49
+ ```
50
+
51
+ We create a new class `ContactFilter` that will describe the searchable columns:
52
+
53
+ ```ruby
54
+ class ContactFilter
55
+ include Minidusen::Filter
56
+
57
+ filter :text do |scope, phrases|
58
+ columns = [:name, :email]
59
+ scope.where_like(columns => phrases)
60
+ end
61
+
62
+ end
63
+ ```
64
+
65
+ We can now use `ContactFilter` to filter a scope of `Contact` records:
66
+
67
+ ```ruby
68
+ # We start by building a scope of all contacts.
69
+ # No SQL query is made.
70
+ all_contacts = Contact.all
71
+ # => ActiveRecord::Relation
72
+
73
+ # Now we filter the scope to only contain contacts with "gmail" in either :name or :email column.
74
+ # Again, no SQL query is made.
75
+ gmail_contacts = ContactFilter.new.filter(all_contacts, 'gmail')
76
+ # => ActiveRecord::Relation
77
+
78
+ # Inspect the filtered scope.
79
+ gmail_contacts.to_sql
80
+ # => "SELECT * FROM contacts WHERE name LIKE '%gmail%' OR email LIKE '%gmail%'"
81
+
82
+ # Finally we load the scope to produce an array of Contact records.
83
+ gmail_contacts.to_a
84
+ # => Array
85
+ ```
86
+
87
+ ### Filtering scopes with existing conditions
88
+
89
+ Note that you can also pass a scope with existing conditions to `ContactFilter#filter`. The returned scope will contain both the existing conditions and the conditions from the filter:
90
+
91
+ ```ruby
92
+ published_contacts = Contact.where(published: true)
93
+ # => ActiveRecord::Relation
94
+
95
+ published_contacts.to_sql
96
+ # => "SELECT * FROM contacts WHERE (published = 1)"
97
+
98
+ gmail_contacts = ContactFilter.new.filter(published_contacts, 'gmail')
99
+ # => ActiveRecord::Relation
100
+
101
+ gmail_contacts.to_sql
102
+ # => "SELECT * FROM contacts WHERE (published = 1) AND (name LIKE '%gmail%' OR email LIKE '%gmail%')"
103
+ ```
104
+
105
+ ### How `where_like` works
106
+
107
+ The example above uses `where_like`. You can call `where_like` on any scope to produce a new scope where the given array of column names must contain all of the given phrases.
108
+
109
+ Let's say we call `ContactFilter.new.filter(Contact.published, 'foo "bar baz" bam')`. This will call the block `filter :text do |scope, phrases|` with the following arguments:
110
+
111
+ ```ruby
112
+ scope == Contact.published
113
+ phrases == ['foo', 'bar baz', 'bam']
114
+ ```
115
+
116
+ The scope `scope.where_like(columns => phrases)` will now represent the following SQL query:
117
+
118
+ ```ruby
119
+ SELECT * FROM contacts
120
+ WHERE (name LIKE "%foo%" OR email LIKE "%foo") AND (email LIKE "%foo%" OR email LIKE "%foo")
121
+ ```
122
+
123
+ You can also use `where_like` to find all the records *not* matching some phrases, using the `:negate` option:
124
+
125
+ ```ruby
126
+ Contact.where_like(name: 'foo', negate: true)
127
+ ```
128
+
129
+ Processing queries for qualified fields
130
+ ---------------------------------------
131
+
132
+ Google supports queries like `filetype:pdf` that filters records by some criteria without performing a full text search. Minidusen gives you a simple way to support such search syntax.
133
+
134
+ Let's support a query like `email:foo@bar.com` to explictly search for a contact's email address, without filtering against other columns.
135
+
136
+ We can learn this syntax by adding a `filter:email` instruction
137
+ to our `ContactFilter` class`:
138
+
139
+ ```ruby
140
+ class ContactFilter
141
+ include Minidusen::Filter
142
+
143
+ search_by :email do |scope, email|
144
+ scope.where(emai: email)
145
+ end
146
+
147
+ search_by :text do |scope, phrases|
148
+ columns = [:name, :email]
149
+ scope.where_like(columns => phrases)
150
+ end
151
+
152
+ end
153
+ ```
154
+
155
+ We can now explicitly search for a user's e-mail address:
156
+
157
+ ```ruby
158
+ ContactFilter.new.filter(Contact, 'email:foo@bar.com').to_sql
159
+ # => "SELECT * FROM contacts WHERE email='foo@bar.com'"
160
+ ```
161
+
162
+ ### Caveat
163
+
164
+ If you search for a phrase containing a colon (e.g. `deploy:rollback`), Minidusen will mistake the first part as a – nonexistent – qualifier and return an empty set.
165
+
166
+ To prevent that, search for a phrase:
167
+
168
+ "deploy:rollback"
169
+
170
+
171
+ Supported Rails versions
172
+ ------------------------
173
+
174
+ Minidusen is tested on:
175
+
176
+ - Rails 3.2
177
+ - Rails 4.2
178
+ - Rails 5.0
179
+ - MySQL 5.6
180
+ - PostgreSQL
181
+
182
+ If you need support for platforms not listed above, please submit a PR!
183
+
184
+
185
+ Development
186
+ -----------
187
+
188
+ - There are tests in `spec`. We only accept PRs with tests.
189
+ - We currently develop using Ruby 2.2.4 (see `.ruby-version`) since that version works for all versions of ActiveRecord that we support.
190
+ - TravisCI will test additional Ruby versions (2.1.8 and 2.3.1)
191
+ - Put your database credentials into `spec/support/database.yml`. There's a `database.sample.yml` you can use as a template.
192
+ - Create a database `minidusen_test` in both MySQL and PostgreSQL.
193
+ - There are gem bundles in `gemfiles` for each combination of ActiveRecord version and database type that we support.
194
+ - You can bundle all test applications by saying `bundle exec rake all:install`
195
+ - You can run specs from the project root by saying `bundle exec rake all:spec`.
196
+
197
+ If you would like to contribute:
198
+
199
+ - Fork the repository.
200
+ - Push your changes **with passing specs**.
201
+ - Send me a pull request.
202
+
203
+ Note that we're very eager to keep this gem lightweight. If you're unsure whether a change would make it into the gem, [open an issue](https://github.com/makandra/minidusen/issues/new).
204
+
205
+
206
+ Credits
207
+ -------
208
+
209
+ Henning Koch from [makandra](http://makandra.com/)
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake'
2
+ require 'bundler/gem_tasks'
3
+
4
+ desc 'Default: Run all specs.'
5
+ task :default => 'all:spec'
6
+
7
+ namespace :all do
8
+
9
+ desc "Run specs on all versions"
10
+ task :spec do
11
+ success = true
12
+ for_each_gemfile do
13
+ success &= system("bundle exec rspec spec")
14
+ end
15
+ fail "Tests failed" unless success
16
+ end
17
+
18
+ desc "Bundle all versions"
19
+ task :install do
20
+ for_each_gemfile do
21
+ system('bundle install')
22
+ end
23
+ end
24
+
25
+ desc "Update all versions"
26
+ task :update do
27
+ for_each_gemfile do
28
+ system('bundle update')
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ def for_each_gemfile
35
+ version = ENV['VERSION'] || '*'
36
+ Dir["gemfiles/Gemfile.#{version}"].sort.each do |gemfile|
37
+ next if gemfile =~ /.lock/
38
+ puts '', "\033[44m#{gemfile}\033[0m", ''
39
+ ENV['BUNDLE_GEMFILE'] = gemfile
40
+ yield
41
+ end
42
+ end
Binary file
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '=3.2.22'
4
+ gem 'rspec', '~> 3.4'
5
+ gem 'mysql2', '= 0.3.17'
6
+
7
+ gem 'byebug'
8
+
9
+ gem 'minidusen', :path => '..'
10
+ gem 'i18n', '=0.6.11' # 0.7 no longer builds for Ruby 1.8.7
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ minidusen (0.7.0)
5
+ activerecord (>= 3.2)
6
+ activesupport (>= 3.2)
7
+ edge_rider (>= 0.2.5)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (3.2.22)
13
+ activesupport (= 3.2.22)
14
+ builder (~> 3.0.0)
15
+ activerecord (3.2.22)
16
+ activemodel (= 3.2.22)
17
+ activesupport (= 3.2.22)
18
+ arel (~> 3.0.2)
19
+ tzinfo (~> 0.3.29)
20
+ activesupport (3.2.22)
21
+ i18n (~> 0.6, >= 0.6.4)
22
+ multi_json (~> 1.0)
23
+ arel (3.0.3)
24
+ builder (3.0.4)
25
+ byebug (8.2.0)
26
+ diff-lcs (1.2.5)
27
+ edge_rider (0.3.1)
28
+ activerecord
29
+ i18n (0.6.11)
30
+ multi_json (1.11.2)
31
+ mysql2 (0.3.17)
32
+ rspec (3.4.0)
33
+ rspec-core (~> 3.4.0)
34
+ rspec-expectations (~> 3.4.0)
35
+ rspec-mocks (~> 3.4.0)
36
+ rspec-core (3.4.1)
37
+ rspec-support (~> 3.4.0)
38
+ rspec-expectations (3.4.0)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-mocks (3.4.1)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.4.0)
44
+ rspec-support (3.4.1)
45
+ tzinfo (0.3.46)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ activerecord (= 3.2.22)
52
+ byebug
53
+ i18n (= 0.6.11)
54
+ minidusen!
55
+ mysql2 (= 0.3.17)
56
+ rspec (~> 3.4)
57
+
58
+ BUNDLED WITH
59
+ 1.12.5
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'activerecord', '~>4.2.1'
4
+ gem 'rspec', '~>3.4'
5
+ gem 'mysql2', '~> 0.3.17'
6
+
7
+ gem 'byebug'
8
+
9
+ gem 'minidusen', :path => '..'
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ minidusen (0.7.0)
5
+ activerecord (>= 3.2)
6
+ activesupport (>= 3.2)
7
+ edge_rider (>= 0.2.5)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (4.2.5)
13
+ activesupport (= 4.2.5)
14
+ builder (~> 3.1)
15
+ activerecord (4.2.5)
16
+ activemodel (= 4.2.5)
17
+ activesupport (= 4.2.5)
18
+ arel (~> 6.0)
19
+ activesupport (4.2.5)
20
+ i18n (~> 0.7)
21
+ json (~> 1.7, >= 1.7.7)
22
+ minitest (~> 5.1)
23
+ thread_safe (~> 0.3, >= 0.3.4)
24
+ tzinfo (~> 1.1)
25
+ arel (6.0.3)
26
+ builder (3.2.2)
27
+ byebug (8.2.0)
28
+ diff-lcs (1.2.5)
29
+ edge_rider (0.3.1)
30
+ activerecord
31
+ i18n (0.7.0)
32
+ json (1.8.3)
33
+ minitest (5.8.3)
34
+ mysql2 (0.3.20)
35
+ rspec (3.4.0)
36
+ rspec-core (~> 3.4.0)
37
+ rspec-expectations (~> 3.4.0)
38
+ rspec-mocks (~> 3.4.0)
39
+ rspec-core (3.4.1)
40
+ rspec-support (~> 3.4.0)
41
+ rspec-expectations (3.4.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.4.0)
44
+ rspec-mocks (3.4.1)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.4.0)
47
+ rspec-support (3.4.1)
48
+ thread_safe (0.3.5)
49
+ tzinfo (1.2.2)
50
+ thread_safe (~> 0.1)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ activerecord (~> 4.2.1)
57
+ byebug
58
+ minidusen!
59
+ mysql2 (~> 0.3.17)
60
+ rspec (~> 3.4)
61
+
62
+ BUNDLED WITH
63
+ 1.12.5