arel_extensions 0.8.7 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8d7cc16253e73e976d81b8beb558c2041c2915f
4
- data.tar.gz: 7ff4c6640d063ef79b6ada768ae7b57cb9bf4dd4
3
+ metadata.gz: d3be3f3b4a82f0721265a42e8ae75fe66da12ba3
4
+ data.tar.gz: a1660c2b64388e6e56bf442de63504da32c2c5ca
5
5
  SHA512:
6
- metadata.gz: 2b2748e84a31a944bc2a835036ff81be4528d3a85940ea34ee6d65389bf86c5c67230ec7dea7c726375395733da138cfd80920463475a54c4e97abc024f3cd76
7
- data.tar.gz: 7779b7ef80ab54c3f08e1bf3016d0e9311393576f18be74d5795d7e86d8fc1390afaf12f6d9271cb47e0a5a6e57e947eafb204d9a06ddae5ae9dae04bf278c9f
6
+ metadata.gz: 4465b08c98214889ca8be08d437a49deeb59df7de899095bcb4c4a7e7ff5d11c8c1cf50a7f8961d0f73b39b5ba0da2db36cfadd3fda4a4e8ee2eaacdc5251978
7
+ data.tar.gz: 5781edd20996ca251937563e1fa15a6fa453a250654aa8191fade92b56970edcb205fe1f5cb37659cbd80460451d0cac858a32f8733919aa6b29bf26640eb519
data/.travis.yml CHANGED
@@ -89,6 +89,10 @@ matrix:
89
89
  - rvm: ruby-head
90
90
  gemfile: gemfiles/rails4.gemfile
91
91
  allow_failures:
92
+ - rvm: rbx-2
93
+ gemfile: gemfiles/rails4.gemfile
94
+ - rvm: rbx-2
95
+ gemfile: gemfiles/rails5.gemfile
92
96
  - rvm: jruby-9.0.5.0
93
97
  gemfile: gemfiles/rails5.gemfile
94
98
  - rvm: jruby-head
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- group :test do
5
+ group :development, :test do
6
6
  gem "sqlite3", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
7
7
  gem "mysql2", :platforms => [:mri, :mswin, :mingw, :x64_mingw]
8
8
  gem "pg", :platforms => [:mri, :mingw, :x64_mingw]
@@ -13,7 +13,7 @@ group :test do
13
13
  gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby
14
14
 
15
15
  gem "tiny_tds", :platforms => [:mri, :mingw, :x64_mingw]
16
- gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw, :x64_mingw]
16
+ gem "activerecord-sqlserver-adapter", '~> 4.2.0', :platforms => [:mri, :mingw, :x64_mingw]
17
17
 
18
18
  gem 'activesupport', '~> 4.0'
19
19
  gem 'activemodel', '~> 4.0'
data/SQL_Challenges.md ADDED
@@ -0,0 +1,29 @@
1
+ # SQL Challenges
2
+
3
+ It should be possible to do any advanced SQL functions of any RDBMS in any other using classical SQL routines. We hope so.
4
+ But here are some of the features we did not succeed to create in some cases. Any help would be very useful.
5
+ A good way could be to create user defined functions to ensure a total transparent compatibility and to encapsulate these improvements.
6
+
7
+
8
+ ## SQLite (without extension)
9
+ - CEIL and FLOOR without pcre
10
+ - FIND_IN_SET
11
+ - LOCATE
12
+ - REGEXP
13
+ - SOUNDEX
14
+
15
+ ## PostgreSQL (without extension)
16
+ - SOUNDEX
17
+
18
+
19
+ ## Oracle
20
+ - Maths Operators on string ('a' <= 'b')
21
+
22
+
23
+ ## SQL Server (any version > 2005, without extension)
24
+ - REGEXP
25
+ - (L/R)TRIM(str, 'x') -> TRIM with arguments
26
+ - Maths Operators on string ('a' <= 'b')
27
+ - GROUP_CONCAT
28
+ - FIND_IN_SET
29
+ - any date format (YYYY/MM/DD HH:MM:SS:MMM for example)
@@ -1,27 +1,27 @@
1
1
  # # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
- # require "arel_extensions"
3
+ require "arel_extensions/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "arel_extensions"
7
- s.version = '0.8.7'
7
+ s.version = ArelExtensions::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Yann Azoury", "Mathilde Pechdimaldjian", "Félix Bellanger"]
10
10
  s.email = ["yann.azoury@faveod.com", "mathilde.pechdimaldjian@gmail.com", "felix.bellanger@faveod.com"]
