arel-extensions 6.0.0.5 → 6.1.0.rc2
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 +1 -0
- data/.travis.yml +34 -14
- data/arel-extensions.gemspec +8 -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/array_predications.rb +4 -14
- data/lib/arel/extensions.rb +5 -2
- data/lib/arel/extensions/version.rb +5 -0
- data/lib/arel/nodes/contained_by.rb +5 -2
- data/lib/arel/nodes/random.rb +7 -0
- data/lib/arel/nodes/relation.rb +6 -2
- data/lib/arel/nodes/ts_rank_cd.rb +3 -2
- data/lib/arel/ts_predications.rb +3 -3
- data/lib/arel/visitors/postgresql_extensions.rb +22 -19
- data/lib/arel/visitors/sunstone_extensions.rb +55 -3
- data/test/database.rb +20 -12
- data/test/order_test.rb +47 -0
- data/test/sunstone_test.rb +53 -2
- data/test/test_helper.rb +85 -7
- data/test/ts_test.rb +15 -0
- metadata +60 -14
- data/Gemfile.lock +0 -54
- data/lib/arel/nodes/contains.rb +0 -6
- data/lib/arel/nodes/overlaps.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5d5fc1f0a60a20f13e1f12d1b445c347bce09e0e070ad0e3a45e1e77b108eab
|
4
|
+
data.tar.gz: c75928cd9e920e0004829c359e5b4cb61d237474e0667a7ef6876045fa01c539
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb8e0f51781d3459bda4514c07fcabe0b51d27ca668f4c17ccdc7a9f6e714d4bde039c13a103697765a9ae076befa3d36285e6a5bf3dae2df4b810fb17b72d19
|
7
|
+
data.tar.gz: e75fa73cfa18eb83e1e22a5941c75721d8bc536092b51900fcce6195d77cb466b082f232fe2b36a784af56a93701cb593ef4c9c160e7df64c110e5feadb7c241
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
dist:
|
1
|
+
dist: bionic
|
2
2
|
language: ruby
|
3
3
|
sudo: false
|
4
4
|
|
@@ -8,40 +8,60 @@ cache:
|
|
8
8
|
- /home/travis/.rvm/gems
|
9
9
|
|
10
10
|
rvm:
|
11
|
-
- 2.
|
12
|
-
- 2.6
|
11
|
+
- 2.7
|
13
12
|
|
14
13
|
env:
|
15
14
|
matrix:
|
16
|
-
- RAILS_VERSION=v6.
|
17
|
-
- RAILS_VERSION=v6.
|
18
|
-
- RAILS_VERSION=v6.
|
19
|
-
- RAILS_VERSION=v6.
|
20
|
-
- RAILS_VERSION=v6.
|
21
|
-
- RAILS_VERSION=v6.
|
15
|
+
- RAILS_VERSION=v6.1.0 TASK='db:mysql:rebuild mysql2:test'
|
16
|
+
- RAILS_VERSION=v6.1.0 TASK='db:mysql:rebuild mysql2:isolated_test'
|
17
|
+
- RAILS_VERSION=v6.1.0 TASK='db:postgresql:rebuild postgresql:test'
|
18
|
+
- RAILS_VERSION=v6.1.0 TASK='db:postgresql:rebuild postgresql:isolated_test'
|
19
|
+
- RAILS_VERSION=v6.1.0 TASK='sqlite3:test'
|
20
|
+
- RAILS_VERSION=v6.1.0 TASK='sqlite3:isolated_test'
|
21
|
+
- RAILS_VERSION=v6.1.0 TASK='sqlite3_mem:test'
|
22
22
|
|
23
23
|
services:
|
24
24
|
- mysql
|
25
25
|
addons:
|
26
|
-
postgresql: "
|
26
|
+
postgresql: "13"
|
27
|
+
apt:
|
28
|
+
packages:
|
29
|
+
- postgresql-13
|
30
|
+
- postgresql-client-13
|
27
31
|
|
28
32
|
before_install:
|
33
|
+
- sudo sed -i 's/port = 5433/port = 5432/' /etc/postgresql/13/main/postgresql.conf
|
34
|
+
- sudo cp /etc/postgresql/{9.3,13}/main/pg_hba.conf
|
35
|
+
- sudo pg_ctlcluster 13 main restart
|
29
36
|
- unset BUNDLE_GEMFILE
|
30
37
|
- gem update --system
|
31
38
|
- gem update bundler
|
39
|
+
- gem install bundler --version 1.17.3
|
40
|
+
- mysql -e "create user rails@localhost;"
|
41
|
+
- mysql -e "grant all privileges on activerecord_unittest.* to rails@localhost;"
|
42
|
+
- mysql -e "grant all privileges on activerecord_unittest2.* to rails@localhost;"
|
43
|
+
- mysql -e "grant all privileges on inexistent_activerecord_unittest.* to rails@localhost;"
|
44
|
+
- mysql -e "create database activerecord_unittest default character set utf8mb4;"
|
45
|
+
- mysql -e "create database activerecord_unittest2 default character set utf8mb4;"
|
32
46
|
|
33
47
|
install:
|
34
|
-
- git clone https://github.com/rails/rails.git ~/build/rails
|
48
|
+
- git clone --branch $RAILS_VERSION https://github.com/rails/rails.git ~/build/rails
|
49
|
+
|
50
|
+
before_script:
|
51
|
+
- sed -i "s/t.warning = true/t.warning = false/g" Rakefile
|
35
52
|
- pushd ~/build/rails
|
36
|
-
- git
|
53
|
+
- git status
|
37
54
|
- sed -i "s/Gem.ruby, '-w'/Gem.ruby, '-w0'/" ~/build/rails/activerecord/Rakefile
|
38
55
|
- sed -i "s/t.warning = true/t.warning = false/g" ~/build/rails/activerecord/Rakefile
|
39
56
|
- sed -i "/require 'support\/connection'/a \$LOAD_PATH.unshift\(File.expand_path\('~\/build\/malomalo\/arel-extensions\/lib'\)\)\nrequire 'arel/extensions'" ~/build/rails/activerecord/test/cases/helper.rb
|
40
57
|
- "sed -i \"/group :db do/a gem 'arel-extensions', require: 'arel/extensions', path: File.expand_path\\('~\\/build\\/malomalo\\/arel-extensions'\\)\" ~/build/rails/Gemfile"
|
41
58
|
- sed -i "/rb-inotify/d" ~/build/rails/Gemfile
|
42
59
|
- cat ~/build/rails/Gemfile
|
43
|
-
-
|
60
|
+
- rm ~/build/rails/Gemfile.lock
|
61
|
+
- bundle update --jobs=3 --retry=3
|
44
62
|
- popd
|
63
|
+
- bundle install --jobs=3 --retry=3
|
45
64
|
|
46
65
|
script:
|
47
|
-
-
|
66
|
+
- bundle exec rake test
|
67
|
+
- cd ~/build/rails/activerecord && bundle exec rake $TASK
|
data/arel-extensions.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require File.expand_path("../lib/arel/extensions/version", __FILE__)
|
2
|
+
|
1
3
|
Gem::Specification.new do |gem|
|
2
4
|
gem.name = 'arel-extensions'
|
3
|
-
gem.version =
|
5
|
+
gem.version = Arel::Extensions::VERSION
|
4
6
|
gem.authors = ["Jon Bracy"]
|
5
7
|
gem.email = ["jonbracy@gmail.com"]
|
6
8
|
gem.summary = %q{Adds support for missing SQL operators and functions to Arel}
|
@@ -11,13 +13,16 @@ Gem::Specification.new do |gem|
|
|
11
13
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
12
14
|
gem.require_paths = ["lib"]
|
13
15
|
|
14
|
-
gem.add_dependency 'activerecord', '>= 6.
|
16
|
+
gem.add_dependency 'activerecord', '>= 6.1.0'
|
15
17
|
|
16
18
|
gem.add_development_dependency "bundler"
|
19
|
+
gem.add_development_dependency "byebug"
|
17
20
|
gem.add_development_dependency "rake"
|
18
21
|
gem.add_development_dependency 'minitest'
|
19
22
|
gem.add_development_dependency 'minitest-reporters'
|
23
|
+
gem.add_development_dependency "sunstone", '>= 6.1.0.rc1'
|
24
|
+
gem.add_development_dependency "webmock"
|
20
25
|
gem.add_development_dependency 'pg'
|
21
26
|
gem.add_development_dependency 'rgeo'
|
22
|
-
|
27
|
+
|
23
28
|
end
|
@@ -1,24 +1,14 @@
|
|
1
1
|
module Arel
|
2
2
|
module ArrayPredications
|
3
|
-
|
4
|
-
# Used by both JSON and ARRAY so it doesn't try to cast to array
|
5
|
-
def contains(value)
|
6
|
-
Arel::Nodes::Contains.new(self, value)
|
7
|
-
end
|
8
|
-
|
3
|
+
|
9
4
|
# Used by both JSON and ARRAY so it doesn't try to cast to array
|
10
5
|
def contained_by(value)
|
11
6
|
Arel::Nodes::ContainedBy.new(self, value)
|
12
7
|
end
|
13
|
-
|
8
|
+
|
14
9
|
def excludes(value)
|
15
10
|
Arel::Nodes::Excludes.new(self, value)
|
16
11
|
end
|
17
|
-
|
18
|
-
def overlaps(*values)
|
19
|
-
values = values[0] if values.size == 1 && values[0].is_a?(Array)
|
20
|
-
Arel::Nodes::Overlaps.new(self, values)
|
21
|
-
end
|
22
|
-
|
12
|
+
|
23
13
|
end
|
24
|
-
end
|
14
|
+
end
|
data/lib/arel/extensions.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require "arel"
|
2
2
|
require File.expand_path('../nodes/hex_encoded_binary', __FILE__)
|
3
3
|
|
4
|
-
require File.expand_path('../nodes/overlaps', __FILE__)
|
5
|
-
require File.expand_path('../nodes/contains', __FILE__)
|
6
4
|
require File.expand_path('../nodes/within', __FILE__)
|
7
5
|
require File.expand_path('../nodes/excludes', __FILE__)
|
8
6
|
require File.expand_path('../nodes/contained_by', __FILE__)
|
9
7
|
require File.expand_path('../array_predications', __FILE__)
|
10
8
|
Arel::Attributes::Attribute.include(Arel::ArrayPredications)
|
11
9
|
|
10
|
+
require File.expand_path('../nodes/random', __FILE__)
|
11
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/nodes/ascending'))
|
12
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/nodes/descending'))
|
13
|
+
require File.expand_path(File.join(__FILE__, '../../../ext/arel/order_predications'))
|
14
|
+
|
12
15
|
|
13
16
|
require File.expand_path('../attributes/key', __FILE__)
|
14
17
|
require File.expand_path('../attributes/cast', __FILE__)
|
data/lib/arel/nodes/relation.rb
CHANGED
@@ -12,7 +12,7 @@ module Arel
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def able_to_type_cast?
|
15
|
-
|
15
|
+
relation.able_to_type_cast?
|
16
16
|
end
|
17
17
|
|
18
18
|
def table_name
|
@@ -25,7 +25,11 @@ module Arel
|
|
25
25
|
self.name == other.name &&
|
26
26
|
self.collection == other.collection
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
|
+
def type_cast_for_database(value)
|
30
|
+
relation.type_cast_for_database(value)
|
31
|
+
end
|
32
|
+
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -2,11 +2,12 @@ module Arel
|
|
2
2
|
module Nodes
|
3
3
|
class TSRankCD < Arel::Nodes::Node
|
4
4
|
|
5
|
-
attr_reader :tsvector, :tsquery
|
5
|
+
attr_reader :tsvector, :tsquery, :normalization
|
6
6
|
|
7
|
-
def initialize(tsvector, tsquery)
|
7
|
+
def initialize(tsvector, tsquery, normalization=nil)
|
8
8
|
@tsvector = tsvector
|
9
9
|
@tsquery = tsquery
|
10
|
+
@normalization = normalization
|
10
11
|
end
|
11
12
|
|
12
13
|
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,36 +8,35 @@ module Arel
|
|
8
8
|
super
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
|
13
|
-
collector << '
|
14
|
-
|
15
|
-
collector
|
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
|
16
25
|
end
|
17
26
|
|
18
|
-
def
|
19
|
-
|
20
|
-
collector << ' <@ '
|
21
|
-
collector << quote(o.left.type_cast_for_database(o.right))
|
22
|
-
collector
|
27
|
+
def visit_Arel_Nodes_RandomOrdering o, collector
|
28
|
+
collector << "RANDOM()"
|
23
29
|
end
|
24
|
-
|
30
|
+
|
25
31
|
def visit_Arel_Nodes_Excludes o, collector
|
26
32
|
collector << 'NOT ('
|
27
33
|
visit o.left, collector
|
28
34
|
collector << ' @> '
|
29
|
-
|
35
|
+
visit o.right, collector
|
30
36
|
collector << ')'
|
31
37
|
collector
|
32
38
|
end
|
33
39
|
|
34
|
-
def visit_Arel_Nodes_Overlaps o, collector
|
35
|
-
visit o.left, collector
|
36
|
-
collector << ' && '
|
37
|
-
collector << quote(o.left.type_cast_for_database(o.right))
|
38
|
-
collector
|
39
|
-
end
|
40
|
-
|
41
40
|
def visit_Arel_Attributes_Key(o, collector, last_key = true)
|
42
41
|
if o.relation.is_a?(Arel::Attributes::Key)
|
43
42
|
visit_Arel_Attributes_Key(o.relation, collector, false)
|
@@ -133,6 +132,10 @@ module Arel
|
|
133
132
|
visit(o.tsvector, collector)
|
134
133
|
collector << ', '
|
135
134
|
visit(o.tsquery, collector)
|
135
|
+
if o.normalization
|
136
|
+
collector << ', '
|
137
|
+
visit(o.normalization, collector)
|
138
|
+
end
|
136
139
|
collector << ')'
|
137
140
|
collector
|
138
141
|
end
|
@@ -3,12 +3,64 @@ module Arel
|
|
3
3
|
class Sunstone
|
4
4
|
private
|
5
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
|
+
|
6
52
|
def visit_Hash o, collector
|
7
|
-
|
53
|
+
rvalue = {}
|
8
54
|
o.each do |key, value|
|
9
|
-
|
55
|
+
rvalue[visit(key, collector)] = visit(value, collector)
|
10
56
|
end
|
11
|
-
|
57
|
+
rvalue
|
58
|
+
end
|
59
|
+
|
60
|
+
alias :visit_String :literal
|
61
|
+
|
62
|
+
def visit_Symbol o, collector
|
63
|
+
o.to_s
|
12
64
|
end
|
13
65
|
|
14
66
|
def visit_Arel_Nodes_Contains o, collector
|
data/test/database.rb
CHANGED
@@ -1,16 +1,14 @@
|
|
1
|
-
task = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new({
|
2
|
-
'adapter' => 'postgresql',
|
3
|
-
'database' => "arel-extensions-test"
|
4
|
-
})
|
5
|
-
task.drop
|
6
|
-
task.create
|
7
|
-
|
8
1
|
ActiveRecord::Base.establish_connection({
|
9
2
|
adapter: "postgresql",
|
10
3
|
database: "arel-extensions-test",
|
11
4
|
encoding: "utf8"
|
12
5
|
})
|
13
6
|
|
7
|
+
db_config = ActiveRecord::Base.connection_db_config
|
8
|
+
task = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(db_config)
|
9
|
+
task.drop
|
10
|
+
task.create
|
11
|
+
|
14
12
|
ActiveRecord::Migration.suppress_messages do
|
15
13
|
ActiveRecord::Schema.define do
|
16
14
|
|
@@ -18,7 +16,7 @@ ActiveRecord::Migration.suppress_messages do
|
|
18
16
|
t.integer "name"
|
19
17
|
t.integer "property_id"
|
20
18
|
end
|
21
|
-
|
19
|
+
|
22
20
|
create_table "properties", force: :cascade do |t|
|
23
21
|
t.string "name", limit: 255
|
24
22
|
t.tsvector 'vector_col'
|
@@ -29,13 +27,23 @@ ActiveRecord::Migration.suppress_messages do
|
|
29
27
|
end
|
30
28
|
|
31
29
|
class Address < ActiveRecord::Base
|
32
|
-
|
33
30
|
belongs_to :property
|
34
|
-
|
35
31
|
end
|
36
32
|
|
37
33
|
class Property < ActiveRecord::Base
|
38
|
-
|
39
34
|
has_many :addresses
|
35
|
+
end
|
36
|
+
|
37
|
+
class SunstoneRecord < ActiveRecord::Base
|
38
|
+
self.abstract_class = true
|
39
|
+
end
|
40
|
+
|
41
|
+
class SunstoneAddress < SunstoneRecord
|
42
|
+
belongs_to :property, class_name: 'SunstoneProperty'
|
43
|
+
end
|
44
|
+
|
45
|
+
class SunstoneProperty < SunstoneRecord
|
46
|
+
has_many :addresses, class_name: 'SunstoneAddress'
|
47
|
+
end
|
40
48
|
|
41
|
-
|
49
|
+
SunstoneRecord.establish_connection(adapter: 'sunstone', endpoint: '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
|
data/test/sunstone_test.rb
CHANGED
@@ -27,8 +27,11 @@ class SunstoneTest < ActiveSupport::TestCase
|
|
27
27
|
# end
|
28
28
|
|
29
29
|
test "::filter json_column: {contains: JSON_HASH}" do
|
30
|
-
query =
|
31
|
-
|
30
|
+
query = SunstoneProperty.where(SunstoneProperty.arel_table['metadata'].contains({json: 'string'}))
|
31
|
+
assert_sar(query, 'GET', '/sunstone_properties', {
|
32
|
+
where: {metadata: {contains: { json: 'string' }}}
|
33
|
+
})
|
34
|
+
|
32
35
|
# query = Property.where(metadata: {contains: {json: 'string'}})
|
33
36
|
# assert_equal(<<-SQL.strip.gsub(/\s+/, ' '), query.to_sql.strip)
|
34
37
|
# SELECT "properties".*
|
@@ -94,5 +97,53 @@ class SunstoneTest < ActiveSupport::TestCase
|
|
94
97
|
# SQL
|
95
98
|
# end
|
96
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
|
97
148
|
|
98
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,8 +29,8 @@ $debugging = false
|
|
27
29
|
|
28
30
|
# File 'lib/active_support/testing/declarative.rb', somewhere in rails....
|
29
31
|
class ActiveSupport::TestCase
|
30
|
-
|
31
|
-
|
32
|
+
include WebMock::API
|
33
|
+
|
32
34
|
# File 'lib/active_support/testing/declarative.rb'
|
33
35
|
def self.test(name, &block)
|
34
36
|
test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
|
@@ -42,7 +44,7 @@ class ActiveSupport::TestCase
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
45
|
-
|
47
|
+
|
46
48
|
def webmock(method, path, query=nil)
|
47
49
|
query = deep_transform_query(query) if query
|
48
50
|
|
@@ -55,6 +57,51 @@ class ActiveSupport::TestCase
|
|
55
57
|
end
|
56
58
|
end
|
57
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
|
104
|
+
|
58
105
|
def debug
|
59
106
|
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
60
107
|
$debugging = true
|
@@ -104,7 +151,7 @@ class ActiveSupport::TestCase
|
|
104
151
|
unless ignore =~ sql
|
105
152
|
if $debugging
|
106
153
|
puts caller.select { |l| l.starts_with?(File.expand_path('../../lib', __FILE__)) }
|
107
|
-
puts "\n\n"
|
154
|
+
puts "\n\n"
|
108
155
|
end
|
109
156
|
end
|
110
157
|
self.class.log << sql unless ignore =~ sql
|
@@ -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
|
@@ -127,5 +205,5 @@ class ActiveSupport::TestCase
|
|
127
205
|
alias :assert_not_predicate :refute_predicate
|
128
206
|
alias :assert_not_respond_to :refute_respond_to
|
129
207
|
alias :assert_not_same :refute_same
|
130
|
-
|
131
|
-
end
|
208
|
+
|
209
|
+
end
|
data/test/ts_test.rb
CHANGED
@@ -133,4 +133,19 @@ class TSTest < ActiveSupport::TestCase
|
|
133
133
|
SQL
|
134
134
|
end
|
135
135
|
|
136
|
+
test 'ts_rank_cd(tsvector, tsquery, normalization)' do
|
137
|
+
query = Property.where(
|
138
|
+
Arel::Nodes::TSRankCD.new(
|
139
|
+
Arel::Nodes::TSVector.new(Property.arel_table[:name]),
|
140
|
+
Arel::Nodes::TSQuery.new('query'),
|
141
|
+
5
|
142
|
+
)
|
143
|
+
)
|
144
|
+
|
145
|
+
assert_equal(<<~SQL.gsub(/( +|\n)/, ' ').strip, query.to_sql)
|
146
|
+
SELECT "properties".* FROM "properties"
|
147
|
+
WHERE ts_rank_cd(to_tsvector("properties"."name"), to_tsquery('query'), 5)
|
148
|
+
SQL
|
149
|
+
end
|
150
|
+
|
136
151
|
end
|
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.
|
4
|
+
version: 6.1.0.rc2
|
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-12-28 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.
|
19
|
+
version: 6.1.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.
|
26
|
+
version: 6.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,34 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sunstone
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 6.1.0.rc1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 6.1.0.rc1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
83
125
|
- !ruby/object:Gem::Dependency
|
84
126
|
name: pg
|
85
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +150,7 @@ dependencies:
|
|
108
150
|
- - ">="
|
109
151
|
- !ruby/object:Gem::Version
|
110
152
|
version: '0'
|
111
|
-
description:
|
153
|
+
description:
|
112
154
|
email:
|
113
155
|
- jonbracy@gmail.com
|
114
156
|
executables: []
|
@@ -118,26 +160,28 @@ files:
|
|
118
160
|
- ".gitignore"
|
119
161
|
- ".travis.yml"
|
120
162
|
- Gemfile
|
121
|
-
- Gemfile.lock
|
122
163
|
- LICENSE
|
123
164
|
- README.md
|
124
165
|
- Rakefile
|
125
166
|
- arel-extensions.gemspec
|
167
|
+
- ext/arel/nodes/ascending.rb
|
168
|
+
- ext/arel/nodes/descending.rb
|
169
|
+
- ext/arel/order_predications.rb
|
126
170
|
- lib/active_record/query_methods.rb
|
127
171
|
- lib/arel/array_predications.rb
|
128
172
|
- lib/arel/attributes/cast.rb
|
129
173
|
- lib/arel/attributes/key.rb
|
130
174
|
- lib/arel/extensions.rb
|
175
|
+
- lib/arel/extensions/version.rb
|
131
176
|
- lib/arel/gis_predications.rb
|
132
177
|
- lib/arel/json_predications.rb
|
133
178
|
- lib/arel/nodes/contained_by.rb
|
134
|
-
- lib/arel/nodes/contains.rb
|
135
179
|
- lib/arel/nodes/excludes.rb
|
136
180
|
- lib/arel/nodes/has_any_key.rb
|
137
181
|
- lib/arel/nodes/has_key.rb
|
138
182
|
- lib/arel/nodes/has_keys.rb
|
139
183
|
- lib/arel/nodes/hex_encoded_binary.rb
|
140
|
-
- lib/arel/nodes/
|
184
|
+
- lib/arel/nodes/random.rb
|
141
185
|
- lib/arel/nodes/relation.rb
|
142
186
|
- lib/arel/nodes/ts_match.rb
|
143
187
|
- lib/arel/nodes/ts_query.rb
|
@@ -150,6 +194,7 @@ files:
|
|
150
194
|
- lib/arel/visitors/sunstone_extensions.rb
|
151
195
|
- lib/arel/visitors/to_sql_extensions.rb
|
152
196
|
- test/database.rb
|
197
|
+
- test/order_test.rb
|
153
198
|
- test/sunstone_test.rb
|
154
199
|
- test/test_helper.rb
|
155
200
|
- test/ts_test.rb
|
@@ -157,7 +202,7 @@ homepage: https://github.com/malomalo/arel-extensions
|
|
157
202
|
licenses:
|
158
203
|
- MIT
|
159
204
|
metadata: {}
|
160
|
-
post_install_message:
|
205
|
+
post_install_message:
|
161
206
|
rdoc_options: []
|
162
207
|
require_paths:
|
163
208
|
- lib
|
@@ -168,16 +213,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
213
|
version: '0'
|
169
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
215
|
requirements:
|
171
|
-
- - "
|
216
|
+
- - ">"
|
172
217
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
218
|
+
version: 1.3.1
|
174
219
|
requirements: []
|
175
|
-
rubygems_version: 3.
|
176
|
-
signing_key:
|
220
|
+
rubygems_version: 3.1.4
|
221
|
+
signing_key:
|
177
222
|
specification_version: 4
|
178
223
|
summary: Adds support for missing SQL operators and functions to Arel
|
179
224
|
test_files:
|
180
225
|
- test/database.rb
|
226
|
+
- test/order_test.rb
|
181
227
|
- test/sunstone_test.rb
|
182
228
|
- test/test_helper.rb
|
183
229
|
- 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)
|
5
|
-
activerecord (>= 6.0.0)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (6.0.0)
|
11
|
-
activesupport (= 6.0.0)
|
12
|
-
activerecord (6.0.0)
|
13
|
-
activemodel (= 6.0.0)
|
14
|
-
activesupport (= 6.0.0)
|
15
|
-
activesupport (6.0.0)
|
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.8)
|
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.8)
|
28
|
-
ansi
|
29
|
-
builder
|
30
|
-
minitest (>= 5.0)
|
31
|
-
ruby-progressbar
|
32
|
-
pg (1.1.4)
|
33
|
-
rake (12.3.3)
|
34
|
-
rgeo (2.1.0)
|
35
|
-
ruby-progressbar (1.10.1)
|
36
|
-
thread_safe (0.3.6)
|
37
|
-
tzinfo (1.2.5)
|
38
|
-
thread_safe (~> 0.1)
|
39
|
-
zeitwerk (2.1.10)
|
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
|
data/lib/arel/nodes/contains.rb
DELETED