postgres_ext 2.1.3 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +13 -22
  4. data/CHANGELOG.md +45 -0
  5. data/README.md +13 -0
  6. data/Rakefile +83 -7
  7. data/docs/querying.md +76 -6
  8. data/lib/postgres_ext/active_record/relation/predicate_builder.rb +2 -2
  9. data/lib/postgres_ext/active_record/relation/query_methods.rb +44 -11
  10. data/lib/postgres_ext/arel/predications.rb +10 -0
  11. data/lib/postgres_ext/arel/visitors/to_sql.rb +1 -1
  12. data/lib/postgres_ext/version.rb +1 -1
  13. data/postgres_ext.gemspec +4 -2
  14. data/test/arel/array_test.rb +92 -0
  15. data/{spec/arel/inet_spec.rb → test/arel/inet_test.rb} +6 -6
  16. data/{spec/queries/array_queries_spec.rb → test/queries/array_queries_test.rb} +22 -14
  17. data/test/queries/common_table_expression_test.rb +49 -0
  18. data/{spec/queries/contains_querie_spec.rb → test/queries/contains_test.rb} +5 -5
  19. data/test/queries/sanity_test.rb +32 -0
  20. data/test/queries/window_functions_test.rb +64 -0
  21. data/test/test_helper.rb +38 -0
  22. metadata +74 -150
  23. data/spec/arel/array_spec.rb +0 -77
  24. data/spec/arel/rank_spec.rb +0 -0
  25. data/spec/dummy/.gitignore +0 -15
  26. data/spec/dummy/README.rdoc +0 -261
  27. data/spec/dummy/Rakefile +0 -7
  28. data/spec/dummy/app/assets/images/rails.png +0 -0
  29. data/spec/dummy/app/assets/javascripts/application.js +0 -15
  30. data/spec/dummy/app/assets/stylesheets/application.css +0 -13
  31. data/spec/dummy/app/controllers/application_controller.rb +0 -3
  32. data/spec/dummy/app/helpers/application_helper.rb +0 -2
  33. data/spec/dummy/app/mailers/.gitkeep +0 -0
  34. data/spec/dummy/app/models/.gitkeep +0 -0
  35. data/spec/dummy/app/models/person.rb +0 -2
  36. data/spec/dummy/app/views/layouts/application.html.erb +0 -14
  37. data/spec/dummy/config.ru +0 -4
  38. data/spec/dummy/config/application.rb +0 -56
  39. data/spec/dummy/config/boot.rb +0 -6
  40. data/spec/dummy/config/database.yml.example +0 -14
  41. data/spec/dummy/config/environment.rb +0 -5
  42. data/spec/dummy/config/environments/development.rb +0 -33
  43. data/spec/dummy/config/environments/production.rb +0 -68
  44. data/spec/dummy/config/environments/test.rb +0 -33
  45. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  46. data/spec/dummy/config/initializers/inflections.rb +0 -15
  47. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  48. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  49. data/spec/dummy/config/initializers/session_store.rb +0 -8
  50. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  51. data/spec/dummy/config/locales/en.yml +0 -5
  52. data/spec/dummy/config/routes.rb +0 -58
  53. data/spec/dummy/db/migrate/20120501163758_create_people.rb +0 -15
  54. data/spec/dummy/db/schema.rb +0 -31
  55. data/spec/dummy/db/seeds.rb +0 -7
  56. data/spec/dummy/lib/assets/.gitkeep +0 -0
  57. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  58. data/spec/dummy/log/.gitkeep +0 -0
  59. data/spec/dummy/public/404.html +0 -26
  60. data/spec/dummy/public/422.html +0 -26
  61. data/spec/dummy/public/500.html +0 -25
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/public/index.html +0 -241
  64. data/spec/dummy/public/robots.txt +0 -5
  65. data/spec/dummy/script/rails +0 -6
  66. data/spec/dummy/spec/factories/people.rb +0 -7
  67. data/spec/dummy/test/fixtures/.gitkeep +0 -0
  68. data/spec/dummy/test/functional/.gitkeep +0 -0
  69. data/spec/dummy/test/integration/.gitkeep +0 -0
  70. data/spec/dummy/test/performance/browsing_test.rb +0 -12
  71. data/spec/dummy/test/test_helper.rb +0 -13
  72. data/spec/dummy/test/unit/.gitkeep +0 -0
  73. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  74. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  75. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  76. data/spec/queries/common_table_expression_spec.rb +0 -36
  77. data/spec/queries/sanity_spec.rb +0 -17
  78. data/spec/queries/window_functions_spec.rb +0 -54
  79. data/spec/spec_helper.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81e5d99adec7bf0164b0e2fc17902e80ef62d264
