filter_me 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +66 -4
- data/filter_me.gemspec +0 -1
- data/lib/filter_me/filter/arel_field_filter.rb +1 -1
- data/lib/filter_me/filter/dsl.rb +2 -4
- data/lib/filter_me/version.rb +1 -1
- data/spec/acceptance/filters/users_filter_spec.rb +16 -0
- data/spec/internal/app/filters/companies_filter.rb +5 -0
- data/spec/internal/app/filters/jobs_filter.rb +5 -0
- data/spec/internal/app/filters/users_filter.rb +1 -0
- data/spec/internal/app/models/company.rb +4 -0
- data/spec/internal/app/models/job.rb +3 -0
- data/spec/internal/app/models/user.rb +2 -0
- data/spec/internal/db/fixtures/jobs.rb +6 -0
- data/spec/internal/db/fixtures/users.rb +10 -2
- data/spec/internal/db/schema.rb +12 -0
- data/spec/unit/arel_field_filter_spec.rb +21 -4
- data/spec/unit/filter_arel_dsl_spec.rb +9 -11
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d20eaf1933fba4c0a52e4c6b04ab9e9bce510c2
|
4
|
+
data.tar.gz: eafa06100f1fd7cf77332a340f1213f7e344beae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5356b764fbe3b6a961fc1dae9a8e7b6a08dce53c4871772a13119fb0623e676acd4fa1074d7b308270d215e6dce9700cbb76ac6590c929643e8770a5891bf86
|
7
|
+
data.tar.gz: b07bbc44c7a7bd6bcec60cbfa453615e28eba848e8c30cc5d2069ac0edfb98f516ef80d26302bf0db7aa39f6188d34f062d7e6b7b87b43a49abb3b1f62e26f4f
|
data/README.md
CHANGED
@@ -1,11 +1,73 @@
|
|
1
|
-
|
2
|
-
filter_me
|
1
|
+
FilterMe
|
3
2
|
=========
|
4
3
|
|
5
|
-
|
4
|
+
[![Build Status](https://travis-ci.org/Samsinite/filter_me.png?branch=master)](https://travis-ci.org/Samsinite/filter_me) [![Code Climate](https://codeclimate.com/github/Samsinite/filter_me.png)](https://codeclimate.com/github/Samsinite/filter_me) [![Gem Version](https://badge.fury.io/rb/filter_me.png)](http://badge.fury.io/rb/filter_me)
|
6
5
|
|
7
|
-
###
|
6
|
+
### A Rails/ActiveRecord filtering gem
|
8
7
|
|
8
|
+
FilterMe provids helpers and classes that provides filtering using Ruby classes and object oriented development
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
``` ruby
|
12
|
+
gem "filter_me", "0.1.0"
|
13
|
+
```
|
14
|
+
|
15
|
+
## Filter:
|
16
|
+
\* Highly subject to change as the API moves closer to 1.0
|
17
|
+
``` ruby
|
18
|
+
class AccountsFilter < FilterMe::ActiveRecordFilter
|
19
|
+
model Account
|
20
|
+
|
21
|
+
field :type, [:matches, :eq, :not_eq] # Uses arel, so any Arel::Predications method should work
|
22
|
+
field :cost, [:lt, :gt, :lteq, :gteq, :eq] # Uses arel, so any Arel::Predications method should work
|
23
|
+
end
|
24
|
+
|
25
|
+
class AccountsController < ApplicationController
|
26
|
+
include FilterMe
|
27
|
+
|
28
|
+
def index
|
29
|
+
@accounts = filter_me(Account.all)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
Given a controller that recieves params like the following:
|
35
|
+
``` ruby
|
36
|
+
params # => {filters: {type: {eq: "admin"} } }
|
37
|
+
```
|
38
|
+
|
39
|
+
The following SQL would be performed (Using ActiveRecord):
|
40
|
+
``` SQL
|
41
|
+
SELECT "accounts".* FROM "accounts" WHERE ("accounts"."type" = "admin")
|
42
|
+
```
|
43
|
+
|
44
|
+
## Nested Filtering:
|
45
|
+
``` ruby
|
46
|
+
class UsersFilter < FilterMe::ActiveRecordFilter
|
47
|
+
model User
|
48
|
+
|
49
|
+
association :account, :filter_class => AccountsFilter
|
50
|
+
field :username, [:matches, :eq, :not_eq] # Uses arel, so any Arel::Predications method should work
|
51
|
+
end
|
52
|
+
|
53
|
+
class UsersController < ApplicationController
|
54
|
+
include FilterMe
|
55
|
+
|
56
|
+
def index
|
57
|
+
@users = filter_me(User.all)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
With the following params:
|
63
|
+
``` ruby
|
64
|
+
params # => {:filters => {:email => {:matches => "%test.com"}, :account => {:cost => {:lt => 100000} } } }
|
65
|
+
```
|
66
|
+
Performs:
|
67
|
+
``` SQL
|
68
|
+
SELECT "users".* FROM "users" INNER JOIN "accounts" ON "accounts"."user_id" = "users"."id"
|
69
|
+
WHERE ("users"."email" LIKE '%test.com') AND ("accounts"."cost" < 100000)
|
70
|
+
```
|
9
71
|
|
10
72
|
## License
|
11
73
|
Copyright (c) 2014, Filter Me is developed and maintained by Sam Clopton, and is released under the open MIT Licence.
|
data/filter_me.gemspec
CHANGED
@@ -20,7 +20,6 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_runtime_dependency 'activerecord', '>= 3.2.0'
|
22
22
|
s.add_runtime_dependency 'activesupport', '>= 3.2.0'
|
23
|
-
#s.add_runtime_dependency 'activemodel', '>= 3.2.0'
|
24
23
|
s.add_development_dependency 'combustion', '~> 0.5.1'
|
25
24
|
s.add_development_dependency 'rspec-rails', '~> 2.13'
|
26
25
|
s.add_development_dependency 'sqlite3', '~> 1.3.7'
|
data/lib/filter_me/filter/dsl.rb
CHANGED
@@ -51,14 +51,12 @@ module FilterMe
|
|
51
51
|
private
|
52
52
|
|
53
53
|
def filter(name, klass, configuration, association = nil)
|
54
|
-
this = self
|
55
54
|
filter_class.send(:define_method, name) do |relation, filters|
|
56
55
|
filter = klass.new(filters, configuration)
|
57
56
|
if association
|
58
|
-
relation
|
59
|
-
filter.filter(relation)
|
57
|
+
relation.joins(name.to_sym).merge(filter.filter(relation))
|
60
58
|
else
|
61
|
-
relation.
|
59
|
+
relation.merge(filter.filter(relation))
|
62
60
|
end
|
63
61
|
end
|
64
62
|
end
|
data/lib/filter_me/version.rb
CHANGED
@@ -48,4 +48,20 @@ describe UsersFilter do
|
|
48
48
|
expect(user.account.cost).to be < 100000
|
49
49
|
end
|
50
50
|
end
|
51
|
+
|
52
|
+
it "can do a deeply nested filter" do
|
53
|
+
mock_controller.params = {:filters => {
|
54
|
+
:businesses => {
|
55
|
+
:jobs => {:name => {:matches => "find%"}}
|
56
|
+
}
|
57
|
+
}}
|
58
|
+
|
59
|
+
mock_controller.index.each do |user|
|
60
|
+
user.businesses.each do |business|
|
61
|
+
business.jobs.each do |job|
|
62
|
+
expect(job.name).to start_with "find"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
51
67
|
end
|
@@ -8,19 +8,27 @@ module Fixtures
|
|
8
8
|
user.create_account!(:cost => 100000)
|
9
9
|
end
|
10
10
|
|
11
|
-
User.create! do |user|
|
11
|
+
user = User.create! do |user|
|
12
12
|
user.username = "test2"
|
13
13
|
user.email = "test2@test.com"
|
14
14
|
|
15
15
|
user.create_account!(:cost => 50000)
|
16
16
|
end
|
17
|
+
business = user.businesses.create! do |business|
|
18
|
+
business.name = "Test"
|
19
|
+
end
|
20
|
+
business.jobs.create!(:name => "find_me")
|
17
21
|
|
18
|
-
User.create! do |user|
|
22
|
+
user = User.create! do |user|
|
19
23
|
user.username = "test3"
|
20
24
|
user.email = "test3@spaz.com"
|
21
25
|
|
22
26
|
user.create_account!(:cost => 10000)
|
23
27
|
end
|
28
|
+
business = user.businesses.create! do |business|
|
29
|
+
business.name = "Test2"
|
30
|
+
end
|
31
|
+
business.jobs.create!(:name => "dont_find_me")
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
data/spec/internal/db/schema.rb
CHANGED
@@ -10,4 +10,16 @@ ActiveRecord::Schema.define do
|
|
10
10
|
t.integer :cost
|
11
11
|
t.timestamps
|
12
12
|
end
|
13
|
+
|
14
|
+
create_table :companies, :force => true do |t|
|
15
|
+
t.integer :owner_id
|
16
|
+
t.string :name
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :jobs, :force => true do |t|
|
21
|
+
t.integer :company_id
|
22
|
+
t.string :name
|
23
|
+
t.timestamps
|
24
|
+
end
|
13
25
|
end
|
@@ -70,7 +70,12 @@ describe FilterMe::Filter::ArelFieldFilter do
|
|
70
70
|
relation_mock = double("relation")
|
71
71
|
|
72
72
|
arel_filter = arel_table[field].lt(10)
|
73
|
-
|
73
|
+
|
74
|
+
expect(model_class).to receive(:where) do |arel_combine_filter|
|
75
|
+
expect(arel_combine_filter).to eq(arel_filter)
|
76
|
+
end
|
77
|
+
|
78
|
+
field_filter.filter(relation_mock)
|
74
79
|
end
|
75
80
|
|
76
81
|
it "builds the correct arel filter with one filter type of two filter values" do
|
@@ -78,7 +83,11 @@ describe FilterMe::Filter::ArelFieldFilter do
|
|
78
83
|
relation_mock = double("relation")
|
79
84
|
|
80
85
|
arel_filter = arel_table[field].matches("%hey%").and(arel_table[field].matches("%hi%"))
|
81
|
-
expect(
|
86
|
+
expect(model_class).to receive(:where) do |arel_combine_filter|
|
87
|
+
expect(arel_combine_filter).to eq(arel_filter)
|
88
|
+
end
|
89
|
+
|
90
|
+
field_filter.filter(relation_mock)
|
82
91
|
end
|
83
92
|
|
84
93
|
it "builds the correct arel filter with two filter types of one filter value each" do
|
@@ -86,7 +95,11 @@ describe FilterMe::Filter::ArelFieldFilter do
|
|
86
95
|
relation_mock = double("relation")
|
87
96
|
|
88
97
|
arel_filter = arel_table[field].lt(10).and(arel_table[field].gt(1))
|
89
|
-
expect(
|
98
|
+
expect(model_class).to receive(:where) do |arel_combine_filter|
|
99
|
+
expect(arel_combine_filter).to eq(arel_filter)
|
100
|
+
end
|
101
|
+
|
102
|
+
field_filter.filter(relation_mock)
|
90
103
|
end
|
91
104
|
|
92
105
|
it "builds the correct arel filter with two filter types of two filter value each" do
|
@@ -97,7 +110,11 @@ describe FilterMe::Filter::ArelFieldFilter do
|
|
97
110
|
.and(arel_table[field].lt("z")
|
98
111
|
.and(arel_table[field].matches("%hey%")
|
99
112
|
.and(arel_table[field].matches("%hi%"))))
|
100
|
-
expect(
|
113
|
+
expect(model_class).to receive(:where) do |arel_combine_filter|
|
114
|
+
expect(arel_combine_filter).to eq(arel_filter)
|
115
|
+
end
|
116
|
+
|
117
|
+
field_filter.filter(relation_mock)
|
101
118
|
end
|
102
119
|
end
|
103
120
|
end
|
@@ -18,7 +18,7 @@ describe FilterMe::Filter::ArelDSL do
|
|
18
18
|
it "initializes a ArelFieldFilter instance with the values to filter and the filter field configuration" do
|
19
19
|
filters = [:test1, :test2]
|
20
20
|
relation_mock = double("relation")
|
21
|
-
|
21
|
+
allow(relation_mock).to receive(:merge)
|
22
22
|
|
23
23
|
model_mock = double("model")
|
24
24
|
|
@@ -26,8 +26,8 @@ describe FilterMe::Filter::ArelDSL do
|
|
26
26
|
obj.whitelisted_filters == self.whitelisted_filters
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
allow(
|
29
|
+
field_filter_instance_mock = double("field filter instance")
|
30
|
+
allow(field_filter_instance_mock).to receive(:filter)
|
31
31
|
|
32
32
|
field_filter_class = double("field filter class")
|
33
33
|
allow(field_filter_class).to receive(:new) do |filters, configuration|
|
@@ -38,7 +38,7 @@ describe FilterMe::Filter::ArelDSL do
|
|
38
38
|
:model_class => model_mock
|
39
39
|
})
|
40
40
|
|
41
|
-
|
41
|
+
field_filter_instance_mock
|
42
42
|
end
|
43
43
|
|
44
44
|
stub_const("FilterMe::Filter::ArelFieldFilter", field_filter_class)
|
@@ -59,12 +59,12 @@ describe FilterMe::Filter::ArelDSL do
|
|
59
59
|
|
60
60
|
it "calls filter on the initialized ArelFieldFilter instance with the relation" do
|
61
61
|
relation_mock = double("relation")
|
62
|
-
|
62
|
+
allow(relation_mock).to receive(:merge)
|
63
63
|
|
64
64
|
model_mock = double("model")
|
65
65
|
|
66
66
|
field_filter_instance = double("field filter instance")
|
67
|
-
expect(field_filter_instance).to receive(:filter)
|
67
|
+
expect(field_filter_instance).to receive(:filter).once
|
68
68
|
|
69
69
|
field_filter_class = double("field filter class")
|
70
70
|
allow(field_filter_class).to receive(:new) { |filters, configuration| field_filter_instance }
|
@@ -83,7 +83,7 @@ describe FilterMe::Filter::ArelDSL do
|
|
83
83
|
|
84
84
|
filter_instance = filter_class.new
|
85
85
|
|
86
|
-
|
86
|
+
filter_instance.test(relation_mock, [:test1, :test2])
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -107,7 +107,7 @@ describe FilterMe::Filter::ArelDSL do
|
|
107
107
|
filters = [:test1, :test2]
|
108
108
|
relation_mock = double("relation")
|
109
109
|
allow(relation_mock).to receive(:joins) { relation_mock }
|
110
|
-
allow(relation_mock).to receive(:
|
110
|
+
allow(relation_mock).to receive(:merge)
|
111
111
|
|
112
112
|
model = double("model")
|
113
113
|
allow(model).to receive(:name) { "Model" }
|
@@ -116,8 +116,6 @@ describe FilterMe::Filter::ArelDSL do
|
|
116
116
|
allow(mock_association_filter).to receive(:filter) { relation_mock }
|
117
117
|
|
118
118
|
mock_association_filter_class = double("assocation filter class")
|
119
|
-
mock_association_filter_class.stub(:new).and_return(mock_association_filter)
|
120
|
-
|
121
119
|
expect(mock_association_filter_class).to receive(:new) do |filters, configuration|
|
122
120
|
expect(filters).to eq(filters)
|
123
121
|
expect(configuration).to eq({})
|
@@ -149,7 +147,7 @@ describe FilterMe::Filter::ArelDSL do
|
|
149
147
|
filters = [:test1, :test2]
|
150
148
|
relation_mock = double("relation")
|
151
149
|
allow(relation_mock).to receive(:joins) { relation_mock }
|
152
|
-
allow(relation_mock).to receive(:
|
150
|
+
allow(relation_mock).to receive(:merge)
|
153
151
|
|
154
152
|
model = double("model")
|
155
153
|
allow(model).to receive(:name) { "Model" }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: filter_me
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Clopton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -106,11 +106,16 @@ files:
|
|
106
106
|
- spec/acceptance/filters/accounts_filter_spec.rb
|
107
107
|
- spec/acceptance/filters/users_filter_spec.rb
|
108
108
|
- spec/internal/app/filters/accounts_filter.rb
|
109
|
+
- spec/internal/app/filters/companies_filter.rb
|
110
|
+
- spec/internal/app/filters/jobs_filter.rb
|
109
111
|
- spec/internal/app/filters/users_filter.rb
|
110
112
|
- spec/internal/app/models/account.rb
|
113
|
+
- spec/internal/app/models/company.rb
|
114
|
+
- spec/internal/app/models/job.rb
|
111
115
|
- spec/internal/app/models/user.rb
|
112
116
|
- spec/internal/config/database.yml
|
113
117
|
- spec/internal/db/fixtures/accounts.rb
|
118
|
+
- spec/internal/db/fixtures/jobs.rb
|
114
119
|
- spec/internal/db/fixtures/users.rb
|
115
120
|
- spec/internal/db/schema.rb
|
116
121
|
- spec/internal/log/.gitignore
|