arel_extensions 0.8.0

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.
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