11
11
  s.homepage = "https://github.com/Faveod/arel-extensions"
12
12
  s.description = "Adds new features to Arel"
13
13
  s.summary = "Extending Arel"
14
- s.license = %q{MIT}
14
+ s.license = 'MIT'
15
15
 
16
16
  s.rdoc_options = ["--main", "README.md"]
17
- s.extra_rdoc_files = ["MIT-LICENSE.txt", "README.md"]
17
+ s.extra_rdoc_files = ["MIT-LICENSE.txt", "README.md", 'functions.html']
18
18
 
19
19
  # Manifest
20
20
  s.files = `git ls-files`.split("\n")
21
21
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
22
  s.require_paths = ["lib"]
23
23
 
24
- s.add_dependency('arel', '~> 6.0')
24
+ s.add_dependency('arel', '>= 6.0')
25
25
 
26
26
  s.add_development_dependency('minitest', '~> 5.9')
27
27
  s.add_development_dependency('rdoc', '~> 4.0')
data/functions.html CHANGED
@@ -199,7 +199,7 @@
199
199
  <td class="tg-j6lv">TRIM()<br></td>
200
200
  <td class="tg-j6lv">TRIM()</td>
201
201
  <td class="tg-baqh">✔</td>
202
- <td class="tg-baqh">✔</td>
202
+ <td class="tg-baqh">LTRIM(RTRIM())</td>
203
203
  <td class="tg-j6lv">TRIM()</td>
204
204
  </tr>
205
205
  <tr>
@@ -12,7 +12,7 @@ group :development, :test do
12
12
  gem "pg", :platforms => [:mri, :mingw, :x64_mingw]
13
13
 
14
14
  gem "tiny_tds", :platforms => [:mri, :mingw, :x64_mingw]
