arel-extensions 6.0.0.5 → 6.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
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