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.
- checksums.yaml +4 -4
- data/.gitignore +6 -5
- data/.travis.yml +7 -0
- data/README.md +169 -12
- data/Rakefile +8 -0
- data/TODO +0 -0
- data/lib/philtre.rb +59 -2
- data/lib/philtre/core_extensions.rb +31 -0
- data/lib/philtre/empty_expression.rb +9 -0
- data/lib/philtre/filter.rb +232 -0
- data/lib/philtre/grinder.rb +195 -0
- data/lib/philtre/place_holder.rb +41 -0
- data/lib/philtre/predicate_dsl.rb +25 -0
- data/lib/philtre/predicate_splitter.rb +40 -0
- data/lib/philtre/predicates.rb +109 -0
- data/lib/philtre/sequel_extensions.rb +30 -0
- data/lib/philtre/version.rb +2 -2
- data/philtre.gemspec +17 -10
- data/spec/dataset_spec.rb +57 -0
- data/spec/filter_spec.rb +502 -0
- data/spec/grinder_spec.rb +180 -0
- data/spec/predicate_splitter_spec.rb +54 -0
- data/tasks/console.rake +10 -0
- metadata +112 -8
@@ -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
|
+
|
data/tasks/console.rake
ADDED
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.
|
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-
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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:
|
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
|