filter_factory 0.0.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.
- data/.gitignore +18 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +66 -0
- data/Rakefile +1 -0
- data/filter_factory.gemspec +18 -0
- data/lib/filter_factory/active_record/condition.rb +53 -0
- data/lib/filter_factory/active_record/filter.rb +17 -0
- data/lib/filter_factory/condition.rb +9 -0
- data/lib/filter_factory/field.rb +10 -0
- data/lib/filter_factory/filter.rb +52 -0
- data/lib/filter_factory/mongoid/condition.rb +53 -0
- data/lib/filter_factory/mongoid/filter.rb +23 -0
- data/lib/filter_factory/version.rb +3 -0
- data/lib/filter_factory.rb +17 -0
- data/spec/factories/factories.rb +15 -0
- data/spec/filter_factory/active_record/model_spec.rb +157 -0
- data/spec/filter_factory/filter_spec.rb +83 -0
- data/spec/filter_factory/mongoid/model_spec.rb +152 -0
- data/spec/models/ar_post.rb +2 -0
- data/spec/models/m_post.rb +9 -0
- data/spec/spec_helper.rb +57 -0
- metadata +74 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in filter_factory.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rails', '>= 3.0'
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem 'mongoid', '>= 3.0'
|
10
|
+
gem 'mysql2'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem 'rspec'
|
15
|
+
gem 'database_cleaner'
|
16
|
+
gem 'factory_girl'
|
17
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Hck
|
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,66 @@
|
|
1
|
+
# FilterFactory
|
2
|
+
|
3
|
+
FilterFactory allows you to easily fetch ActiveRecord/Mongoid models that match specified filters.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'filter_factory'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install filter_factory
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Describe your filter:
|
22
|
+
|
23
|
+
@filter = FilterFactory.create do
|
24
|
+
# filter field definition: field name for ActiveRecord/Mongoid model, filter type
|
25
|
+
field :title, :regex
|
26
|
+
field :author, :eq
|
27
|
+
field :views, :gte
|
28
|
+
# ...
|
29
|
+
end
|
30
|
+
|
31
|
+
Render form as you want in your view:
|
32
|
+
|
33
|
+
<%= form_for @filter, as: :filter do |f| %>
|
34
|
+
<div>
|
35
|
+
<%= f.label :title %>
|
36
|
+
<br/>
|
37
|
+
<%= f.text_field %>
|
38
|
+
</div>
|
39
|
+
<div>
|
40
|
+
<%= f.label :author %>
|
41
|
+
<br/>
|
42
|
+
<%= f.select Author.all.map{|r| [r.name, r.id]} %>
|
43
|
+
</div>
|
44
|
+
<div>
|
45
|
+
<%= f.label :views %>
|
46
|
+
<br/>
|
47
|
+
<%= f.number_field :views %>
|
48
|
+
</div>
|
49
|
+
<div class="actions">
|
50
|
+
<%= f.submit "Filter" %>
|
51
|
+
</div>
|
52
|
+
<% end %>
|
53
|
+
|
54
|
+
Filter your models in controller:
|
55
|
+
|
56
|
+
@filter.attributes(params[:filter]) # update filter with values supplied from the form
|
57
|
+
|
58
|
+
@posts = Post.filter(@filter) # fetch records that match specified filters
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'filter_factory/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "filter_factory"
|
8
|
+
gem.version = FilterFactory::VERSION
|
9
|
+
gem.authors = ["Hck"]
|
10
|
+
gem.description = %q{Gem for easy ActiveRecord/Mongoid models filtering}
|
11
|
+
gem.summary = %q{FilterFactory allows you to easily fetch ActiveRecord/Mongoid models that match specified filters.}
|
12
|
+
gem.homepage = "https://github.com/hck/filter_factory"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($/)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module FilterFactory
|
2
|
+
module ActiveRecord
|
3
|
+
class Condition < FilterFactory::Condition
|
4
|
+
def eq(obj)
|
5
|
+
obj.where(field_name => value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def ne(obj)
|
9
|
+
obj.where("#{field_name} != ?", value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def lt(obj)
|
13
|
+
obj.where("#{field_name} < ?", value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def lte(obj)
|
17
|
+
obj.where("#{field_name} <= ?", value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def gt(obj)
|
21
|
+
obj.where("#{field_name} > ?", value)
|
22
|
+
end
|
23
|
+
|
24
|
+
def gte(obj)
|
25
|
+
obj.where("#{field_name} >= ?", value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def all(obj)
|
29
|
+
raise NotImplementedError, "all operator is not available for ActiveRecord"
|
30
|
+
end
|
31
|
+
|
32
|
+
def in(obj)
|
33
|
+
obj.where("#{field_name} IN (?)", value)
|
34
|
+
end
|
35
|
+
|
36
|
+
def nin(obj)
|
37
|
+
obj.where("#{field_name} NOT IN (?)", value)
|
38
|
+
end
|
39
|
+
|
40
|
+
def regex(obj)
|
41
|
+
obj.where("#{field_name} REGEXP ?", value)
|
42
|
+
end
|
43
|
+
|
44
|
+
def exists(obj)
|
45
|
+
raise NotImplementedError, "all operator is not available for ActiveRecord"
|
46
|
+
end
|
47
|
+
|
48
|
+
def presents(obj)
|
49
|
+
obj.where("(#{field_name} IS NOT NULL) = ?", value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FilterFactory
|
2
|
+
module ActiveRecord
|
3
|
+
module Filter
|
4
|
+
def filter(filter_object)
|
5
|
+
conditions = filter_object.filled_fields.map do |field|
|
6
|
+
FilterFactory::ActiveRecord::Condition.new(field.name, field.value).method(field.condition)
|
7
|
+
end
|
8
|
+
|
9
|
+
conditions.inject(nil) do |res,condition|
|
10
|
+
res ? res.instance_eval(&condition) : instance_eval(&condition)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveRecord::Base.send(:extend, FilterFactory::ActiveRecord::Filter) if defined?(ActiveRecord::Base)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module FilterFactory
|
4
|
+
class Filter
|
5
|
+
include ActiveModel::Conversion
|
6
|
+
extend ActiveModel::Naming
|
7
|
+
|
8
|
+
attr_reader :fields
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@fields = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def attributes
|
15
|
+
@fields.inject(HashWithIndifferentAccess.new) do |acc,field|
|
16
|
+
acc[field.name] = field.value
|
17
|
+
acc
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def attributes=(attributes = {})
|
22
|
+
return unless attributes
|
23
|
+
attributes.each do |name, value|
|
24
|
+
public_send("#{name}=", value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def filled_fields
|
29
|
+
fields.select{|f| !f.value.nil? && f.value != ''}
|
30
|
+
end
|
31
|
+
|
32
|
+
def persisted?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def field(name, condition)
|
38
|
+
Field.new(name, condition).tap do |field|
|
39
|
+
define_singleton_method(name){ field.value }
|
40
|
+
define_singleton_method("#{name}="){|val| field.value = val }
|
41
|
+
|
42
|
+
@fields << field
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << self
|
47
|
+
def create &block
|
48
|
+
new.tap{|filter| filter.instance_eval &block}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module FilterFactory
|
2
|
+
module Mongoid
|
3
|
+
class Condition < FilterFactory::Condition
|
4
|
+
def eq(obj)
|
5
|
+
obj.where(field_name => value)
|
6
|
+
end
|
7
|
+
|
8
|
+
def ne(obj)
|
9
|
+
obj.where(field_name => {'$ne' => value})
|
10
|
+
end
|
11
|
+
|
12
|
+
def lt(obj)
|
13
|
+
obj.where(field_name => {'$lt' => value})
|
14
|
+
end
|
15
|
+
|
16
|
+
def lte(obj)
|
17
|
+
obj.where(field_name => {'$lte' => value})
|
18
|
+
end
|
19
|
+
|
20
|
+
def gt(obj)
|
21
|
+
obj.where(field_name => {'$gt' => value})
|
22
|
+
end
|
23
|
+
|
24
|
+
def gte(obj)
|
25
|
+
obj.where(field_name => {'$gte' => value})
|
26
|
+
end
|
27
|
+
|
28
|
+
def all(obj)
|
29
|
+
obj.where(field_name => {'$all' => value})
|
30
|
+
end
|
31
|
+
|
32
|
+
def in(obj)
|
33
|
+
obj.where(field_name => {'$in' => value})
|
34
|
+
end
|
35
|
+
|
36
|
+
def nin(obj)
|
37
|
+
obj.where(field_name => {'$nin' => value})
|
38
|
+
end
|
39
|
+
|
40
|
+
def regex(obj)
|
41
|
+
obj.where(field_name => /#{Regexp.escape(value)}/)
|
42
|
+
end
|
43
|
+
|
44
|
+
def exists(obj)
|
45
|
+
obj.where(field_name => {'$exists' => value})
|
46
|
+
end
|
47
|
+
|
48
|
+
def presents(obj)
|
49
|
+
['true', '1', 1].include?(value) ? obj.where(field_name => {'$nin' => [nil, '', []]}) : obj.where(field_name => {'$in' => [nil, '', []]})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FilterFactory
|
2
|
+
module Mongoid
|
3
|
+
module Filter
|
4
|
+
def filter(filter_object)
|
5
|
+
conditions = filter_object.filled_fields.map do |field|
|
6
|
+
FilterFactory::Mongoid::Condition.new(field.name, field.value).method(field.condition)
|
7
|
+
end
|
8
|
+
|
9
|
+
conditions.inject(nil) do |res,condition|
|
10
|
+
res ? res.instance_eval(&condition) : instance_eval(&condition)
|
11
|
+
end || self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if defined?(Mongoid::Document)
|
18
|
+
Mongoid::Document.module_eval do
|
19
|
+
def self.included(base)
|
20
|
+
base.extend FilterFactory::Mongoid::Filter
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "filter_factory/version"
|
2
|
+
|
3
|
+
require "filter_factory/condition"
|
4
|
+
require "filter_factory/field"
|
5
|
+
require "filter_factory/filter"
|
6
|
+
|
7
|
+
require "filter_factory/active_record/condition"
|
8
|
+
require "filter_factory/active_record/filter"
|
9
|
+
|
10
|
+
require "filter_factory/mongoid/condition"
|
11
|
+
require "filter_factory/mongoid/filter"
|
12
|
+
|
13
|
+
module FilterFactory
|
14
|
+
def self.create &block
|
15
|
+
FilterFactory::Filter.create &block
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :mongoid_post, class: MPost do
|
3
|
+
sequence(:title) {|n| "post_#{n}"}
|
4
|
+
sequence(:author) {|n| "author_#{n}"}
|
5
|
+
sequence(:views) {|n| n}
|
6
|
+
#views {rand(0..1000)}
|
7
|
+
end
|
8
|
+
|
9
|
+
factory :active_record_post, class: ARPost do
|
10
|
+
sequence(:title) {|n| "post_#{n}"}
|
11
|
+
sequence(:author) {|n| "author_#{n}"}
|
12
|
+
sequence(:views) {|n| n}
|
13
|
+
#views {rand(0..1000)}
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe ARPost do
|
4
|
+
before(:each) do
|
5
|
+
@posts = FactoryGirl.create_list(:active_record_post, 10)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should respond to ::filter method" do
|
9
|
+
described_class.should respond_to(:filter)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should execute filter methods chain" do
|
13
|
+
filter = FilterFactory.create do
|
14
|
+
field :title, :eq
|
15
|
+
field :author, :eq
|
16
|
+
field :views, :gte
|
17
|
+
end
|
18
|
+
|
19
|
+
sample = @posts.sample
|
20
|
+
|
21
|
+
filter.title = sample.title
|
22
|
+
filter.author = sample.author
|
23
|
+
|
24
|
+
described_class.filter(filter).to_a.should == [sample]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return records with column' values equal to specified value" do
|
28
|
+
sample = @posts.sample
|
29
|
+
|
30
|
+
filter = FilterFactory.create do
|
31
|
+
field :id, :eq
|
32
|
+
end
|
33
|
+
filter.id = sample.id
|
34
|
+
|
35
|
+
described_class.filter(filter).to_a.should == [sample]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return records with column' values not equal specified value" do
|
39
|
+
sample = @posts.sample
|
40
|
+
|
41
|
+
filter = FilterFactory.create do
|
42
|
+
field :id, :ne
|
43
|
+
end
|
44
|
+
filter.id = sample.id
|
45
|
+
|
46
|
+
described_class.filter(filter).to_a.sort.should == @posts.reject{|p| p.id == sample.id}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return records with column' values less than specified value" do
|
50
|
+
sample = @posts.sample
|
51
|
+
|
52
|
+
filter = FilterFactory.create do
|
53
|
+
field :views, :lt
|
54
|
+
end
|
55
|
+
filter.views = sample.views
|
56
|
+
|
57
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views < sample.views}.map(&:id).sort
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return records with column' values less than or equal to specified value" do
|
61
|
+
sample = @posts.sample
|
62
|
+
|
63
|
+
filter = FilterFactory.create do
|
64
|
+
field :views, :lte
|
65
|
+
end
|
66
|
+
filter.views = sample.views
|
67
|
+
|
68
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views <= sample.views}.map(&:id).sort
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return records with column' values greater than specified value" do
|
72
|
+
sample = @posts.sample
|
73
|
+
|
74
|
+
filter = FilterFactory.create do
|
75
|
+
field :views, :gt
|
76
|
+
end
|
77
|
+
filter.views = sample.views
|
78
|
+
|
79
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views > sample.views}.map(&:id).sort
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return records with column' values greater than or equal to specified value" do
|
83
|
+
sample = @posts.sample
|
84
|
+
|
85
|
+
filter = FilterFactory.create do
|
86
|
+
field :views, :gte
|
87
|
+
end
|
88
|
+
filter.views = sample.views
|
89
|
+
|
90
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views >= sample.views}.map(&:id).sort
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should raise NotImplementedError if using 'all' condition" do
|
94
|
+
filter = FilterFactory.create do
|
95
|
+
field :opts, :all
|
96
|
+
end
|
97
|
+
filter.opts = [1, 2, 3, 4]
|
98
|
+
|
99
|
+
expect {described_class.filter(filter)}.to raise_error(NotImplementedError)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return records with column' values in specified values" do
|
103
|
+
sample = @posts.sample(3)
|
104
|
+
|
105
|
+
filter = FilterFactory.create do
|
106
|
+
field :id, :in
|
107
|
+
end
|
108
|
+
filter.id = sample.map(&:id)
|
109
|
+
|
110
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should return records with column' values not in specified values" do
|
114
|
+
sample = @posts.sample(3)
|
115
|
+
|
116
|
+
filter = FilterFactory.create do
|
117
|
+
field :id, :nin
|
118
|
+
end
|
119
|
+
filter.id = sample.map(&:id)
|
120
|
+
|
121
|
+
described_class.filter(filter).map(&:id).sort.should == (@posts.map(&:id) - sample.map(&:id)).sort
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should return records with column' values which match the specified regexp" do
|
125
|
+
sample = @posts.sample(3)
|
126
|
+
sample.each_with_index{|r,i| r.update_attribute(:title, "my_title_#{i}")}
|
127
|
+
|
128
|
+
filter = FilterFactory.create do
|
129
|
+
field :title, :regex
|
130
|
+
end
|
131
|
+
|
132
|
+
filter.title = '_title_'
|
133
|
+
|
134
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should raise NotImplementedError if using 'exists' condition" do
|
138
|
+
filter = FilterFactory.create do
|
139
|
+
field :not_exists, :exists
|
140
|
+
end
|
141
|
+
filter.not_exists = true
|
142
|
+
|
143
|
+
expect {described_class.filter(filter)}.to raise_error(NotImplementedError)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should return records with column' values not nil equal to specified value" do
|
147
|
+
sample = @posts.sample(3)
|
148
|
+
sample.each{|r| r.update_attribute(:title, nil)}
|
149
|
+
|
150
|
+
filter = FilterFactory.create do
|
151
|
+
field :title, :presents
|
152
|
+
end
|
153
|
+
filter.title = false
|
154
|
+
|
155
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FilterFactory::Filter do
|
4
|
+
it "should create filter and execute block" do
|
5
|
+
test_fields = [[:field1, :eq], [:field2, :eq], [:field3, :eq]]
|
6
|
+
|
7
|
+
filter = described_class.create do
|
8
|
+
test_fields.each do |arr|
|
9
|
+
field *arr
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
filter.should be_a(described_class)
|
14
|
+
|
15
|
+
filter.fields.map{|f| [f.name, f.condition]}.should == test_fields
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should define singleton method for defined field" do
|
19
|
+
filter = described_class.create do
|
20
|
+
field :name, :eq
|
21
|
+
end
|
22
|
+
|
23
|
+
filter.should respond_to(:name, :'name=')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should get field value" do
|
27
|
+
filter = described_class.create do
|
28
|
+
field :name, :eq
|
29
|
+
end
|
30
|
+
|
31
|
+
filter.fields.first.value = "sample name"
|
32
|
+
filter.name.should == "sample name"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set field value" do
|
36
|
+
filter = described_class.create do
|
37
|
+
field :name, :eq
|
38
|
+
end
|
39
|
+
|
40
|
+
filter.name = "sample name"
|
41
|
+
filter.fields.first.value.should == "sample name"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should respond_to attributes & attributes= methods" do
|
45
|
+
filter = described_class.create do
|
46
|
+
field :name, :eq
|
47
|
+
end
|
48
|
+
|
49
|
+
filter.should respond_to(:attributes, :attributes=)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return valid attributes" do
|
53
|
+
filter = described_class.create do
|
54
|
+
field :name, :eq
|
55
|
+
field :surname, :regex
|
56
|
+
end
|
57
|
+
filter.name = "test name"
|
58
|
+
|
59
|
+
filter.attributes.should == HashWithIndifferentAccess.new({name: "test name", surname: nil})
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should fill filter values from hash" do
|
63
|
+
filter = described_class.create do
|
64
|
+
field :name, :eq
|
65
|
+
field :surname, :regex
|
66
|
+
end
|
67
|
+
|
68
|
+
attributes = {name: "my test name", surname: "surname here"}
|
69
|
+
filter.attributes = attributes
|
70
|
+
filter.attributes.should == HashWithIndifferentAccess.new(attributes)
|
71
|
+
end
|
72
|
+
|
73
|
+
#describe "#conditions" do
|
74
|
+
# it "should return result of query method for each of the condition as a Method object" do
|
75
|
+
# filter = described_class.create do
|
76
|
+
# field :name, :eq
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# filter.name = "sample name"
|
80
|
+
# filter.conditions.first.should be_a(Method)
|
81
|
+
# end
|
82
|
+
#end
|
83
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe MPost do
|
4
|
+
before(:each) do
|
5
|
+
@posts = FactoryGirl.create_list(:mongoid_post, 10)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should respond to ::filter method" do
|
9
|
+
described_class.should respond_to(:filter)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should execute filter methods chain" do
|
13
|
+
sample = @posts.sample
|
14
|
+
|
15
|
+
filter = FilterFactory.create do
|
16
|
+
field :title, :eq
|
17
|
+
field :author, :eq
|
18
|
+
field :views, :gte
|
19
|
+
end
|
20
|
+
|
21
|
+
filter.title = sample.title
|
22
|
+
filter.author = sample.author
|
23
|
+
|
24
|
+
described_class.filter(filter).to_a.should == [sample]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return records with column' values equal to specified value" do
|
28
|
+
sample = @posts.sample
|
29
|
+
|
30
|
+
filter = FilterFactory.create do
|
31
|
+
field :id, :eq
|
32
|
+
end
|
33
|
+
filter.id = sample.id
|
34
|
+
|
35
|
+
described_class.filter(filter).to_a.should == [sample]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return records with column' values not equal specified value" do
|
39
|
+
sample = @posts.sample
|
40
|
+
|
41
|
+
filter = FilterFactory.create do
|
42
|
+
field :id, :ne
|
43
|
+
end
|
44
|
+
filter.id = sample.id
|
45
|
+
|
46
|
+
described_class.filter(filter).to_a.sort.should == @posts.reject{|p| p.id == sample.id}
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return records with column' values less than specified value" do
|
50
|
+
sample = @posts.sample
|
51
|
+
|
52
|
+
filter = FilterFactory.create do
|
53
|
+
field :views, :lt
|
54
|
+
end
|
55
|
+
filter.views = sample.views
|
56
|
+
|
57
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views < sample.views}.map(&:id).sort
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should return records with column' values less than or equal to specified value" do
|
61
|
+
sample = @posts.sample
|
62
|
+
|
63
|
+
filter = FilterFactory.create do
|
64
|
+
field :views, :lte
|
65
|
+
end
|
66
|
+
filter.views = sample.views
|
67
|
+
|
68
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views <= sample.views}.map(&:id).sort
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return records with column' values greater than specified value" do
|
72
|
+
sample = @posts.sample
|
73
|
+
|
74
|
+
filter = FilterFactory.create do
|
75
|
+
field :views, :gt
|
76
|
+
end
|
77
|
+
filter.views = sample.views
|
78
|
+
|
79
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views > sample.views}.map(&:id).sort
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return records with column' values greater than or equal to specified value" do
|
83
|
+
sample = @posts.sample
|
84
|
+
|
85
|
+
filter = FilterFactory.create do
|
86
|
+
field :views, :gte
|
87
|
+
end
|
88
|
+
filter.views = sample.views
|
89
|
+
|
90
|
+
described_class.filter(filter).map(&:id).sort.should == @posts.select{|p| p.views >= sample.views}.map(&:id).sort
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return records with column' values all equal to specified value" do
|
94
|
+
sample = @posts.sample(2)
|
95
|
+
sample.each{|r| r.update_attribute(:opts, [1, 2, 3, 4])}
|
96
|
+
|
97
|
+
filter = FilterFactory.create do
|
98
|
+
field :opts, :all
|
99
|
+
end
|
100
|
+
filter.opts = [1, 2, 3, 4]
|
101
|
+
|
102
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should return records with column' values in specified values" do
|
106
|
+
sample = @posts.sample(3)
|
107
|
+
|
108
|
+
filter = FilterFactory.create do
|
109
|
+
field :id, :in
|
110
|
+
end
|
111
|
+
filter.id = sample.map(&:id)
|
112
|
+
|
113
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should return records with column' values not in specified values" do
|
117
|
+
sample = @posts.sample(3)
|
118
|
+
|
119
|
+
filter = FilterFactory.create do
|
120
|
+
field :id, :nin
|
121
|
+
end
|
122
|
+
filter.id = sample.map(&:id)
|
123
|
+
|
124
|
+
described_class.filter(filter).map(&:id).sort.should == (@posts.map(&:id) - sample.map(&:id)).sort
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should return records with column' values which match the specified regexp" do
|
128
|
+
sample = @posts.sample(3)
|
129
|
+
sample.each_with_index{|r,i| r.update_attribute(:title, "my_title_#{i}")}
|
130
|
+
|
131
|
+
filter = FilterFactory.create do
|
132
|
+
field :title, :regex
|
133
|
+
end
|
134
|
+
|
135
|
+
filter.title = '_title_'
|
136
|
+
|
137
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should return records with existing column' values" do
|
141
|
+
sample = @posts.sample(3)
|
142
|
+
sample.each{|r| r.update_attribute(:not_exists, rand(0..25))}
|
143
|
+
|
144
|
+
filter = FilterFactory.create do
|
145
|
+
field :not_exists, :exists
|
146
|
+
end
|
147
|
+
|
148
|
+
filter.not_exists = true
|
149
|
+
|
150
|
+
described_class.filter(filter).map(&:id).sort.should == sample.map(&:id).sort
|
151
|
+
end
|
152
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
MODELS = File.join(File.dirname(__FILE__), 'models')
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
require 'mongoid'
|
6
|
+
require 'active_record'
|
7
|
+
require 'database_cleaner'
|
8
|
+
require 'factory_girl'
|
9
|
+
|
10
|
+
require 'filter_factory'
|
11
|
+
|
12
|
+
Dir["#{MODELS}/*.rb"].each { |f| require f }
|
13
|
+
|
14
|
+
Mongoid.configure do |config|
|
15
|
+
config.connect_to 'mongoid_filter_factory_test'
|
16
|
+
end
|
17
|
+
#Mongoid.logger = Logger.new($stdout)
|
18
|
+
#Moped.logger = Logger.new($stdout)
|
19
|
+
|
20
|
+
ActiveRecord::Base.establish_connection(
|
21
|
+
adapter: "mysql2",
|
22
|
+
database: "active_record_filter_factory_test"
|
23
|
+
)
|
24
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS ar_posts")
|
25
|
+
ActiveRecord::Base.connection.create_table(:ar_posts) do |t|
|
26
|
+
t.string :title
|
27
|
+
t.string :author
|
28
|
+
t.integer :views
|
29
|
+
end
|
30
|
+
#ActiveRecord::Base.logger = Logger.new($stdout)
|
31
|
+
#ActiveRecord::Base.logger.level = Logger::DEBUG
|
32
|
+
|
33
|
+
FactoryGirl.definition_file_paths = [File.join(File.dirname(__FILE__), 'factories')]
|
34
|
+
FactoryGirl.find_definitions
|
35
|
+
|
36
|
+
RSpec.configure do |config|
|
37
|
+
config.mock_with :rspec
|
38
|
+
config.color_enabled = true
|
39
|
+
|
40
|
+
config.before(:suite) do
|
41
|
+
mongoid = DatabaseCleaner[:mongoid]
|
42
|
+
mongoid.strategy = :truncation
|
43
|
+
mongoid.clean_with(:truncation)
|
44
|
+
|
45
|
+
active_record = DatabaseCleaner[:active_record]
|
46
|
+
active_record.strategy = :truncation
|
47
|
+
active_record.clean_with(:truncation)
|
48
|
+
end
|
49
|
+
|
50
|
+
config.before(:each) do
|
51
|
+
DatabaseCleaner.start
|
52
|
+
end
|
53
|
+
|
54
|
+
config.after(:each) do
|
55
|
+
DatabaseCleaner.clean
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: filter_factory
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Hck
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-05 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Gem for easy ActiveRecord/Mongoid models filtering
|
15
|
+
email:
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- .gitignore
|
21
|
+
- Gemfile
|
22
|
+
- LICENSE.txt
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- filter_factory.gemspec
|
26
|
+
- lib/filter_factory.rb
|
27
|
+
- lib/filter_factory/active_record/condition.rb
|
28
|
+
- lib/filter_factory/active_record/filter.rb
|
29
|
+
- lib/filter_factory/condition.rb
|
30
|
+
- lib/filter_factory/field.rb
|
31
|
+
- lib/filter_factory/filter.rb
|
32
|
+
- lib/filter_factory/mongoid/condition.rb
|
33
|
+
- lib/filter_factory/mongoid/filter.rb
|
34
|
+
- lib/filter_factory/version.rb
|
35
|
+
- spec/factories/factories.rb
|
36
|
+
- spec/filter_factory/active_record/model_spec.rb
|
37
|
+
- spec/filter_factory/filter_spec.rb
|
38
|
+
- spec/filter_factory/mongoid/model_spec.rb
|
39
|
+
- spec/models/ar_post.rb
|
40
|
+
- spec/models/m_post.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
homepage: https://github.com/hck/filter_factory
|
43
|
+
licenses: []
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.8.23
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: FilterFactory allows you to easily fetch ActiveRecord/Mongoid models that
|
66
|
+
match specified filters.
|
67
|
+
test_files:
|
68
|
+
- spec/factories/factories.rb
|
69
|
+
- spec/filter_factory/active_record/model_spec.rb
|
70
|
+
- spec/filter_factory/filter_spec.rb
|
71
|
+
- spec/filter_factory/mongoid/model_spec.rb
|
72
|
+
- spec/models/ar_post.rb
|
73
|
+
- spec/models/m_post.rb
|
74
|
+
- spec/spec_helper.rb
|