提交 522b72fd 编写于 作者: A Aaron Patterson

Merge branch 'master' into instance_reader

* master:
  Fix GH #4720. Routing problem with nested namespace and already camelized controller option.
  make Range#overlaps? accept Range of Time
  improved test case for partial indices
  Made schema dumper recognize partial indices' where statements
  Added where option to add_index to support postgresql partial indices
......@@ -31,6 +31,7 @@ def call(env)
end
def prepare_params!(params)
normalize_controller!(params)
merge_default_action!(params)
split_glob_param!(params) if @glob_param
end
......@@ -66,6 +67,10 @@ def dispatch(controller, action, env)
controller.action(action).call(env)
end
def normalize_controller!(params)
params[:controller] = params[:controller].underscore if params.key?(:controller)
end
def merge_default_action!(params)
params[:action] ||= 'index'
end
......
......@@ -2449,6 +2449,32 @@ def test_missing_routes_are_still_missing
end
end
class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
module ::Admin
class StorageFilesController < ActionController::Base
def index
render :text => "admin/storage_files#index"
end
end
end
DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new
DefaultScopeRoutes.draw do
namespace :admin do
resources :storage_files, :controller => "StorageFiles"
end
end
def app
DefaultScopeRoutes
end
def test_controller_options
get '/admin/storage_files'
assert_equal "admin/storage_files#index", @response.body
end
end
class TestDefaultScope < ActionDispatch::IntegrationTest
module ::Blog
class PostsController < ActionController::Base
......
## Rails 4.0.0 (unreleased) ##
* Added support for partial indices to PostgreSQL adapter
The `add_index` method now supports a `where` option that receives a
string with the partial index criteria.
add_index(:accounts, :code, :where => "active")
Generates
CREATE INDEX index_accounts_on_code ON accounts(code) WHERE active
*Marcelo Silveira*
* Implemented ActiveRecord::Relation#none method
The `none` method returns a chainable relation with zero records
......
......@@ -6,7 +6,7 @@
module ActiveRecord
module ConnectionAdapters #:nodoc:
class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders) #:nodoc:
class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where) #:nodoc:
end
# Abstract representation of a column definition. Instances of this type
......
......@@ -381,9 +381,16 @@ def rename_column(table_name, column_name, new_column_name)
#
# Note: mysql doesn't yet support index order (it accepts the syntax but ignores it)
#
# ====== Creating a partial index
# add_index(:accounts, [:branch_id, :party_id], :unique => true, :where => "active")
# generates
# CREATE UNIQUE INDEX index_accounts_on_branch_id_and_party_id ON accounts(branch_id, party_id) WHERE active
#
# Note: only supported by PostgreSQL
#
def add_index(table_name, column_name, options = {})
index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})"
index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options)
execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}"
end
# Remove the given index from the table.
......@@ -581,6 +588,9 @@ def add_index_options(table_name, column_name, options = {})
if Hash === options # legacy support, since this param was a string
index_type = options[:unique] ? "UNIQUE" : ""
index_name = options[:name].to_s if options.key?(:name)
if supports_partial_index?
index_options = options[:where] ? " WHERE #{options[:where]}" : ""
end
else
index_type = options
end
......@@ -593,7 +603,7 @@ def add_index_options(table_name, column_name, options = {})
end
index_columns = quoted_columns_for_index(column_names, options).join(", ")
[index_name, index_type, index_columns]
[index_name, index_type, index_columns, index_options]
end
def index_name_for_remove(table_name, options = {})
......
......@@ -142,6 +142,11 @@ def supports_index_sort_order?
false
end
# Does this adapter support partial indices?
def supports_partial_index?
false
end
# Does this adapter support explain? As of this writing sqlite3,
# mysql2, and postgresql are the only ones that do.
def supports_explain?
......
......@@ -303,6 +303,10 @@ def supports_index_sort_order?
true
end
def supports_partial_index?
true
end
class StatementPool < ConnectionAdapters::StatementPool
def initialize(connection, max)
super
......@@ -903,8 +907,9 @@ def indexes(table_name, name = nil)
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
desc_order_columns = inddef.scan(/(\w+) DESC/).flatten
orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {}
where = inddef.scan(/WHERE (.+)$/).flatten[0]
column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders)
column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where)
end.compact
end
......
......@@ -197,6 +197,8 @@ def indexes(table, stream)
index_orders = (index.orders || {})
statement_parts << (':order => ' + index.orders.inspect) unless index_orders.empty?
statement_parts << (':where => ' + index.where.inspect) if index.where
' ' + statement_parts.join(', ')
end
......
......@@ -21,6 +21,18 @@ def test_create_database_with_encoding
assert_equal %(CREATE DATABASE "aimonetti" ENCODING = 'latin1'), create_database(:aimonetti, :encoding => :latin1)
end
def test_add_index
# add_index calls index_name_exists? which can't work since execute is stubbed
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:define_method, :index_name_exists?) do |*|
false
end
expected = %(CREATE UNIQUE INDEX "index_people_on_last_name" ON "people" ("last_name") WHERE state = 'active')
assert_equal expected, add_index(:people, :last_name, :unique => true, :where => "state = 'active'")
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:remove_method, :index_name_exists?)
end
private
def method_missing(method_symbol, *arguments)
ActiveRecord::Base.connection.send(method_symbol, *arguments)
......
......@@ -179,6 +179,12 @@ def test_substitute_at
assert_equal Arel.sql('$2'), bind
end
def test_partial_index
@connection.add_index 'ex', %w{ id number }, :name => 'partial', :where => "number > 100"
index = @connection.indexes('ex').find { |idx| idx.name == 'partial' }
assert_equal "(number > 100)", index.where
end
private
def insert(ctx, data)
binds = data.map { |name, value|
......
......@@ -171,6 +171,15 @@ def test_add_index
end
end
def test_add_partial_index
skip 'only on pg' unless current_adapter?(:PostgreSQLAdapter)
connection.add_index("testings", "last_name", :where => "first_name = 'john doe'")
assert connection.index_exists?("testings", "last_name")
connection.remove_index("testings", "last_name")
assert !connection.index_exists?("testings", "last_name")
end
end
end
end
......@@ -185,6 +185,15 @@ def test_schema_dumps_index_columns_in_right_order
assert_equal 'add_index "companies", ["firm_id", "type", "rating", "ruby_type"], :name => "company_index"', index_definition
end
def test_schema_dumps_partial_indices
index_definition = standard_dump.split(/\n/).grep(/add_index.*company_partial_index/).first.strip
if current_adapter?(:PostgreSQLAdapter)
assert_equal 'add_index "companies", ["firm_id", "type"], :name => "company_partial_index", :where => "(rating > 10)"', index_definition
else
assert_equal 'add_index "companies", ["firm_id", "type"], :name => "company_partial_index"', index_definition
end
end
def test_schema_dump_should_honor_nonstandard_primary_keys
output = standard_dump
match = output.match(%r{create_table "movies"(.*)do})
......
......@@ -175,6 +175,7 @@ def create_table(*args, &block)
end
add_index :companies, [:firm_id, :type, :rating, :ruby_type], :name => "company_index"
add_index :companies, [:firm_id, :type], :name => "company_partial_index", :where => "rating > 10"
create_table :computers, :force => true do |t|
t.integer :developer, :null => false
......
......@@ -3,6 +3,6 @@ class Range
# (1..5).overlaps?(4..6) # => true
# (1..5).overlaps?(7..9) # => false
def overlaps?(other)
include?(other.first) || other.include?(first)
cover?(other.first) || other.cover?(first)
end
end
......@@ -71,4 +71,16 @@ def test_cover_is_not_override
range = (1..3)
assert range.method(:include?) != range.method(:cover?)
end
def test_overlaps_on_time
time_range_1 = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30)
time_range_2 = Time.utc(2005, 12, 10, 17, 00)..Time.utc(2005, 12, 10, 18, 00)
assert time_range_1.overlaps?(time_range_2)
end
def test_no_overlaps_on_time
time_range_1 = Time.utc(2005, 12, 10, 15, 30)..Time.utc(2005, 12, 10, 17, 30)
time_range_2 = Time.utc(2005, 12, 10, 17, 31)..Time.utc(2005, 12, 10, 18, 00)
assert !time_range_1.overlaps?(time_range_2)
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册