Use Case
I'm using SQLAlchemy and SQLite for a standalone application (non-web) and I need to store numerical ranges in a database. I'm doing this by saving the start and end of each range in SQLite like so:
[[float("-inf"), 0], [1, 1000],..., [9999, 12000], [12001, float("inf")]]
In the final application I need to determine what range an arbitrary number
falls within. I'm doing something like below:
...
for range_ in ranges:
range_start, range_end = range_
if range_start <= number <= range_end:
return range_
...
number
can be any integer or infinity so the ranges in the db must stretch from negative infinity to positive infinity
Problem
The following code works fine
import sqlalchemy as sa
from sqlalchemy.orm import declarative_base, sessionmaker, scoped_session
Base = declarative_base()
class MyMappedClass(Base):
__tablename__ = "my_table"
id = sa.Column(sa.Integer, primary_key=True)
ranges = sa.Column(sa.JSON)
if __name__ == "__main__":
engine = sa.create_engine("sqlite://", future=True)
Session = scoped_session(sessionmaker(bind=engine))
session = Session()
Base.metadata.create_all(session.bind)
mapped_class = MyMappedClass(
ranges=[[float("-inf"), 1], [1, float("inf")]],
)
with session:
session.add(mapped_class)
session.commit()
But when I add a CheckConstraint
calling json_array_length(ranges)
I get a malformed JSON
error:
...
ranges = sa.Column(
sa.JSON,
sa.CheckConstraint("json_array_length(ranges) >= 2"),
)
...
Traceback:
...
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) malformed JSON
...
I confirmed [[float("-inf"), 1], [1, float("inf")]]
isn't being converted to valid JSON by changing the CheckConstraint
to json_valid(ranges)
and it fails only when infinity is in the column.
I must be able to add CheckConstraint
s to the ranges
column. There are data validation steps I need to do with other columns. The details of which are complex and beyond the scope of this question.
Workarounds
I think I can get around this by replacing float("inf")
with "inf"
like so
mapped_class = MyMappedClass(
ranges=[["-inf", 1], [1, "inf"]],
)
And I can determine the range of an arbitrary number
like:
...
for range_ in ranges:
range_start, range_end = range
if float(range_start) <= number <= float(range_end):
return range_
...
But now I have mixed types in the column and I would prefer only numbers present.
Back to the Question
Is there any way to store infinity in a JSON1 column? If there are other databases that support infinity in an array (that are suitable for a standalone application) please share. Ideally, SQLAlchemy supports this database.