case_insensitive_arel 0.0.0 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +80 -2
- data/Rakefile +4 -5
- data/VERSION +1 -1
- data/case_insensitive_arel.gemspec +7 -8
- data/lib/case_insensitive_arel.rb +30 -24
- data/test/test_comparisons.rb +11 -11
- metadata +10 -10
data/README.rdoc
CHANGED
@@ -1,8 +1,86 @@
|
|
1
1
|
= case_insensitive_arel
|
2
2
|
|
3
|
-
|
3
|
+
If you're using Oracle or another DBMS that uses case-sensitive collation sequences, and don't want to litter your
|
4
|
+
code with snippets of proprietary case-conversion SQL, this may be the solution you're looking for.
|
4
5
|
|
5
|
-
==
|
6
|
+
== How It Works
|
7
|
+
|
8
|
+
This gem is pretty simple in its operation. Working at the Arel level, it takes +String+, +Arel_Attributes_Attribute+,
|
9
|
+
and +Arel_Attributes_String+ values, and executes a proc that is responsible for converting them into
|
10
|
+
a common format for comparison e.g. uppercase or lowercase. This proc can be overridden to do whatever you want. For
|
11
|
+
example, you might prefer to convert the values to lowercase, or use another conversion method. No problem! You can
|
12
|
+
also enable and disable the case-insensitive comparison behaviour by setting a flag, see below for details.
|
13
|
+
|
14
|
+
It's important to note that any custom SQL you create will _not_ be modified by this gem. Everything that is generated
|
15
|
+
by Arel however should be handled as you'd expect. If you find something that doesn't work the way you think it should,
|
16
|
+
please let me know.
|
17
|
+
|
18
|
+
== Examples
|
19
|
+
|
20
|
+
Here are some examples of what +case_insensitive_arel+ will do:
|
21
|
+
|
22
|
+
users.where(users[:name].eq('Steve')).to_sql
|
23
|
+
|
24
|
+
=> SELECT FROM "USERS" WHERE UPPER("USERS"."NAME") = UPPER('Steve')
|
25
|
+
|
26
|
+
users.where(users[:name].matches('Steve%')).to_sql
|
27
|
+
|
28
|
+
=> SELECT FROM "USERS" WHERE UPPER("USERS"."NAME") LIKE UPPER('Steve%')
|
29
|
+
|
30
|
+
users.where(users[:name].in(%w(Steve Barb))).to_sql
|
31
|
+
|
32
|
+
=> SELECT FROM "USERS" WHERE UPPER("USERS"."NAME") IN (UPPER('Steve'), UPPER('Barb')')
|
33
|
+
|
34
|
+
users.group(users[:name]).to_sql
|
35
|
+
|
36
|
+
=> SELECT FROM "USERS" GROUP BY UPPER("USERS"."NAME")
|
37
|
+
|
38
|
+
users.join(photos).on(users[:name].eq(photos[:name])).to_sql
|
39
|
+
|
40
|
+
=> SELECT FROM "USERS" INNER JOIN "PHOTOS" ON UPPER("USERS"."NAME") = UPPER("PHOTOS"."USER_NAME")
|
41
|
+
|
42
|
+
users.project(users[:name]).where(users[:name].eq('Steve'))
|
43
|
+
|
44
|
+
=> SELECT "USERS"."NAME" FROM "USERS" WHERE UPPER("USERS"."NAME") = UPPER('Steve')
|
45
|
+
|
46
|
+
== Customization
|
47
|
+
|
48
|
+
The following default settings can be overridden in your code as required:
|
49
|
+
|
50
|
+
Arel::CaseInsensitive.case_insensitive = false
|
51
|
+
Arel::CaseInsensitive.conversion_proc = Proc.new { |val| "UPPER(#{val})" }
|
52
|
+
|
53
|
+
These settings, which were used for the above examples, work for Oracle. You can customize the +convert_attribute+
|
54
|
+
setting to specify an alternative conversion function for your DBMS in your application. The +convert_string+ setting is
|
55
|
+
used to convert a string literal into a form that can be compared in a case-insensitive fasion to the result of what's
|
56
|
+
returned by +convert_attribute+ as the query is processed by the DBMS. Finally, the +case_insensitive+ setting can be
|
57
|
+
used to disable case-insensitive behaviour if need be.
|
58
|
+
|
59
|
+
As an example, you could add this code to your app if you wanted to use lowercase for conversions:
|
60
|
+
|
61
|
+
Arel::CaseInsensitive.conversion_proc = Proc.new { |val| "LOWER(#{val})" }
|
62
|
+
|
63
|
+
== Known Issues
|
64
|
+
|
65
|
+
=== Performance/Query Optimization
|
66
|
+
|
67
|
+
Due to the wrapping of column names with function calls, certain DBMS' optimizers may ignore indexes on those columns
|
68
|
+
that might otherwise be used for a query. If supported by your DBMS, you may be able to create a special index on
|
69
|
+
these columns to help out wih your query. As an example, Oracle supports _function-based indexes_.
|
70
|
+
|
71
|
+
For more information, please refer to your DBMS's documentation.
|
72
|
+
|
73
|
+
=== Single Connection Only
|
74
|
+
|
75
|
+
Because this implementation applies across all adapters, there may be issues with applications that use multiple
|
76
|
+
database adapters.
|
77
|
+
|
78
|
+
=== Custom SQL
|
79
|
+
|
80
|
+
Rather than risk madness, I didn't even bother trying to make this work with custom SQL. Stick with Arel and there
|
81
|
+
won't be any issues.
|
82
|
+
|
83
|
+
== Contributing
|
6
84
|
|
7
85
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
86
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
data/Rakefile
CHANGED
@@ -15,16 +15,14 @@ Jeweler::Tasks.new do |gem|
|
|
15
15
|
gem.name = "case_insensitive_arel"
|
16
16
|
gem.homepage = "http://github.com/slamotte/case_insensitive_arel"
|
17
17
|
gem.license = "MIT"
|
18
|
-
gem.summary = %Q{
|
19
|
-
gem.description =
|
20
|
-
If you're using Oracle or another DBMS that has case-insensitive collation sequences, this gem is for you.
|
21
|
-
EOF
|
18
|
+
gem.summary = %Q{Forces Arel queries to be case-insensitive}
|
19
|
+
gem.description = %Q{If you're using Oracle or another DBMS that has case-insensitive collation sequences, and you don't want to litter your database access code with case conversions, this gem is for you.}
|
22
20
|
gem.email = "steve@lexor.ca"
|
23
21
|
gem.authors = ["Steve Lamotte"]
|
24
22
|
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
25
23
|
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
26
24
|
gem.add_runtime_dependency 'arel', '>= 2.0.9'
|
27
|
-
gem.add_runtime_dependency 'activesupport'
|
25
|
+
gem.add_runtime_dependency 'activesupport', '>= 2.0.0'
|
28
26
|
end
|
29
27
|
Jeweler::RubygemsDotOrgTasks.new
|
30
28
|
|
@@ -52,4 +50,5 @@ Rake::RDocTask.new do |rdoc|
|
|
52
50
|
rdoc.title = "case_insensitive_arel #{version}"
|
53
51
|
rdoc.rdoc_files.include('README*')
|
54
52
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
rdoc.options += %w(--line-numbers --inline-source --accessor cattr_accessor)
|
55
54
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
@@ -5,13 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{case_insensitive_arel}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Steve Lamotte"]
|
12
|
-
s.date = %q{2011-03-
|
13
|
-
s.description = %q{If you're using Oracle or another DBMS that has case-insensitive collation sequences, this gem is for you.
|
14
|
-
}
|
12
|
+
s.date = %q{2011-03-19}
|
13
|
+
s.description = %q{If you're using Oracle or another DBMS that has case-insensitive collation sequences, and you don't want to litter your database access code with case conversions, this gem is for you.}
|
15
14
|
s.email = %q{steve@lexor.ca}
|
16
15
|
s.extra_rdoc_files = [
|
17
16
|
"LICENSE.txt",
|
@@ -38,7 +37,7 @@ Gem::Specification.new do |s|
|
|
38
37
|
s.licenses = ["MIT"]
|
39
38
|
s.require_paths = ["lib"]
|
40
39
|
s.rubygems_version = %q{1.3.7}
|
41
|
-
s.summary = %q{
|
40
|
+
s.summary = %q{Forces Arel queries to be case-insensitive}
|
42
41
|
s.test_files = [
|
43
42
|
"test/helper.rb",
|
44
43
|
"test/support/fake_record.rb",
|
@@ -60,7 +59,7 @@ Gem::Specification.new do |s|
|
|
60
59
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
61
60
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
62
61
|
s.add_runtime_dependency(%q<arel>, [">= 2.0.9"])
|
63
|
-
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
62
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 2.0.0"])
|
64
63
|
else
|
65
64
|
s.add_dependency(%q<arel>, [">= 2.0.9"])
|
66
65
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
@@ -69,7 +68,7 @@ Gem::Specification.new do |s|
|
|
69
68
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
70
69
|
s.add_dependency(%q<rcov>, [">= 0"])
|
71
70
|
s.add_dependency(%q<arel>, [">= 2.0.9"])
|
72
|
-
s.add_dependency(%q<activesupport>, [">= 0"])
|
71
|
+
s.add_dependency(%q<activesupport>, [">= 2.0.0"])
|
73
72
|
end
|
74
73
|
else
|
75
74
|
s.add_dependency(%q<arel>, [">= 2.0.9"])
|
@@ -79,7 +78,7 @@ Gem::Specification.new do |s|
|
|
79
78
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
80
79
|
s.add_dependency(%q<rcov>, [">= 0"])
|
81
80
|
s.add_dependency(%q<arel>, [">= 2.0.9"])
|
82
|
-
s.add_dependency(%q<activesupport>, [">= 0"])
|
81
|
+
s.add_dependency(%q<activesupport>, [">= 2.0.0"])
|
83
82
|
end
|
84
83
|
end
|
85
84
|
|
@@ -1,51 +1,57 @@
|
|
1
1
|
require 'active_support/core_ext/class/attribute_accessors'
|
2
2
|
require 'active_support/core_ext/module/aliasing'
|
3
3
|
|
4
|
-
module Arel
|
5
|
-
module Visitors
|
4
|
+
module Arel #:nodoc:
|
5
|
+
module Visitors #:nodoc: all
|
6
6
|
class ToSql
|
7
|
-
# List of Arel types that should be converted to
|
7
|
+
# List of Arel types that should be converted to make them comparable in a case-insensitive fashion
|
8
8
|
%w(Arel_Attributes_Attribute Arel_Attributes_String String).each do |arel_type_name|
|
9
|
-
convert_method = case arel_type_name
|
10
|
-
when /^Arel_Attributes_.+/
|
11
|
-
:convert_attribute
|
12
|
-
when 'String'
|
13
|
-
:convert_string
|
14
|
-
else
|
15
|
-
raise "Unexpected Arel type name: #{arel_type_name}"
|
16
|
-
end
|
17
9
|
define_method "visit_#{arel_type_name}_with_case_insensitive" do |o|
|
18
10
|
value = send("visit_#{arel_type_name}_without_case_insensitive", o)
|
19
|
-
|
11
|
+
|
12
|
+
# If the object has been tagged with
|
13
|
+
o.respond_to?(:do_not_make_case_insensitive?) ? value : Arel::CaseInsensitive.convert_value(value)
|
20
14
|
end
|
21
15
|
alias_method_chain "visit_#{arel_type_name}", :case_insensitive
|
22
16
|
end
|
23
17
|
end
|
24
18
|
end
|
25
19
|
|
20
|
+
# Controls case-insensitive comparisons. The following attributes can be set to customize behaviour.
|
26
21
|
class CaseInsensitive
|
27
|
-
|
22
|
+
# Boolean that determines whether case-insensitive processing is enabled or not. Defaults to:
|
23
|
+
# Arel::CaseInsensitive.case_insensitive = true
|
24
|
+
cattr_accessor :case_insensitive
|
25
|
+
|
26
|
+
# Proc that accepts an Arel object and converts it into something that can be compared in a case-insensitive manner. Defaults to:
|
27
|
+
# Arel::CaseInsensitive.conversion_proc = Proc.new { |val| "UPPER(#{val})" }
|
28
|
+
cattr_accessor :conversion_proc
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
private
|
31
|
+
|
32
|
+
# Return the converted value or the value itself depending on the current state of +case_insensitive+
|
33
|
+
def self.convert_value(val)
|
34
|
+
case_insensitive ? conversion_proc.call(val) : val
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
|
-
class Table
|
38
|
+
class Table # :nodoc:
|
39
|
+
# We don't want an attribute in the SELECT to be processed by the conversion proc. As such, tag +project+'s' parameters with a special
|
40
|
+
# singleton method to prevent them from being converted.
|
35
41
|
def project_with_case_insensitive(*things)
|
36
|
-
|
37
|
-
|
38
|
-
|
42
|
+
# If a +thing+ is used elsewhere (e.g. in the WHERE clause), tagging it will cause the WHERE clause to be affected as well. So create a new
|
43
|
+
# list of things and tag them instead.
|
44
|
+
new_things = things.map do |thing|
|
45
|
+
new_thing = thing.clone
|
46
|
+
def new_thing.do_not_make_case_insensitive?; end
|
39
47
|
new_thing
|
40
48
|
end
|
41
|
-
project_without_case_insensitive *
|
49
|
+
project_without_case_insensitive *new_things
|
42
50
|
end
|
43
51
|
alias_method_chain :project, :case_insensitive
|
44
52
|
end
|
45
53
|
end
|
46
54
|
|
47
|
-
# Set the default values (for Oracle)
|
55
|
+
# Set the default values (these work for Oracle)
|
48
56
|
Arel::CaseInsensitive.case_insensitive = true
|
49
|
-
Arel::CaseInsensitive.
|
50
|
-
Arel::CaseInsensitive.convert_string = Proc.new{ |val| val.upcase }
|
51
|
-
|
57
|
+
Arel::CaseInsensitive.conversion_proc = Proc.new { |val| "UPPER(#{val})" }
|
data/test/test_comparisons.rb
CHANGED
@@ -3,15 +3,15 @@ require 'helper'
|
|
3
3
|
class TestComparisons < Test::Unit::TestCase
|
4
4
|
should "work correctly in case-insensitive mode" do
|
5
5
|
Arel::CaseInsensitive.case_insensitive = true
|
6
|
-
should_be_like @users.where(@users[:name].eq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") = '
|
7
|
-
should_be_like @users.where(@users[:name].not_eq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") != '
|
8
|
-
should_be_like @users.where(@users[:name].matches('Ste%')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") LIKE '
|
9
|
-
should_be_like @users.where(@users[:name].does_not_match('Ste%')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") NOT LIKE '
|
6
|
+
should_be_like @users.where(@users[:name].eq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") = UPPER('Steve')"
|
7
|
+
should_be_like @users.where(@users[:name].not_eq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") != UPPER('Steve')"
|
8
|
+
should_be_like @users.where(@users[:name].matches('Ste%')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") LIKE UPPER('Ste%')"
|
9
|
+
should_be_like @users.where(@users[:name].does_not_match('Ste%')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") NOT LIKE UPPER('Ste%')"
|
10
10
|
should_be_like @users.where(@users[:name].eq(@users[:name])).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") = UPPER(\"users\".\"name\")"
|
11
|
-
should_be_like @users.where(@users[:name].gteq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") >= '
|
12
|
-
should_be_like @users.where(@users[:name].in(
|
13
|
-
should_be_like @users.where(@users[:name].not_in(
|
14
|
-
should_be_like @users.where(@users[:name].matches_any(
|
11
|
+
should_be_like @users.where(@users[:name].gteq('Steve')).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") >= UPPER('Steve')"
|
12
|
+
should_be_like @users.where(@users[:name].in(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") IN (UPPER('Steve'), UPPER('Barb'))"
|
13
|
+
should_be_like @users.where(@users[:name].not_in(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE UPPER(\"users\".\"name\") NOT IN (UPPER('Steve'), UPPER('Barb'))"
|
14
|
+
should_be_like @users.where(@users[:name].matches_any(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE (UPPER(\"users\".\"name\") LIKE UPPER('Steve') OR UPPER(\"users\".\"name\") LIKE UPPER('Barb'))"
|
15
15
|
end
|
16
16
|
|
17
17
|
should "work correctly in case-sensitive mode" do
|
@@ -22,8 +22,8 @@ class TestComparisons < Test::Unit::TestCase
|
|
22
22
|
should_be_like @users.where(@users[:name].does_not_match('Ste%')).to_sql, "SELECT FROM \"users\" WHERE \"users\".\"name\" NOT LIKE 'Ste%'"
|
23
23
|
should_be_like @users.where(@users[:name].eq(@users[:name])).to_sql, "SELECT FROM \"users\" WHERE \"users\".\"name\" = \"users\".\"name\""
|
24
24
|
should_be_like @users.where(@users[:name].gteq('Steve')).to_sql, "SELECT FROM \"users\" WHERE \"users\".\"name\" >= 'Steve'"
|
25
|
-
should_be_like @users.where(@users[:name].in(
|
26
|
-
should_be_like @users.where(@users[:name].not_in(
|
27
|
-
should_be_like @users.where(@users[:name].matches_any(
|
25
|
+
should_be_like @users.where(@users[:name].in(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE \"users\".\"name\" IN ('Steve', 'Barb')"
|
26
|
+
should_be_like @users.where(@users[:name].not_in(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE \"users\".\"name\" NOT IN ('Steve', 'Barb')"
|
27
|
+
should_be_like @users.where(@users[:name].matches_any(%w(Steve Barb))).to_sql, "SELECT FROM \"users\" WHERE (\"users\".\"name\" LIKE 'Steve' OR \"users\".\"name\" LIKE 'Barb')"
|
28
28
|
end
|
29
29
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: case_insensitive_arel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.0
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Steve Lamotte
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-19 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -134,15 +134,15 @@ dependencies:
|
|
134
134
|
requirements:
|
135
135
|
- - ">="
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
hash:
|
137
|
+
hash: 15
|
138
138
|
segments:
|
139
|
+
- 2
|
139
140
|
- 0
|
140
|
-
|
141
|
+
- 0
|
142
|
+
version: 2.0.0
|
141
143
|
requirement: *id008
|
142
144
|
type: :runtime
|
143
|
-
description:
|
144
|
-
If you're using Oracle or another DBMS that has case-insensitive collation sequences, this gem is for you.
|
145
|
-
|
145
|
+
description: If you're using Oracle or another DBMS that has case-insensitive collation sequences, and you don't want to litter your database access code with case conversions, this gem is for you.
|
146
146
|
email: steve@lexor.ca
|
147
147
|
executables: []
|
148
148
|
|
@@ -200,7 +200,7 @@ rubyforge_project:
|
|
200
200
|
rubygems_version: 1.3.7
|
201
201
|
signing_key:
|
202
202
|
specification_version: 3
|
203
|
-
summary:
|
203
|
+
summary: Forces Arel queries to be case-insensitive
|
204
204
|
test_files:
|
205
205
|
- test/helper.rb
|
206
206
|
- test/support/fake_record.rb
|