arel_extensions 0.9.3 → 0.9.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2aee321fcafb1aa18404760b6ea01de96837b0bf
4
- data.tar.gz: 008c6af57efc1775384616d797c96eb2895481b2
3
+ metadata.gz: c99e78c300658b7506cbdf8969ed28c8556e37c0
4
+ data.tar.gz: 116346eed66e6d9cc920f4b21116db9f8d4f95b0
5
5
  SHA512:
6
- metadata.gz: daa6d2206846f0eb7d28de5a4392888630d3120a2913b572cb4250609617574983cb708dfc38b1e8a28c39e72aaeaddb18826e379e4b9bc3098c2904d1ad48e6
7
- data.tar.gz: 09080c3f2ae5800ee9722804630450274b61887c5816a52bf42d2580e94e332843607958e6830f35cf30724bf36ca5680dce5cdc6b91a7a91b081e2329e2a02e
6
+ metadata.gz: b16119b4bc898a852af9e7db829ca34bb4afca30779a651b4302847ea515d7d406378d01470535c91f6315c473ee0c59d52f20a5d324f8c9932de84f97a1ec86
7
+ data.tar.gz: 5973956e3049621ea31c4f981fd6fc5dce8b9a1ba20ba33e4e9eee88d454ca6956375447a9681359ecdc5a3c49c89a9476b983122c5688e02a094fee7cb57274
data/SQL_Challenges.md CHANGED
@@ -22,7 +22,6 @@ A good way could be to create user defined functions to ensure a total transpare
22
22
 
23
23
  ## SQL Server (any version > 2005, without extension)
24
24
  - REGEXP
25
- - (L/R)TRIM(str, 'x') -> TRIM with arguments
26
25
  - Maths Operators on string ('a' <= 'b')
27
26
  - GROUP_CONCAT
28
27
  - FIND_IN_SET
data/TODO CHANGED
@@ -19,8 +19,9 @@ Code quality:
19
19
  New features:
20
20
  - POSIX format numbers (%.2f)
21
21
  - easy unions
22
- - cast
22
+ - cast, to_char
23
23
 
24
24
  Tests improvements:
25
25
  - SQL Server
26
- - DB2
26
+ - DB2
27
+ - Informix
data/init/mssql.sql CHANGED
@@ -22,22 +22,39 @@ BEGIN
22
22
 
23
23
  RETURN @value
24
24
  END;
25
-
26
25
  GO
27
26
 
28
- -----------------------------
29
- -- GO
27
+ IF OBJECT_ID (N'dbo.SplitStringWithDelim', N'IF') IS NOT NULL
28
+ DROP FUNCTION dbo.SplitStringWithDelim;
29
+ GO
30
+ CREATE FUNCTION dbo.SplitStringWithDelim(@List NVARCHAR(4000), @Delimiter NCHAR(1))
31
+ RETURNS TABLE AS
32
+ RETURN
33
+ (
34
+ WITH SplitStringCte(stpos,endpos)
35
+ AS(
36
+ SELECT 0 AS stpos, CHARINDEX(@Delimiter, @List) AS endpos
37
+ UNION ALL
38
+ SELECT endpos + 1, CHARINDEX(@Delimiter, @List, endpos + 1)
39
+ FROM SplitStringCte
40
+ WHERE endpos > 0
41
+ )
42
+ SELECT 'Id' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
43
+ 'Data' = SUBSTRING(@List, stpos, COALESCE(NULLIF(endpos, 0), LEN(@List) + 1) - stpos)
44
+ FROM SplitStringCte
45
+ )
46
+ GO
30
47
 
31
48
  IF OBJECT_ID (N'dbo.FIND_IN_SET', N'FN') IS NOT NULL
32
49
  DROP FUNCTION dbo.FIND_IN_SET;
33
50
  GO
34
- -- CREATE FUNCTION dbo.FIND_IN_SET(@value VARCHAR(MAX), @list VARCHAR(MAX), @delim VARCHAR(MAX))
35
- -- RETURNS VARCHAR(MAX)
36
- -- AS BEGIN
37
- -- RETURN LTRIM(RTRIM(@value));
38
- -- END;
39
-
40
- -- GO
51
+ CREATE FUNCTION dbo.FIND_IN_SET(@Value VARCHAR(MAX), @List VARCHAR(MAX), @Delimiter VARCHAR(MAX))
52
+ RETURNS BIGINT
53
+ AS
54
+ BEGIN
55
+ RETURN COALESCE((SELECT MIN(Id) FROM dbo.SplitStringWithDelim(@List, COALESCE(@Delimiter, ',')) WHERE Data = @Value), 0)
56
+ END
57
+ GO
41
58
 
42
59
  --IF OBJECT_ID (N'dbo.SplitString', N'FN') IS NOT NULL