15
- gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw, :x64_mingw]
15
+ gem "activerecord-sqlserver-adapter", '~> 4.2.0', :platforms => [:mri, :mingw, :x64_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.6.0' if ENV.has_key? 'ORACLE_HOME'
data/init/mssql.sql CHANGED
@@ -1,6 +1,44 @@
1
- CREATE FUNCTION TRIM(@string VARCHAR(MAX))
1
+ IF OBJECT_ID (N'dbo.TRIM', N'FN') IS NOT NULL
2
+ DROP FUNCTION dbo.TRIM;
3
+ GO
4
+ CREATE FUNCTION dbo.TRIM (@string VARCHAR(MAX))
2
5
  RETURNS VARCHAR(MAX)
6
+ AS
3
7
  BEGIN
4
- RETURN LTRIM(RTRIM(@string))
5
- END
8
+ RETURN LTRIM(RTRIM(@string));
9
+ END;
10
+ GO
11
+
12
+ -----------------------------
13
+ -- GO
14
+
15
+ IF OBJECT_ID (N'dbo.FIND_IN_SET', N'FN') IS NOT NULL
16
+ DROP FUNCTION dbo.FIND_IN_SET;
6
17
  GO
18
+ -- CREATE FUNCTION dbo.FIND_IN_SET(@value VARCHAR(MAX), @list VARCHAR(MAX), @delim VARCHAR(MAX))
19
+ -- RETURNS VARCHAR(MAX)
20
+ -- AS BEGIN
21
+ -- RETURN LTRIM(RTRIM(@value));
22
+ -- END;
23
+
24
+ -- GO
25
+
26
+ --IF OBJECT_ID (N'dbo.SplitString', N'FN') IS NOT NULL
27
+ -- DROP FUNCTION dbo.SplitString;
28
+ --GO
29
+ --CREATE FUNCTION dbo.SplitString (@List NVARCHAR(MAX), @Delim VARCHAR(255))
30
+ --RETURNS TABLE
31
+ --AS
32
+ --BEGIN
33
+ -- RETURN ( SELECT [Value] FROM
34
+ -- (
35
+ -- SELECT
36
+ -- [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
37
+ -- CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
38
+ -- FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
39
+ -- FROM sys.all_objects) AS x
40
+ -- WHERE Number <= LEN(@List)
41
+ -- AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
42
+ -- ) AS y
43
+ -- );
44
+ --END;
@@ -4,7 +4,8 @@ module ArelExtensions
4
4
  @@return_type = :boolean
5
5
 
6
6
  def initialize expr
7
- super [expr.first.coalesce('').trim.trim("\t").trim("\n")]
7
+ # super [expr.first.coalesce('').trim.trim("\t").trim("\n")]
8
+ super expr
8
9
  end
9
10
  end
10
11
  end
@@ -90,8 +90,32 @@ module ArelExtensions
90
90
  elsif @date_type == :datetime
91
91
  Arel.sql("INTERVAL '%s' SECOND" % v.to_i)
92
92
  end
93
- # elsif Arel::Attributes::Attribute === v
94
- # v
93
+ else
94
+ v
95
+ end
96
+ end
97
+
98
+ def mssql_value(v = nil)
99
+ v ||= self.expressions.last
100
+ if defined?(ActiveSupport::Duration) && ActiveSupport::Duration === v
101
+ if @date_type == :date
102
+ v.inspect.to_i
103
+ elsif @date_type == :datetime
104
+ v.to_i
105
+ end
106
+ else
107
+ v
108
+ end
109
+ end
110
+
111
+ def mssql_datepart(v = nil)
112
+ v ||= self.expressions.last
113
+ if defined?(ActiveSupport::Duration) && ActiveSupport::Duration === v
114
+ if @date_type == :date
115
+ Arel.sql('day')
116
+ elsif @date_type == :datetime
117
+ Arel.sql('second')
118
+ end
95
119
  else
96
120
  v
97
121
  end
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module ArelExtensions
3
- VERSION = "0.8.7".freeze
3
+ VERSION = "0.9.0".freeze
4
4
  end
@@ -3,4 +3,21 @@ require 'arel_extensions/visitors/mysql'
3
3
  require 'arel_extensions/visitors/oracle'
4
4
  require 'arel_extensions/visitors/postgresql'
5
5
  require 'arel_extensions/visitors/sqlite'
6
- require 'arel_extensions/visitors/mssql'
6
+ require 'arel_extensions/visitors/mssql'
7
+
8
+ Arel::Visitors::MSSQL.class_eval do
9
+ include ArelExtensions::Visitors::MSSQL
10
+ end
11
+
12
+ begin
13
+ require 'arel_sqlserver'
14
+ if Arel::VERSION.to_i == 6
15
+ if Arel::Visitors::VISITORS['sqlserver'] && Arel::Visitors::VISITORS['sqlserver'] != Arel::Visitors::MSSQL
16
+ Arel::Visitors::VISITORS['sqlserver'].class_eval do
17
+ include ArelExtensions::Visitors::MSSQL
18
+ end
19
+ end
20
+ end
21
+ rescue LoadError
22
+ rescue => e
23
+ end
@@ -1,12 +1,25 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::MSSQL.class_eval do
3
+ module MSSQL
4
+ Arel::Visitors::MSSQL::DATE_MAPPING = {'d' => 'day', 'm' => 'month', 'y' => 'year', 'wd' => 'weekday', 'w' => 'week'}
4
5
  Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES = {
5
- '%Y' => 'yy', '%C' => '', '%y' => 'yy', '%m' => 'mm', '%B' => '', '%b' => '', '%^b' => '', # year, month
6
- '%d' => 'dd', '%e' => '', '%j' => '', '%w' => 'dw', '%A' => '', # day, weekday
6
+ '%Y' => 'YYYY', '%C' => '', '%y' => 'YY', '%m' => 'MM', '%B' => '', '%b' => '', '%^b' => '', # year, month
7
+ '%d' => 'DD', '%e' => '', '%j' => '', '%w' => 'dw', '%A' => '', # day, weekday
7
8
  '%H' => 'hh', '%k' => '', '%I' => '', '%l' => '', '%P' => '', '%p' => '', # hours
8
9
  '%M' => 'mi', '%S' => 'ss', '%L' => 'ms', '%N' => 'ns', '%z' => 'tz'
9
10
  }
11
+ # TODO all others... http://www.sql-server-helper.com/tips/date-formats.aspx
12
+ Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS = {
13
+ 'YYYY-MM-DD' => 120,
14
+ 'YY-MM-DD' => 120,
15
+ 'MM/DD/YYYY' => 101,
16
+ 'MM-DD-YYYY' => 110,
17
+ 'YYYY/MM/DD' => 111,
18
+ 'DD-MM-YYYY' => 105,
19
+ 'DD-MM-YY' => 5,
20
+ 'DD.MM.YYYY' => 104,
21
+ 'YYYY-MM-DDTHH:MM:SS:MMM' => 126
22
+ }
10
23
 
11
24
  # Math Functions
12
25
  def visit_ArelExtensions_Nodes_Ceil o, collector
@@ -16,7 +29,16 @@ module ArelExtensions
16
29
  collector
17
30
  end
18
31
 
19
- def visit_ArelExtensions_Nodes_Concat o, collector
32
+ def visit_ArelExtensions_Nodes_IsNull o, collector
33
+ collector << "("
34
+ collector = visit o.left, collector
35
+ # collector << Arel::Visitors::MSSQL::COMMA
36
+ collector << " IS NULL)"
37
+ collector
38
+ end
39
+
40
+ # Deprecated
41
+ def visit_ArelExtensions_Nodes_ConcatOld o, collector
20
42
  arg = o.left.relation.engine.columns.find{|c| c.name == o.left.name.to_s}.type
21
43
  if(o.right.is_a?(Arel::Attributes::Attribute))
22
44
  collector = visit o.left, collector
@@ -24,7 +46,10 @@ module ArelExtensions
24
46
  collector = visit o.right, collector
25
47
  collector
26
48
  elsif ( arg == :date || arg == :datetime)
27
- collector << "DATEADD(day,#{o.right},"
49
+ collector << "DATEADD(day"
50
+ collector << Arel::Visitors::MSSQL::COMMA
51
+ collector = visit o.right, collector
52
+ collector << Arel::Visitors::MSSQL::COMMA
28
53
  collector = visit o.left, collector
29
54
  collector
30
55
  else
@@ -35,8 +60,19 @@ module ArelExtensions
35
60
  end
36
61
  end
37
62
 
63
+ def visit_ArelExtensions_Nodes_Concat o, collector
64
+ collector << "CONCAT("
65
+ o.expressions.each_with_index { |arg, i|
66
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
67
+ collector = visit arg, collector
68
+ }
69
+ collector << ")"
70
+ collector
71
+ end
72
+
38
73
  def visit_ArelExtensions_Nodes_DateDiff o, collector
39
- collector << "DATEDIFF(day,"
74
+ collector << "DATEDIFF(day"
75
+ collector << Arel::Visitors::MSSQL::COMMA
40
76
  collector = visit o.left, collector
41
77
  collector << Arel::Visitors::MSSQL::COMMA
42
78
  collector = visit o.right, collector
@@ -44,94 +80,190 @@ module ArelExtensions
44
80
  collector
45
81
  end
46
82
 
83
+ def visit_ArelExtensions_Nodes_DateAdd o, collector
84
+ collector << "DATEADD("
85
+ collector << o.mssql_datepart(o.right)
86
+ collector << Arel::Visitors::MSSQL::COMMA
87
+ collector = visit o.mssql_value(o.right), collector
88
+ collector << Arel::Visitors::MSSQL::COMMA
89
+ collector = visit o.left, collector
90
+ collector << ")"
91
+ collector
92
+ end
47
93
 
48
94
  def visit_ArelExtensions_Nodes_Duration o, collector
49
- #visit left for period
50
- if(o.left == "d")
51
- collector << "DAY("
52
- elsif(o.left == "m")
53
- collector << "MONTH("
54
- elsif (o.left == "w")
55
- collector << "WEEK"
56
- elsif (o.left == "y")
57
- collector << "YEAR("
58
- end
59
- #visit right
95
+ collector << 'DATEPART('
96
+ collector << Arel::Visitors::MSSQL::DATE_MAPPING[o.left]
97
+ collector << Arel::Visitors::MSSQL::COMMA
60
98
  collector = visit o.right, collector
61
99
  collector << ")"
62
100
  collector
63
101
  end
64
102
 
65
- def visit_ArelExtensions_Nodes_Length o, collector
66
- collector << "LEN("
67
- collector = visit o.expr, collector
68
- collector << ")"
69
- collector
70
- end
103
+ def visit_ArelExtensions_Nodes_Length o, collector
104
+ collector << "LEN("
105
+ collector = visit o.expr, collector
106
+ collector << ")"
107
+ collector
108
+ end
71
109
 
110
+ def visit_ArelExtensions_Nodes_Round o, collector
111
+ collector << "ROUND("
112
+ o.expressions.each_with_index { |arg, i|
113
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
114
+ collector = visit arg, collector
115
+ }
116
+ if o.expressions.length == 1
117
+ collector << Arel::Visitors::MSSQL::COMMA
118
+ collector << "0"
119
+ end
120
+ collector << ")"
121
+ collector
122
+ end
72
123
 
73
124
  def visit_ArelExtensions_Nodes_Locate o, collector
74
125
  collector << "CHARINDEX("
75
- collector = visit o.val, collector
126
+ collector = visit o.right, collector
76
127
  collector << Arel::Visitors::MSSQL::COMMA
77
- collector = visit o.expr, collector
128
+ collector = visit o.left, collector
78
129
  collector << ")"
79
130
  collector
80
131
  end
81
132
 
82
- def visit_ArelExtensions_Nodes_Format o, collector
83
- collector << "CONCAT("
133
+ # TODO manage 2nd argument
134
+ def visit_ArelExtensions_Nodes_Trim o, collector
135
+ collector << "LTRIM(RTRIM("
136
+ collector = visit o.left, collector
137
+ collector << "))"
138
+ collector
139
+ end
140
+
141
+ # TODO manage 2nd argument
142
+ def visit_ArelExtensions_Nodes_Ltrim o, collector
143
+ collector << "LTRIM("
144
+ collector = visit o.left, collector
145
+ collector << ")"
146
+ collector
147
+ end
148
+
149
+ # TODO manage 2nd argument
150
+ def visit_ArelExtensions_Nodes_Rtrim o, collector
151
+ collector << "RTRIM("
152
+ collector = visit o.left, collector
153
+ collector << ")"
154
+ collector
155
+ end
84
156
 
85
- t = o.iso_format.split('%')
86
- t.each_with_index {|str, i|
87
- if i == 0 && f[0] != '%'
88
- collector = visit Arel::Nodes.build_quoted(str), collector
89
- elsif str.length > 0
90
- if !Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]].blank?
91
- collector << 'DATEPART('
92
- collector << Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]]
93
- collector << Arel::Visitors::MSSQL::COMMA
94
- collector = visit o.left, collector
95
- collector << ')'
157
+ def visit_ArelExtensions_Nodes_Blank o, collector
158
+ collector << 'CASE WHEN LEN(LTRIM(RTRIM(ISNULL('
159
+ collector = visit o.left, collector
160
+ collector << ", '')))) = 0 THEN 1 ELSE 0 END"
161
+ collector
162
+ end
163
+
164
+ def visit_ArelExtensions_Nodes_Format o, collector
165
+ f = o.iso_format.dup
166
+ Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES.each { |d, r| f.gsub!(d, r) }
167
+ if Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS[f]
168
+ collector << "CONVERT(VARCHAR(#{f.length})"
169
+ collector << Arel::Visitors::MSSQL::COMMA
170
+ collector = visit o.left, collector
171
+ collector << Arel::Visitors::MSSQL::COMMA
172
+ collector << Arel::Visitors::MSSQL::DATE_CONVERT_FORMATS[f].to_s
173
+ collector << ')'
174
+ collector
175
+ else
176
+ collector << "("
177
+ t = o.iso_format.split('%')
178
+ t.each_with_index {|str, i|
179
+ if i == 0 && t[0] != '%'
180
+ collector = visit Arel::Nodes.build_quoted(str), collector
96
181
  if str.length > 1
97
182
  collector << Arel::Visitors::MSSQL::COMMA
98
183
  collector = visit Arel::Nodes.build_quoted(str.sub(/\A./, '')), collector
99
184
  end
185
+ elsif str.length > 0
186
+ if !Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]].blank?
187
+ collector << 'LTRIM(STR(DATEPART('
188
+ collector << Arel::Visitors::MSSQL::DATE_FORMAT_DIRECTIVES['%' + str[0]]
189
+ collector << Arel::Visitors::MSSQL::COMMA
190
+ collector = visit o.left, collector
191
+ collector << ')))'
192
+ if str.length > 1
193
+ collector << ' + '
194
+ collector = visit Arel::Nodes.build_quoted(str.sub(/\A./, '')), collector
195
+ end
196
+ end
100
197
  end
