1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
from decimal import Decimal
import pytest
import sqlalchemy as sa
from sqlalchemy_utils import NumericRangeType
from sqlalchemy_utils.compat import _select_args
intervals = None
inf = 0
try:
import intervals
from infinity import inf
except ImportError:
pass
@pytest.fixture
def create_car(session, Car):
def create_car(number_range):
car = Car(
price_range=number_range
)
session.add(car)
session.commit()
return session.query(Car).first()
return create_car
@pytest.mark.skipif('intervals is None')
class NumericRangeTestCase:
@pytest.fixture
def Car(self, Base):
class Car(Base):
__tablename__ = 'car'
id = sa.Column(sa.Integer, primary_key=True)
price_range = sa.Column(NumericRangeType)
return Car
@pytest.fixture
def init_models(self, Car):
pass
def test_nullify_range(self, create_car):
car = create_car(None)
assert car.price_range is None
@pytest.mark.parametrize(
'number_range',
(
[1, 3],
(1, 3)
)
)
def test_save_number_range(self, create_car, number_range):
car = create_car(number_range)
assert car.price_range.lower == 1
assert car.price_range.upper == 3
def test_infinite_upper_bound(self, create_car):
car = create_car([1, inf])
assert car.price_range.lower == 1
assert car.price_range.upper == inf
def test_infinite_lower_bound(self, create_car):
car = create_car([-inf, 1])
assert car.price_range.lower == -inf
assert car.price_range.upper == 1
def test_nullify_number_range(self, session, Car):
car = Car(
price_range=intervals.DecimalInterval([1, 3])
)
session.add(car)
session.commit()
car = session.query(Car).first()
car.price_range = None
session.commit()
car = session.query(Car).first()
assert car.price_range is None
def test_integer_coercion(self, Car):
car = Car(price_range=15)
assert car.price_range.lower == 15
assert car.price_range.upper == 15
def test_compilation(self, session, Car):
query = sa.select(*_select_args(Car.price_range))
# the type should be cacheable and not throw exception
session.execute(query)
@pytest.mark.usefixtures('postgresql_dsn')
class TestNumericRangeOnPostgres(NumericRangeTestCase):
@pytest.mark.parametrize(
('number_range', 'length'),
(
([1, 3], 2),
([1, 1], 0),
([-1, 1], 2),
([-inf, 1], None),
([0, inf], None),
([0, 0], 0),
([-3, -1], 2)
)
)
def test_length(self, session, Car, create_car, number_range, length):
create_car(number_range)
query = (
session.query(Car.price_range.length)
)
assert query.scalar() == length
def test_literal_param(self, session, Car):
clause = Car.price_range == [1, 3]
compiled = str(clause.compile(compile_kwargs={'literal_binds': True}))
assert compiled == "car.price_range = '[1, 3]'"
@pytest.mark.skipif('intervals is None')
class TestNumericRangeWithStep:
@pytest.fixture
def Car(self, Base):
class Car(Base):
__tablename__ = 'car'
id = sa.Column(sa.Integer, primary_key=True)
price_range = sa.Column(NumericRangeType(step=Decimal('0.5')))
return Car
@pytest.fixture
def init_models(self, Car):
pass
def test_passes_step_argument_to_interval_object(self, create_car):
car = create_car([Decimal('0.2'), Decimal('0.8')])
assert car.price_range.lower == Decimal('0')
assert car.price_range.upper == Decimal('1')
assert car.price_range.step == Decimal('0.5')
def test_passes_step_fetched_objects(self, session, Car, create_car):
create_car([Decimal('0.2'), Decimal('0.8')])
session.expunge_all()
car = session.query(Car).first()
assert car.price_range.lower == Decimal('0')
assert car.price_range.upper == Decimal('1')
assert car.price_range.step == Decimal('0.5')
|