4
- data.tar.gz: ca7ab1ff4f77d91b31062130e17e87a055db719c
3
+ metadata.gz: 9078ca33d9a9b96fa41f3082157f2bceb46319b9
4
+ data.tar.gz: 8797b9642f4c3757d3b450bbdef4ffbcc00dce72
5
5
  SHA512:
6
- metadata.gz: 029878e575cb456781db615deb004839836a5bb46ccbd3a14c184b8e9b3b153c21c22b921e1938ed82378c9fc7f409799e882f623ff1913fb4dbd46e618685ca
7
- data.tar.gz: 30a7dd666faf99922130a77cad0f25a148bc030b152ede31722475fe0c67addc29f08bf3f479a5e727ab3ff560667970ed96cf07f9ca2ad57d5039acdf8d78d7
6
+ metadata.gz: 96d7943795f68ab0e4ca85e12ca0d508844d29f78ff7baec44e952bb23c012290ffadceef317d5496a395cb896d1110289a2cf395998a107574a556dabb2e97c
7
+ data.tar.gz: 75c699237d3dfa87a62099d52dd84a1c77936d0ae730207bf3801bc1acc4112acfd0cf64521c2407cf79199033b025c3eeab91c747ef6b1c2ff3ae9d21c36ed0
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .env
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
data/.travis.yml CHANGED
@@ -1,28 +1,19 @@
1
1
  rvm:
2
- - 1.9.3
3
- - 2.0.0
4
- - jruby-19mode
2
+ - 1.9.3
3
+ - 2.0.0
4
+ - jruby-19mode
5
+
6
+ env: DATABASE_URL=postgres://postgres@localhost/postgres_ext_test
5
7
 
6
8
  before_script:
7
- - sudo /etc/init.d/postgresql stop
8
- - sudo cp /etc/postgresql/9.1/main/pg_hba.conf ./
9
- - sudo apt-get remove postgresql postgresql-9.1 -qq --purge
10
- - source /etc/lsb-release
11
- - echo "deb http://apt.postgresql.org/pub/repos/apt/ $DISTRIB_CODENAME-pgdg main" > pgdg.list
12
- - sudo mv pgdg.list /etc/apt/sources.list.d/
13
- - wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
14
- - sudo apt-get update -qq
15
- - sudo apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" install postgresql-9.2 postgresql-contrib-9.2 -qq
16
- - sudo /etc/init.d/postgresql stop
17
- - sudo cp ./pg_hba.conf /etc/postgresql/9.2/main
18
- - sudo /etc/init.d/postgresql start
19
- - psql -c 'create database postgres_ext_test;' -U postgres -h localhost
20
- - cp spec/dummy/config/database.yml.example spec/dummy/config/database.yml
21
- - RAILS_ENV=test rake db:migrate
9
+ - psql -c 'create database postgres_ext_test;' -U postgres -h localhost
10
+ - rake db:migrate
22
11
 
23
12
  notifications:
24
- email:
25
- - git@danmcclain.net
26
- campfire:
13
+ email:
14
+ - git@danmcclain.net
15
+ hipchat:
27
16
  rooms:
