Skip to content

Commit

Permalink
RUBY-2928 Implement BSON::Decimal128 comparison operators (#283)
Browse files Browse the repository at this point in the history
Co-authored-by: Oleg Pudeyev <[email protected]>
  • Loading branch information
p-mongo and p committed Apr 13, 2022
1 parent 5a8e17c commit b8dc6a8
Show file tree
Hide file tree
Showing 2 changed files with 227 additions and 2 deletions.
14 changes: 12 additions & 2 deletions lib/bson/decimal128.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module BSON

class Decimal128
include JSON
include Comparable

# A Decimal128 is type 0x13 in the BSON spec.
#
Expand Down Expand Up @@ -97,15 +98,24 @@ def ==(other)
end
alias :eql? :==

# Create a new Decimal128 from a BigDecimal.
def <=>(other)
to_big_decimal <=> case other
when Decimal128
other.to_big_decimal
else
other
end
end

# Create a new Decimal128 from a string or a BigDecimal instance.
#
# @example Create a Decimal128 from a BigDecimal.
# Decimal128.new(big_decimal)
#
# @param [ String, BigDecimal ] object The BigDecimal or String to use for
# instantiating a Decimal128.
#
# @raise [ InvalidBigDecimal ] Raise error unless object argument is a BigDecimal.
# @raise [ InvalidArgument ] When argument is not a String or BigDecimal.
#
# @since 4.2.0
def initialize(object)
Expand Down
215 changes: 215 additions & 0 deletions spec/bson/decimal128_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1602,4 +1602,219 @@
expect(registered).to eq(described_class)
end
end

%w(== ===).each do |eq_op|
let(:lhs) { described_class.new('1.2e12') }

describe "##{eq_op}" do
context 'when rhs is equal to lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.2e12') }

it 'is true' do
(lhs == rhs).should be true
end
end

context 'when rhs is of a different type' do
[
1200000000000,
1200000000000.0,
BigDecimal('1.2e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is true' do
pending 'RUBY-2952'

(lhs == rhs).should be true
end
end
end
end
end

context 'when rhs is not equal to lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.21e12') }

it 'is false' do
(lhs == rhs).should be false
end
end

context 'when rhs is of a different type' do

[
1200000000001,
1200000000001.0,
BigDecimal('1.21e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is false' do
(lhs == rhs).should be false
end
end
end
end
end
end
end

describe "#<=>" do

let(:lhs) { described_class.new('1.2e12') }

context 'when lhs is less than rhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.21e12') }

it 'is -1' do
(lhs <=> rhs).should be -1
end
end

context 'when rhs is of a different type' do
[
1200000000001,
1200000000001.0,
BigDecimal('1.21e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is -1' do
(lhs <=> rhs).should be -1
end
end
end
end
end

context 'when rhs is equal to lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.2e12') }

it 'is 0' do
(lhs <=> rhs).should be 0
end
end

context 'when rhs is of a different type' do

[
1200000000000,
1200000000000.0,
BigDecimal('1.2e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is 0' do
(lhs <=> rhs).should be 0
end
end
end
end
end

context 'when rhs is greater than lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.1e12') }

it 'is 1' do
(lhs <=> rhs).should be 1
end
end

context 'when rhs is of a different type' do

[
1100000000000,
1100000000000.0,
BigDecimal('1.1e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is 1' do
(lhs <=> rhs).should be 1
end
end
end
end
end
end

describe "#<" do

let(:lhs) { described_class.new('1.2e12') }

context 'when lhs is less than rhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.21e12') }

it 'is true' do
(lhs < rhs).should be true
end
end

context 'when rhs is of a different type' do
[
1200000000001,
1200000000001.0,
BigDecimal('1.21e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is true' do
(lhs < rhs).should be true
end
end
end
end
end

context 'when rhs is equal to lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.2e12') }

it 'is false' do
(lhs < rhs).should be false
end
end

context 'when rhs is of a different type' do

[
1200000000000,
1200000000000.0,
BigDecimal('1.2e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is false' do
(lhs < rhs).should be false
end
end
end
end
end

context 'when rhs is greater than lhs' do
context 'when both are Decimal128 instances' do
let(:rhs) { described_class.new('1.1e12') }

it 'is false' do
(lhs < rhs).should be false
end
end

context 'when rhs is of a different type' do

[
1100000000000,
1100000000000.0,
BigDecimal('1.1e12'),
].each do |rhs|
context "when rhs is #{rhs.class}" do
it 'is false' do
(lhs < rhs).should be false
end
end
end
end
end
end
end

0 comments on commit b8dc6a8

Please sign in to comment.