arel-extensions 6.0.0 → 6.0.0.8
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 +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -5
- data/arel-extensions.gemspec +4 -3
- data/ext/arel/nodes/ascending.rb +14 -0
- data/ext/arel/nodes/descending.rb +15 -0
- data/ext/arel/order_predications.rb +14 -0
- data/lib/arel/extensions.rb +10 -0
- data/lib/arel/nodes/random.rb +7 -0
- data/lib/arel/nodes/relation.rb +35 -0
- data/lib/arel/ts_predications.rb +3 -3
- data/lib/arel/visitors/postgresql_extensions.rb +20 -0
- data/lib/arel/visitors/sunstone_extensions.rb +85 -1
- data/lib/arel/visitors/to_sql_extensions.rb +11 -0
- data/test/database.rb +15 -4
- data/test/order_test.rb +47 -0
- data/test/sunstone_test.rb +149 -0
- data/test/test_helper.rb +80 -2
- metadata +47 -10
- data/Gemfile.lock +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87c1e3d344cef64601be578c9efa5e05ca8a0fb2a0443cb81f586c06a3e1009f
|
4
|
+
data.tar.gz: 361a92b9257df496481556ccb63f78e399168dc021a5461f5a3b5b4e324a401e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e83c72da829bf31e4113d777f4cede440c1ecb8d3ad7c552225978788956af72030c669b782aa935cc4945990bb02449c224e582643ed8e88694d4b439a1995
|
7
|
+
data.tar.gz: ade28f1b9fad88a81eeeb0d25a7a3608900c802858f0579a9f0713dd68a655433ce2c2f4504939c83600db20e77e4a28995feb2bd0db2573772c4ba762f00372
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -8,14 +8,13 @@ cache:
|
|
8
8
|
- /home/travis/.rvm/gems
|
9
9
|
|
10
10
|
rvm:
|
11
|
-
- 2.5
|
12
11
|
- 2.6
|
13
12
|
|
14
13
|
env:
|
15
14
|
matrix:
|
16
|
-
- RAILS_VERSION=v6.0.
|
17
|
-
- RAILS_VERSION=v6.0.
|
18
|
-
- RAILS_VERSION=v6.0.
|
15
|
+
- RAILS_VERSION=v6.0.3.1 GEM=activerecord:mysql2
|
16
|
+
- RAILS_VERSION=v6.0.3.1 GEM=activerecord:sqlite3
|
17
|
+
- RAILS_VERSION=v6.0.3.1 GEM=activerecord:postgresql
|
19
18
|
|
20
19
|
services:
|
21
20
|
- mysql
|
@@ -26,6 +25,7 @@ before_install:
|
|
26
25
|
- unset BUNDLE_GEMFILE
|
27
26
|
- gem update --system
|
28
27
|
- gem update bundler
|
28
|
+
- gem install bundler -v 1.17.3
|
29
29
|
|
30
30
|
install:
|
31
31
|
- git clone https://github.com/rails/rails.git ~/build/rails
|
@@ -37,7 +37,7 @@ install:
|
|
37
37
|
- "sed -i \"/group :db do/a gem 'arel-extensions', require: 'arel/extensions', path: File.expand_path\\('~\\/build\\/malomalo\\/arel-extensions'\\)\" ~/build/rails/Gemfile"
|
38
38
|
- sed -i "/rb-inotify/d" ~/build/rails/Gemfile
|
39
39
|
- cat ~/build/rails/Gemfile
|
40
|
-
- bundle install --jobs=3 --retry=3
|
40
|
+
- bundle install --jobs=3 --retry=3 --full-index
|
41
41
|
- popd
|
42
42
|
|
43
43
|
script:
|
data/arel-extensions.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'arel-extensions'
|
3
|
-
gem.version
|
4
|
-
|
3
|
+
gem.version = '6.0.0.8'
|
5
4
|
gem.authors = ["Jon Bracy"]
|
6
5
|
gem.email = ["jonbracy@gmail.com"]
|
7
6
|
gem.summary = %q{Adds support for missing SQL operators and functions to Arel}
|
@@ -12,12 +11,14 @@ Gem::Specification.new do |gem|
|
|
12
11
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
13
12
|
gem.require_paths = ["lib"]
|
14
13
|
|
15
|
-
gem.add_dependency 'activerecord', '>= 6.0.0
|
14
|
+
gem.add_dependency 'activerecord', '>= 6.0.0'
|
16
15
|
|
17
16
|
gem.add_development_dependency "bundler"
|
18
17
|
gem.add_development_dependency "rake"
|
19
18
|
gem.add_development_dependency 'minitest'
|
20
19
|
gem.add_development_dependency 'minitest-reporters'
|
20
|
+
gem.add_development_dependency "sunstone"
|
21
|
+
gem.add_development_dependency "webmock"
|
21
22
|
gem.add_development_dependency 'pg'
|
22
23
|
gem.add_development_dependency 'rgeo'
|
23
24
|
|
data/lib/arel/extensions.rb
CHANGED
@@ -9,6 +9,11 @@ require File.expand_path('../nodes/contained_by', __FILE__)
|
|
9
9
|
require File.expand_path('../array_predications', __FILE__)
|
10
10
|
Arel::Attributes::Attribute.include(Arel::ArrayPredications)
|
11
11
|
|
12
|
+
require File.expand_path('../nodes/random', __FILE__)
|
13
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/nodes/ascending'))
|
14
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/nodes/descending'))
|
15
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/order_predications'))
|
16
|
+
|
12
17
|
|
13
18
|
require File.expand_path('../attributes/key', __FILE__)
|
14
19
|
require File.expand_path('../attributes/cast', __FILE__)
|
@@ -26,6 +31,7 @@ require File.expand_path('../nodes/ts_rank_cd', __FILE__)
|
|
26
31
|
require File.expand_path('../ts_predications', __FILE__)
|
27
32
|
Arel::Attributes::Attribute.include(Arel::TSPredications)
|
28
33
|
|
34
|
+
require File.expand_path('../nodes/relation', __FILE__)
|
29
35
|
|
30
36
|
require File.expand_path('../gis_predications', __FILE__)
|
31
37
|
Arel::Attributes::Attribute.include(Arel::GISPredications)
|
@@ -38,4 +44,8 @@ end
|
|
38
44
|
|
39
45
|
if defined?(Arel::Visitors::Sunstone)
|
40
46
|
require File.expand_path('../visitors/sunstone_extensions', __FILE__)
|
47
|
+
end
|
48
|
+
|
49
|
+
if defined?(Arel::Visitors::ToSql)
|
50
|
+
require File.expand_path('../visitors/to_sql_extensions', __FILE__)
|
41
51
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Arel
|
2
|
+
module Attributes
|
3
|
+
class Relation < Attribute
|
4
|
+
|
5
|
+
attr_accessor :collection, :for_write
|
6
|
+
|
7
|
+
def initialize(relation, name, collection = false, for_write=false)
|
8
|
+
self[:relation] = relation
|
9
|
+
self[:name] = name
|
10
|
+
@collection = collection
|
11
|
+
@for_write = for_write
|
12
|
+
end
|
13
|
+
|
14
|
+
def able_to_type_cast?
|
15
|
+
false
|
16
|
+
end
|
17
|
+
|
18
|
+
def table_name
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def eql? other
|
23
|
+
self.class == other.class &&
|
24
|
+
self.relation == other.relation &&
|
25
|
+
self.name == other.name &&
|
26
|
+
self.collection == other.collection
|
27
|
+
end
|
28
|
+
|
29
|
+
def type_cast_for_database(value)
|
30
|
+
relation.type_cast_for_database(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/arel/ts_predications.rb
CHANGED
@@ -2,11 +2,11 @@ module Arel
|
|
2
2
|
module TSPredications
|
3
3
|
|
4
4
|
def ts_query(expression, language=nil)
|
5
|
-
vector = Arel::Nodes::TSVector.new(self, language)
|
6
|
-
query = Arel::Nodes::TSQuery.new(expression, language)
|
5
|
+
vector = Arel::Nodes::TSVector.new(self, language: language)
|
6
|
+
query = Arel::Nodes::TSQuery.new(expression, language: language)
|
7
7
|
|
8
8
|
Arel::Nodes::TSMatch.new(vector, query)
|
9
9
|
end
|
10
10
|
|
11
11
|
end
|
12
|
-
end
|
12
|
+
end
|
@@ -8,6 +8,26 @@ module Arel
|
|
8
8
|
super
|
9
9
|
end
|
10
10
|
|
11
|
+
def visit_Arel_Nodes_Ascending o, collector
|
12
|
+
case o.nulls
|
13
|
+
when :nulls_first then visit(o.expr, collector) << ' ASC NULLS FIRST'
|
14
|
+
when :nulls_last then visit(o.expr, collector) << ' ASC NULLS LAST'
|
15
|
+
else visit(o.expr, collector) << ' ASC'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def visit_Arel_Nodes_Descending o, collector
|
20
|
+
case o.nulls
|
21
|
+
when :nulls_first then visit(o.expr, collector) << ' DESC NULLS FIRST'
|
22
|
+
when :nulls_last then visit(o.expr, collector) << ' DESC NULLS LAST'
|
23
|
+
else visit(o.expr, collector) << ' DESC'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_Arel_Nodes_RandomOrdering o, collector
|
28
|
+
collector << "RANDOM()"
|
29
|
+
end
|
30
|
+
|
11
31
|
def visit_Arel_Nodes_Contains o, collector
|
12
32
|
visit o.left, collector
|
13
33
|
collector << ' @> '
|
@@ -2,7 +2,67 @@ module Arel
|
|
2
2
|
module Visitors
|
3
3
|
class Sunstone
|
4
4
|
private
|
5
|
+
|
6
|
+
def visit_Arel_Nodes_Ascending o, collector
|
7
|
+
hash = visit(o.expr, collector)
|
8
|
+
|
9
|
+
value = case o.nulls
|
10
|
+
when :nulls_first
|
11
|
+
{asc: :nulls_first}
|
12
|
+
when :nulls_last
|
13
|
+
{asc: :nulls_last}
|
14
|
+
else
|
15
|
+
:asc
|
16
|
+
end
|
17
|
+
|
18
|
+
if hash.is_a?(Hash)
|
19
|
+
add_to_bottom_of_hash_or_array(hash, value)
|
20
|
+
else
|
21
|
+
hash = { hash => value }
|
22
|
+
end
|
23
|
+
|
24
|
+
hash
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_Arel_Nodes_Descending o, collector
|
28
|
+
hash = visit(o.expr, collector)
|
29
|
+
|
30
|
+
value = case o.nulls
|
31
|
+
when :nulls_first
|
32
|
+
{desc: :nulls_first}
|
33
|
+
when :nulls_last
|
34
|
+
{desc: :nulls_last}
|
35
|
+
else
|
36
|
+
:desc
|
37
|
+
end
|
38
|
+
|
39
|
+
if hash.is_a?(Hash)
|
40
|
+
add_to_bottom_of_hash_or_array(hash, value)
|
41
|
+
else
|
42
|
+
hash = { hash => value }
|
43
|
+
end
|
44
|
+
|
45
|
+
hash
|
46
|
+
end
|
47
|
+
|
48
|
+
def visit_Arel_Nodes_RandomOrdering o, collector
|
49
|
+
:random
|
50
|
+
end
|
51
|
+
|
52
|
+
def visit_Hash o, collector
|
53
|
+
rvalue = {}
|
54
|
+
o.each do |key, value|
|
55
|
+
rvalue[visit(key, collector)] = visit(value, collector)
|
56
|
+
end
|
57
|
+
rvalue
|
58
|
+
end
|
5
59
|
|
60
|
+
alias :visit_String :literal
|
61
|
+
|
62
|
+
def visit_Symbol o, collector
|
63
|
+
o.to_s
|
64
|
+
end
|
65
|
+
|
6
66
|
def visit_Arel_Nodes_Contains o, collector
|
7
67
|
key = visit(o.left, collector)
|
8
68
|
value = { contains: visit(o.right, collector) }
|
@@ -40,6 +100,30 @@ module Arel
|
|
40
100
|
end
|
41
101
|
end
|
42
102
|
|
103
|
+
def visit_Arel_Nodes_Overlaps o, collector
|
104
|
+
key = visit(o.left, collector)
|
105
|
+
value = { overlaps: o.left.type_cast_for_database(o.right) }
|
106
|
+
|
107
|
+
if key.is_a?(Hash)
|
108
|
+
add_to_bottom_of_hash_or_array(key, value)
|
109
|
+
key
|
110
|
+
else
|
111
|
+
{key => value}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def visit_Arel_Nodes_NotOverlaps o, collector
|
116
|
+
key = visit(o.left, collector)
|
117
|
+
value = { not_overlaps: o.left.type_cast_for_database(o.right) }
|
118
|
+
|
119
|
+
if key.is_a?(Hash)
|
120
|
+
add_to_bottom_of_hash_or_array(key, value)
|
121
|
+
key
|
122
|
+
else
|
123
|
+
{key => value}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
43
127
|
def visit_Arel_Nodes_HasKey o, collector
|
44
128
|
key = visit(o.left, collector)
|
45
129
|
value = {has_key: (o.right.nil? ? nil : o.right.to_s)}
|
@@ -64,7 +148,7 @@ module Arel
|
|
64
148
|
|
65
149
|
def visit_Arel_Nodes_HasAnyKey o, collector
|
66
150
|
key = visit(o.left, collector)
|
67
|
-
value = {has_any_key: Array(o.right)
|
151
|
+
value = { has_any_key: visit(Array(o.right), collector) }
|
68
152
|
|
69
153
|
if key.is_a?(Hash)
|
70
154
|
add_to_bottom_of_hash(key, value)
|
data/test/database.rb
CHANGED
@@ -22,19 +22,30 @@ ActiveRecord::Migration.suppress_messages do
|
|
22
22
|
create_table "properties", force: :cascade do |t|
|
23
23
|
t.string "name", limit: 255
|
24
24
|
t.tsvector 'vector_col'
|
25
|
+
t.jsonb 'metadata'
|
25
26
|
end
|
26
27
|
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
31
|
class Address < ActiveRecord::Base
|
31
|
-
|
32
32
|
belongs_to :property
|
33
|
-
|
34
33
|
end
|
35
34
|
|
36
35
|
class Property < ActiveRecord::Base
|
37
|
-
|
38
36
|
has_many :addresses
|
37
|
+
end
|
38
|
+
|
39
|
+
class SunstoneRecord < ActiveRecord::Base
|
40
|
+
self.abstract_class = true
|
41
|
+
end
|
42
|
+
|
43
|
+
class SunstoneAddress < SunstoneRecord
|
44
|
+
belongs_to :property, class_name: 'SunstoneProperty'
|
45
|
+
end
|
46
|
+
|
47
|
+
class SunstoneProperty < SunstoneRecord
|
48
|
+
has_many :addresses, class_name: 'SunstoneAddress'
|
49
|
+
end
|
39
50
|
|
40
|
-
|
51
|
+
SunstoneRecord.establish_connection(adapter: 'sunstone', url: 'http://example.com')
|
data/test/order_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class OrderTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
test '::order(column.asc)' do
|
6
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].asc))
|
7
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" ASC
|
8
|
+
SQL
|
9
|
+
end
|
10
|
+
|
11
|
+
test '::order(column1.asc, column2.asc)' do
|
12
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].asc, Property.arel_table[:name].asc))
|
13
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" ASC, "properties"."name" ASC
|
14
|
+
SQL
|
15
|
+
end
|
16
|
+
|
17
|
+
test '::order(column.desc)' do
|
18
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].desc))
|
19
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" DESC
|
20
|
+
SQL
|
21
|
+
end
|
22
|
+
|
23
|
+
test '::order(column.asc(:nulls_first))' do
|
24
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].asc(:nulls_first)))
|
25
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" ASC NULLS FIRST
|
26
|
+
SQL
|
27
|
+
end
|
28
|
+
|
29
|
+
test '::order(column.asc(:nulls_last))' do
|
30
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].asc(:nulls_last)))
|
31
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" ASC NULLS LAST
|
32
|
+
SQL
|
33
|
+
end
|
34
|
+
|
35
|
+
test '::order(column.desc(:nulls_first))' do
|
36
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].desc(:nulls_first)))
|
37
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" DESC NULLS FIRST
|
38
|
+
SQL
|
39
|
+
end
|
40
|
+
|
41
|
+
test '::order(column.desc(:nulls_last))' do
|
42
|
+
assert_sql(<<~SQL, Property.order(Property.arel_table[:id].desc(:nulls_last)))
|
43
|
+
SELECT "properties".* FROM "properties" ORDER BY "properties"."id" DESC NULLS LAST
|
44
|
+
SQL
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SunstoneTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
# schema do
|
6
|
+
# create_table "properties", force: :cascade do |t|
|
7
|
+
# t.jsonb 'metadata'
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
|
11
|
+
# class Property < ActiveRecord::Base
|
12
|
+
# end
|
13
|
+
|
14
|
+
# test "::filter json_column: STRING throws an error" do
|
15
|
+
# assert_raises(ActiveRecord::UnkownFilterError) do
|
16
|
+
# Property.filter(metadata: 'string').load
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
|
20
|
+
# test "::filter json_column: {eq: JSON_HASH}" do
|
21
|
+
# query = Property.where(metadata: {eq: {json: 'string'}})
|
22
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
23
|
+
# SELECT "properties".*
|
24
|
+
# FROM "properties"
|
25
|
+
# WHERE "properties"."metadata" = '{\"json\":\"string\"}'
|
26
|
+
# SQL
|
27
|
+
# end
|
28
|
+
|
29
|
+
test "::filter json_column: {contains: JSON_HASH}" do
|
30
|
+
query = SunstoneProperty.where(SunstoneProperty.arel_attribute('metadata').contains({json: 'string'}))
|
31
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
32
|
+
where: {metadata: {contains: { json: 'string' }}}
|
33
|
+
})
|
34
|
+
|
35
|
+
# query = Property.where(metadata: {contains: {json: 'string'}})
|
36
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
37
|
+
# SELECT "properties".*
|
38
|
+
# FROM "properties"
|
39
|
+
# WHERE "properties"."metadata" @> '{\"json\":\"string\"}'
|
40
|
+
# SQL
|
41
|
+
end
|
42
|
+
|
43
|
+
# test "::filter json_column: {contained_by: JSON_HASH}" do
|
44
|
+
# query = Property.filter(metadata: {contained_by: {json: 'string'}})
|
45
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
46
|
+
# SELECT "properties".*
|
47
|
+
# FROM "properties"
|
48
|
+
# WHERE "properties"."metadata" <@ '{\"json\":\"string\"}'
|
49
|
+
# SQL
|
50
|
+
# end
|
51
|
+
|
52
|
+
# test "::filter json_column: {has_key: STRING}" do
|
53
|
+
# query = Property.filter(metadata: {has_key: 'string'})
|
54
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
55
|
+
# SELECT "properties".*
|
56
|
+
# FROM "properties"
|
57
|
+
# WHERE "properties"."metadata" ? 'string'
|
58
|
+
# SQL
|
59
|
+
# end
|
60
|
+
|
61
|
+
# test "::filter json_column.subkey: {eq: JSON_HASH}" do
|
62
|
+
# query = Property.filter("metadata.subkey" => {eq: 'string'})
|
63
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
64
|
+
# SELECT "properties".*
|
65
|
+
# FROM "properties"
|
66
|
+
# WHERE "properties"."metadata"#>'{subkey}' = 'string'
|
67
|
+
# SQL
|
68
|
+
# end
|
69
|
+
|
70
|
+
# test "::filter json_column: BOOLEAN" do
|
71
|
+
# query = Property.filter(metadata: true)
|
72
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
73
|
+
# SELECT "properties".*
|
74
|
+
# FROM "properties"
|
75
|
+
# WHERE "properties"."metadata" IS NOT NULL
|
76
|
+
# SQL
|
77
|
+
|
78
|
+
# query = Property.filter(metadata: "true")
|
79
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
80
|
+
# SELECT "properties".*
|
81
|
+
# FROM "properties"
|
82
|
+
# WHERE "properties"."metadata" IS NOT NULL
|
83
|
+
# SQL
|
84
|
+
|
85
|
+
# query = Property.filter(metadata: false)
|
86
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
87
|
+
# SELECT "properties".*
|
88
|
+
# FROM "properties"
|
89
|
+
# WHERE "properties"."metadata" IS NULL
|
90
|
+
# SQL
|
91
|
+
|
92
|
+
# query = Property.filter(metadata: "false")
|
93
|
+
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
94
|
+
# SELECT "properties".*
|
95
|
+
# FROM "properties"
|
96
|
+
# WHERE "properties"."metadata" IS NULL
|
97
|
+
# SQL
|
98
|
+
# end
|
99
|
+
|
100
|
+
test '::order(column.asc)' do
|
101
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].asc)
|
102
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
103
|
+
order: [{ id: :asc }]
|
104
|
+
})
|
105
|
+
end
|
106
|
+
|
107
|
+
test '::order(column1.asc, column2.asc)' do
|
108
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].asc, SunstoneProperty.arel_table[:name].asc)
|
109
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
110
|
+
order: [{ id: :asc }, { name: :asc }]
|
111
|
+
})
|
112
|
+
end
|
113
|
+
|
114
|
+
test '::order(column.desc)' do
|
115
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].desc)
|
116
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
117
|
+
order: [{ id: :desc }]
|
118
|
+
})
|
119
|
+
end
|
120
|
+
|
121
|
+
test '::order(column.asc(:nulls_first))' do
|
122
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].asc(:nulls_first))
|
123
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
124
|
+
order: [{ id: { asc: :nulls_first } }]
|
125
|
+
})
|
126
|
+
end
|
127
|
+
|
128
|
+
test '::order(column.asc(:nulls_last))' do
|
129
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].asc(:nulls_last))
|
130
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
131
|
+
order: [{ id: { asc: :nulls_last } }]
|
132
|
+
})
|
133
|
+
end
|
134
|
+
|
135
|
+
test '::order(column.desc(:nulls_first))' do
|
136
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].desc(:nulls_first))
|
137
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
138
|
+
order: [{ id: { desc: :nulls_first } }]
|
139
|
+
})
|
140
|
+
end
|
141
|
+
|
142
|
+
test '::order(column.desc(:nulls_last))' do
|
143
|
+
query = SunstoneProperty.order(SunstoneProperty.arel_table[:id].desc(:nulls_last))
|
144
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
145
|
+
order: [{ id: { desc: :nulls_last } }]
|
146
|
+
})
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -12,11 +12,13 @@ require 'rgeo'
|
|
12
12
|
require "minitest/autorun"
|
13
13
|
require 'minitest/unit'
|
14
14
|
require 'minitest/reporters'
|
15
|
-
|
15
|
+
require 'webmock/minitest'
|
16
16
|
# require 'mocha/minitest'
|
17
17
|
require 'active_record'
|
18
|
+
require 'sunstone'
|
18
19
|
require 'arel/extensions'
|
19
20
|
|
21
|
+
|
20
22
|
# Setup the test db
|
21
23
|
ActiveSupport.test_order = :random
|
22
24
|
require File.expand_path('../database', __FILE__)
|
@@ -27,7 +29,7 @@ $debugging = false
|
|
27
29
|
|
28
30
|
# File 'lib/active_support/testing/declarative.rb', somewhere in rails....
|
29
31
|
class ActiveSupport::TestCase
|
30
|
-
|
32
|
+
include WebMock::API
|
31
33
|
|
32
34
|
# File 'lib/active_support/testing/declarative.rb'
|
33
35
|
def self.test(name, &block)
|
@@ -54,6 +56,51 @@ class ActiveSupport::TestCase
|
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
59
|
+
|
60
|
+
def setup
|
61
|
+
sunstone_schema = {
|
62
|
+
addresses: {
|
63
|
+
columns: {
|
64
|
+
id: { type: :integer, primary_key: true, null: false, array: false },
|
65
|
+
name: { type: :string, primary_key: false, null: true, array: false },
|
66
|
+
property_id: { type: :integer, primary_key: false, null: true, array: false }
|
67
|
+
}
|
68
|
+
},
|
69
|
+
properties: {
|
70
|
+
columns: {
|
71
|
+
id: { type: :integer, primary_key: true, null: false, array: false },
|
72
|
+
name: { type: :string, primary_key: false, null: true, array: false },
|
73
|
+
metadata: { type: :json, primary_key: false, null: true, array: false }
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
req_stub = stub_request(:get, /^http:\/\/example.com/).with do |req|
|
79
|
+
case req.uri.path
|
80
|
+
when '/tables'
|
81
|
+
true
|
82
|
+
when /^\/\w+\/schema$/i
|
83
|
+
true
|
84
|
+
else
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
req_stub.to_return do |req|
|
90
|
+
case req.uri.path
|
91
|
+
when '/tables'
|
92
|
+
{
|
93
|
+
body: sunstone_schema.keys.to_json,
|
94
|
+
headers: { 'StandardAPI-Version' => '5.0.0.5' }
|
95
|
+
}
|
96
|
+
when /^\/(\w+)\/schema$/i
|
97
|
+
{
|
98
|
+
body: sunstone_schema[$1.to_sym].to_json,
|
99
|
+
headers: { 'StandardAPI-Version' => '5.0.0.5' }
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
57
104
|
|
58
105
|
def debug
|
59
106
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
@@ -112,6 +159,37 @@ class ActiveSupport::TestCase
|
|
112
159
|
end
|
113
160
|
ActiveSupport::Notifications.subscribe('sql.active_record', SQLLogger.new)
|
114
161
|
|
162
|
+
def deep_transform_query(object)
|
163
|
+
case object
|
164
|
+
when Hash
|
165
|
+
object.each_with_object({}) do |(key, value), result|
|
166
|
+
result[key.to_s] = deep_transform_query(value)
|
167
|
+
end
|
168
|
+
when Array
|
169
|
+
object.map {|e| deep_transform_query(e) }
|
170
|
+
when Symbol
|
171
|
+
object.to_s
|
172
|
+
else
|
173
|
+
object
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def assert_sar(query, method, path, query_params = {}, body = nil)
|
178
|
+
sar = query.to_sar
|
179
|
+
|
180
|
+
assert_equal method, sar.method
|
181
|
+
assert_equal path, sar.path.split('?').first
|
182
|
+
assert_equal deep_transform_query(query_params), MessagePack.unpack(CGI::unescape(sar.path.split('?').last))
|
183
|
+
if body.nil?
|
184
|
+
assert_nil sar.body
|
185
|
+
else
|
186
|
+
assert_equal body, sar.body
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def assert_sql(expected, query)
|
191
|
+
assert_equal expected.strip, query.to_sql.strip.gsub(/\s+/, ' ')
|
192
|
+
end
|
115
193
|
# test/unit backwards compatibility methods
|
116
194
|
alias :assert_raise :assert_raises
|
117
195
|
alias :assert_not_empty :refute_empty
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arel-extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.0
|
4
|
+
version: 6.0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.0.0
|
19
|
+
version: 6.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.0.0
|
26
|
+
version: 6.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sunstone
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: pg
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +136,7 @@ dependencies:
|
|
108
136
|
- - ">="
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '0'
|
111
|
-
description:
|
139
|
+
description:
|
112
140
|
email:
|
113
141
|
- jonbracy@gmail.com
|
114
142
|
executables: []
|
@@ -118,11 +146,13 @@ files:
|
|
118
146
|
- ".gitignore"
|
119
147
|
- ".travis.yml"
|
120
148
|
- Gemfile
|
121
|
-
- Gemfile.lock
|
122
149
|
- LICENSE
|
123
150
|
- README.md
|
124
151
|
- Rakefile
|
125
152
|
- arel-extensions.gemspec
|
153
|
+
- ext/arel/nodes/ascending.rb
|
154
|
+
- ext/arel/nodes/descending.rb
|
155
|
+
- ext/arel/order_predications.rb
|
126
156
|
- lib/active_record/query_methods.rb
|
127
157
|
- lib/arel/array_predications.rb
|
128
158
|
- lib/arel/attributes/cast.rb
|
@@ -138,6 +168,8 @@ files:
|
|
138
168
|
- lib/arel/nodes/has_keys.rb
|
139
169
|
- lib/arel/nodes/hex_encoded_binary.rb
|
140
170
|
- lib/arel/nodes/overlaps.rb
|
171
|
+
- lib/arel/nodes/random.rb
|
172
|
+
- lib/arel/nodes/relation.rb
|
141
173
|
- lib/arel/nodes/ts_match.rb
|
142
174
|
- lib/arel/nodes/ts_query.rb
|
143
175
|
- lib/arel/nodes/ts_rank.rb
|
@@ -147,14 +179,17 @@ files:
|
|
147
179
|
- lib/arel/ts_predications.rb
|
148
180
|
- lib/arel/visitors/postgresql_extensions.rb
|
149
181
|
- lib/arel/visitors/sunstone_extensions.rb
|
182
|
+
- lib/arel/visitors/to_sql_extensions.rb
|
150
183
|
- test/database.rb
|
184
|
+
- test/order_test.rb
|
185
|
+
- test/sunstone_test.rb
|
151
186
|
- test/test_helper.rb
|
152
187
|
- test/ts_test.rb
|
153
188
|
homepage: https://github.com/malomalo/arel-extensions
|
154
189
|
licenses:
|
155
190
|
- MIT
|
156
191
|
metadata: {}
|
157
|
-
post_install_message:
|
192
|
+
post_install_message:
|
158
193
|
rdoc_options: []
|
159
194
|
require_paths:
|
160
195
|
- lib
|
@@ -169,11 +204,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
169
204
|
- !ruby/object:Gem::Version
|
170
205
|
version: '0'
|
171
206
|
requirements: []
|
172
|
-
rubygems_version: 3.
|
173
|
-
signing_key:
|
207
|
+
rubygems_version: 3.1.2
|
208
|
+
signing_key:
|
174
209
|
specification_version: 4
|
175
210
|
summary: Adds support for missing SQL operators and functions to Arel
|
176
211
|
test_files:
|
177
212
|
- test/database.rb
|
213
|
+
- test/order_test.rb
|
214
|
+
- test/sunstone_test.rb
|
178
215
|
- test/test_helper.rb
|
179
216
|
- test/ts_test.rb
|
data/Gemfile.lock
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
arel-extensions (6.0.0)
|
5
|
-
activerecord (>= 6.0.0.rc1)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (6.0.0.rc1)
|
11
|
-
activesupport (= 6.0.0.rc1)
|
12
|
-
activerecord (6.0.0.rc1)
|
13
|
-
activemodel (= 6.0.0.rc1)
|
14
|
-
activesupport (= 6.0.0.rc1)
|
15
|
-
activesupport (6.0.0.rc1)
|
16
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
-
i18n (>= 0.7, < 2)
|
18
|
-
minitest (~> 5.1)
|
19
|
-
tzinfo (~> 1.1)
|
20
|
-
zeitwerk (~> 2.1, >= 2.1.4)
|
21
|
-
ansi (1.5.0)
|
22
|
-
builder (3.2.3)
|
23
|
-
concurrent-ruby (1.1.5)
|
24
|
-
i18n (1.6.0)
|
25
|
-
concurrent-ruby (~> 1.0)
|
26
|
-
minitest (5.11.3)
|
27
|
-
minitest-reporters (1.3.5)
|
28
|
-
ansi
|
29
|
-
builder
|
30
|
-
minitest (>= 5.0)
|
31
|
-
ruby-progressbar
|
32
|
-
pg (1.1.3)
|
33
|
-
rake (12.3.1)
|
34
|
-
rgeo (1.0.0)
|
35
|
-
ruby-progressbar (1.10.0)
|
36
|
-
thread_safe (0.3.6)
|
37
|
-
tzinfo (1.2.5)
|
38
|
-
thread_safe (~> 0.1)
|
39
|
-
zeitwerk (2.1.6)
|
40
|
-
|
41
|
-
PLATFORMS
|
42
|
-
ruby
|
43
|
-
|
44
|
-
DEPENDENCIES
|
45
|
-
arel-extensions!
|
46
|
-
bundler
|
47
|
-
minitest
|
48
|
-
minitest-reporters
|
49
|
-
pg
|
50
|
-
rake
|
51
|
-
rgeo
|
52
|
-
|
53
|
-
BUNDLED WITH
|
54
|
-
1.17.3
|