arel_extensions 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,12 +7,12 @@ group :development, :test do
7
7
  gem 'activemodel', '~> 4.0'
8
8
  gem 'activerecord', '~> 4.0'
9
9
 
10
- gem "sqlite3", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
11
- gem "mysql2", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
12
- gem "pg", :platforms => [:mri, :mingw, :x64_mingw]
10
+ gem "sqlite3", :platforms => [:mri, :mswin, :mingw]
11
+ gem "mysql2", :platforms => [:mri, :mswin, :mingw]
12
+ gem "pg", :platforms => [:mri, :mingw]
13
13
 
14
- gem "tiny_tds", :platforms => [:mri, :mingw, :x64_mingw]
15
- gem "activerecord-sqlserver-adapter", '~> 4.2.0', :platforms => [:mri, :mingw, :x64_mingw]
14
+ gem "tiny_tds", :platforms => [:mri, :mingw, :mswin]
15
+ gem "activerecord-sqlserver-adapter", '~> 4.2.0', :platforms => [:mri, :mingw, :mswin]
16
16
 
17
17
  gem 'ruby-oci8', :platforms => [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
18
18
  gem 'activerecord-oracle_enhanced-adapter', '~> 1.6.0' if ENV.has_key? 'ORACLE_HOME'
@@ -7,12 +7,12 @@ group :development, :test do
7
7
  gem 'activemodel', '~> 5'
8
8
  gem 'activerecord', '~> 5'
9
9
 
10
- gem "sqlite3", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
11
- gem "mysql2", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
12
- gem "pg", :platforms => [:mri, :mingw, :x64_mingw]
10
+ gem "sqlite3", :platforms => [:mri, :mswin, :mingw]
11
+ gem "mysql2", :platforms => [:mri, :mswin, :mingw]
12
+ gem "pg", :platforms => [:mri, :mingw]
13
13
 
14
- gem "tiny_tds", :platforms => [:mri, :mingw, :x64_mingw]
15
- # gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw, :x64_mingw]
14
+ gem "tiny_tds", :platforms => [:mri, :mingw]
15
+ # gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw]
16
16
 
17
17
  gem 'ruby-oci8', :platforms => [:mri, :mswin, :mingw] if ENV.has_key? 'ORACLE_HOME'
18
18
  gem 'activerecord-oracle_enhanced-adapter', '~> 1.7.0' if ENV.has_key? 'ORACLE_HOME'
data/init/sqlite.sql CHANGED
@@ -1 +0,0 @@
1
-
@@ -1,5 +1,7 @@
1
1
  require 'arel'
2
2
 
3
+ require 'arel_extensions/railtie' if defined?(Rails::Railtie)
4
+
3
5
  # UnaryOperation|Grouping|Extract < Unary < Arel::Nodes::Node
4
6
  # Equality|Regexp|Matches < Binary < Arel::Nodes::Node
5
7
  # Count|NamedFunction < Function < Arel::Nodes::Node
@@ -12,6 +12,16 @@ module ArelExtensions
12
12
  #Date and integer adds or subtracts a specified time interval from a date.
13
13
  def +(other)
14
14
  return ArelExtensions::Nodes::Concat.new [self, other] if self.is_a?(Arel::Nodes::Quoted)
15
+ return case self.class.return_type
16
+ when :string, :text
17
+ ArelExtensions::Nodes::Concat.new [self, other]
18
+ when :integer, :decimal, :float, :number
19
+ Arel::Nodes::Grouping.new(Arel::Nodes::Addition.new self, other)
20
+ when :date, :datetime
21
+ ArelExtensions::Nodes::DateAdd.new [self, other]
22
+ else
23
+ ArelExtensions::Nodes::Concat.new [self, other]
24
+ end if self.is_a?(ArelExtensions::Nodes::Function)
15
25
  arg = Arel::Table.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
16
26
  if arg == :integer
17
27
  other = other.to_i if other.is_a?(String)
@@ -29,6 +39,16 @@ module ArelExtensions
29
39
  #function returns the time between two dates
30
40
  #function returns the susbration between two int
31
41
  def -(other)
42
+ return case self.class.return_type
43
+ when :string, :text # ???
44
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other)) # ??
45
+ when :integer, :decimal, :float, :number
46
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other))
47
+ when :date, :datetime
48
+ ArelExtensions::Nodes::DateSub.new [self, other]
49
+ else
50
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other))
51
+ end if self.is_a?(ArelExtensions::Nodes::Function)
32
52
  arg = Arel::Table.engine.connection.schema_cache.columns_hash(self.relation.table_name)[self.name.to_s].type
