corny-sql_filter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +53 -0
- data/init.rb +2 -0
- data/lib/sql_filter.rb +152 -0
- data/sql_filter.gemspec +26 -0
- data/test/sql_filter_test.rb +133 -0
- metadata +60 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [Julian K., Can Filip S.]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
= sql_filter
|
2
|
+
|
3
|
+
sql_filter helps you to build sql-conditions from parameters
|
4
|
+
and avoids sql injections.
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
== INSTALL:
|
10
|
+
|
11
|
+
coming soon
|
12
|
+
|
13
|
+
== EXAMPLE:
|
14
|
+
|
15
|
+
=== Options for attributes
|
16
|
+
|
17
|
+
* value => fixed value or array of allowed values
|
18
|
+
* operator => fixed operator or list of allowed operators [default: =]
|
19
|
+
* default_operator => operator or first element of operator
|
20
|
+
* ignore_blank => Boolean [default: true]
|
21
|
+
* escape => Boolean [default: true]
|
22
|
+
|
23
|
+
=== Simple
|
24
|
+
MyFilter < SqlFilter
|
25
|
+
attributes :foo
|
26
|
+
end
|
27
|
+
|
28
|
+
filter = MyFilter.new(:foo => 'bar')
|
29
|
+
filter.to_a == ["1 AND (`foo` = ?)",'bar']
|
30
|
+
|
31
|
+
=== With default
|
32
|
+
MyFilter < SqlFilter
|
33
|
+
attributes :name, :default => 'any', :operator => :like
|
34
|
+
end
|
35
|
+
|
36
|
+
filter = MyFilter.new(:foo => 'bar')
|
37
|
+
filter.to_a == ["1 AND (`foo` LIKE ?)",'%bar%']
|
38
|
+
|
39
|
+
=== Custom method
|
40
|
+
MyFilter < SqlFilter
|
41
|
+
attributes :name
|
42
|
+
|
43
|
+
def name_to_sql
|
44
|
+
["foreign_id IN (SELECT id FROM foreigns WHERE name LIKE ?)",name]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
filter = MyFilter.new(:foo => 'bar')
|
50
|
+
filter.to_a == ["1 AND `foreign_id` IN (SELECT id FROM foreigns WHERE name LIKE ?))","bar"]
|
51
|
+
|
52
|
+
|
53
|
+
Copyright (c) 2009 Julian K., released under the MIT license
|
data/init.rb
ADDED
data/lib/sql_filter.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# SqlFilter
|
2
|
+
|
3
|
+
|
4
|
+
module SqlFilterAttributes
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def inherited(subclass)
|
13
|
+
subclass.instance_variable_set('@attributes', instance_variable_get('@attributes').clone)
|
14
|
+
end
|
15
|
+
|
16
|
+
# returns the configuration hash
|
17
|
+
def attributes
|
18
|
+
@attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class SqlFilter
|
26
|
+
|
27
|
+
include SqlFilterAttributes
|
28
|
+
|
29
|
+
@attributes = {}
|
30
|
+
|
31
|
+
def self.attribute(*args)
|
32
|
+
options = args.delete_at(args.size-1) if args.last.is_a?(Hash)
|
33
|
+
options ||= {}
|
34
|
+
|
35
|
+
#puts "#############################"
|
36
|
+
#puts self
|
37
|
+
#puts "#############################"
|
38
|
+
|
39
|
+
for attr in args
|
40
|
+
|
41
|
+
|
42
|
+
class_method_lines = []
|
43
|
+
|
44
|
+
options[:escape] ||= true
|
45
|
+
options[:ignore_blank] ||= true
|
46
|
+
|
47
|
+
value = options[:value]
|
48
|
+
operator = options[:operator] || "="
|
49
|
+
|
50
|
+
if operator.is_a?(Array)
|
51
|
+
attr_accessor "operator_for_#{attr}"
|
52
|
+
class_method_lines << "def operator_for_#{attr}"
|
53
|
+
class_method_lines << " options = self.class.attributes[:#{attr}]"
|
54
|
+
class_method_lines << " @operator_for_#{attr} ||= options[:default_operator]"
|
55
|
+
if options[:ignore_blank]
|
56
|
+
class_method_lines << " return nil if @operator_for_#{attr}.to_s.empty?"
|
57
|
+
end
|
58
|
+
class_method_lines << " raise 'unknown operator '+@operator_for_#{attr}+' for #{attr}' unless options[:operator].include?(@operator_for_#{attr})"
|
59
|
+
class_method_lines << " @operator_for_#{attr}"
|
60
|
+
class_method_lines << "end"
|
61
|
+
|
62
|
+
else
|
63
|
+
class_method_lines << "def operator_for_#{attr}"
|
64
|
+
class_method_lines << " '#{operator.to_s.upcase}'"
|
65
|
+
class_method_lines << "end"
|
66
|
+
end
|
67
|
+
|
68
|
+
class_method_lines << "def #{attr}_to_sql"
|
69
|
+
class_method_lines << "return nil unless operator_for_#{attr}"
|
70
|
+
|
71
|
+
# wenn kein statischer Wert vorgegeben ist
|
72
|
+
unless options[:value].is_a?(String)
|
73
|
+
attr_accessor attr
|
74
|
+
# leere Werte bei Wunsch ignorieren
|
75
|
+
if options[:ignore_blank]
|
76
|
+
class_method_lines << "return nil if @#{attr}.to_s.empty?"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
right_sql = nil
|
82
|
+
if value
|
83
|
+
if value.is_a?(Array)
|
84
|
+
# eingabe überprüfen
|
85
|
+
class_method_lines << "raise 'xxx' unless self.class.attributes[:#{attr}][:value].include?(#{attr})"
|
86
|
+
right_sql = attr.to_s
|
87
|
+
else
|
88
|
+
# vorgabe einsetzen
|
89
|
+
right_sql = value.inspect
|
90
|
+
end
|
91
|
+
else
|
92
|
+
if operator==:like
|
93
|
+
right_sql = "'%'+#{attr}+'%'"
|
94
|
+
else
|
95
|
+
# nur methode aufrufen
|
96
|
+
right_sql = attr.to_s
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
field = options[:field] ? options[:field] : attr
|
101
|
+
field = field.to_s.split(".").collect{|c| "`"+c+"`"}.join "."
|
102
|
+
if options[:escape] == false
|
103
|
+
class_method_lines << " '#{field} ' + operator_for_#{attr} + " + right_sql
|
104
|
+
else
|
105
|
+
class_method_lines << " ['#{field} ' + operator_for_#{attr} + ' ?', " + right_sql + ']'
|
106
|
+
end
|
107
|
+
|
108
|
+
class_method_lines << "end"
|
109
|
+
|
110
|
+
@attributes[attr] = options
|
111
|
+
|
112
|
+
|
113
|
+
#puts class_method_lines.join "\n"
|
114
|
+
class_eval class_method_lines.join "\n"
|
115
|
+
|
116
|
+
operator = options[:operators]
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def initialize(vars=nil)
|
122
|
+
# set default values
|
123
|
+
for attr,options in self.class.attributes
|
124
|
+
instance_variable_set '@'+attr.to_s, options[:default]
|
125
|
+
end
|
126
|
+
|
127
|
+
if vars
|
128
|
+
# send input values to setter methods
|
129
|
+
for key,val in vars
|
130
|
+
send "#{key}=", val
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Build the whole conditions array
|
136
|
+
def to_a
|
137
|
+
sql = ["1"]
|
138
|
+
|
139
|
+
for key, options in self.class.attributes
|
140
|
+
val = instance_variable_get("@#{key}") || options[:default]
|
141
|
+
res = send "#{key}_to_sql"
|
142
|
+
if res.is_a?(Array)
|
143
|
+
sql[0] << " AND (#{res.shift})"
|
144
|
+
sql = sql + res
|
145
|
+
elsif res # nicht nil
|
146
|
+
sql[0] << " AND (#{res})"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
sql
|
151
|
+
end
|
152
|
+
end
|
data/sql_filter.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{sql_filter}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Corny", "Averell"]
|
9
|
+
s.date = %q{2009-02-04}
|
10
|
+
s.description = %q{sql_filter helps you to build sql-conditions from parameters and avoids sql injections.}
|
11
|
+
s.email = %q{mail@digineo.de}
|
12
|
+
s.files = %w(
|
13
|
+
MIT-LICENSE
|
14
|
+
README.rdoc
|
15
|
+
init.rb
|
16
|
+
sql_filter.gemspec
|
17
|
+
lib/sql_filter.rb
|
18
|
+
test/sql_filter_test.rb
|
19
|
+
)
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.homepage = %q{http://github.com/corny/sql_filter/tree/master}
|
22
|
+
s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
s.rubygems_version = %q{1.3.0}
|
25
|
+
s.summary = %q{sql_filter helps you to build sql-conditions from parameters and avoids sql injections.}
|
26
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.join(File.dirname(__FILE__), "../init")
|
3
|
+
|
4
|
+
class SqlFilterTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
# erwartet: nichts
|
7
|
+
class EmptyFilter < SqlFilter
|
8
|
+
end
|
9
|
+
|
10
|
+
# erwartet:
|
11
|
+
# * name
|
12
|
+
class NameFilter < SqlFilter
|
13
|
+
attribute :name, :field=>'certificate.issuer'
|
14
|
+
end
|
15
|
+
|
16
|
+
# erwartet:
|
17
|
+
# * name
|
18
|
+
class NameLikeFilter < SqlFilter
|
19
|
+
attribute :name, :operator => :like
|
20
|
+
end
|
21
|
+
|
22
|
+
# erwartet:
|
23
|
+
# * state
|
24
|
+
class OptionsFilter < SqlFilter
|
25
|
+
attribute :state, :value => %w(new open closed)
|
26
|
+
end
|
27
|
+
|
28
|
+
# erwartet:
|
29
|
+
# * operator_for_issued_at
|
30
|
+
class OperatorFilter < SqlFilter
|
31
|
+
attribute :issued_at, :operator => %w(< >), :value => "NOW()", :escape => false, :default_operator=>"<"
|
32
|
+
end
|
33
|
+
|
34
|
+
# erwartet:
|
35
|
+
# * updated_at
|
36
|
+
# * operator_for_updated_at
|
37
|
+
class OperatorValueFilter < SqlFilter
|
38
|
+
attribute :issued_at, :operator => %w(< = >)
|
39
|
+
end
|
40
|
+
|
41
|
+
# empty filter
|
42
|
+
def test_empty_filter
|
43
|
+
filter = EmptyFilter.new
|
44
|
+
# darf nicht auf :name reagieren
|
45
|
+
assert !filter.respond_to?(:name)
|
46
|
+
|
47
|
+
# Conditions muss leer sein
|
48
|
+
assert_equal ["1"], filter.to_a
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_assertion
|
52
|
+
value = 'foo bar'
|
53
|
+
|
54
|
+
filter = NameFilter.new
|
55
|
+
assert_nil filter.name
|
56
|
+
|
57
|
+
filter.name = value
|
58
|
+
assert_equal value, filter.name
|
59
|
+
|
60
|
+
filter = NameFilter.new :name => value
|
61
|
+
assert_equal value, filter.name
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_name_filter
|
65
|
+
text = 'hello world'
|
66
|
+
filter = NameFilter.new(:name => text)
|
67
|
+
|
68
|
+
# sollte auf :name reagieren
|
69
|
+
assert_respond_to filter, :name
|
70
|
+
|
71
|
+
assert_equal ["1 AND (`certificate`.`issuer` = ?)",text], filter.to_a
|
72
|
+
|
73
|
+
text = 'Test'
|
74
|
+
filter.name = text
|
75
|
+
assert_equal ["1 AND (`certificate`.`issuer` = ?)",text], filter.to_a
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_name_like_filter
|
79
|
+
filter = EmptyFilter.new
|
80
|
+
|
81
|
+
text = 'hello world'
|
82
|
+
filter = NameLikeFilter.new(:name => text)
|
83
|
+
|
84
|
+
assert_equal ["1 AND (`name` LIKE ?)","%#{text}%"], filter.to_a
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_options_filter
|
88
|
+
filter = OptionsFilter.new
|
89
|
+
|
90
|
+
# leerer wert
|
91
|
+
assert_equal ["1"], filter.to_a
|
92
|
+
|
93
|
+
filter = OptionsFilter.new(:state => 'closed')
|
94
|
+
assert_equal ["1 AND (`state` = ?)", "closed"], filter.to_a
|
95
|
+
|
96
|
+
assert_raises RuntimeError do
|
97
|
+
filter = OptionsFilter.new(:state => 'sldjfh sdkjfh oiz3 4 zr')
|
98
|
+
assert_equal ["1 AND (`state` = ?)", "sldjfh sdkjfh oiz3 4 zr"], filter.to_a
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_operator_filter
|
103
|
+
|
104
|
+
# leerer wert
|
105
|
+
filter = OperatorFilter.new
|
106
|
+
assert_equal ["1 AND (`issued_at` < ?)", "NOW()"], filter.to_a
|
107
|
+
|
108
|
+
# Gültiger Wert
|
109
|
+
filter = OperatorFilter.new(:operator_for_issued_at=>">")
|
110
|
+
assert_equal ["1 AND (`issued_at` > ?)", "NOW()"], filter.to_a
|
111
|
+
|
112
|
+
# Ungültiger Wert
|
113
|
+
assert_raises RuntimeError do
|
114
|
+
filter = OperatorFilter.new(:operator_for_issued_at=>"sddlkh234097f ")
|
115
|
+
assert_equal ["1 AND (`issued_at` < ?)", "sddlkh234097f"], filter.to_a
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_operator_value_filter
|
120
|
+
filter = OptionsFilter.new
|
121
|
+
|
122
|
+
# leerer wert
|
123
|
+
assert_equal ["1"], filter.to_a
|
124
|
+
|
125
|
+
filter = OperatorValueFilter.new(:issued_at => "NOW()", :operator_for_issued_at=>">")
|
126
|
+
assert_equal ["1 AND (`issued_at` > ?)", "NOW()"], filter.to_a
|
127
|
+
|
128
|
+
assert_raises RuntimeError do
|
129
|
+
filter = OperatorValueFilter.new(:issued_at => "NOW()", :operator_for_issued_at=>"sdfsklödf")
|
130
|
+
assert_equal ["1 AND (`issued_at` sdfsklödf ?)", "NOW()"], filter.to_a
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: corny-sql_filter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Corny
|
8
|
+
- Averell
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-02-04 00:00:00 -08:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: sql_filter helps you to build sql-conditions from parameters and avoids sql injections.
|
18
|
+
email: mail@digineo.de
|
19
|
+
executables: []
|
20
|
+
|
21
|
+
extensions: []
|
22
|
+
|
23
|
+
extra_rdoc_files: []
|
24
|
+
|
25
|
+
files:
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- init.rb
|
29
|
+
- sql_filter.gemspec
|
30
|
+
- lib/sql_filter.rb
|
31
|
+
- test/sql_filter_test.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: http://github.com/corny/sql_filter/tree/master
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options:
|
36
|
+
- --inline-source
|
37
|
+
- --charset=UTF-8
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: "0"
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
requirements: []
|
53
|
+
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.2.0
|
56
|
+
signing_key:
|
57
|
+
specification_version: 2
|
58
|
+
summary: sql_filter helps you to build sql-conditions from parameters and avoids sql injections.
|
59
|
+
test_files: []
|
60
|
+
|