corny-sql_filter 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,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.
@@ -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
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require File.join(File.dirname(__FILE__), "/lib/sql_filter")
@@ -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
@@ -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
+