101
- end
102
- collector << Arel::Visitors::MSSQL::COMMA unless i < (t.length - 1)
103
- }
198
+ collector << ' + ' if t[i + 1]
199
+ }
104
200
 
105
- collector << ")"
106
- collector
201
+ collector << ')'
202
+ collector
203
+ end
107
204
  end
108
205
 
109
206
  def visit_ArelExtensions_Nodes_Replace o, collector
110
207
  collector << "REPLACE("
111
- collector = visit o.expr,collector
112
- collector << Arel::Visitors::MSSQL::COMMA
113
- collector = visit o.left, collector
114
-
115
- collector << Arel::Visitors::MSSQL::COMMA
116
- collector = visit o.right, collector
208
+ o.expressions.each_with_index { |arg, i|
209
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
210
+ collector = visit arg, collector
211
+ }
117
212
  collector << ")"
118
213
  collector
119
214
  end
120
215
 
121
216
 
217
+ # TODO manage case insensitivity
218
+ def visit_ArelExtensions_Nodes_IMatches o, collector
219
+ collector = infix_value o, collector, ' LIKE '
220
+ if o.escape
221
+ collector << ' ESCAPE '
222
+ visit o.escape, collector
223
+ else
224
+ collector
225
+ end
226
+ end
227
+
228
+ # TODO manage case insensitivity
229
+ def visit_ArelExtensions_Nodes_IDoesNotMatch o, collector
230
+ collector = infix_value o, collector, ' NOT LIKE '
231
+ if o.escape
232
+ collector << ' ESCAPE '
233
+ collector = visit o.escape, collector
234
+ end
235
+ collector
236
+ end
237
+
122
238
  # SQL Server does not know about REGEXP