43
60
  -- DROP FUNCTION dbo.SplitString;
@@ -57,6 +57,7 @@ Arel::Nodes::Function.class_eval do
57
57
  include ArelExtensions::MathFunctions
58
58
  include ArelExtensions::StringFunctions
59
59
  include ArelExtensions::BooleanFunctions
60
+ include ArelExtensions::NullFunctions
60
61
  end
61
62
 
62
63
  Arel::Nodes::Unary.class_eval do
@@ -26,7 +26,14 @@ module ArelExtensions
26
26
  end
27
27
 
28
28
  def type_of_attribute(att)
29
- Arel::Table.engine.connection.schema_cache.columns_hash(att.relation.table_name)[att.name.to_s].type
29
+ case att
30
+ when Arel::Attributes::Attribute
31
+ Arel::Table.engine.connection.schema_cache.columns_hash(att.relation.table_name)[att.name.to_s].type
32
+ when ArelExtensions::Nodes::Function
33
+ att.class.return_type
34
+ else
35
+ nil
36
+ end
30
37
  end
31
38
 
32
39
  def convert_to_node(object)
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module ArelExtensions
3
- VERSION = "0.9.3".freeze
3
+ VERSION = "0.9.4".freeze
4
4
  end
@@ -9,24 +9,13 @@ module ArelExtensions
9
9
  collector
10
10
  end
11
11
 
12
- def visit_ArelExtensions_Nodes_Concat o, collector
13
- arg = o.left.relation.engine.columns.find{|c| c.name == o.left.name.to_s}.type
14
- if(o.right.is_a?(Arel::Attributes::Attribute))
15
- collector << "CONCAT("
16
- collector = visit o.left, collector
17
- collector<< ","
18
- collector = visit o.right, collector
19
- collector << ")"
20
- elsif ( arg == :date || arg == :datetime)
21
- collector = visit o.left, collector
22
- collector<< "+"
23
- collector << "#{o.right} days"
24
- else
25
- collector << "CONCAT("
26
- collector = visit o.left, collector
27
- collector<< ","
28
- collector <<"#{o.right})"
29
- end
12
+ def visit_ArelExtensions_Nodes_Trim o, collector
13
+ collector << "LTRIM(RTRIM("
14
+ o.expressions.each_with_index { |arg, i|
15
+ collector << Arel::Visitors::ToSql::COMMA unless i == 0
16
+ collector = visit arg, collector
17
+ }
18
+ collector << "))"
30
19
  collector
31
20
  end
32
21
 
@@ -137,27 +137,54 @@ module ArelExtensions
137
137
  collector
138
138
  end
139
139
 
140
- # TODO manage 2nd argument
141
140
  def visit_ArelExtensions_Nodes_Trim o, collector
142
- collector << "LTRIM(RTRIM("
143
- collector = visit o.left, collector
144
- collector << "))"
141
+ if o.right
142
+ collector << "REPLACE(REPLACE(LTRIM(RTRIM(REPLACE(REPLACE("
143
+ collector = visit o.left, collector
144
+ collector << ", ' ', '~'), "
145
+ collector = visit o.right, collector
146
+ collector << ", ' '))), ' ', "
147
+ collector = visit o.right, collector
148
+ collector << "), '~', ' ')"
149
+ else
150
+ collector << "LTRIM(RTRIM("
151
+ collector = visit o.left, collector
152
+ collector << "))"
153
+ end
145
154
  collector
146
155
  end
147
156
 
148
- # TODO manage 2nd argument
149
157
  def visit_ArelExtensions_Nodes_Ltrim o, collector
150
- collector << "LTRIM("
151
- collector = visit o.left, collector
152
- collector << ")"
158
+ if o.right
159
+ collector << "REPLACE(REPLACE(LTRIM(REPLACE(REPLACE("
160
+ collector = visit o.left, collector
161
+ collector << ", ' ', '~'), "
162
+ collector = visit o.right, collector
163
+ collector << ", ' ')), ' ', "
164
+ collector = visit o.right, collector
165
+ collector << "), '~', ' ')"
166
+ else
167
+ collector << "LTRIM("
168
+ collector = visit o.left, collector
169
+ collector << ")"
170
+ end
153
171
  collector
154
172
  end
155
173
 
156
- # TODO manage 2nd argument
157
174
  def visit_ArelExtensions_Nodes_Rtrim o, collector
158
- collector << "RTRIM("
159
- collector = visit o.left, collector
160
- collector << ")"
175
+ if o.right
176
+ collector << "REPLACE(REPLACE(RTRIM(REPLACE(REPLACE("
177
+ collector = visit o.left, collector
178
+ collector << ", ' ', '~'), "
179
+ collector = visit o.right, collector
180
+ collector << ", ' ')), ' ', "
181
+ collector = visit o.right, collector
182
+ collector << "), '~', ' ')"
183
+ else
184
+ collector << "RTRIM("
185
+ collector = visit o.left, collector
186
+ collector << ")"
187
+ end
161
188
  collector