33
53
  if (arg == :date || arg == :datetime)
34
54
  case other
@@ -45,8 +65,14 @@ module ArelExtensions
45
65
  ArelExtensions::Nodes::DateSub.new [self, other]
46
66
  end
47
67
  else
48
- other = Arel.sql(other) if other.is_a?(String)# Arel should accept Float & BigDecimal!
49
- Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other))
68
+ case other
69
+ when Fixnum, Float, BigDecimal
70
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, Arel.sql(other.to_s)))
71
+ when String
72
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, Arel.sql(other)))
73
+ else
74
+ Arel::Nodes::Grouping.new(Arel::Nodes::Subtraction.new(self, other))
75
+ end
50
76
  end
51
77
  end
52
78
 
@@ -1,11 +1,28 @@
1
1
  module ArelExtensions
2
2
  module Nodes
3
3
  class Coalesce < Function
4
+ include ArelExtensions::Math
5
+ attr_accessor :left_node_type
6
+
4
7
 
5
8
  def initialize expr
6
9
  tab = expr.map { |arg|
7
10
  convert_to_node(arg)
8
11
  }
12
+ case expr.first
13
+ when String
14
+ @left_node_type = :string
15
+ when Integer, Fixnum, Float
16
+ @left_node_type = :number
17
+ when ArelExtensions::Nodes::Coalesce, ArelExtensions::Nodes::Function
18
+ @left_node_type = expr.first.try(:left_node_type)
19
+ when Arel::Nodes::Node, Arel::Attributes::Attribute
20
+ @left_node_type = type_of_attribute(expr.first)
21
+ when Date
22
+ @left_node_type = :ruby_date
23
+ when DateTime, Time
24
+ @left_node_type = :ruby_time
25
+ end
9
26
  return super(tab)
10
27
  end
11
28
 
@@ -0,0 +1,21 @@
1
+ module ArelExtensions
2
+ module Nodes
3
+ class Substring < Function
4
+
5
+ def initialize expr
6
+ tab = [convert_to_node(expr[0]), convert_to_node(expr[1])]
7
+ if expr[2]
8
+ tab << convert_to_node(expr[2])
9
+ # else
10
+ # tab << expr[0].length
11
+ end
12
+ return super(tab)
13
+ end
14
+
15
+ def +(other)
16
+ return ArelExtensions::Nodes::Concat.new(self.expressions + [other])
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ require 'rails'
2
+
3
+ module ArelExtensions
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load 'arel_extensions/tasks.rb'
7
+ end
8
+ end
9
+ end
@@ -1,6 +1,7 @@
1
1
  require 'arel_extensions/nodes/concat' if Arel::VERSION.to_i < 7
2
2
  require 'arel_extensions/nodes/length'
3
3
  require 'arel_extensions/nodes/locate'
4
+ require 'arel_extensions/nodes/substring'
4
5
  require 'arel_extensions/nodes/matches'
5
6
  require 'arel_extensions/nodes/find_in_set'
6
7
  require 'arel_extensions/nodes/replace'
@@ -28,6 +29,20 @@ module ArelExtensions
28
29
  ArelExtensions::Nodes::Locate.new [self, val]
29
30
  end
30
31
 
32
+ def substring start, len = nil
33
+ ArelExtensions::Nodes::Substring.new [self, start, len]
34
+ end
35
+ def [](start, ind = nil)
36
+ start += 1 if start.is_a?(Integer)
37
+ if start.is_a?(Range)
38
+ ArelExtensions::Nodes::Substring.new [self, start.begin + 1, start.end - start.begin + 1]
39
+ elsif start.is_a?(Integer) && !ind
40
+ ArelExtensions::Nodes::Substring.new [self, start, 1]
41
+ else
42
+ ArelExtensions::Nodes::Substring.new [self, start, ind - start + 1]
43
+ end
44
+ end
45
+
31
46
  #SOUNDEX function returns a character string containing the phonetic representation of char.
32
47
  def soundex
33
48
  ArelExtensions::Nodes::Soundex.new [self]
