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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77163aa72e10eb31450da65c1b1df14a021e5b4075fb4593d5fef7bcc99b5601
4
- data.tar.gz: 6f3c923426a618ff4cab75573a9249f5ff96f03ce270fa4f70218815df617fed
3
+ metadata.gz: e5d5fc1f0a60a20f13e1f12d1b445c347bce09e0e070ad0e3a45e1e77b108eab
4
+ data.tar.gz: c75928cd9e920e0004829c359e5b4cb61d237474e0667a7ef6876045fa01c539
5
5
  SHA512:
6
- metadata.gz: 6b4ba6222a1324e349ee69e4f6463f5fa964b4f965291db74712876749af64ddc77fe957c38fd2081cfcbf7263440989aa5230708a69ce6562a76417a131eef3
7
- data.tar.gz: 448a6441598e3a7648df5f9e261b52840988ad1d0ac2836eecfbd45110a1d2918033622702261efd7cf9b6ca604e9d130cc878e6f34dc5a20032e21700c3e610
6
+ metadata.gz: fb8e0f51781d3459bda4514c07fcabe0b51d27ca668f4c17ccdc7a9f6e714d4bde039c13a103697765a9ae076befa3d36285e6a5bf3dae2df4b810fb17b72d19
7
+ data.tar.gz: e75fa73cfa18eb83e1e22a5941c75721d8bc536092b51900fcce6195d77cb466b082f232fe2b36a784af56a93701cb593ef4c9c160e7df64c110e5feadb7c241
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  .DS_Store
2
2
  *.gem
3
+ Gemfile.lock
@@ -1,4 +1,4 @@
1
- dist: xenial
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.5
12
- - 2.6
11
+ - 2.7
13
12
 
14
13
  env:
15
14
  matrix:
16
- - RAILS_VERSION=v6.0.0.rc1 GEM=activerecord:mysql2
17
- - RAILS_VERSION=v6.0.0.rc1 GEM=activerecord:sqlite3
18
- - RAILS_VERSION=v6.0.0.rc1 GEM=activerecord:postgresql
19
- - RAILS_VERSION=v6.0.0.rc2 GEM=activerecord:mysql2
20
- - RAILS_VERSION=v6.0.0.rc2 GEM=activerecord:sqlite3
21
- - RAILS_VERSION=v6.0.0.rc2 GEM=activerecord:postgresql
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: "10"
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 checkout $RAILS_VERSION
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
- - bundle install --jobs=3 --retry=3
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
- - cd ~/build/rails && ci/travis.rb
66
+ - bundle exec rake test
67
+ - cd ~/build/rails/activerecord && bundle exec rake $TASK
@@ -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 = '6.0.0.5'
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.0.0'
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
@@ -0,0 +1,14 @@
1
+ module Arel
2
+ module Nodes
3
+ class Ascending < Ordering
4
+
5
+ attr_accessor :nulls
6
+
7
+ def initialize expr, nulls=nil
8
+ super(expr)
9
+ @nulls = nulls
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Arel
2
+ module Nodes
3
+ class Descending < Ordering
4
+
5
+ attr_accessor :nulls
6
+
7
+ def initialize expr, nulls=nil
8
+ super(expr)
9
+ @nulls = nulls
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ # Ordering with :nulls_last, :nulls_first options
2
+ module Arel
3
+ module OrderPredications
4
+
5
+ def asc(nulls=nil)
6
+ Nodes::Ascending.new self, nulls
7
+ end
8
+
9
+ def desc(nulls=nil)
10
+ Nodes::Descending.new self, nulls
11
+ end
12
+
13
+ end
14
+ 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
@@ -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__)
@@ -0,0 +1,5 @@
1
+ module Arel
2
+ module Extensions
3
+ VERSION = '6.1.0.rc2'
4
+ end
5
+ end
@@ -1,6 +1,9 @@
1
1
  module Arel
2
2
  module Nodes
3
- class ContainedBy < Binary
3
+ class ContainedBy < InfixOperation
4
+ def initialize(left, right)
5
+ super(:"<@", left, right)
6
+ end
4
7
  end
5
8
  end
6
- end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Arel
2
+ module Nodes
3
+ class RandomOrdering < Arel::Nodes::Node
4
+
5
+ end
6
+ end
7
+ end
@@ -12,7 +12,7 @@ module Arel
12
12
  end
13
13
 
14
14
  def able_to_type_cast?
15
- false
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
@@ -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 visit_Arel_Nodes_Contains o, collector
12
- visit o.left, collector
13
- collector << ' @> '
14
- collector << quote(o.left.type_cast_for_database(o.right))
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 visit_Arel_Nodes_ContainedBy o, collector
19
- visit o.left, collector
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
- collector << quote(o.left.type_cast_for_database(o.right))
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
- value = {}
53
+ rvalue = {}
8
54
  o.each do |key, value|
9
- value[visit(key, collector)] = visit(value, collector)
55
+ rvalue[visit(key, collector)] = visit(value, collector)
10
56
  end
11
- value
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
@@ -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
- end
49
+ SunstoneRecord.establish_connection(adapter: 'sunstone', endpoint: 'http://example.com')
@@ -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
@@ -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 = Property.where(Property.arel_attribute('metadata').contains({json: 'string'}))
31
- assert_equal '', query.to_sar.path
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
@@ -12,11 +12,13 @@ require 'rgeo'
12
12
  require "minitest/autorun"
13
13
  require 'minitest/unit'
14
14
  require 'minitest/reporters'
15
- # require 'webmock/minitest'
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
- # include WebMock::API
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
@@ -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.0.0.5
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: 2019-09-18 00:00:00.000000000 Z
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.0.0
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.0.0
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/overlaps.rb
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: '0'
218
+ version: 1.3.1
174
219
  requirements: []
175
- rubygems_version: 3.0.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
@@ -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
@@ -1,6 +0,0 @@
1
- module Arel
2
- module Nodes
3
- class Contains < Binary
4
- end
5
- end
6
- end
@@ -1,6 +0,0 @@
1
- module Arel
2
- module Nodes
3
- class Overlaps < Binary
4
- end
5
- end
6
- end