Updating sorting to new syntax

This commit is contained in:
Durran Jordan 2009-10-06 19:20:21 -04:00 committed by Mike Dirolf
parent 22588828f8
commit 20f65039f3
4 changed files with 243 additions and 18 deletions

View File

@ -23,4 +23,7 @@ module Mongo
# Raised when an invalid name is used.
class InvalidName < RuntimeError; end
# Raised when the client supplies an invalid values for a sorting.
class InvalidSortValueError < RuntimeError; end
end

View File

@ -16,11 +16,12 @@
require 'mongo/message/message'
require 'mongo/message/opcodes'
require 'mongo/util/conversions'
require 'mongo/util/ordered_hash'
module Mongo
class QueryMessage < Message
include Mongo::Conversions
attr_reader :query
@ -37,24 +38,14 @@ module Mongo
sel = OrderedHash.new
sel['query'] = query.selector
if query.order_by && query.order_by.length > 0
sel['orderby'] = case query.order_by
when String
{query.order_by => 1}
when Array
h = OrderedHash.new
query.order_by.each { |ob|
case ob
when String
h[ob] = 1
when Hash # should have one entry; will handle all
ob.each { |k,v| h[k] = v }
else
raise "illegal query order_by value #{query.order_by.inspect}"
end
}
h
order_by = query.order_by
sel['orderby'] = case order_by
when String then string_as_sort_parameters(order_by)
when Symbol then symbol_as_sort_parameters(order_by)
when Array then array_as_sort_parameters(order_by)
when Hash # Should be an ordered hash, but this message doesn't care
query.order_by
warn_if_deprecated(order_by)
order_by
else
raise "illegal order_by: is a #{query.order_by.class.name}, must be String, Array, Hash, or OrderedHash"
end

View File

@ -0,0 +1,110 @@
# --
# Copyright (C) 2008-2009 10gen Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ++
module Mongo #:nodoc:
# Utility module to include when needing to convert certain types of
# objects to mongo-friendly parameters.
module Conversions
ASCENDING = ["ascending", "asc", "1"]
DESCENDING = ["descending", "desc", "-1"]
# Converts the supplied +Array+ to a +Hash+ to pass to mongo as
# sorting parameters. The returned +Hash+ will vary depending
# on whether the passed +Array+ is one or two dimensional.
#
# Example:
#
# *DEPRECATED
#
# <tt>array_as_sort_parameters(["field1", "field2"])</tt> =>
# <tt>{ "field1" => "1", "field2" => "1" }</tt>
#
# *New Syntax:
#
# <tt>array_as_sort_parameters([["field1", :asc], ["field2", :desc]])</tt> =>
# <tt>{ "field1" => 1, "field2" => -1}</tt>
def array_as_sort_parameters(value)
warn_if_deprecated(value)
order_by = OrderedHash.new
value.each do |param|
if (param.class.name == "String")
order_by[param] = 1
else
order_by[param[0]] = sort_value(param[1]) unless param[1].nil?
end
end
order_by
end
# Converts the supplied +String+ to a +Hash+ to pass to mongo as
# a sorting parameter with ascending order. If the +String+
# is empty then an empty +Hash+ will be returned.
#
# Example:
#
# *DEPRECATED
#
# <tt>string_as_sort_parameters("field")</tt> => <tt>{ "field" => 1 }</tt>
# <tt>string_as_sort_parameters("")</tt> => <tt>{}</tt>
def string_as_sort_parameters(value)
warn_if_deprecated(value)
return {} if value.empty?
{ value => 1 }
end
# Converts the supplied +Symbol+ to a +Hash+ to pass to mongo as
# a sorting parameter with ascending order.
#
# Example:
#
# *DEPRECATED
#
# <tt>symbol_as_sort_parameters(:field)</tt> => <tt>{ "field" => 1 }</tt>
def symbol_as_sort_parameters(value)
warn_if_deprecated(value)
{ value.to_s => 1 }
end
# Converts the +String+, +Symbol+, or +Integer+ to the
# corresponding sort value in MongoDB.
#
# Valid conversions (case-insensitive):
#
# <tt>ascending, asc, :ascending, :asc, 1</tt> => <tt>1</tt>
# <tt>descending, desc, :descending, :desc, -1</tt> => <tt>-1</tt>
#
# If the value is invalid then an error will be raised.
def sort_value(value)
val = value.to_s.downcase
return 1 if ASCENDING.include?(val)
return -1 if DESCENDING.include?(val)
raise InvalidSortValueError.new(
"#{self} was supplied as a sort value when acceptable values are: " +
"ascending, asc, :ascending, :asc, 1, descending, desc, :descending, :desc, -1.")
end
# This is the method to call when the client needs to be warned of
# deprecation in the way sorting parameters are supplied.
def warn_if_deprecated(value)
unless value.is_a?(Array) && value.first.is_a?(Array)
warn("\nSorting has been deprecated in favor of a new syntax: \n" +
" :sort => [['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]")
end
end
end
end