162
189
  end
163
190
 
@@ -227,6 +254,16 @@ module ArelExtensions
227
254
  collector
228
255
  end
229
256
 
257
+ def visit_ArelExtensions_Nodes_FindInSet o, collector
258
+ collector << "dbo.FIND_IN_SET("
259
+ o.expressions.each_with_index { |arg, i|
260
+ collector << Arel::Visitors::MSSQL::COMMA unless i == 0
261
+ collector = visit arg, collector
262
+ }
263
+ collector << ")"
264
+ collector
265
+ end
266
+
230
267
 
231
268
  # TODO manage case insensitivity
232
269
  def visit_ArelExtensions_Nodes_IMatches o, collector
@@ -1,6 +1,7 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
3
  Arel::Visitors::Oracle.class_eval do
4
+ SPECIAL_CHARS = {"\t" => 'CHR(9)', "\n" => 'CHR(10)', "\r" => 'CHR(13)'}
4
5
  Arel::Visitors::Oracle::DATE_MAPPING = {'d' => 'DAY', 'm' => 'MONTH', 'w' => 'IW', 'y' => 'YEAR', 'wd' => 'D', 'h' => 'HOUR', 'mn' => 'MINUTE', 's' => 'SECOND'}
5
6
  Arel::Visitors::Oracle::DATE_FORMAT_DIRECTIVES = {
6
7
  '%Y' => 'IYYY', '%C' => 'CC', '%y' => 'YY', '%m' => 'MM', '%B' => 'Month', '%^B' => 'MONTH', '%b' => 'Mon', '%^b' => 'MON',
@@ -165,19 +166,25 @@ module ArelExtensions
165
166
 
166
167
  def visit_ArelExtensions_Nodes_Trim o, collector
167
168
  collector << 'TRIM(' # BOTH
168
- case o.right.expr
169
- when "\t"
170
- collector << 'CHR(9)'
171
- when "\n"
172
- collector << 'CHR(10)'
173
- when "\r"
174
- collector << 'CHR(13)'
169
+ if o.right.expr && SPECIAL_CHARS[o.right.expr]
170
+ collector << SPECIAL_CHARS[o.right.expr]
175
171
  else
176
172
  collector = visit o.right, collector
177
173
  end
178
174
  collector << ' FROM '
179
175
  collector << '(' if o.left.is_a? ArelExtensions::Nodes::Trim
180
- collector = visit o.left, collector
176
+ if o.type_of_attribute(o.left) == :text
177
+ collector << 'dbms_lob.substr('
178
+ collector = visit o.left, collector
179
+ collector << Arel::Visitors::Oracle::COMMA
180
+ collector << 'dbms_lob.getlength('
181
+ collector = visit o.left, collector
182
+ collector << ')'
183
+ collector << Arel::Visitors::Oracle::COMMA
184
+ collector << '1)'
185
+ else
186
+ collector = visit o.left, collector
187
+ end
181
188
  collector << ')' if o.left.is_a? ArelExtensions::Nodes::Trim
182
189
  collector << ")"
183
190
  collector
@@ -185,7 +192,11 @@ module ArelExtensions
185
192
 
186
193
  def visit_ArelExtensions_Nodes_Ltrim o, collector
187
194
  collector << 'TRIM(LEADING '
188
- collector = visit o.right, collector
195
+ if o.right.expr && SPECIAL_CHARS[o.right.expr]
196
+ collector << SPECIAL_CHARS[o.right.expr]
197
+ else
198
+ collector = visit o.right, collector
199
+ end
189
200
  collector << ' FROM '
190
201
  collector = visit o.left, collector
191
202
  collector << ")"
@@ -194,24 +205,33 @@ module ArelExtensions
194
205
 
195
206
  def visit_ArelExtensions_Nodes_Rtrim o, collector
196
207
  collector << 'TRIM(TRAILING '
197
- collector = visit o.right, collector
208
+ if o.right.expr && SPECIAL_CHARS[o.right.expr]
209
+ collector << SPECIAL_CHARS[o.right.expr]
210
+ else
211
+ collector = visit o.right, collector
212
+ end
198
213
  collector << ' FROM '
199
214
  collector = visit o.left, collector
200
215
  collector << ")"
201
216
  collector
202
217
  end
203
218
 
219
+ # blank ? <param> : NULL
204
220
  def visit_ArelExtensions_Nodes_Blank o, collector
205
221
  collector << '(CASE WHEN ('
206
- collector = visit o.left, collector
207
- collector << " = '') THEN 1 ELSE 0 END)"
222
+ collector = visit o.left.trim, collector
223
+ collector << " IS NULL) THEN 'blank'"
224
+ collector << " ELSE NULL END)"
208
225
  collector
209
226
  end
210
227
 
228
+ # not blank ? <param> : NULL
211
229
  def visit_ArelExtensions_Nodes_NotBlank o, collector
212
230
  collector << '(CASE WHEN ('
213
- collector = visit o.left, collector
214
- collector << " = '') THEN 0 ELSE 1 END)"
231
+ collector = visit o.left.trim, collector
232
+ collector << " IS NOT NULL) THEN "
233
+ collector = visit o.left.trim, collector
234
+ collector << " ELSE NULL END)"
215
235
  collector
216
236
  end
217
237
 
@@ -81,7 +81,7 @@ module ArelExtensions
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)
84
- u = User.create :age => 23, :name => "Myung", :created_at => d, :score => 20.16
84
+ u = User.create :age => 23, :name => "Myung", :created_at => d, :score => 20.16, :comments => ' '
85
85
  @myung = User.where(:id => u.id)