123
239
  def visit_Arel_Nodes_Regexp o, collector
124
240
  collector = visit o.left, collector
125
- collector << "LIKE '% #{o.right}%'"
241
+ collector << "LIKE '%#{o.right}%'"
126
242
  collector
127
243
  end
128
244
 
129
245
  def visit_Arel_Nodes_NotRegexp o, collector
130
246
  collector = visit o.left, collector
131
- collector << "NOT LIKE '% #{o.right}%'"
247
+ collector << "NOT LIKE '%#{o.right}%'"
132
248
  collector
133
249
  end
134
250
 
251
+ # TODO
252
+ def visit_ArelExtensions_Nodes_GroupConcat o, collector
253
+ collector << "(LISTAGG("
254
+ collector = visit o.left, collector
255
+ if o.right
256
+ collector << Arel::Visitors::Oracle::COMMA
257
+ collector = visit o.right, collector
258
+ end
259
+ collector << ") WITHIN GROUP (ORDER BY "
260
+ collector = visit o.left, collector
261
+ collector << "))"
262
+ collector
263
+ end
264
+
265
+
266
+
135
267
  end
136
268
  end
137
- end
269
+ end
@@ -153,9 +153,11 @@ module ArelExtensions
153
153
  end
154
154
 
155
155
  def visit_ArelExtensions_Nodes_Blank o, collector
