philtre 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,180 @@
1
+ require 'rspec'
2
+ require 'faker'
3
+ require 'sequel'
4
+ require 'ripar'
5
+
6
+ require_relative '../lib/philtre.rb'
7
+
8
+ Sequel.extension :blank
9
+ Sequel.extension :core_extensions
10
+
11
+ describe Philtre::Grinder do
12
+ def ds
13
+ @ds ||= Sequel.mock[:t].filter( :name.lieu, :title.lieu ).order( :birth_year.lieu )
14
+ end
15
+
16
+ def other_ds
17
+ @other_ds ||= Sequel.mock[:ods]
18
+ end
19
+
20
+ def grinder
21
+ @grinder ||= Philtre::Grinder.new
22
+ end
23
+
24
+ it 'shows placeholders' do
25
+ ds.sql.should =~ /\$name/
26
+ ds.sql.should =~ /\$title/
27
+ ds.sql.should =~ /\$birth_year/
28
+ end
29
+
30
+ it 'shows comments' do
31
+ ds.sql.should =~ %r{\$name/\*\S+\*/}
32
+ ds.sql.should =~ %r{\$title/\*\S+\*/}
33
+ ds.sql.should =~ %r{\$birth_year/\*\S+\*/}
34
+ end
35
+
36
+ describe '#places' do
37
+ it 'collects placeholders' do
38
+ nds = grinder.transform ds, apply_unknown: false
39
+ grinder.places.flat_map{|k,v| v.keys}.should == %i[name title birth_year]
40
+ end
41
+
42
+ it 'fails before transform' do
43
+ ->{grinder.places}.should raise_error(/Call transform.*place/)
44
+ end
45
+ end
46
+
47
+ describe '#unknown' do
48
+ it 'fails before transform' do
49
+ ->{grinder.unknown}.should raise_error(/Call transform.*not.*filter/)
50
+ end
51
+
52
+ it 'has a list of unknowns' do
53
+ grinder = Philtre::Grinder.new Philtre::Filter.new( location: 'Spain', name: 'Bartholemew del Pince-Nez', :order => 'name_desc')
54
+ nds = grinder.transform ds, apply_unknown: true
55
+ grinder.unknown.should == %i[location]
56
+ end
57
+ end
58
+
59
+ it 'removes empty expressions' do
60
+ nds = grinder.transform ds, apply_unknown: false
61
+ nds.sql.should_not =~ /name/
62
+ nds.sql.should_not =~ /title/
63
+ nds.sql.should_not =~ /birth_year/
64
+ end
65
+
66
+ it 'removes empty clauses' do
67
+ nds = grinder.transform ds, apply_unknown: false
68
+ nds.sql.should_not =~ /where/i
69
+ nds.sql.should_not =~ /order by/i
70
+ end
71
+
72
+ it 'raises on unknown filter expressions' do
73
+ grinder = Philtre::Grinder.new Philtre::Filter.new(blah: Faker::Name.name)
74
+ ->{ grinder.transform( ds, apply_unknown: false ) }.should raise_error(/unknown value/)
75
+ end
76
+
77
+ it 'raises on unknown order expressions' do
78
+ grinder = Philtre::Grinder.new Philtre::Filter.new( :troll => :name.asc )
79
+ ->{ grinder.transform( ds, apply_unknown: false ) }.should raise_error(/unknown value/)
80
+ end
81
+
82
+ it 'substitutes expressions' do
83
+ grinder = Philtre::Grinder.new Philtre::Filter.new( title: 'Jonathan Wrinklebottom' )
84
+ nds = grinder.transform ds, apply_unknown: false
85
+ nds.sql.should =~ /title = ['"`]Jonathan Wrinklebottom['"`]/i
86
+ end
87
+
88
+ it 'substitutes field names' do
89
+ grinder = Philtre::Grinder.new Philtre::Filter.new( replace_this: 'Marna von Pffefferhaus' )
90
+ nds = grinder.transform( ds.filter( :replace_this.lieu(:with_other) ), apply_unknown: false )
91
+ nds.sql.should =~ /with_other = ['"`]Marna von Pffefferhaus['"`]/i
92
+ end
93
+
94
+ it 'handles order/where name clashes' do
95
+ ods = ds.order( :name.lieu )
96
+ grinder = Philtre::Grinder.new Philtre::Filter.new( name: 'Fannie Rosebottom', :order => 'name_desc')
97
+ nds = grinder.transform ods, apply_unknown: false
98
+ nds.sql.should == %q{SELECT * FROM t WHERE ((name = 'Fannie Rosebottom')) ORDER BY name DESC}
99
+ end
100
+
101
+ describe 'select placeholder' do
102
+ it 'remove empty' do
103
+ mds = ds.select(:name.lieu,:title,:age).where(:title_gt.lieu)
104
+ grinder = Philtre::Grinder.new Philtre::Filter.new( title_gt: 'sir', name: '')
105
+ nds = grinder.transform mds, apply_unknown: false
106
+ nds.sql.should == %q{SELECT title, age FROM t WHERE ((title > 'sir'))}
107
+ end
108
+
109
+ it 'keep non-empty' do
110
+ mds = ds.select(:name.lieu,:title,:age).where(:title_gt.lieu)
111
+ grinder = Philtre::Grinder.new Philtre::Filter.new( title_gt: 'sir', name: 'Klaas Arendse')
112
+ nds = grinder.transform mds, apply_unknown: false
113
+ nds.sql.should == %q{SELECT name, title, age FROM t WHERE ((name = 'Klaas Arendse') AND (title > 'sir'))}
114
+ end
115
+ end
116
+
117
+ it 'handles subselects' do
118
+ mds = Sequel.mock.from(ds.select(Sequel.lit 'sum(age) as age')).filter( :age.lieu )
119
+ mds.sql.should =~ /age/
120
+ nds = grinder.transform mds, apply_unknown: false
121
+ nds.sql.should =~ %r{^SELECT \* FROM \(SELECT}
122
+ nds.sql.should =~ /t1/
123
+ end
124
+
125
+ it 'applies extra parameters to the dataset after the placeholders' do
126
+ grinder = Philtre::Grinder.new Philtre::Filter.new( location: 'Spain', name: 'Bartholemew del Pince-Nez', :order => 'name_desc')
127
+ nds = grinder.transform ds, apply_unknown: true
128
+ grinder.unknown.should_not be_empty
129
+ nds.sql.should =~ /Spain/
130
+ end
131
+
132
+ it 'ordering survives application of extra parameters' do
133
+ skip 'in Grinder#transform ordering parameters are stripped out by filter.subset'
134
+ grinder = Philtre::Grinder.new Philtre::Filter.new( name: 'Finky Steetchas', :order => ['name_desc', 'dunno'])
135
+ nds = grinder.transform ds, apply_unknown: true
136
+ grinder.unknown.should_not be_empty
137
+ end
138
+
139
+ describe 'subset stack' do
140
+ def ds
141
+ @ds ||=
142
+ begin
143
+ subselect = Sequel.mock[:sub].select(:id)
144
+ Sequel.mock[:t].filter( :name.lieu, :title.lieu, person_id: subselect ).order( :birth_year.lieu )
145
+ end
146
+ end
147
+
148
+ it 'gets back to where after a subselect' do
149
+ grinder = Philtre::Grinder.new Philtre::Filter.new(person_id: 42)
150
+ nds = grinder.transform ds
151
+ nds.sql.should =~ /person_id IN/
152
+ nds.sql.should =~ /person_id\s*=\s*42/
153
+ end
154
+ end
155
+
156
+ it 'handle sub-datasets' do
157
+ grinder = Philtre::Grinder.new Philtre::Filter.new(person_id: 212728)
158
+ tds = ds.filter( linkage: other_ds.where( :person_id.lieu ) )
159
+ nds = grinder.transform tds
160
+ nds.sql.should =~ /FROM\s+ods\s+WHERE\s*\(\s*person_id\s*=\s*212728\s*\)/
161
+ end
162
+
163
+ it 'handles rollers' do
164
+ grinder = Philtre::Grinder.new Philtre::Filter.new(person_id: 212728)
165
+ tds = ds.roller do
166
+ where linkage: other_ds.where( :person_id.lieu )
167
+ end
168
+ tds.__class__.should == Ripar::Roller
169
+
170
+ nds = grinder.transform tds
171
+ nds.sql.should =~ /FROM\s+ods\s+WHERE\s*\(\s*person_id\s*=\s*212728\s*\)/
172
+ end
173
+
174
+ it 'handles Models' do
175
+ Sequel::Model.db = Sequel.sqlite
176
+ class Ods < Sequel::Model(:ods); end
177
+ Philtre::Grinder.new( Philtre::Filter.new ).transform(Ods).should be_a(Sequel::Dataset)
178
+ Philtre::Grinder.new( Philtre::Filter.new ).transform(Ods).sql.should =~ /SELECT \* FROM .ods./
179
+ end
180
+ end
@@ -0,0 +1,54 @@
1
+ require 'rspec'
2
+ require 'faker'
3
+
4
+ require_relative '../lib/philtre/predicate_splitter.rb'
5
+
6
+ # for blank?
7
+ Sequel.extension :blank
8
+
9
+ describe Philtre::PredicateSplitter do
10
+ describe '#split_key' do
11
+ describe 'successful' do
12
+ let(:splitter){ Philtre::PredicateSplitter.new( 'birth_year_like', 'fifteeen' ) }
13
+
14
+ it 'returns true' do
15
+ splitter.split_key( :like ).should be_truthy
16
+ end
17
+
18
+ it 'keeps field as symbol' do
19
+ splitter.split_key :like
20
+ splitter.field.should == :birth_year
21
+ end
22
+
23
+ it 'keeps op as symbol' do
24
+ splitter.split_key :like
25
+ splitter.op.should == :like
26
+ end
27
+ end
28
+
29
+ describe 'unsuccessful' do
30
+ let(:splitter){ Philtre::PredicateSplitter.new 'birth_year', 'fifteeen' }
31
+ it 'returns false' do
32
+ splitter.split_key( :like ).should be_falsey
33
+ end
34
+
35
+ it 'keeps key as symbol' do
36
+ splitter.split_key :like
37
+ splitter.field.should == :birth_year
38
+ end
39
+
40
+ it 'op is nil' do
41
+ splitter.split_key :like
42
+ splitter.op.should be_nil
43
+ end
44
+ end
45
+
46
+ describe 'custom predicate' do
47
+ let(:splitter){ Philtre::PredicateSplitter.new( 'custom_predicate', 'fifteeen' ) }
48
+ it 'accepts the whole thing' do
49
+ (splitter === :custom_predicate).should === 0
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,10 @@
1
+ desc "pry with libs"
2
+ task :console do
3
+ ARGV.shift()
4
+ ENV['RUBYLIB'] ||= ''
5
+ ENV['RUBYLIB'] += ":#{File.expand_path('.')}/lib/philtre"
6
+ exec "pry -r philtre -I ./lib -I ."
7
+ end
8
+
9
+ task :pry => :console
10
+ task :irb => :pry
metadata CHANGED
@@ -1,29 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philtre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Anderson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-30 00:00:00.000000000 Z
11
+ date: 2014-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sequel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fastandand
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ripar
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.3
13
55
  - !ruby/object:Gem::Dependency
14
56
  name: bundler
15
57
  requirement: !ruby/object:Gem::Requirement
16
58
  requirements:
17
59
  - - "~>"
18
60
  - !ruby/object:Gem::Version
19
- version: '1.6'
61
+ version: '1.5'
20
62
  type: :development
21
63
  prerelease: false
22
64
  version_requirements: !ruby/object:Gem::Requirement
23
65
  requirements:
24
66
  - - "~>"
25
67
  - !ruby/object:Gem::Version
26
- version: '1.6'
68
+ version: '1.5'
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: rake
29
71
  requirement: !ruby/object:Gem::Requirement
@@ -38,7 +80,49 @@ dependencies:
38
80
  - - ">="
39
81
  - !ruby/object:Gem::Version
40
82
  version: '0'
41
- description: If this doesn't make you fall in love, I don't know what will.
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: faker
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sqlite3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Encode various filtering operations in http parameter hashes
42
126
  email:
43
127
  - panic@semiosix.com
44
128
  executables: []
@@ -46,14 +130,30 @@ extensions: []
46
130
  extra_rdoc_files: []
47
131
  files:
48
132
  - ".gitignore"
133
+ - ".travis.yml"
49
134
  - Gemfile
50
135
  - LICENSE.txt
51
136
  - README.md
52
137
  - Rakefile
138
+ - TODO
53
139
  - lib/philtre.rb
140
+ - lib/philtre/core_extensions.rb
141
+ - lib/philtre/empty_expression.rb
142
+ - lib/philtre/filter.rb
143
+ - lib/philtre/grinder.rb
144
+ - lib/philtre/place_holder.rb
145
+ - lib/philtre/predicate_dsl.rb
146
+ - lib/philtre/predicate_splitter.rb
147
+ - lib/philtre/predicates.rb
148
+ - lib/philtre/sequel_extensions.rb
54
149
  - lib/philtre/version.rb
55
150
  - philtre.gemspec
56
- homepage: https://github.com/djellemah/philtre
151
+ - spec/dataset_spec.rb
152
+ - spec/filter_spec.rb
153
+ - spec/grinder_spec.rb
154
+ - spec/predicate_splitter_spec.rb
155
+ - tasks/console.rake
156
+ homepage: http://github.com/djellemah/philtre
57
157
  licenses:
58
158
  - MIT
59
159
  metadata: {}
@@ -76,5 +176,9 @@ rubyforge_project:
76
176
  rubygems_version: 2.2.2
77
177
  signing_key:
78
178
  specification_version: 4
79
- summary: The Sequel equivalent for Ransack, Metasearch, Searchlogic
80
- test_files: []
179
+ summary: http parameter-hash friendly filtering for Sequel
180
+ test_files:
181
+ - spec/dataset_spec.rb
182
+ - spec/filter_spec.rb
183
+ - spec/grinder_spec.rb
184
+ - spec/predicate_splitter_spec.rb