86
86
  u = User.create :age => 25, :name => "Laure", :created_at => d, :score => 20.16
87
87
  @laure = User.where(:id => u.id)
@@ -234,7 +234,6 @@ module ArelExtensions
234
234
  def test_trim
235
235
  assert_equal "Myung", t(@myung, @name.trim)
236
236
  assert_equal "Myung", t(@myung, @name.trim.ltrim.rtrim)
237
- skip "SQL Server does not manage argument for (L/R)TRIM" if @env_db == 'mssql'
238
237
  assert_equal "Myun", t(@myung, @name.rtrim("g"))
239
238
  assert_equal "yung", t(@myung, @name.ltrim("M"))
240
239
  assert_equal "yung", t(@myung, (@name + "M").trim("M"))
@@ -246,9 +245,18 @@ module ArelExtensions
246
245
  if @env_db == 'postgresql'
247
246
  assert_includes [false, 'f'], t(@myung, @name.blank) # depends of adapter
248
247
  assert_includes [true, 't'], t(@myung, @name.not_blank) # depends of adapter
248
+ assert_includes [true, 't'], t(@myung, @comments.blank)
249
+ assert_includes [false, 'f'], t(@myung, @comments.not_blank)
250
+ elsif @env_db == 'oracle'
251
+ assert_equal '42', t(@myung, @name.blank.coalesce('42'))
252
+ assert_equal 'Myung', t(@myung, @name.not_blank.coalesce('42'))
253
+ assert_equal 'blank', t(@myung, @comments.blank.coalesce('42'))
254
+ assert_equal '42', t(@myung, @comments.not_blank.coalesce('42'))
249
255
  else
250
256
  assert_equal 0, t(@myung, @name.blank)
251
257
  assert_equal 1, t(@myung, @name.not_blank)
258
+ assert_equal 1, t(@myung, @comments.blank)
259
+ assert_equal 0, t(@myung, @comments.not_blank)
252
260
  end
253
261
  skip "Oracle requires cast for CLOB" if @env_db == 'oracle' # comments is CLOB, CHAR expected
254
262
  if @env_db == 'postgresql'
@@ -260,7 +268,7 @@ module ArelExtensions
260
268
 
261
269
  def test_format
262
270
  assert_equal '2016-05-23', t(@lucas, @created_at.format('%Y-%m-%d'))
263
- skip "SQL Server does not accept any format" if @env_db == 'mssql'
271
+ skip "SQL Server does not accept any format" if @env_db == 'mssql'
264
272
  assert_equal '2014/03/03 12:42:00', t(@lucas, @updated_at.format('%Y/%m/%d %H:%M:%S'))
265
273
  end
266
274
 
@@ -318,11 +326,15 @@ module ArelExtensions
318
326
 
319
327
  def test_datetime_diff
320
328
  assert_equal 0, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 42)).to_i
321
- assert_equal 42, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
322
- assert_equal(-3600, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
329
+ if @env_db == 'oracle' && Arel::VERSION.to_i > 6 # in rails 5, result is multiplied by 24*60*60 = 86400...
330
+ assert_equal 42 * 86400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
331
+ assert_equal(-3600 * 86400, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
332
+ else
333
+ assert_equal 42, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 12, 41, 18)).to_i
334
+ assert_equal(-3600, t(@lucas, @updated_at - Time.utc(2014, 3, 3, 13, 42)).to_i)
335
+ end
323
336
  end
324
337
 
325
-
326
338
  def test_cast_types
327
339
  skip "not implemented yet"
328
340
  assert_equal true, t(@arthur, @score =~ /22/)
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.9.3
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yann Azoury
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-11-17 00:00:00.000000000 Z
13
+ date: 2016-11-24 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: arel