156
- collector << '('
156
+ collector << 'LENGTH(TRIM(COALESCE('
157
157
  collector = visit o.left, collector
158
- collector << " = '')"
158
+ collector << Arel::Visitors::ToSql::COMMA
159
+ collector = visit Arel::Nodes.build_quoted(''), collector
160
+ collector << "))) = 0"
159
161
  collector
160
162
  end
161
163
 
@@ -271,7 +273,7 @@ module ArelExtensions
271
273
  collector << "DATE_ADD("
272
274
  collector = visit o.left, collector
273
275
  collector << Arel::Visitors::ToSql::COMMA
274
- collector = visit o.right, collector
276
+ collector = visit o.sqlite_value(o.right), collector
275
277
  collector << ")"
276
278
  collector
277
279
  end
data/test/database.yml CHANGED
@@ -3,7 +3,7 @@ sqlite:
3
3
  database: ":memory:"
4
4
  timeout: 500
5
5
  jdbc-sqlite:
6
- adapter: jdbcsqlite3
6
+ adapter: jdbcsqlite3
7
7
  database: ":memory:"
8
8
  timeout: 500
9
9
  mysql:
@@ -41,7 +41,6 @@ ibm_db:
41
41
  mssql:
42
42
  adapter: sqlserver
43
43
  host: localhost
44
- dataserver: localhost\SQL2014
45
44
  database: master
46
45
  username: sa
47
46
  password: Password12!
@@ -45,6 +45,10 @@ module FakeRecord
45
45
  @tables.include? name.to_s
46
46
  end
47
47
 
48
+ def data_source_exists? name
49
+ @tables.include? name.to_s
50
+ end
51
+
48
52
  def columns name, message = nil
49
53
  @columns[name.to_s]
50
54
  end
@@ -110,6 +114,10 @@ module FakeRecord
110
114
  connection.tables.include? name.to_s
111
115
  end
112
116
 
117
+ def data_source_exists? name
118
+ connection.tables.include? name.to_s
119
+ end
120
+
113
121
  def columns_hash