@@ -0,0 +1,18 @@
1
+ namespace :arelextensions do
2
+ desc 'Install DB functions'
3
+ task :install_functions => :environment do
4
+ if ENV['DB'] == 'oracle' && ((defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx") || (RUBY_PLATFORM == 'java')) # not supported
5
+ @env_db = (RUBY_PLATFORM == 'java' ? "jdbc-sqlite" : 'sqlite')
6
+ else
7
+ @env_db = ENV['DB']
8
+ end
9
+ ActiveRecord::Base.establish_connection(@env_db.try(:to_sym) || (RUBY_PLATFORM == 'java' ? :"jdbc-sqlite" : :sqlite))
10
+ @cnx = ActiveRecord::Base.connection
11
+ if File.exist?("init/#{@env_db}.sql")
12
+ sql = File.read("init/#{@env_db}.sql")
13
+ unless sql.blank?
14
+ @cnx.execute(sql) rescue $stderr << "can't create functions\n"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module ArelExtensions
3
- VERSION = "0.9.5".freeze
3
+ VERSION = "0.9.6".freeze
4
4
  end
@@ -23,11 +23,11 @@ module ArelExtensions
23
23
  def visit_ArelExtensions_Nodes_DateDiff o, collector
24
24
  collector << "DAY("
25
25
  collector = visit o.left, collector
26
- collector<< ","
27
- if(o.right.is_a?(Arel::Attributes::Attribute))
26
+ collector << ","
27
+ if o.right.is_a?(Arel::Attributes::Attribute)
28
28
  collector = visit o.right, collector
29
29
  else
30
- collector<< "'#{o.right}'"
30
+ collector << "'#{o.right}'"
31
31
  end
32
32
  collector << ")"
33
33
  collector
@@ -36,17 +36,17 @@ module ArelExtensions
36
36
 
37
37
  def visit_ArelExtensions_Nodes_Duration o , collector
38
38
  #visit left for period
39
- if(o.left == "d")
39
+ if o.left == "d"
40
40
  collector << "DAY("
41
- elsif(o.left == "m")
41
+ elsif o.left == "m"
42
42
  collector << "MONTH("
43
- elsif (o.left == "w")
43
+ elsif o.left == "w"
44
44
  collector << "WEEK"
45
- elsif (o.left == "y")
45
+ elsif o.left == "y"
46
46
  collector << "YEAR("
47
47
  end
48
48
  #visit right
49
- if(o.right.is_a?(Arel::Attributes::Attribute))
49
+ if o.right.is_a?(Arel::Attributes::Attribute)
50
50
  collector = visit o.right, collector
51
51
  else
52
52
  collector << "'#{o.right}'"
@@ -56,7 +56,6 @@ module ArelExtensions
56
56
  end
57
57
 
58
58
 
59
-
60
59
  def visit_ArelExtensions_Nodes_IsNull o, collector
61
60
  collector << "COALESCE("
62
61
  collector = visit o.left, collector
@@ -66,10 +65,10 @@ module ArelExtensions
66
65
  else
67
66
  collector << "'#{o.right}'"
68
67
  end
69
- collector <<")"
68
+ collector << ")"
70
69
  collector
71
70
  end
72
71
 
73
72
  end
74
73
  end
75
- end
74
+ end
@@ -137,6 +137,21 @@ module ArelExtensions
137
137
  collector
138
138
  end
139
139
 
140
+ def visit_ArelExtensions_Nodes_Substring o, collector
141
+ collector << "SUBSTRING("
142
+ collector = visit o.expressions[0], collector
143
+ collector << Arel::Visitors::MSSQL::COMMA
144
+ collector = visit o.expressions[1], collector
145
+ collector << Arel::Visitors::MSSQL::COMMA
146
+ if !o.expressions[2]
147
+ collector = visit o.expressions[0].length, collector
148
+ else
149
+ collector = visit o.expressions[2], collector
150
+ end
151
+ collector << ")"
152
+ collector
153
+ end
154
+
140
155
  def visit_ArelExtensions_Nodes_Trim o, collector
141
156
  if o.right
142
157
  collector << "REPLACE(REPLACE(LTRIM(RTRIM(REPLACE(REPLACE("
@@ -61,7 +61,17 @@ module ArelExtensions
61
61
  collector << "COALESCE("
62
62
  o.expressions.each_with_index { |arg, i|
63
63
  collector << Arel::Visitors::Oracle::COMMA unless i == 0
64
- collector = visit arg, collector
64
+ if i > 0 && o.left_node_type == :text
65
+ if arg == ''
66
+ collector << 'empty_clob()'
67
+ else
68
+ collector << 'TO_CLOB('
69
+ collector = visit arg, collector
70
+ collector << ')'
71
+ end
72
+ else
73
+ collector = visit arg, collector
74
+ end
65
75
  }
66
76
  collector << ")"
67
77
  collector
@@ -164,6 +174,16 @@ module ArelExtensions
164
174
  collector
165
175
  end
166
176
 
177
+ def visit_ArelExtensions_Nodes_Substring o, collector
178
+ collector << "SUBSTR("
179
+ o.expressions.each_with_index { |arg, i|
180
+ collector << Arel::Visitors::Oracle::COMMA unless i == 0
181
+ collector = visit arg, collector
182
+ }
183
+ collector << ")"
184
+ collector
185
+ end
186
+
167
187
  def visit_ArelExtensions_Nodes_Trim o, collector
168
188
  collector << 'TRIM(' # BOTH
169
189
  if o.right.expr && SPECIAL_CHARS[o.right.expr]
@@ -129,6 +129,16 @@ module ArelExtensions
129
129
  collector
130
130
  end
131
131
 
132
+ def visit_ArelExtensions_Nodes_Substring o, collector
133
+ collector << "SUBSTR("
134
+ o.expressions.each_with_index { |arg, i|
135
+ collector << Arel::Visitors::PostgreSQL::COMMA unless i == 0
136
+ collector = visit arg, collector
137
+ }
138
+ collector << ")"
139
+ collector
140
+ end
141
+
132
142
  def visit_ArelExtensions_Nodes_IsNull o, collector
133
143
  collector = visit o.left, collector
134
144
  collector << ' IS NULL'
@@ -77,6 +77,16 @@ module ArelExtensions
77
77
  collector
78
78
  end
79
79
 
80
+ def visit_ArelExtensions_Nodes_Substring o, collector
81
+ collector << "SUBSTR("
82
+ o.expressions.each_with_index { |arg, i|
83
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
84
+ collector = visit arg, collector
85
+ }
86
+ collector << ")"
87
+ collector
88
+ end
89
+
80
90
  def visit_ArelExtensions_Nodes_IsNull o, collector
81
91
  collector = visit o.left, collector
82
92
  collector << ' IS NULL'
@@ -109,12 +119,40 @@ module ArelExtensions
109
119
  end
110
120
 
111
121
  def visit_ArelExtensions_Nodes_Wday o, collector
112
- collector << "strftime('%w',"
122
+ collector << "STRFTIME('%w',"
113
123
  collector = visit o.date, collector
114
124
  collector << ")"
115
125
  collector
116
126
  end
117
127
 
128
+ # CASE WHEN ROUND(3.42,1) > round(3.42) THEN round(3.42) ELSE round(3.42)-1 END
129
+ # OR CAST(3.14 AS INTEGER)
130
+ def visit_ArelExtensions_Nodes_Floor o, collector
131
+ collector << "CASE WHEN ROUND("
132
+ collector = visit o.left, collector
133
+ collector << ", 1) > ROUND("
134
+ collector = visit o.left, collector
135
+ collector << ") THEN ROUND("
136
+ collector = visit o.left, collector
137
+ collector << ") ELSE ROUND("
138
+ collector = visit o.left, collector
139
+ collector << ") - 1 END"
140
+ collector
141
+ end
142
+
143
+ def visit_ArelExtensions_Nodes_Ceil o, collector
144
+ collector << "CASE WHEN ROUND("
145
+ collector = visit o.left, collector
146
+ collector << ", 1) > ROUND("
147
+ collector = visit o.left, collector
148
+ collector << ") THEN ROUND("
149
+ collector = visit o.left, collector
150
+ collector << ") + 1 ELSE ROUND("
151
+ collector = visit o.left, collector
152
+ collector << ") END"
153
+ collector
154
+ end
155
+
118
156
  def visit_ArelExtensions_InsertManager_BulkValues o, collector
119
157
  o.left.each_with_index do |row, idx|
120
158
  collector << 'SELECT '
@@ -91,6 +91,16 @@ module ArelExtensions
91
91
  collector
92
92
  end
93
93
 
94
+ def visit_ArelExtensions_Nodes_Substring o, collector
95
+ collector << "SUBSTRING("
96
+ o.expressions.each_with_index { |arg, i|
97
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
98
+ collector = visit arg, collector
99
+ }
100
+ collector << ")"
101
+ collector
102
+ end
103
+
94
104
  def visit_ArelExtensions_Nodes_Replace o, collector
95
105
  collector << "REPLACE("
96
106
  o.expressions.each_with_index { |arg, i|
@@ -77,7 +77,7 @@ module ArelExtensions
77
77
  @lucas = User.where(:id => u.id)
78
78
  u = User.create :age => 15, :name => "Sophie", :created_at => d, :score => 20.16
79
79
  @sophie = User.where(:id => u.id)
80
- u = User.create :age => 20, :name => "Camille", :created_at => d, :score => 20.16
80
+ u = User.create :age => 20, :name => "Camille", :created_at => d, :score => -20.16
81
81
  @camille = User.where(:id => u.id)
82
82
  u = User.create :age => 21, :name => "Arthur", :created_at => d, :score => 65.62
83
83
  @arthur = User.where(:id => u.id)
@@ -115,19 +115,24 @@ module ArelExtensions
115
115
 
116
116
  def test_abs
117
117
  assert_equal 42, t(@neg, @age.abs)
118
+ assert_equal 20.16, t(@camille, @score.abs)
118
119
  assert_equal 14, t(@laure, (@age - 39).abs)
119
120
  assert_equal 28, t(@laure, (@age - 39).abs + (@age - 39).abs)
120
121
  end
121
122
 
122
123
  def test_ceil
123
- skip "Sqlite version can't load extension for ceil" if $sqlite && $load_extension_disabled
124
- assert_equal 1, t(@neg, @score.ceil)
124
+ # skip "Sqlite version can't load extension for ceil" if $sqlite && $load_extension_disabled
125
+ assert_equal 2, t(@test, @score.ceil) # 1.62
126
+ assert_equal (-20), t(@camille, @score.ceil) # -20.16
127
+ assert_equal (-20), t(@camille, (@score - 0.5).ceil) # -20.16
125
128
  assert_equal 63, t(@arthur, @age.ceil + 42)
126
129
  end
127
130
 
128
131
  def test_floor
129
- skip "Sqlite version can't load extension for floor" if $sqlite && $load_extension_disabled
132
+ # skip "Sqlite version can't load extension for floor" if $sqlite && $load_extension_disabled
130
133
  assert_equal 0, t(@neg, @score.floor)
134
+ assert_equal 1, t(@test, @score.floor) # 1.62
135
+ assert_equal (-9), t(@test, (@score - 10).floor) # 1.62
131
136
  assert_equal 42, t(@arthur, @score.floor - 23)
132
137
  end
133
138
 
@@ -185,6 +190,18 @@ module ArelExtensions
185
190
  assert_equal 5, t(@lucas, @name.locate("s"))
186
191
  end
187
192
 
193
+ def test_substring
194
+ assert_equal 'C', t(@camille, @name.substring(1, 1))
195
+ assert_equal (@env_db == 'oracle' ? nil : ''), t(@lucas, @name.substring(42))
196
+ assert_equal 'Lu', t(@lucas, @name.substring(1,2))
197
+
198
+ assert_equal 'C', t(@camille, @name[0, 1])
199
+ assert_equal 'C', t(@camille, @name[0])
200
+ assert_equal (@env_db == 'oracle' ? nil : ''), t(@lucas, @name[42])
201
+ assert_equal 'Lu', t(@lucas, @name[0,2])
202
+ assert_equal 'Lu', t(@lucas, @name[0..1])
203
+ end
204
+
188
205
  def test_find_in_set
189
206
  skip "Sqlite version can't load extension for find_in_set" if $sqlite && $load_extension_disabled
190
207
  skip "SQL Server does not know about FIND_IN_SET" if @env_db == 'mssql'
@@ -269,6 +286,12 @@ module ArelExtensions
269
286
  end
270
287
 
271
288
  def test_coalesce
289
+ assert_equal 'Camille concat', t(@camille, @name.coalesce(nil, "default") + ' concat')
290
+
291
+ assert_equal ' ', t(@myung, @comments.coalesce("Myung").coalesce('ignored'))
292
+ assert_equal 'Laure', t(@laure, @comments.coalesce("Laure"))
293
+ assert_equal '', t(@laure, @comments.coalesce(""))
294
+
272
295
  if @env_db == 'postgresql'
273
296
  assert_equal 100, t(@test, @age.coalesce(100))
274
297
  assert_equal "Camille", t(@camille, @name.coalesce(nil, "default"))