arel_extensions 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +46 -0
  4. data/Gemfile +10 -0
  5. data/MIT-LICENSE.txt +20 -0
  6. data/README.md +101 -0
  7. data/Rakefile +14 -0
  8. data/arel_extensions.gemspec +32 -0
  9. data/functions.html +344 -0
  10. data/gemfiles/Gemfile.rails3 +10 -0
  11. data/gemfiles/Gemfile.rails5 +10 -0
  12. data/init/mssql.sql +6 -0
  13. data/init/mysql.sql +0 -0
  14. data/init/oracle.sql +31 -0
  15. data/init/postgresql.sql +12 -0
  16. data/init/sqlite.sql +1 -0
  17. data/lib/arel_extensions.rb +84 -0
  18. data/lib/arel_extensions/attributes.rb +26 -0
  19. data/lib/arel_extensions/comparators.rb +59 -0
  20. data/lib/arel_extensions/date_duration.rb +28 -0
  21. data/lib/arel_extensions/insert_manager.rb +33 -0
  22. data/lib/arel_extensions/math.rb +48 -0
  23. data/lib/arel_extensions/math_functions.rb +35 -0
  24. data/lib/arel_extensions/nodes.rb +27 -0
  25. data/lib/arel_extensions/nodes/abs.rb +6 -0
  26. data/lib/arel_extensions/nodes/ceil.rb +6 -0
  27. data/lib/arel_extensions/nodes/coalesce.rb +22 -0
  28. data/lib/arel_extensions/nodes/concat.rb +33 -0
  29. data/lib/arel_extensions/nodes/date_diff.rb +106 -0
  30. data/lib/arel_extensions/nodes/duration.rb +30 -0
  31. data/lib/arel_extensions/nodes/find_in_set.rb +16 -0
  32. data/lib/arel_extensions/nodes/floor.rb +6 -0
  33. data/lib/arel_extensions/nodes/function.rb +17 -0
  34. data/lib/arel_extensions/nodes/isnull.rb +30 -0
  35. data/lib/arel_extensions/nodes/length.rb +6 -0
  36. data/lib/arel_extensions/nodes/locate.rb +33 -0
  37. data/lib/arel_extensions/nodes/ltrim.rb +28 -0
  38. data/lib/arel_extensions/nodes/matches.rb +22 -0
  39. data/lib/arel_extensions/nodes/rand.rb +23 -0
  40. data/lib/arel_extensions/nodes/replace.rb +36 -0
  41. data/lib/arel_extensions/nodes/round.rb +15 -0
  42. data/lib/arel_extensions/nodes/rtrim.rb +29 -0
  43. data/lib/arel_extensions/nodes/soundex.rb +23 -0
  44. data/lib/arel_extensions/nodes/sum.rb +23 -0
  45. data/lib/arel_extensions/nodes/trim.rb +26 -0
  46. data/lib/arel_extensions/nodes/wday.rb +23 -0
  47. data/lib/arel_extensions/null_functions.rb +16 -0
  48. data/lib/arel_extensions/string_functions.rb +68 -0
  49. data/lib/arel_extensions/version.rb +4 -0
  50. data/lib/arel_extensions/visitors.rb +6 -0
  51. data/lib/arel_extensions/visitors/ibm_db.rb +206 -0
  52. data/lib/arel_extensions/visitors/mssql.rb +213 -0
  53. data/lib/arel_extensions/visitors/mysql.rb +184 -0
  54. data/lib/arel_extensions/visitors/oracle.rb +267 -0
  55. data/lib/arel_extensions/visitors/postgresql.rb +258 -0
  56. data/lib/arel_extensions/visitors/sqlite.rb +218 -0
  57. data/lib/arel_extensions/visitors/to_sql.rb +199 -0
  58. data/test/helper.rb +18 -0
  59. data/test/real_db_test.rb +251 -0
  60. data/test/support/fake_record.rb +137 -0
  61. data/test/test_comparators.rb +49 -0
  62. data/test/visitors/test_bulk_insert_oracle.rb +30 -0
  63. data/test/visitors/test_bulk_insert_sqlite.rb +31 -0
  64. data/test/visitors/test_bulk_insert_to_sql.rb +32 -0
  65. data/test/visitors/test_oracle.rb +105 -0
  66. data/test/visitors/test_to_sql.rb +148 -0
  67. data/test/with_ar/test_bulk_sqlite.rb +44 -0
  68. data/test/with_ar/test_math_sqlite.rb +59 -0
  69. data/test/with_ar/test_string_sqlite.rb +69 -0
  70. metadata +230 -0
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
7
+ # for JRuby
8
+ gem "jdbc-sqlite3", :platform => :jrubyend
9
+ gem 'activerecord', '~> 3.0'
10
+ end
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
7
+ # for JRuby
8
+ gem "jdbc-sqlite3", :platform => :jrubyend
9
+ gem 'activerecord', '~> 5.0'
10
+ end
data/init/mssql.sql ADDED
@@ -0,0 +1,6 @@
1
+ CREATE FUNCTION TRIM(@string VARCHAR(MAX))
2
+ RETURNS VARCHAR(MAX)
3
+ BEGIN
4
+ RETURN LTRIM(RTRIM(@string))
5
+ END
6
+ GO
data/init/mysql.sql ADDED
File without changes
data/init/oracle.sql ADDED
@@ -0,0 +1,31 @@
1
+ CREATE OR REPLACE FUNCTION find_in_set(
2
+ i_value IN VARCHAR2,
3
+ i_list IN VARCHAR2,
4
+ i_delim IN VARCHAR2 DEFAULT ','
5
+ ) RETURN INT DETERMINISTIC
6
+ AS
7
+ p_result INT := 0;
8
+ p_start NUMBER(5) := 1;
9
+ p_end NUMBER(5);
10
+ c_len CONSTANT NUMBER(5) := LENGTH( i_list );
11
+ c_ld CONSTANT NUMBER(5) := LENGTH( i_delim );
12
+ BEGIN
13
+ IF c_len > 0 THEN
14
+ p_end := INSTR( i_list, i_delim, p_start );
15
+ WHILE p_end > 0 LOOP
16
+ p_result := p_result + 1;
17
+ IF ( SUBSTR( i_list, p_start, p_end - p_start ) = i_value )
18
+ THEN
19
+ RETURN p_result;
20
+ END IF;
21
+ p_start := p_end + c_ld;
22
+ p_end := INSTR( i_list, i_delim, p_start );
23
+ END LOOP;
24
+ IF p_start <= c_len + 1
25
+ AND SUBSTR( i_list, p_start, c_len - p_start + 1 ) = i_value
26
+ THEN
27
+ RETURN p_result + 1;
28
+ END IF;
29
+ END IF;
30
+ RETURN 0;
31
+ END;
@@ -0,0 +1,12 @@
1
+ CREATE OR REPLACE FUNCTION public.find_in_set(n INTEGER, s TEXT)
2
+ RETURNS BOOLEAN
3
+ LANGUAGE sql
4
+ AS $function$
5
+ select bool(int4(z.row_number))
6
+ from
7
+ (
8
+ select row_number() over(), y.x
9
+ from (select unnest(('{' || $2 || '}')::int[]) as x) as y
10
+ ) as z
11
+ where z.x = $1
12
+ $function$
data/init/sqlite.sql ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,84 @@
1
+ require 'arel'
2
+
3
+ # UnaryOperation|Grouping|Extract < Unary < Arel::Nodes::Node
4
+ # Equality|Regexp|Matches < Binary < Arel::Nodes::Node
5
+ # Count|NamedFunction < Function < Arel::Nodes::Node
6
+
7
+ # pure Arel internals improvements
8
+ Arel::Nodes::Binary.class_eval do
9
+ include Arel::AliasPredication
10
+ end
11
+
12
+ Arel::Nodes::Unary.class_eval do
13
+ include Arel::Math
14
+ include Arel::AliasPredication
15
+ include Arel::Expressions
16
+ end
17
+
18
+ Arel::Nodes::Grouping.class_eval do
19
+ include Arel::Math
20
+ include Arel::AliasPredication
21
+ include Arel::Expressions
22
+ end
23
+
24
+ Arel::Nodes::Function.class_eval do
25
+ include Arel::Math
26
+ include Arel::Expressions
27
+ end
28
+
29
+ require 'arel_extensions/version'
30
+ require 'arel_extensions/attributes'
31
+ require 'arel_extensions/visitors'
32
+ require 'arel_extensions/nodes'
33
+ require 'arel_extensions/comparators'
34
+ require 'arel_extensions/date_duration'
35
+ require 'arel_extensions/null_functions'
36
+ require 'arel_extensions/math'
37
+ require 'arel_extensions/math_functions'
38
+ require 'arel_extensions/string_functions'
39
+
40
+ require 'arel_extensions/insert_manager'
41
+
42
+ module Arel
43
+ def self.rand
44
+ ArelExtensions::Nodes::Rand.new
45
+ end
46
+ end
47
+
48
+ Arel::Attributes::Attribute.class_eval do
49
+ include Arel::Math
50
+ include ArelExtensions::Attributes
51
+ end
52
+
53
+ Arel::Nodes::Function.class_eval do
54
+ include ArelExtensions::Comparators
55
+ include ArelExtensions::DateDuration
56
+ include ArelExtensions::MathFunctions
57
+ include ArelExtensions::StringFunctions
58
+ end
59
+
60
+ Arel::Nodes::Unary.class_eval do
61
+ include ArelExtensions::Math
62
+ include ArelExtensions::Attributes
63
+ include ArelExtensions::MathFunctions
64
+ include ArelExtensions::Comparators
65
+ end
66
+
67
+ Arel::Nodes::Binary.class_eval do
68
+ include ArelExtensions::Math
69
+ include ArelExtensions::Attributes
70
+ include ArelExtensions::MathFunctions
71
+ include ArelExtensions::Comparators
72
+ end
73
+
74
+ Arel::Nodes::Equality.class_eval do
75
+ include ArelExtensions::Comparators
76
+ include ArelExtensions::DateDuration
77
+ include ArelExtensions::MathFunctions
78
+ include ArelExtensions::StringFunctions
79
+ end
80
+
81
+
82
+ Arel::InsertManager.class_eval do
83
+ include ArelExtensions::InsertManager
84
+ end
@@ -0,0 +1,26 @@
1
+ require 'arel_extensions/comparators'
2
+ require 'arel_extensions/date_duration'
3
+ require 'arel_extensions/math'
4
+ require 'arel_extensions/math_functions'
5
+ require 'arel_extensions/null_functions'
6
+ require 'arel_extensions/string_functions'
7
+
8
+ module ArelExtensions
9
+ module Attributes
10
+ include ArelExtensions::Comparators
11
+ include ArelExtensions::DateDuration
12
+ include ArelExtensions::Math
13
+ include ArelExtensions::MathFunctions
14
+ include ArelExtensions::NullFunctions
15
+ include ArelExtensions::StringFunctions
16
+
17
+ def ==(other)
18
+ Arel::Nodes::Equality.new self, Arel::Nodes.build_quoted(other, self)
19
+ end
20
+
21
+ def !=(other)
22
+ Arel::Nodes::NotEqual.new self, Arel::Nodes.build_quoted(other, self)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,59 @@
1
+ module ArelExtensions
2
+ module Comparators
3
+
4
+ def >(other)
5
+ Arel::Nodes::GreaterThan.new self, Arel::Nodes.build_quoted(other, self)
6
+ end
7
+
8
+ def >=(other)
9
+ Arel::Nodes::GreaterThanOrEqual.new self, Arel::Nodes.build_quoted(other, self)
10
+ end
11
+
12
+ def <(other)
13
+ Arel::Nodes::LessThan.new self, Arel::Nodes.build_quoted(other, self)
14
+ end
15
+
16
+ def <=(other)
17
+ Arel::Nodes::LessThanOrEqual.new self, Arel::Nodes.build_quoted(other, self)
18
+ end
19
+
20
+
21
+ #REGEXP function
22
+ #Pattern matching using regular expressions
23
+ def =~(other)
24
+ # arg = self.relation.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
25
+ # if arg == :string || arg == :text
26
+ Arel::Nodes::Regexp.new self, convert_regexp(other)
27
+ # end
28
+ end
29
+
30
+ #NOT_REGEXP function
31
+ #Negation of Regexp
32
+ def !~(other)
33
+ # arg = self.relation.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
34
+ # if arg == :string || arg == :text
35
+ Arel::Nodes::NotRegexp.new self, convert_regexp(other)
36
+ # end
37
+ end
38
+
39
+ private
40
+ #Function use for not_regexp
41
+ def convert_regexp(other)
42
+ case other
43
+ when String
44
+ #Do nothing
45
+ when Regexp
46
+ other = other.source.gsub('\A','^')
47
+ other.gsub!('\Z','$')
48
+ other.gsub!('\d','[0-9]')
49
+ other.gsub!('\D','[^0-9]')
50
+ other.gsub!('\w','[0-9A-Za-z]')
51
+ other.gsub!('\W','[^A-Za-z0-9_]')
52
+ else
53
+ raise(ArgumentError)
54
+ end
55
+ Arel::Nodes.build_quoted(other, self)
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ module ArelExtensions
2
+ module DateDuration
3
+ #function returns the year (as a number) given a date value.
4
+ def year
5
+ ArelExtensions::Nodes::Duration.new "y",self
6
+ end
7
+
8
+ #function returns the month (as a number) given a date value.
9
+ def month
10
+ ArelExtensions::Nodes::Duration.new "m",self
11
+ end
12
+
13
+ #function returns the week (as a number) given a date value.
14
+ def week
15
+ ArelExtensions::Nodes::Duration.new "w",self
16
+ end
17
+
18
+ #function returns the month (as a number) given a date value.
19
+ def day
20
+ ArelExtensions::Nodes::Duration.new "d",self
21
+ end
22
+
23
+ def wday
24
+ ArelExtensions::Nodes::Wday.new self
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ require 'arel'
2
+
3
+ module ArelExtensions
4
+ module InsertManager
5
+
6
+ def bulk_insert(cols, data)
7
+ case cols.first
8
+ when String, Symbol
9
+ cols.each { |c|
10
+ @ast.columns << @ast.relation[c]
11
+ }
12
+ when Array
13
+ if String === cols.first.first
14
+ @ast.columns = cols.map {|c| [@ast.relation[c.first]] }
15
+ elsif Arel::Attributes::Attribute == cols.first.first
16
+ @ast.columns = cols
17
+ end
18
+ when NilClass
19
+ @ast.columns = @ast.relation.columns
20
+ end
21
+ self.values = BulkValues.new(@ast.columns, data)
22
+ end
23
+
24
+ class BulkValues < Arel::Nodes::Node
25
+ attr_accessor :left, :cols
26
+ def initialize(cols, values)
27
+ @left = values
28
+ @cols = cols
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,48 @@
1
+ module ArelExtensions
2
+ module Math
3
+ #function + between
4
+ #String and others (convert in string) allows you to concatenate 2 or more strings together.
5
+ #Date and integer adds or subtracts a specified time interval from a date.
6
+ def +(other)
7
+ return ArelExtensions::Nodes::Concat.new(self.expressions + [other]) if self.is_a?(ArelExtensions::Nodes::Concat)
8
+ arg = self.relation.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
9
+ if arg == :integer || arg == :decimal || arg == :float
10
+ if other.is_a?(String)
11
+ other = other.to_i
12
+ end
13
+ Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new self, other)
14
+ elsif arg == :datetime || arg == :date
15
+ ArelExtensions::Nodes::DateAdd.new [self, other]
16
+ elsif arg == :string
17
+ ArelExtensions::Nodes::Concat.new [self, other]
18
+ end
19
+ end
20
+
21
+ #function returns the time between two dates
22
+ #function returns the susbration between two int
23
+ def -(other)
24
+ arg = self.relation.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
25
+ if (arg == :date || arg == :datetime)
26
+ case other
27
+ when Arel::Attributes::Attribute
28
+ arg2 = other.relation.engine.connection.schema_cache.columns_hash(other.relation.table_name)[other.name.to_s].type
29
+ if arg2 == :date || arg2 == :datetime
30
+ ArelExtensions::Nodes::DateDiff.new self, other
31
+ else
32
+ ArelExtensions::Nodes::DateSub.new self, other
33
+ end
34
+ when Arel::Nodes::Node, DateTime, Time, String, Date
35
+ ArelExtensions::Nodes::DateDiff.new self, other
36
+ when Fixnum
37
+ ArelExtensions::Nodes::DateSub.new self, other
38
+ end
39
+ else
40
+ if other.is_a?(String)
41
+ other = other.to_i
42
+ end
43
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other))
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,35 @@
1
+ module ArelExtensions
2
+ module MathFunctions
3
+
4
+ # Abs function returns the absolute value of a number passed as argument #
5
+ def abs
6
+ ArelExtensions::Nodes::Abs.new [self]
7
+ end
8
+
9
+ # will rounded up any positive or negative decimal value within the function upwards #
10
+ def ceil
11
+ ArelExtensions::Nodes::Ceil.new [self]
12
+ end
13
+
14
+ # function rounded up any positive or negative decimal value down to the next least integer
15
+ def floor
16
+ ArelExtensions::Nodes::Floor.new [self]
17
+ end
18
+
19
+ #function that can be invoked to produce random numbers between 0 and 1
20
+ # def rand seed = nil
21
+ # ArelExtensions::Nodes::Rand.new [seed]
22
+ # end
23
+ alias_method :random, :rand
24
+
25
+ #function is used to round a numeric field to the number of decimals specified
26
+ def round precision = nil
27
+ if precision
28
+ ArelExtensions::Nodes::Round.new [self, Arel::Nodes.build_quoted(precision)]
29
+ else
30
+ ArelExtensions::Nodes::Round.new [self]
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require 'arel_extensions/nodes/function'
2
+ # Math functions
3
+ require 'arel_extensions/nodes/abs'
4
+ require 'arel_extensions/nodes/ceil'
5
+ require 'arel_extensions/nodes/floor'
6
+ require 'arel_extensions/nodes/round'
7
+ require 'arel_extensions/nodes/rand'
8
+ require 'arel_extensions/nodes/sum'
9
+
10
+ # String functions
11
+ require 'arel_extensions/nodes/concat' if Arel::VERSION.to_i < 7
12
+ require 'arel_extensions/nodes/length'
13
+ require 'arel_extensions/nodes/locate'
14
+ require 'arel_extensions/nodes/matches'
15
+ require 'arel_extensions/nodes/find_in_set'
16
+ require 'arel_extensions/nodes/replace'
17
+ require 'arel_extensions/nodes/soundex'
18
+ require 'arel_extensions/nodes/trim'
19
+ require 'arel_extensions/nodes/ltrim'
20
+ require 'arel_extensions/nodes/rtrim'
21
+
22
+
23
+ require 'arel_extensions/nodes/coalesce'
24
+ require 'arel_extensions/nodes/date_diff'
25
+ require 'arel_extensions/nodes/duration'
26
+ require 'arel_extensions/nodes/isnull'
27
+ require 'arel_extensions/nodes/wday'
@@ -0,0 +1,6 @@
1
+ module ArelExtensions
2
+ module Nodes
3
+ class Abs < Function
4
+ end
5
+ end
6
+ end