diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-09-20 12:21:14 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-09-20 12:34:46 -0400 |
commit | 9ae645d5d1a8cc7732a6d335be6205d0b21e31b1 (patch) | |
tree | 00265efd4658b42bf7bd3d794dc82568a73f7ea1 /lib/sqlalchemy/dialects/postgresql/ranges.py | |
parent | 214d1ad7c38deebec6547da22b99c0a4804bf820 (diff) | |
download | sqlalchemy-9ae645d5d1a8cc7732a6d335be6205d0b21e31b1.tar.gz |
auto-cast PG range types
Range type handling has been enhanced so that it automatically
renders type casts, so that in-place round trips for statements that don't
provide the database with any context don't require the :func:`_sql.cast`
construct to be explicit for the database to know the desired type.
Change-Id: Id630b726f8a23059dd2f4cbc410bf5229d89cbfb
References: #8540
Diffstat (limited to 'lib/sqlalchemy/dialects/postgresql/ranges.py')
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/ranges.py | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/ranges.py b/lib/sqlalchemy/dialects/postgresql/ranges.py index edbe165d9..327feb409 100644 --- a/lib/sqlalchemy/dialects/postgresql/ranges.py +++ b/lib/sqlalchemy/dialects/postgresql/ranges.py @@ -91,6 +91,35 @@ class AbstractRange(sqltypes.TypeEngine): """ # noqa: E501 + render_bind_cast = True + + def adapt(self, impltype): + """dynamically adapt a range type to an abstract impl. + + For example ``INT4RANGE().adapt(_Psycopg2NumericRange)`` should + produce a type that will have ``_Psycopg2NumericRange`` behaviors + and also render as ``INT4RANGE`` in SQL and DDL. + + """ + if issubclass(impltype, AbstractRangeImpl): + # two ways to do this are: 1. create a new type on the fly + # or 2. have AbstractRangeImpl(visit_name) constructor and a + # visit_abstract_range_impl() method in the PG compiler. + # I'm choosing #1 as the resulting type object + # will then make use of the same mechanics + # as if we had made all these sub-types explicitly, and will + # also look more obvious under pdb etc. + # The adapt() operation here is cached per type-class-per-dialect, + # so is not much of a performance concern + visit_name = self.__visit_name__ + return type( + f"{visit_name}RangeImpl", + (impltype, self.__class__), + {"__visit_name__": visit_name}, + )() + else: + return super().adapt(impltype) + class comparator_factory(sqltypes.Concatenable.Comparator): """Define comparison operations for range types.""" @@ -165,10 +194,20 @@ class AbstractRange(sqltypes.TypeEngine): return self.expr.op("+")(other) +class AbstractRangeImpl(AbstractRange): + """marker for AbstractRange that will apply a subclass-specific + adaptation""" + + class AbstractMultiRange(AbstractRange): """base for PostgreSQL MULTIRANGE types""" +class AbstractMultiRangeImpl(AbstractRangeImpl, AbstractMultiRange): + """marker for AbstractRange that will apply a subclass-specific + adaptation""" + + class INT4RANGE(AbstractRange): """Represent the PostgreSQL INT4RANGE type.""" |