28
- - secure: "dNVxAfeOqRuA7k4Wu3H63deqV8Z1mmpVBdPEtkK2ry+mp+51RFHcO0cUJ/fI\nN4PXZu2wNWQlvz5LCMRPe+hxio/w8hTvgQxzBVvi0kuOh/22wXumdy7LR/RJ\nvyrrbP3+1hSxhzufyvIe/fOU11v31d3WRA1/q80ls9EkwzoDTNI="
17
+ secure: gebjx8Q/jmnNmf6l+SyQHHJjGn9RfA6s4e8sIoRBVt9pomkOCBvHq7++AjpVlqkXcvV6rK2L90rAEPKMP0QUS04vRtRY6LvwmjiQHFo99/gktG6LO+5/QGvy9zbK4PxWe35Yr1F98Gs0mQ+y/ZbU6u8rJsI7DM1iPq2ULzo/QUw=
18
+ addons:
19
+ postgresql: '9.3'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,48 @@
1
+ ## 2.2.0
2
+
3
+ * Adds Arel predications for `ANY` and `ALL` - Dan McClain
4
+ * Fixes errors with has\_and\_belongs\_to\_many associations - Jacob Swanner
5
+ * Adds with.recursive for recursive CTEs - Cody Cutrer
6
+ * Relation.with now accepts Arel::SelectMangers - Dan McClain
7
+
8
+ ## 2.1.3
9
+
10
+ * Fixes Arel 4.0.1 issues - Dan McClain
11
+ * Prevents coversion of string to order statement - Dan McClain
12
+
13
+ ## 2.1.2
14
+
15
+ * Fixes calls to count when ranking a relation - Dan McClain
16
+
17
+ ## 2.1.1
18
+
19
+ * Fixes cte proxy so that it can create records - Dan McClain
20
+
21
+ ## 2.1.0
22
+
23
+ * Support added for common table expressions - Dan McClain
24
+ * Support added for rank windowing function - Dan McClain
25
+ * Insert Code Climate badge into README - Doug Yun
26
+
27
+ # 2.0.0
28
+
29
+ * JRuby fixes - Dan McClain
30
+ * Updates docs and description - Dan McClain
31
+ * Rails 4 support - Dan McClain
32
+
33
+ # 1.0.0
34
+
35
+ 1.0.0 is the last major and minor release for Rails 3.2.x. Postgres\_ext
36
+ will only receive bug fixes in the future. Also, bug fixes for 1.0.x
37
+ will come from PRs only, future development efforts are concentrated on
38
+ 2.x.
39
+
40
+ * Fixing array tests in jruby - Dan McClain
41
+ * Removes encoding patches from PostgreSQLAdapter - Dan McClain
42
+ * Update documentation to reflect changes in 0.3.0 - Fabian Schwahn
43
+ * Allow conversion of string/text columns to array - Valentino
44
+ * Fix link to github issues in readme - Carlos Antonio da Silva
45
+
1
46
  ## 0.4.0
2
47
  * Adds support for (limited) support for PostgreSQL ranges - Dan McClain
3
48
 
data/README.md CHANGED
@@ -4,6 +4,7 @@ Adds missing native PostgreSQL data types to ActiveRecord and convenient queryin
4
4
 
