--- /dev/null
+.. change::
+ :tags: pg8000
+ :tickets: 9965
+
+ The pg8000 dialect now supports :class:`_postgresql.Range` types and multirange
+ types. Range and multirange types are supported in the pg8000 driver from version
+ 1.29.8.
import decimal
import re
+from . import ranges
from .array import ARRAY as PGARRAY
from .base import _DECIMAL_TYPES
from .base import _FLOAT_TYPES
pass
+class _Pg8000Range(ranges.AbstractRangeImpl):
+ def bind_processor(self, dialect):
+ pg8000_Range = dialect.dbapi.Range
+
+ def to_range(value):
+ if isinstance(value, ranges.Range):
+ value = pg8000_Range(
+ value.lower, value.upper, value.bounds, value.empty
+ )
+ return value
+
+ return to_range
+
+ def result_processor(self, dialect, coltype):
+ def to_range(value):
+ if value is not None:
+ value = ranges.Range(
+ value.lower,
+ value.upper,
+ bounds=value.bounds,
+ empty=value.is_empty,
+ )
+ return value
+
+ return to_range
+
+
+class _Pg8000MultiRange(ranges.AbstractMultiRangeImpl):
+ def bind_processor(self, dialect):
+ pg8000_Range = dialect.dbapi.Range
+
+ def to_multirange(value):
+ if isinstance(value, list):
+ mr = []
+ for v in value:
+ if isinstance(v, ranges.Range):
+ mr.append(
+ pg8000_Range(v.lower, v.upper, v.bounds, v.empty)
+ )
+ else:
+ mr.append(v)
+ return mr
+ else:
+ return value
+
+ return to_multirange
+
+ def result_processor(self, dialect, coltype):
+ def to_multirange(value):
+ if value is None:
+ return None
+
+ mr = []
+ for v in value:
+ mr.append(
+ ranges.Range(
+ v.lower, v.upper, bounds=v.bounds, empty=v.is_empty
+ )
+ )
+ return mr
+
+ return to_multirange
+
+
_server_side_id = util.counter()
sqltypes.Enum: _PGEnum,
sqltypes.ARRAY: _PGARRAY,
OIDVECTOR: _PGOIDVECTOR,
+ ranges.INT4RANGE: _Pg8000Range,
+ ranges.INT8RANGE: _Pg8000Range,
+ ranges.NUMRANGE: _Pg8000Range,
+ ranges.DATERANGE: _Pg8000Range,
+ ranges.TSRANGE: _Pg8000Range,
+ ranges.TSTZRANGE: _Pg8000Range,
+ ranges.INT4MULTIRANGE: _Pg8000MultiRange,
+ ranges.INT8MULTIRANGE: _Pg8000MultiRange,
+ ranges.NUMMULTIRANGE: _Pg8000MultiRange,
+ ranges.DATEMULTIRANGE: _Pg8000MultiRange,
+ ranges.TSMULTIRANGE: _Pg8000MultiRange,
+ ranges.TSTZMULTIRANGE: _Pg8000MultiRange,
},
)
)
self._assert_data(connection)
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_insert_text(self, connection):
connection.execute(
self.tables.data_table.insert(), {"range": self._data_str()}
data = connection.execute(select(range_ + range_)).fetchall()
eq_(data, [(self._data_obj(),)])
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_union_result_text(self, connection):
# insert
connection.execute(
data = connection.execute(select(range_ * range_)).fetchall()
eq_(data, [(self._data_obj(),)])
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_intersection_result_text(self, connection):
# insert
connection.execute(
data = connection.execute(select(range_ - range_)).fetchall()
eq_(data, [(self._data_obj().__class__(empty=True),)])
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_difference_result_text(self, connection):
# insert
connection.execute(
)
self._assert_data(connection)
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_insert_text(self, connection):
connection.execute(
self.tables.data_table.insert(), {"range": self._data_str()}
)
self._assert_data(connection)
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_union_result_text(self, connection):
# insert
connection.execute(
data = connection.execute(select(range_ + range_)).fetchall()
eq_(data, [(self._data_obj(),)])
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_intersection_result_text(self, connection):
# insert
connection.execute(
data = connection.execute(select(range_ * range_)).fetchall()
eq_(data, [(self._data_obj(),)])
- @testing.requires.any_psycopg_compatibility
+ @testing.requires.psycopg_or_pg8000_compatibility
def test_difference_result_text(self, connection):
# insert
connection.execute(
@property
def range_types(self):
- return only_on(["+psycopg2", "+psycopg", "+asyncpg"])
+ return only_on(["+psycopg2", "+psycopg", "+asyncpg", "+pg8000"])
@property
def multirange_types(self):
- return only_on(["+psycopg", "+asyncpg"]) + only_on("postgresql >= 14")
+ return only_on(["+psycopg", "+asyncpg", "+pg8000"]) + only_on(
+ "postgresql >= 14"
+ )
@property
def async_dialect(self):