philtre 0.0.0 → 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.
@@ -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