5
5
  [![Build Status](https://secure.travis-ci.org/dockyard/postgres_ext.png?branch=master)](http://travis-ci.org/dockyard/postgres_ext)
6
6
  [![Code Climate](https://codeclimate.com/github/dockyard/postgres_ext.png)](https://codeclimate.com/github/dockyard/postgres_ext)
7
+ [![Gem Version](https://badge.fury.io/rb/postgres_ext.png)](http://badge.fury.io/rb/postgres_ext)
7
8
 
8
9
  ## Looking for help? ##
9
10
 
@@ -39,6 +40,18 @@ Where are the datatypes from PostgresExt 1.x? ActiveRecord 4.x includes
39
40
  all the data types that PostgresExt added to ActiveRecord 3.2.x. We'll
40
41
  be adding more datatypes as we come across them.
41
42
 
43
+ ## Developing
44
+
45
+ To work on postgres\_ext locally, follow these steps:
46
+
47
+ 1. Run `bundle install`, this will install all the development
48
+ dependencies
49
+ 2. Run `rake setup`, this will set up the `.env` file necessary to run
50
+ the tests and set up the database
51
+ 3. Run `rake db:create`, this will create the test database
52
+ 4. Run `rake db:migrate`, this will set up the database tables required
53
+ by the test
54
+
42
55
  ## Authors
43
56
 
44
57
  Dan McClain [twitter](http://twitter.com/_danmcclain) [github](http://github.com/danmcclain)
data/Rakefile CHANGED
@@ -4,6 +4,7 @@ begin
4
4
  rescue LoadError
5
5
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
6
  end
7
+
7
8
  begin
8
9
  require 'rdoc/task'
9
10
  rescue LoadError
@@ -20,14 +21,89 @@ RDoc::Task.new(:rdoc) do |rdoc|
20
21
  rdoc.rdoc_files.include('lib/**/*.rb')
21
22
  end
22
23
 
23
- APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
24
- load 'rails/tasks/engine.rake'
25
-
26
24
  Bundler::GemHelper.install_tasks
27
25
 
28
- require 'rspec/core/rake_task'
29
- RSpec::Core::RakeTask.new(:spec) do |t|
30
- t.pattern = 'spec/**/*_spec.rb'
26
+ require 'rake/testtask'
27
+
28
+ Rake::TestTask.new(:test) do |t|
29
+ t.libs << 'lib'
30
+ t.libs << 'test'
31
+ t.pattern = 'test/**/*_test.rb'
32
+ t.verbose = false
33
+ end
34
+
35
+ task :default => :test
36
+
37
+ task :setup do
38
+ if File.exist?('.env')
39
+ puts 'This will overwrite your existing .env file'
40
+ end
41
+ print 'Enter your database name: [postgres_ext_test] '
42
+ db_name = STDIN.gets.chomp
43
+ print 'Enter your database user: [] '
44
+ db_user = STDIN.gets.chomp
45
+ print 'Enter your database password: [] '
46
+ db_password = STDIN.gets.chomp
47
+ print 'Enter your database server: [localhost] '
48
+ db_server = STDIN.gets.chomp
49
+
50
+ db_name = 'postgres_ext_test' if db_name.empty?
51
+ db_password = ":#{db_password}" unless db_password.empty?
52
+ db_server = 'localhost' if db_server.empty?
53
+
54
+ db_server = "@#{db_server}" unless db_user.empty?
55
+
56
+ env_path = File.expand_path('./.env')
57
+ File.open(env_path, 'w') do |file|
58
+ file.puts "DATABASE_NAME=#{db_name}"
59
+ file.puts "DATABASE_URL=\"postgres://#{db_user}#{db_password}#{db_server}/#{db_name}\""
60
+ end
61
+
62
+ puts '.env file saved'
31
63
  end
32
64
 
33
- task :default => :spec
65
+ namespace :db do
66
+ task :load_db_settings do
67
+ require 'active_record'
68
+ unless ENV['DATABASE_URL']
69
+ require 'dotenv'
70
+ Dotenv.load
71
+ end
72
+ end
73
+
74
+ task :drop => :load_db_settings do
75
+ %x{ dropdb #{ENV['DATABASE_NAME']} }
76
+ end
77
+
78
+ task :create => :load_db_settings do
79
+ %x{ createdb #{ENV['DATABASE_NAME']} }
80
+ end
81
+
82
+ task :migrate => :load_db_settings do
83
+ ActiveRecord::Base.establish_connection
84
+
85
+ ActiveRecord::Base.connection.create_table :people, force: true do |t|
86
+ t.inet "ip"
87
+ t.cidr "subnet"
88
+ t.integer "tag_ids", array: true
89
+ t.string "tags", array: true
90
+ t.integer "lucky_number"
91
+ t.datetime "created_at"
92
+ t.datetime "updated_at"
93
+ end
94
+
95
+ ActiveRecord::Base.connection.create_table :people_tags, force: true do |t|
96
+ t.integer "person_id"
97
+ t.integer "tag_id"
98
+ end
99
+
100
+ ActiveRecord::Base.connection.create_table :tags, force: true do |t|
101
+ t.integer "person_id"
102
+ t.string "categories", array: true
103
+ t.datetime "created_at"
104
+ t.datetime "updated_at"
105
+ end
106
+
107
+ puts 'Database migrated'
108
+ end
109
+ end
data/docs/querying.md CHANGED
@@ -1,3 +1,76 @@
1
+ # Common Table Expressions (CTEs)
2
+
3
+ Postgres\_ext adds CTE expression support to ActiveRecord via two
4
+ methods:
5
+
6
+ * [`Relation#with`](#with)
7
+ * [`Model.from_cte`](#from_cte)
8
+
9
+ ## with
10
+
11
+ We can add CTEs to queries by chaining `#with` off a relation.
12
+ `Relation#with` accepts a hash, and will convert `Relation`s to the
13
+ proper SQL in the CTE.
14
+
15
+ Let's expand a `#with` call to it's resulting SQL code:
16
+
17
+ ```ruby
18
+ Score.with(my_games: Game.where(id: 1)).joins('JOIN my_games ON scores.game_id = my_games.id')
19
+ ```
20
+
21
+ The following will be generated when that relation is evaluated:
22
+
23
+ ```SQL
24
+ WITH my_games AS (
25
+ SELECT games.*
26
+ FROM games
27
+ WHERE games.id = 1
28
+ )
29
+ SELECT *
30
+ FROM scores
31
+ JOIN my_games
32
+ ON scores.games_id = my_games.id
33
+ ```
34
+
35
+ You can also do a recursive with:
36
+
37
+ ```ruby
38
+ Graph.with.recursive(search_graph:
39
+ " SELECT g.id, g.link, g.data, 1 AS depth
40
+ FROM graph g
41
+ UNION ALL
42
+ SELECT g.id, g.link, g.data, sg.depth + 1
43
+ FROM graph g, search_graph sg
44
+ WHERE g.id = sg.link").from(:search_graph)
45
+ ```
46
+
47
+ ## from\_cte
48
+
49
+ `Model.from_cte` is similiar to `Model.find_by_sql`, taking the CTE
50
+ passed in, but allowing you to chain off of it further, instead of just
51
+ retrieving the results.
52
+
53
+ Take the following ActiveRecord call:
54
+
55
+ ```ruby
56
+ Score.from_cte('scores_for_game', Score.where(game_id: 1)).where(user_id: 1)
57
+ ```
58
+
59
+ The following SQL will be called:
60
+
61
+ ```SQL
62
+ WITH scores_for_game AS (
63
+ SELECT *
64
+ FROM scores
65
+ WHERE game_id = 1
66
+ )
67
+ SELECT *
68
+ FROM scores_for_game
69
+ WHERE scores_for_game.user_id = 1
70
+ ```
71
+
72
+ And will be converted to `Score` objects
73
+
1
74
  # Querying PostgreSQL datatypes
2
75
 
3
76
  * [Arrays](#arrays)
@@ -109,16 +182,13 @@ accompish this:
109
182
  ```ruby
110
183
  user_arel = User.arel_table
111
184
 
112
- any_tags_function = Arel::Nodes::NamedFunction.new('ANY', [user_arel[:tags]])
113
- predicate = Arel::Nodes::Equality.new('test', any_tags_function)
114
-
115
185
  # Execute the query
116
- User.where(predicate)
186
+ User.where(user_arel[:tags].any('test'))
117
187
  #=> SELECT \"users\".* FROM \"users\" WHERE 'test' = ANY(\"users\".\"tags\")
118
188
  ```
119
189
 
120
- The ALL version of this same predicate can be generated by swap `'ANY'`
121
- for `'ALL'` in the named function.
190
+ The ALL version of this same predicate can be generated by swapping
191
+ `#any()` for `#all()`.
122
192
 
123
193
  ## INET/CIDR Queries
124
194
 
@@ -8,8 +8,8 @@ module ActiveRecord
8
8
  case value
9
9
  when Array
10
10
  engine = attribute.relation.engine
11
- column = engine.columns.detect{ |col| col.name == attribute.name }
12
- if column.array
11
+ column = engine.columns.detect{ |col| col.name.to_s == attribute.name.to_s }
12
+ if column && column.array
13
13
  attribute.eq(value)
14
14
  else
15
15
  values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x}
@@ -67,6 +67,21 @@ module ActiveRecord
67
67
  end
68
68
  end
69
69
 
70
+ # WithChain objects act as placeholder for queries in which #with does not have any parameter.
71
+ # In this case, #with must be chained with #recursive to return a new relation.
72
+ class WithChain
73
+ def initialize(scope)
74
+ @scope = scope
75
+ end
76
+
77
+ # Returns a new relation expressing WITH RECURSIVE
78
+ def recursive(*args)
79
+ @scope.with_values += args
80
+ @scope.recursive_value = true
81
+ @scope
82
+ end
83
+ end
84
+
70
85
  [:with].each do |name|
71
86
  class_eval <<-CODE, __FILE__, __LINE__ + 1
72
87
  def #{name}_values # def select_values
@@ -80,7 +95,7 @@ module ActiveRecord
80
95
  CODE
81
96
  end
82
97
 
83
- [:rank].each do |name|
98
+ [:rank, :recursive].each do |name|
84
99
  class_eval <<-CODE, __FILE__, __LINE__ + 1
85
100
  def #{name}_value=(value) # def readonly_value=(value)
86
101
  raise ImmutableRelation if @loaded # raise ImmutableRelation if @loaded
@@ -93,14 +108,23 @@ module ActiveRecord
93
108
  CODE
94
109
  end
95
110
 
96
- def with(*args)
97
- check_if_method_has_arguments!('with', args)
98
- spawn.with!(*args.compact.flatten)
111
+ def with(opts = :chain, *rest)
112
+ if opts == :chain
113
+ WithChain.new(spawn)
114
+ elsif opts.blank?
115
+ self
116
+ else
117
+ spawn.with!(opts, *rest)
118
+ end
99
119
  end
100
120
 
101
- def with!(*args)
102
- self.with_values += args
103
- self
121
+ def with!(opts = :chain, *rest) # :nodoc:
122
+ if opts == :chain
123
+ WithChain.new(self)
124
+ else
125
+ self.with_values += [opts] + rest
126
+ self
127
+ end
104
128
  end
105
129
 
106
130
  def ranked(options = :order)
@@ -115,15 +139,16 @@ module ActiveRecord
115
139
  def build_arel_with_extensions
116
140
  arel = build_arel_without_extensions
117
141
 
118
- build_with(arel, with_values)
142
+ build_with(arel)
119
143
 
120
144
  build_rank(arel, rank_value) if rank_value
121
145
 
122
146
  arel
123
147
  end
124
148
 
125
- def build_with(arel, withs)
126
- with_statements = withs.flat_map do |with_value|
149
+ def build_with(arel)
150
+ visitor = arel.engine.connection.visitor
151
+ with_statements = with_values.flat_map do |with_value|
127
152
  case with_value
128
153
  when String
129
154
  with_value
@@ -134,12 +159,20 @@ module ActiveRecord
134
159
  select = Arel::SqlLiteral.new "(#{expression})"
135
160
  when ActiveRecord::Relation
136
161
  select = Arel::SqlLiteral.new "(#{expression.to_sql})"
162
+ when Arel::SelectManager
163
+ select = Arel::SqlLiteral.new visitor.accept(expression)
137
164
  end
138
165
  as = Arel::Nodes::As.new Arel::SqlLiteral.new(name.to_s), select
139
166
  end
140
167
  end
141
168
  end
142
- arel.with with_statements unless with_statements.empty?
169
+ unless with_statements.empty?
170
+ if recursive_value
171
+ arel.with :recursive, with_statements
172
+ else
173
+ arel.with with_statements
174
+ end
175
+ end
143
176
  end
144
177
 
145
178
  def build_rank(arel, rank_window_options)