minidusen 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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