121
test/test_conversions.rb Normal file
View File

@ -0,0 +1,121 @@
$LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
require 'mongo/errors'
require 'mongo/util/conversions'
require 'mongo/util/ordered_hash'
require 'test/unit'
class ConversionsTest < Test::Unit::TestCase
include Mongo::Conversions
def test_array_as_sort_parameters_with_array_of_strings
params = array_as_sort_parameters(["field1", "field2"])
assert_equal({ "field1" => 1, "field2" => 1 }, params)
end
def test_array_as_sort_parameters_with_array_of_string_and_values
params = array_as_sort_parameters([["field1", :asc], ["field2", :desc]])
assert_equal({ "field1" => 1, "field2" => -1 }, params)
end
def test_string_as_sort_parameters_with_string
params = string_as_sort_parameters("field")
assert_equal({ "field" => 1 }, params)
end
def test_string_as_sort_parameters_with_empty_string
params = string_as_sort_parameters("")
assert_equal({}, params)
end
def test_symbol_as_sort_parameters
params = symbol_as_sort_parameters(:field)
assert_equal({ "field" => 1 }, params)
end
def test_sort_value_when_value_is_one
assert_equal 1, sort_value(1)
end
def test_sort_value_when_value_is_one_as_a_string
assert_equal 1, sort_value("1")
end
def test_sort_value_when_value_is_negative_one
assert_equal -1, sort_value(-1)
end
def test_sort_value_when_value_is_negative_one_as_a_string
assert_equal -1, sort_value("-1")
end
def test_sort_value_when_value_is_ascending
assert_equal 1, sort_value("ascending")
end
def test_sort_value_when_value_is_asc
assert_equal 1, sort_value("asc")
end
def test_sort_value_when_value_is_uppercase_ascending
assert_equal 1, sort_value("ASCENDING")
end
def test_sort_value_when_value_is_uppercase_asc
assert_equal 1, sort_value("ASC")
end
def test_sort_value_when_value_is_symbol_ascending
assert_equal 1, sort_value(:ascending)
end
def test_sort_value_when_value_is_symbol_asc
assert_equal 1, sort_value(:asc)
end
def test_sort_value_when_value_is_symbol_uppercase_ascending
assert_equal 1, sort_value(:ASCENDING)
end
def test_sort_value_when_value_is_symbol_uppercase_asc
assert_equal 1, sort_value(:ASC)
end
def test_sort_value_when_value_is_descending
assert_equal -1, sort_value("descending")
end
def test_sort_value_when_value_is_desc
assert_equal -1, sort_value("desc")
end
def test_sort_value_when_value_is_uppercase_descending
assert_equal -1, sort_value("DESCENDING")
end
def test_sort_value_when_value_is_uppercase_desc
assert_equal -1, sort_value("DESC")
end
def test_sort_value_when_value_is_symbol_descending
assert_equal -1, sort_value(:descending)
end
def test_sort_value_when_value_is_symbol_desc
assert_equal -1, sort_value(:desc)
end
def test_sort_value_when_value_is_uppercase_symbol_descending
assert_equal -1, sort_value(:DESCENDING)
end
def test_sort_value_when_value_is_uppercase_symbol_desc
assert_equal -1, sort_value(:DESC)
end
def test_sort_value_when_value_is_invalid
assert_raise Mongo::InvalidSortValueError do
sort_value(2)
end
end
end