diff options
author | Federico Caselli <cfederico87@gmail.com> | 2020-04-19 20:09:39 +0200 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2020-04-20 11:54:20 -0400 |
commit | aaec1bdedfc73ead3aef3a3e4d835a8df339e2dd (patch) | |
tree | 70dd9f841bcd9e9c8b14d6d7f4238abeda64fc46 /lib/sqlalchemy/dialects/postgresql/array.py | |
parent | 2f617f56f2acdce00b88f746c403cf5ed66d4d27 (diff) | |
download | sqlalchemy-aaec1bdedfc73ead3aef3a3e4d835a8df339e2dd.tar.gz |
Support `ARRAY` of `Enum`, `JSON` or `JSONB`
Added support for columns or type :class:`.ARRAY` of :class:`.Enum`,
:class:`.JSON` or :class:`_postgresql.JSONB` in PostgreSQL.
Previously a workaround was required in these use cases.
Raise an explicit :class:`.exc.CompileError` when adding a table with a
column of type :class:`.ARRAY` of :class:`.Enum` configured with
:paramref:`.Enum.native_enum` set to ``False`` when
:paramref:`.Enum.create_constraint` is not set to ``False``
Fixes: #5265
Fixes: #5266
Change-Id: I83a2d20a599232b7066d0839f3e55ff8b78cd8fc
Diffstat (limited to 'lib/sqlalchemy/dialects/postgresql/array.py')
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/array.py | 53 |
1 files changed, 41 insertions, 12 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/array.py b/lib/sqlalchemy/dialects/postgresql/array.py index a3537ba60..84fbd2e50 100644 --- a/lib/sqlalchemy/dialects/postgresql/array.py +++ b/lib/sqlalchemy/dialects/postgresql/array.py @@ -5,19 +5,14 @@ # This module is part of SQLAlchemy and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -from .base import colspecs -from .base import ischema_names +import re + from ... import types as sqltypes +from ... import util from ...sql import expression from ...sql import operators -try: - from uuid import UUID as _python_UUID # noqa -except ImportError: - _python_UUID = None - - def Any(other, arrexpr, operator=operators.eq): """A synonym for the :meth:`.ARRAY.Comparator.any` method. @@ -318,6 +313,25 @@ class ARRAY(sqltypes.ARRAY): for x in arr ) + @util.memoized_property + def _require_cast(self): + return self._against_native_enum or isinstance( + self.item_type, sqltypes.JSON + ) + + @util.memoized_property + def _against_native_enum(self): + return ( + isinstance(self.item_type, sqltypes.Enum) + and self.item_type.native_enum + ) + + def bind_expression(self, bindvalue): + if self._require_cast: + return expression.cast(bindvalue, self) + else: + return bindvalue + def bind_processor(self, dialect): item_proc = self.item_type.dialect_impl(dialect).bind_processor( dialect @@ -349,8 +363,23 @@ class ARRAY(sqltypes.ARRAY): tuple if self.as_tuple else list, ) - return process - + if self._against_native_enum: + super_rp = process + + def handle_raw_string(value): + inner = re.match(r"^{(.*)}$", value).group(1) + return inner.split(",") if inner else [] + + def process(value): + if value is None: + return value + # isinstance(value, util.string_types) is required to handle + # the # case where a TypeDecorator for and Array of Enum is + # used like was required in sa < 1.3.17 + return super_rp( + handle_raw_string(value) + if isinstance(value, util.string_types) + else value + ) -colspecs[sqltypes.ARRAY] = ARRAY -ischema_names["_array"] = ARRAY + return process |