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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +46 -0
- data/Gemfile +10 -0
- data/MIT-LICENSE.txt +20 -0
- data/README.md +101 -0
- data/Rakefile +14 -0
- data/arel_extensions.gemspec +32 -0
- data/functions.html +344 -0
- data/gemfiles/Gemfile.rails3 +10 -0
- data/gemfiles/Gemfile.rails5 +10 -0
- data/init/mssql.sql +6 -0
- data/init/mysql.sql +0 -0
- data/init/oracle.sql +31 -0
- data/init/postgresql.sql +12 -0
- data/init/sqlite.sql +1 -0
- data/lib/arel_extensions.rb +84 -0
- data/lib/arel_extensions/attributes.rb +26 -0
- data/lib/arel_extensions/comparators.rb +59 -0
- data/lib/arel_extensions/date_duration.rb +28 -0
- data/lib/arel_extensions/insert_manager.rb +33 -0
- data/lib/arel_extensions/math.rb +48 -0
- data/lib/arel_extensions/math_functions.rb +35 -0
- data/lib/arel_extensions/nodes.rb +27 -0
- data/lib/arel_extensions/nodes/abs.rb +6 -0
- data/lib/arel_extensions/nodes/ceil.rb +6 -0
- data/lib/arel_extensions/nodes/coalesce.rb +22 -0
- data/lib/arel_extensions/nodes/concat.rb +33 -0
- data/lib/arel_extensions/nodes/date_diff.rb +106 -0
- data/lib/arel_extensions/nodes/duration.rb +30 -0
- data/lib/arel_extensions/nodes/find_in_set.rb +16 -0
- data/lib/arel_extensions/nodes/floor.rb +6 -0
- data/lib/arel_extensions/nodes/function.rb +17 -0
- data/lib/arel_extensions/nodes/isnull.rb +30 -0
- data/lib/arel_extensions/nodes/length.rb +6 -0
- data/lib/arel_extensions/nodes/locate.rb +33 -0
- data/lib/arel_extensions/nodes/ltrim.rb +28 -0
- data/lib/arel_extensions/nodes/matches.rb +22 -0
- data/lib/arel_extensions/nodes/rand.rb +23 -0
- data/lib/arel_extensions/nodes/replace.rb +36 -0
- data/lib/arel_extensions/nodes/round.rb +15 -0
- data/lib/arel_extensions/nodes/rtrim.rb +29 -0
- data/lib/arel_extensions/nodes/soundex.rb +23 -0
- data/lib/arel_extensions/nodes/sum.rb +23 -0
- data/lib/arel_extensions/nodes/trim.rb +26 -0
- data/lib/arel_extensions/nodes/wday.rb +23 -0
- data/lib/arel_extensions/null_functions.rb +16 -0
- data/lib/arel_extensions/string_functions.rb +68 -0
- data/lib/arel_extensions/version.rb +4 -0
- data/lib/arel_extensions/visitors.rb +6 -0
- data/lib/arel_extensions/visitors/ibm_db.rb +206 -0
- data/lib/arel_extensions/visitors/mssql.rb +213 -0
- data/lib/arel_extensions/visitors/mysql.rb +184 -0
- data/lib/arel_extensions/visitors/oracle.rb +267 -0
- data/lib/arel_extensions/visitors/postgresql.rb +258 -0
- data/lib/arel_extensions/visitors/sqlite.rb +218 -0
- data/lib/arel_extensions/visitors/to_sql.rb +199 -0
- data/test/helper.rb +18 -0
- data/test/real_db_test.rb +251 -0
- data/test/support/fake_record.rb +137 -0
- data/test/test_comparators.rb +49 -0
- data/test/visitors/test_bulk_insert_oracle.rb +30 -0
- data/test/visitors/test_bulk_insert_sqlite.rb +31 -0
- data/test/visitors/test_bulk_insert_to_sql.rb +32 -0
- data/test/visitors/test_oracle.rb +105 -0
- data/test/visitors/test_to_sql.rb +148 -0
- data/test/with_ar/test_bulk_sqlite.rb +44 -0
- data/test/with_ar/test_math_sqlite.rb +59 -0
- data/test/with_ar/test_string_sqlite.rb +69 -0
- metadata +230 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
module FakeRecord
|
2
|
+
class Column < Struct.new(:name, :type)
|
3
|
+
end
|
4
|
+
|
5
|
+
class Connection
|
6
|
+
attr_reader :tables
|
7
|
+
attr_accessor :visitor
|
8
|
+
|
9
|
+
def initialize(visitor = nil)
|
10
|
+
@tables = %w{ users photos developers products}
|
11
|
+
@columns = {
|
12
|
+
'users' => [
|
13
|
+
Column.new('id', :integer),
|
14
|
+
Column.new('name', :string),
|
15
|
+
Column.new('comments', :text),
|
16
|
+
Column.new('bool', :boolean),
|
17
|
+
Column.new('created_at', :date),
|
18
|
+
Column.new('updated_at', :datetime)
|
19
|
+
],
|
20
|
+
'products' => [
|
21
|
+
Column.new('id', :integer),
|
22
|
+
Column.new('price', :decimal)
|
23
|
+
]
|
24
|
+
}
|
25
|
+
@columns_hash = {
|
26
|
+
'users' => Hash[@columns['users'].map { |x| [x.name, x] }],
|
27
|
+
'products' => Hash[@columns['products'].map { |x| [x.name, x] }]
|
28
|
+
}
|
29
|
+
@primary_keys = {
|
30
|
+
'users' => 'id',
|
31
|
+
'products' => 'id'
|
32
|
+
}
|
33
|
+
@visitor = visitor
|
34
|
+
end
|
35
|
+
|
36
|
+
def columns_hash table_name
|
37
|
+
@columns_hash[table_name]
|
38
|
+
end
|
39
|
+
|
40
|
+
def primary_key name
|
41
|
+
@primary_keys[name.to_s]
|
42
|
+
end
|
43
|
+
|
44
|
+
def table_exists? name
|
45
|
+
@tables.include? name.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def columns name, message = nil
|
49
|
+
@columns[name.to_s]
|
50
|
+
end
|
51
|
+
|
52
|
+
def quote_table_name name
|
53
|
+
"\"#{name.to_s}\""
|
54
|
+
end
|
55
|
+
|
56
|
+
def quote_column_name name
|
57
|
+
"\"#{name.to_s}\""
|
58
|
+
end
|
59
|
+
|
60
|
+
def schema_cache
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def quote thing, column = nil
|
65
|
+
if column && !thing.nil?
|
66
|
+
case column.type
|
67
|
+
when :integer
|
68
|
+
thing = thing.to_i
|
69
|
+
when :string
|
70
|
+
thing = thing.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
case thing
|
75
|
+
when DateTime
|
76
|
+
"'#{thing.strftime("%Y-%m-%d %H:%M:%S")}'"
|
77
|
+
when Date
|
78
|
+
"'#{thing.strftime("%Y-%m-%d")}'"
|
79
|
+
when true
|
80
|
+
"'t'"
|
81
|
+
when false
|
82
|
+
"'f'"
|
83
|
+
when nil
|
84
|
+
'NULL'
|
85
|
+
when Numeric
|
86
|
+
thing
|
87
|
+
else
|
88
|
+
"'#{thing.to_s.gsub("'", "\\\\'")}'"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class ConnectionPool
|
94
|
+
class Spec < Struct.new(:config)
|
95
|
+
end
|
96
|
+
|
97
|
+
attr_reader :spec, :connection
|
98
|
+
|
99
|
+
def initialize
|
100
|
+
@spec = Spec.new(:adapter => 'america')
|
101
|
+
@connection = Connection.new
|
102
|
+
@connection.visitor = Arel::Visitors::ToSql.new(connection)
|
103
|
+
end
|
104
|
+
|
105
|
+
def with_connection
|
106
|
+
yield connection
|
107
|
+
end
|
108
|
+
|
109
|
+
def table_exists? name
|
110
|
+
connection.tables.include? name.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def columns_hash
|
114
|
+
connection.columns_hash
|
115
|
+
end
|
116
|
+
|
117
|
+
def schema_cache
|
118
|
+
connection
|
119
|
+
end
|
120
|
+
|
121
|
+
def quote thing, column = nil
|
122
|
+
connection.quote thing, column
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Base
|
127
|
+
attr_accessor :connection_pool
|
128
|
+
|
129
|
+
def initialize
|
130
|
+
@connection_pool = ConnectionPool.new
|
131
|
+
end
|
132
|
+
|
133
|
+
def connection
|
134
|
+
connection_pool.connection
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Arel
|
4
|
+
module Nodes
|
5
|
+
|
6
|
+
describe ArelExtensions::Comparators do
|
7
|
+
it "< is equal lt" do
|
8
|
+
relation = Arel::Table.new(:users)
|
9
|
+
mgr = relation.project relation[:id]
|
10
|
+
mgr.where relation[:id]<(10)
|
11
|
+
res = mgr.to_sql
|
12
|
+
res.must_be_like('SELECT "users"."id" FROM "users" WHERE "users"."id" < 10')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "<= is equal lteq" do
|
16
|
+
relation = Arel::Table.new(:users)
|
17
|
+
mgr = relation.project relation[:id]
|
18
|
+
mgr.where relation[:id]<=(10)
|
19
|
+
res = mgr.to_sql
|
20
|
+
res.must_be_like('SELECT "users"."id" FROM "users" WHERE "users"."id" <= 10')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "> is equal gt" do
|
24
|
+
relation = Arel::Table.new(:users)
|
25
|
+
mgr = relation.project relation[:id]
|
26
|
+
mgr.where relation[:id]>(10)
|
27
|
+
res = mgr.to_sql
|
28
|
+
res.must_be_like('SELECT "users"."id" FROM "users" WHERE "users"."id" > 10')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "< is equal gteq" do
|
32
|
+
relation = Arel::Table.new(:users)
|
33
|
+
mgr = relation.project relation[:id]
|
34
|
+
mgr.where relation[:id]>=(10)
|
35
|
+
res = mgr.to_sql
|
36
|
+
res.must_be_like('SELECT "users"."id" FROM "users" WHERE "users"."id" >= 10')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should compare with dates" do
|
40
|
+
relation = Table.new(:users)
|
41
|
+
mgr = relation.project relation[:created_at]
|
42
|
+
mgr.where(relation[:created_at] >= Date.new(2016, 3, 31))
|
43
|
+
mgr.to_sql.must_match %{"users"."created_at" >= '2016-03-31'}
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module ArelExtensions
|
4
|
+
module BulkInsertOracle
|
5
|
+
describe 'the oracle bulk insert visitor' do
|
6
|
+
before do
|
7
|
+
@conn = FakeRecord::Base.new
|
8
|
+
@visitor = Arel::Visitors::Oracle.new @conn.connection
|
9
|
+
@table = Arel::Table.new(:users)
|
10
|
+
@cols = ['id', 'name', 'comments', 'created_at']
|
11
|
+
@data = [
|
12
|
+
[23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
|
13
|
+
[25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
def compile node
|
18
|
+
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should import large set of data in Oracle" do
|
22
|
+
insert_manager = Arel::InsertManager.new(@conn).into(@table)
|
23
|
+
insert_manager.bulk_insert(@cols, @data)
|
24
|
+
sql = compile(insert_manager.ast)
|
25
|
+
sql.must_be_like %Q[INSERT ALL INTO "users" ("id", "name", "comments", "created_at") VALUES (23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01') INTO "users" ("id", "name", "comments", "created_at") VALUES (25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01') SELECT 1 FROM dual]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module ArelExtensions
|
4
|
+
module BulkInsertSQLlite
|
5
|
+
|
6
|
+
describe 'the sqlite visitor can bulk insert' do
|
7
|
+
before do
|
8
|
+
@conn = FakeRecord::Base.new
|
9
|
+
@visitor = Arel::Visitors::SQLite.new @conn.connection
|
10
|
+
@table = Arel::Table.new(:users)
|
11
|
+
@cols = ['id', 'name', 'comments', 'created_at']
|
12
|
+
@data = [
|
13
|
+
[23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
|
14
|
+
[25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def compile node
|
19
|
+
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should import large set of data" do
|
23
|
+
insert_manager = Arel::InsertManager.new(@conn).into(@table)
|
24
|
+
insert_manager.bulk_insert(@cols, @data)
|
25
|
+
sql = compile(insert_manager.ast)
|
26
|
+
sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") VALUES (23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01'), (25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01')]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module ArelExtensions
|
4
|
+
module BulkInsertToSql
|
5
|
+
describe 'the to_sql visitor can bulk insert' do
|
6
|
+
before do
|
7
|
+
@conn = FakeRecord::Base.new
|
8
|
+
@visitor = Arel::Visitors::ToSql.new @conn.connection
|
9
|
+
@table = Arel::Table.new(:users)
|
10
|
+
@cols = ['id', 'name', 'comments', 'created_at']
|
11
|
+
@data = [
|
12
|
+
[23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
|
13
|
+
[25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
def compile node
|
18
|
+
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it "should import large set of data using ToSql" do
|
23
|
+
insert_manager = Arel::InsertManager.new(@conn).into(@table)
|
24
|
+
insert_manager.bulk_insert(@cols, @data)
|
25
|
+
sql = compile(insert_manager.ast)
|
26
|
+
sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") VALUES (23, 'nom1', 'sdfdsfdsfsdf', '2016-01-01'), (25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01')]
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module ArelExtensions
|
4
|
+
module VisitorOracle
|
5
|
+
describe 'the Oracle visitor' do
|
6
|
+
before do
|
7
|
+
@conn = FakeRecord::Base.new
|
8
|
+
@visitor = Arel::Visitors::Oracle.new @conn.connection
|
9
|
+
@table = Arel::Table.new(:users)
|
10
|
+
@attr = @table[:id]
|
11
|
+
@date = Date.new(2016, 3, 31)
|
12
|
+
end
|
13
|
+
|
14
|
+
def compile node
|
15
|
+
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
16
|
+
end
|
17
|
+
|
18
|
+
# Comparators
|
19
|
+
|
20
|
+
it "should accept comparators on integers" do
|
21
|
+
compile(@table[:id] == 42).must_match %{"users"."id" = 42}
|
22
|
+
compile(@table[:id] == @table[:id]).must_be_like %{"users"."id" = "users"."id"}
|
23
|
+
compile(@table[:id] != 42).must_match %{"users"."id" != 42}
|
24
|
+
compile(@table[:id] > 42).must_match %{"users"."id" > 42}
|
25
|
+
compile(@table[:id] >= 42).must_match %{"users"."id" >= 42}
|
26
|
+
compile(@table[:id] >= @table[:id]).must_be_like %{"users"."id" >= "users"."id"}
|
27
|
+
compile(@table[:id] < 42).must_match %{"users"."id" < 42}
|
28
|
+
compile(@table[:id] <= 42).must_match %{"users"."id" <= 42}
|
29
|
+
compile((@table[:id] <= 42).as('new_name')).must_match %{("users"."id" <= 42) AS new_name}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should accept comparators on dates" do
|
33
|
+
c = @table[:created_at]
|
34
|
+
u = @table[:updated_at]
|
35
|
+
compile(c > @date).must_be_like %{"users"."created_at" > '2016-03-31'}
|
36
|
+
compile(u >= @date).must_be_like %{"users"."updated_at" >= '2016-03-31'}
|
37
|
+
compile(c < u).must_be_like %{"users"."created_at" < "users"."updated_at"}
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should accept comparators on strings" do
|
41
|
+
c = @table[:name]
|
42
|
+
compile(c == 'test').must_be_like %{"users"."name" = 'test'}
|
43
|
+
compile(c != 'test').must_be_like %{"users"."name" != 'test'}
|
44
|
+
compile(c > 'test').must_be_like %{"users"."name" > 'test'}
|
45
|
+
compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
|
46
|
+
compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
|
47
|
+
compile(c =~ /\Atest\Z/).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
|
48
|
+
compile(c =~ '^test$').must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
|
49
|
+
compile(c !~ /\Ate\Dst\Z/).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
|
50
|
+
compile(c.imatches('%test%')).must_be_like %{LOWER("users"."name") LIKE LOWER('%test%')}
|
51
|
+
compile(c.imatches_any(['%test%', 't2'])).must_be_like %{(LOWER("users"."name") LIKE LOWER('%test%') OR LOWER("users"."name") LIKE LOWER('t2'))}
|
52
|
+
compile(c.idoes_not_match('%test%')).must_be_like %{LOWER("users"."name") NOT LIKE LOWER('%test%')}
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Maths
|
57
|
+
# DateDiff
|
58
|
+
it "should diff date col and date" do
|
59
|
+
compile(@table[:created_at] - Date.new(2016, 3, 31)).must_match %{"users"."created_at" - '2016-03-31'}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should diff date col and datetime col" do
|
63
|
+
compile(@table[:created_at] - @table[:updated_at]).must_match %{"users"."created_at" - "users"."updated_at"}
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should diff date col and datetime col with AS" do
|
67
|
+
sql = compile((@table[:updated_at] - @table[:created_at]).as('new_name'))
|
68
|
+
sql.must_be_like %{("users"."updated_at" - "users"."created_at") AS new_name}
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should diff between time values" do
|
72
|
+
d2 = Time.new(2015,6,1)
|
73
|
+
d1 = DateTime.new(2015,6,2)
|
74
|
+
sql = compile(ArelExtensions::Nodes::DateDiff.new(d1,d2))
|
75
|
+
sql.must_match("'2015-06-02' - '2015-06-01'")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should diff between time values and time col" do
|
79
|
+
d1 = DateTime.new(2015,6,2)
|
80
|
+
sql = compile(ArelExtensions::Nodes::DateDiff.new(d1, @table[:updated_at]))
|
81
|
+
sql.must_match %{'2015-06-02' - "users"."updated_at"}
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should accept operators on dates with numbers" do
|
85
|
+
c = @table[:created_at]
|
86
|
+
# u = @table[:updated_at]
|
87
|
+
compile(c - 42).must_be_like %{DATE_SUB("users"."created_at", 42)}
|
88
|
+
compile(c - @table[:id]).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
|
89
|
+
end
|
90
|
+
|
91
|
+
# Maths on sums
|
92
|
+
it "should accept math operators on anything" do
|
93
|
+
c = @table[:name]
|
94
|
+
(c == 'test').to_sql.must_be_like %{"users"."name" = 'test'}
|
95
|
+
(c != 'test').to_sql.must_be_like %{"users"."name" != 'test'}
|
96
|
+
(c > 'test').to_sql.must_be_like %{"users"."name" > 'test'}
|
97
|
+
compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
|
98
|
+
compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
|
99
|
+
compile(c =~ /\Atest\Z/).must_be_like %{REGEXP_LIKE("users"."name", '^test$')}
|
100
|
+
compile(c !~ /\Ate\Dst\Z/).must_be_like %{NOT REGEXP_LIKE("users"."name", '^te[^0-9]st$')}
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module ArelExtensions
|
5
|
+
module VisitorToSql
|
6
|
+
describe 'the to_sql visitor' do
|
7
|
+
before do
|
8
|
+
@conn = FakeRecord::Base.new
|
9
|
+
Arel::Table.engine = @conn
|
10
|
+
@visitor = Arel::Visitors::ToSql.new @conn.connection
|
11
|
+
@table = Arel::Table.new(:users)
|
12
|
+
@attr = @table[:id]
|
13
|
+
@date = Date.new(2016, 3, 31)
|
14
|
+
@price = Arel::Table.new(:products)[:price]
|
15
|
+
end
|
16
|
+
|
17
|
+
def compile node
|
18
|
+
@visitor.accept(node, Arel::Collectors::SQLString.new).value
|
19
|
+
end
|
20
|
+
|
21
|
+
# Math Functions
|
22
|
+
|
23
|
+
it "should not break Arel functions" do
|
24
|
+
compile(@price + 42).must_be_like %{("products"."price" + 42)}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return right calculations on numbers" do
|
28
|
+
compile(@price.abs + 42).must_be_like %{(ABS("products"."price") + 42)}
|
29
|
+
compile(@price.ceil + 42).must_be_like %{(CEIL("products"."price") + 42)}
|
30
|
+
compile(@price.floor + 42).must_be_like %{(FLOOR("products"."price") + 42)}
|
31
|
+
compile(@price.ceil + @price.floor).must_be_like %{(CEIL("products"."price") + FLOOR("products"."price"))}
|
32
|
+
compile((@price.ceil + @price.floor).abs).must_be_like %{ABS((CEIL("products"."price") + FLOOR("products"."price")))}
|
33
|
+
compile(@price.round + 42).must_be_like %{(ROUND("products"."price") + 42)}
|
34
|
+
compile(@price.round(2) + 42).must_be_like %{(ROUND("products"."price", 2) + 42)}
|
35
|
+
compile(Arel.rand + 42).must_be_like %{(RAND() + 42)}
|
36
|
+
compile(@price.sum + 42).must_be_like %{(SUM("products"."price") + 42)}
|
37
|
+
compile((@price + 42).sum).must_be_like %{SUM(("products"."price" + 42))}
|
38
|
+
compile((@price + 42).average).must_be_like %{AVG(("products"."price" + 42))}
|
39
|
+
compile((Arel.rand * 9).round + 42).must_be_like %{(ROUND(RAND() * 9) + 42)}
|
40
|
+
compile((Arel.rand * @price).round(2) + @price).must_be_like %{(ROUND(RAND() * "products"."price", 2) + "products"."price")}
|
41
|
+
end
|
42
|
+
|
43
|
+
# String Functions
|
44
|
+
it "should accept functions on strings" do
|
45
|
+
c = @table[:name]
|
46
|
+
compile(c + 'test').must_be_like %{"users"."name" || 'test'}
|
47
|
+
compile(c + 'test' + ' chain').must_be_like %{"users"."name" || 'test' || ' chain'}
|
48
|
+
compile(c.length).must_be_like %{LENGTH("users"."name")}
|
49
|
+
compile(c.length.round + 42).must_be_like %{(ROUND(LENGTH("users"."name")) + 42)}
|
50
|
+
compile(c.locate('test')).must_be_like %{LOCATE("users"."name", 'test')}
|
51
|
+
compile(c & 42).must_be_like %{FIND_IN_SET(42, "users"."name")}
|
52
|
+
|
53
|
+
compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
|
54
|
+
compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
|
55
|
+
compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
|
56
|
+
compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
|
57
|
+
compile(c.imatches('%test%')).must_be_like %{"users"."name" ILIKE '%test%'}
|
58
|
+
compile(c.imatches_any(['%test%', 't2'])).must_be_like %{("users"."name" ILIKE '%test%' OR "users"."name" ILIKE 't2')}
|
59
|
+
compile(c.idoes_not_match('%test%')).must_be_like %{"users"."name" NOT ILIKE '%test%'}
|
60
|
+
end
|
61
|
+
|
62
|
+
# Comparators
|
63
|
+
|
64
|
+
it "should accept comparators on integers" do
|
65
|
+
compile(@table[:id] == 42).must_match %{"users"."id" = 42}
|
66
|
+
compile(@table[:id] == @table[:id]).must_be_like %{"users"."id" = "users"."id"}
|
67
|
+
compile(@table[:id] != 42).must_match %{"users"."id" != 42}
|
68
|
+
compile(@table[:id] > 42).must_match %{"users"."id" > 42}
|
69
|
+
compile(@table[:id] >= 42).must_match %{"users"."id" >= 42}
|
70
|
+
compile(@table[:id] >= @table[:id]).must_be_like %{"users"."id" >= "users"."id"}
|
71
|
+
compile(@table[:id] < 42).must_match %{"users"."id" < 42}
|
72
|
+
compile(@table[:id] <= 42).must_match %{"users"."id" <= 42}
|
73
|
+
compile((@table[:id] <= 42).as('new_name')).must_match %{("users"."id" <= 42) AS new_name}
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should accept comparators on dates" do
|
77
|
+
c = @table[:created_at]
|
78
|
+
u = @table[:updated_at]
|
79
|
+
compile(c > @date).must_be_like %{"users"."created_at" > '2016-03-31'}
|
80
|
+
compile(u >= @date).must_be_like %{"users"."updated_at" >= '2016-03-31'}
|
81
|
+
compile(c < u).must_be_like %{"users"."created_at" < "users"."updated_at"}
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should accept comparators on strings" do
|
85
|
+
c = @table[:name]
|
86
|
+
compile(c == 'test').must_be_like %{"users"."name" = 'test'}
|
87
|
+
compile(c != 'test').must_be_like %{"users"."name" != 'test'}
|
88
|
+
compile(c > 'test').must_be_like %{"users"."name" > 'test'}
|
89
|
+
compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
|
90
|
+
compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
|
91
|
+
compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
|
92
|
+
compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
|
93
|
+
compile(c.imatches('%test%')).must_be_like %{"users"."name" ILIKE '%test%'}
|
94
|
+
compile(c.imatches_any(['%test%', 't2'])).must_be_like %{("users"."name" ILIKE '%test%' OR "users"."name" ILIKE 't2')}
|
95
|
+
compile(c.idoes_not_match('%test%')).must_be_like %{"users"."name" NOT ILIKE '%test%'}
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# Maths
|
100
|
+
# DateDiff
|
101
|
+
it "should diff date col and date" do
|
102
|
+
compile(@table[:created_at] - Date.new(2016, 3, 31)).must_match %{DATEDIFF("users"."created_at", '2016-03-31')}
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should diff date col and datetime col" do
|
106
|
+
compile(@table[:created_at] - @table[:updated_at]).must_match %{DATEDIFF("users"."created_at", "users"."updated_at")}
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should diff date col and datetime col with AS" do
|
110
|
+
sql = compile((@table[:updated_at] - @table[:created_at]).as('new_name'))
|
111
|
+
sql.must_match %{DATEDIFF("users"."updated_at", "users"."created_at") AS new_name}
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should diff between time values" do
|
115
|
+
d2 = Time.new(2015,6,1)
|
116
|
+
d1 = DateTime.new(2015,6,2)
|
117
|
+
sql = compile(ArelExtensions::Nodes::DateDiff.new(d1,d2))
|
118
|
+
sql.must_match("DATEDIFF('2015-06-02', '2015-06-01')")
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should diff between time values and time col" do
|
122
|
+
d1 = DateTime.new(2015,6,2)
|
123
|
+
sql = compile(ArelExtensions::Nodes::DateDiff.new(d1, @table[:updated_at]))
|
124
|
+
sql.must_match %{DATEDIFF('2015-06-02', "users"."updated_at")}
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should accept operators on dates with numbers" do
|
128
|
+
c = @table[:created_at]
|
129
|
+
# u = @table[:updated_at]
|
130
|
+
compile(c - 42).must_be_like %{DATE_SUB("users"."created_at", 42)}
|
131
|
+
compile(c - @table[:id]).must_be_like %{DATE_SUB("users"."created_at", "users"."id")}
|
132
|
+
end
|
133
|
+
|
134
|
+
# Maths on sums
|
135
|
+
it "should accept math operators on anything" do
|
136
|
+
c = @table[:name]
|
137
|
+
(c == 'test').to_sql.must_be_like %{"users"."name" = 'test'}
|
138
|
+
(c != 'test').to_sql.must_be_like %{"users"."name" != 'test'}
|
139
|
+
(c > 'test').to_sql.must_be_like %{"users"."name" > 'test'}
|
140
|
+
compile((c >= 'test').as('new_name')).must_be_like %{("users"."name" >= 'test') AS new_name}
|
141
|
+
compile(c <= @table[:comments]).must_be_like %{"users"."name" <= "users"."comments"}
|
142
|
+
compile(c =~ /\Atest\Z/).must_be_like %{"users"."name" REGEXP '^test$'}
|
143
|
+
compile(c !~ /\Ate\Dst\Z/).must_be_like %{"users"."name" NOT REGEXP '^te[^0-9]st$'}
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|