filter_me 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 48be03e95db1c79700cb86c0e4d7d5fc3bb0105f
4
- data.tar.gz: 1dadc42cd98cf3c249139deff59d5bb381e02f93
3
+ metadata.gz: 1d20eaf1933fba4c0a52e4c6b04ab9e9bce510c2
4
+ data.tar.gz: eafa06100f1fd7cf77332a340f1213f7e344beae
5
5
  SHA512:
6
- metadata.gz: 0176700ff8445af02e848c65c8ad4e9018bce1c863ad8dab7932d349c1a5574a67c68190a0e21f28eacf320d82ef6b27c2d7a3e6414ebe7d4c656600b153d764
7
- data.tar.gz: ef3971291473338f4d2728d9fa99d11e12be7f78b3bc962da835567b2f64bea9ea6e728ba404aa3027dd10458395d18d2fefd3c72a48165fe17414f5d7089d15
6
+ metadata.gz: a5356b764fbe3b6a961fc1dae9a8e7b6a08dce53c4871772a13119fb0623e676acd4fa1074d7b308270d215e6dce9700cbb76ac6590c929643e8770a5891bf86
7
+ data.tar.gz: b07bbc44c7a7bd6bcec60cbfa453615e28eba848e8c30cc5d2069ac0edfb98f516ef80d26302bf0db7aa39f6188d34f062d7e6b7b87b43a49abb3b1f62e26f4f
data/README.md CHANGED
@@ -1,11 +1,73 @@
1
- [![Code Climate](https://codeclimate.com/github/Samsinite/filter_me.png)](https://codeclimate.com/github/Samsinite/filter_me)
2
- filter_me
1
+ FilterMe
3
2
  =========
4
3
 
5
- A Rails/ActiveRecord filtering gem
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
- ### Coming Soon to a application near you!
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'
@@ -13,7 +13,7 @@ module FilterMe
13
13
  end
14
14
 
15
15
  def filter(relation)
16
- arel_filters.inject { |arel_relation, filter| filter.and(arel_relation) }
16
+ model_class.where(arel_filters.inject { |arel_relation, filter| filter.and(arel_relation) })
17
17
  end
18
18
 
19
19
  private
@@ -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 = relation.joins(name.to_sym)
59
- filter.filter(relation)
57
+ relation.joins(name.to_sym).merge(filter.filter(relation))
60
58
  else
61
- relation.where(filter.filter(relation))
59
+ relation.merge(filter.filter(relation))
62
60
  end
63
61
  end
64
62
  end
@@ -1,3 +1,3 @@
1
1
  module FilterMe
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -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
@@ -0,0 +1,5 @@
1
+ class CompaniesFilter < FilterMe::ActiveRecordFilter
2
+ model Company
3
+
4
+ association :jobs, :filter_class => JobsFilter
5
+ end
@@ -0,0 +1,5 @@
1
+ class JobsFilter < FilterMe::ActiveRecordFilter
2
+ model Job
3
+
4
+ field :name, [:matches]
5
+ end
@@ -2,6 +2,7 @@ class UsersFilter < FilterMe::ActiveRecordFilter
2
2
  model User
3
3
 
4
4
  association :account, :filter_class => AccountsFilter
5
+ association :businesses, :filter_class => CompaniesFilter
5
6
  field :email, :all
6
7
  field :username, :matches
7
8
  end
@@ -0,0 +1,4 @@
1
+ class Company < ActiveRecord::Base
2
+ belongs_to :owner, :class_name => User
3
+ has_many :jobs, :inverse_of => :company
4
+ end
@@ -0,0 +1,3 @@
1
+ class Job < ActiveRecord::Base
2
+ belongs_to :company, :inverse_of => :jobs
3
+ end
@@ -1,3 +1,5 @@
1
1
  class User < ActiveRecord::Base
2
2
  has_one :account
3
+ has_many :businesses, :class_name => Company, :foreign_key => :owner_id, :inverse_of => :owner
4
+ has_many :jobs, :through => :businesses
3
5
  end
@@ -0,0 +1,6 @@
1
+ module Fixtures
2
+ module Accounts
3
+ def load_jobs
4
+ end
5
+ end
6
+ 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
@@ -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
- expect(field_filter.filter(relation_mock)).to eq(arel_filter)
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(field_filter.filter(relation_mock)).to eq(arel_filter)
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(field_filter.filter(relation_mock)).to eq(arel_filter)
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(field_filter.filter(relation_mock)).to eq(arel_filter)
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
- expect(relation_mock).to receive(:where) { |relation| relation }
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
- field_filter_instance = double("field filter instance")
30
- allow(field_filter_instance).to receive(:filter).once
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
- field_filter_instance
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
- expect(relation_mock).to receive(:where) { |relation| relation }
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) { |relation| relation }
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
- expect(filter_instance.test(relation_mock, [:test1, :test2])).to eq(relation_mock)
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(:where) { relation_mock }
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(:where) { relation_mock }
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.0
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-16 00:00:00.000000000 Z
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