114
122
  connection.columns_hash
115
123
  end
@@ -5,6 +5,7 @@ module ArelExtensions
5
5
  module WthAr
6
6
 
7
7
  class ListTest < Minitest::Test
8
+ require 'minitest/pride'
8
9
  def setup_db
9
10
  ActiveRecord::Base.configurations = YAML.load_file('test/database.yml')
10
11
  if ENV['DB'] == 'oracle' && ((defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx") || (RUBY_PLATFORM == 'java')) # not supported
@@ -39,7 +40,13 @@ module ArelExtensions
39
40
  end
40
41
  if File.exist?("init/#{@env_db}.sql")
41
42
  sql = File.read("init/#{@env_db}.sql")
42
- @cnx.execute(sql) unless sql.blank?
43
+ if @env_db == 'mssql'
44
+ sql.split(/^GO\s*$/).each {|str|
45
+ @cnx.execute(str.strip) unless str.blank?
46
+ }
47
+ else
48
+ @cnx.execute(sql) unless sql.blank?
49
+ end
43
50
  end
44
51
  @cnx.drop_table(:user_tests) rescue nil
45
52
  @cnx.create_table :user_tests do |t|
@@ -138,16 +145,25 @@ module ArelExtensions
138
145
  end
139
146
 
140
147
  def test_sum
141
- assert_equal 68, User.select((@age.sum + 1).as("res")).take(50).first.res
142
- assert_equal 134, User.select((@age.sum + @age.sum).as("res")).take(50).first.res
143
- assert_equal 201, User.select(((@age * 3).sum).as("res")).take(50).first.res
144
- assert_equal 4009, User.select(((@age * @age).sum).as("res")).take(50).first.res
148
+ if @env_db == 'mssql'
149
+ skip "SQL Server forces order?" # TODO
150
+ assert_equal 68, User.select((@age.sum + 1).as("res"), User.arel_table[:id].sum).take(50).reorder(@age).first.res
151
+ assert_equal 134, User.reorder(nil).select((@age.sum + @age.sum).as("res"), User.arel_table[:id].sum).take(50).first.res
152
+ assert_equal 201, User.reorder(nil).select(((@age * 3).sum).as("res"), User.arel_table[:id].sum).take(50).first.res
153
+ assert_equal 4009, User.reorder(nil).select(((@age * @age).sum).as("res"), User.arel_table[:id].sum).take(50).first.res
154
+ else
155
+ assert_equal 68, User.select((@age.sum + 1).as("res")).take(50).first.res
156
+ assert_equal 134, User.select((@age.sum + @age.sum).as("res")).take(50).first.res
157
+ assert_equal 201, User.select(((@age * 3).sum).as("res")).take(50).first.res
158
+ assert_equal 4009, User.select(((@age * @age).sum).as("res")).take(50).first.res
159
+ end
145
160
  end
146
161
 
147
162
  # String Functions
148
163
  def test_concat
149
164
  assert_equal 'Camille Camille', t(@camille, @name + ' ' + @name)
150
165
  assert_equal 'Laure 2', t(@laure, @name + ' ' + 2)
166
+ skip "TODO: find a way... to do group_concat/listagg in SQL Server" if @env_db == 'mssql'
151
167
  if @env_db == 'postgresql'
152
168
  assert_equal "Lucas Sophie", t(User.reorder(nil).from(User.select(:name).where(:name => ['Lucas', 'Sophie']).reorder(:name).as('user_tests')), @name.group_concat(' '))
153
169
  else
@@ -170,12 +186,14 @@ module ArelExtensions
170
186
 
171
187
  def test_find_in_set
172
188
  skip "Sqlite version can't load extension for find_in_set" if $sqlite && $load_extension_disabled
189
+ skip "SQL Server does not know about FIND_IN_SET" if @env_db == 'mssql'
173
190
  assert_equal 5, t(@neg, @comments & 2)
174
191
  assert_equal 0, t(@neg, @comments & 6) # not found
175
192
  end
176
193
 
177
194
  def test_string_comparators
178
195
  skip "Oracle can't use math operators to compare strings" if @env_db == 'oracle' # use GREATEST ?
196
+ skip "SQL Server can't use math operators to compare strings" if @env_db == 'mssql' # use GREATEST ?
179
197
  if @env_db == 'postgresql' # may return real boolean
180
198
  assert t(@neg, @name >= 'Mest') == true || t(@neg, @name >= 'Mest') == 't' # depends of ar version
181
199
  assert t(@neg, @name <= (@name + 'Z')) == true || t(@neg, @name <= (@name + 'Z')) == 't'
@@ -187,6 +205,7 @@ module ArelExtensions
187
205
 
188
206
  def test_regexp_not_regexp
189
207
  skip "Sqlite version can't load extension for regexp" if $sqlite && $load_extension_disabled
208
+ skip "SQL Server does not know about REGEXP without extensions" if @env_db == 'mssql'
190
209
  assert_equal 1, User.where(@name =~ '^M').count
191
210
  assert_equal 6, User.where(@name !~ '^L').count
192
211
  assert_equal 1, User.where(@name =~ /^M/).count
@@ -213,9 +232,10 @@ module ArelExtensions
213
232
 
214
233
  def test_trim
215
234
  assert_equal "Myung", t(@myung, @name.trim)
235
+ assert_equal "Myung", t(@myung, @name.trim.ltrim.rtrim)
236
+ skip "SQL Server does not manage argument for (L/R)TRIM" if @env_db == 'mssql'
216
237
  assert_equal "Myun", t(@myung, @name.rtrim("g"))
217
238
  assert_equal "yung", t(@myung, @name.ltrim("M"))
218
- assert_equal "Myung", t(@myung, @name.trim.ltrim.rtrim)
219
239
  assert_equal "yung", t(@myung, (@name + "M").trim("M"))
220
240
  skip "Oracle does not accept multi char trim" if @env_db == 'oracle'
221
241
  assert_equal "", t(@myung, @name.rtrim(@name))
@@ -237,6 +257,7 @@ module ArelExtensions
237
257
 
238
258
  def test_format
239
259
  assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
260
+ skip "SQL Server does not accept any format" if @env_db == 'mssql'
240
261
  assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
241
262
  end
242
263
 
@@ -276,7 +297,7 @@ module ArelExtensions
276
297
  assert_equal 5, t(@camille, @created_at.month).to_i
277
298
  assert_equal 8, User.where(@created_at.month.eq("05")).count
278
299
  #Week
279
- assert_equal 21, t(@arthur, @created_at.week).to_i
300
+ assert_equal (@env_db == 'mssql' ? 22 : 21), t(@arthur, @created_at.week).to_i
280
301
  assert_equal 8, User.where(@created_at.month.eq("05")).count
281
302
  #Day
282
303
  assert_equal 23, t(@laure, @created_at.day).to_i
@@ -327,7 +348,7 @@ module ArelExtensions
327
348
 
328
349
  def test_wday
329
350
  d = Date.new(2016, 6, 26)
330
- assert_equal(@env_db == 'oracle' ? 2 : 1, t(@myung, @created_at.wday).to_i) # monday
351
+ assert_equal(@env_db == 'oracle' || @env_db == 'mssql' ? 2 : 1, t(@myung, @created_at.wday).to_i) # monday
331
352
  assert_equal 0, User.select(d.wday).as("res").first.to_i
332
353
  end
333
354
 
@@ -19,7 +19,9 @@ module ArelExtensions
19
19
  Arel::Table.engine = ActiveRecord::Base
20
20
  if File.exist?("init/#{@env_db}.sql")
21
21
  sql = File.read("init/#{@env_db}.sql")
22
- @cnx.execute(sql) unless sql.blank?
22
+ unless sql.blank?
23
+ @cnx.execute(sql) rescue $stderr << "can't create functions"
24
+ end
23
25
  end
24
26
  @cnx.drop_table(:user_tests) rescue nil
25
27
  @cnx.create_table :user_tests do |t|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arel_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.7
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yann Azoury
@@ -10,20 +10,20 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-09-28 00:00:00.000000000 Z
13
+ date: 2016-11-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: arel
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '6.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - "~>"
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: '6.0'
29
29
  - !ruby/object:Gem::Dependency
@@ -78,6 +78,7 @@ extensions: []
78
78
  extra_rdoc_files:
79
79
  - MIT-LICENSE.txt
80
80
  - README.md
81
+ - functions.html
81
82
  files:
82
83
  - ".gitignore"
83
84
  - ".travis.yml"
@@ -90,6 +91,7 @@ files:
90
91
  - MIT-LICENSE.txt
91
92
  - README.md
92
93
  - Rakefile
94
+ - SQL_Challenges.md
93
95
  - TODO
94
96
  - appveyor.yml
95
97
  - arel_extensions.gemspec