summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/dialects/postgresql/hstore.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/dialects/postgresql/hstore.py')
-rw-r--r--lib/sqlalchemy/dialects/postgresql/hstore.py129
1 files changed, 81 insertions, 48 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/hstore.py b/lib/sqlalchemy/dialects/postgresql/hstore.py
index b6c9e7124..e4bac692a 100644
--- a/lib/sqlalchemy/dialects/postgresql/hstore.py
+++ b/lib/sqlalchemy/dialects/postgresql/hstore.py
@@ -14,38 +14,50 @@ from ...sql import functions as sqlfunc
from ...sql import operators
from ... import util
-__all__ = ('HSTORE', 'hstore')
+__all__ = ("HSTORE", "hstore")
idx_precedence = operators._PRECEDENCE[operators.json_getitem_op]
GETITEM = operators.custom_op(
- "->", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "->",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
HAS_KEY = operators.custom_op(
- "?", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "?",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
HAS_ALL = operators.custom_op(
- "?&", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "?&",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
HAS_ANY = operators.custom_op(
- "?|", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "?|",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
CONTAINS = operators.custom_op(
- "@>", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "@>",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
CONTAINED_BY = operators.custom_op(
- "<@", precedence=idx_precedence, natural_self_precedent=True,
- eager_grouping=True
+ "<@",
+ precedence=idx_precedence,
+ natural_self_precedent=True,
+ eager_grouping=True,
)
@@ -122,7 +134,7 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
"""
- __visit_name__ = 'HSTORE'
+ __visit_name__ = "HSTORE"
hashable = False
text_type = sqltypes.Text()
@@ -139,7 +151,8 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
self.text_type = text_type
class Comparator(
- sqltypes.Indexable.Comparator, sqltypes.Concatenable.Comparator):
+ sqltypes.Indexable.Comparator, sqltypes.Concatenable.Comparator
+ ):
"""Define comparison operations for :class:`.HSTORE`."""
def has_key(self, other):
@@ -169,7 +182,8 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
keys of the argument jsonb expression.
"""
return self.operate(
- CONTAINED_BY, other, result_type=sqltypes.Boolean)
+ CONTAINED_BY, other, result_type=sqltypes.Boolean
+ )
def _setup_getitem(self, index):
return GETITEM, index, self.type.text_type
@@ -223,12 +237,15 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
return _serialize_hstore(value).encode(encoding)
else:
return value
+
else:
+
def process(value):
if isinstance(value, dict):
return _serialize_hstore(value)
else:
return value
+
return process
def result_processor(self, dialect, coltype):
@@ -240,16 +257,19 @@ class HSTORE(sqltypes.Indexable, sqltypes.Concatenable, sqltypes.TypeEngine):
return _parse_hstore(value.decode(encoding))
else:
return value
+
else:
+
def process(value):
if value is not None:
return _parse_hstore(value)
else:
return value
+
return process
-ischema_names['hstore'] = HSTORE
+ischema_names["hstore"] = HSTORE
class hstore(sqlfunc.GenericFunction):
@@ -279,43 +299,44 @@ class hstore(sqlfunc.GenericFunction):
:class:`.HSTORE` - the PostgreSQL ``HSTORE`` datatype.
"""
+
type = HSTORE
- name = 'hstore'
+ name = "hstore"
class _HStoreDefinedFunction(sqlfunc.GenericFunction):
type = sqltypes.Boolean
- name = 'defined'
+ name = "defined"
class _HStoreDeleteFunction(sqlfunc.GenericFunction):
type = HSTORE
- name = 'delete'
+ name = "delete"
class _HStoreSliceFunction(sqlfunc.GenericFunction):
type = HSTORE
- name = 'slice'
+ name = "slice"
class _HStoreKeysFunction(sqlfunc.GenericFunction):
type = ARRAY(sqltypes.Text)
- name = 'akeys'
+ name = "akeys"
class _HStoreValsFunction(sqlfunc.GenericFunction):
type = ARRAY(sqltypes.Text)
- name = 'avals'
+ name = "avals"
class _HStoreArrayFunction(sqlfunc.GenericFunction):
type = ARRAY(sqltypes.Text)
- name = 'hstore_to_array'
+ name = "hstore_to_array"
class _HStoreMatrixFunction(sqlfunc.GenericFunction):
type = ARRAY(sqltypes.Text)
- name = 'hstore_to_matrix'
+ name = "hstore_to_matrix"
#
@@ -326,7 +347,8 @@ class _HStoreMatrixFunction(sqlfunc.GenericFunction):
# My best guess at the parsing rules of hstore literals, since no formal
# grammar is given. This is mostly reverse engineered from PG's input parser
# behavior.
-HSTORE_PAIR_RE = re.compile(r"""
+HSTORE_PAIR_RE = re.compile(
+ r"""
(
"(?P<key> (\\ . | [^"])* )" # Quoted key
)
@@ -335,11 +357,16 @@ HSTORE_PAIR_RE = re.compile(r"""
(?P<value_null> NULL ) # NULL value
| "(?P<value> (\\ . | [^"])* )" # Quoted value
)
-""", re.VERBOSE)
+""",
+ re.VERBOSE,
+)
-HSTORE_DELIMITER_RE = re.compile(r"""
+HSTORE_DELIMITER_RE = re.compile(
+ r"""
[ ]* , [ ]*
-""", re.VERBOSE)
+""",
+ re.VERBOSE,
+)
def _parse_error(hstore_str, pos):
@@ -348,16 +375,19 @@ def _parse_error(hstore_str, pos):
ctx = 20
hslen = len(hstore_str)
- parsed_tail = hstore_str[max(pos - ctx - 1, 0):min(pos, hslen)]
- residual = hstore_str[min(pos, hslen):min(pos + ctx + 1, hslen)]
+ parsed_tail = hstore_str[max(pos - ctx - 1, 0) : min(pos, hslen)]
+ residual = hstore_str[min(pos, hslen) : min(pos + ctx + 1, hslen)]
if len(parsed_tail) > ctx:
- parsed_tail = '[...]' + parsed_tail[1:]
+ parsed_tail = "[...]" + parsed_tail[1:]
if len(residual) > ctx:
- residual = residual[:-1] + '[...]'
+ residual = residual[:-1] + "[...]"
return "After %r, could not parse residual at position %d: %r" % (
- parsed_tail, pos, residual)
+ parsed_tail,
+ pos,
+ residual,
+ )
def _parse_hstore(hstore_str):
@@ -377,13 +407,15 @@ def _parse_hstore(hstore_str):
pair_match = HSTORE_PAIR_RE.match(hstore_str)
while pair_match is not None:
- key = pair_match.group('key').replace(r'\"', '"').replace(
- "\\\\", "\\")
- if pair_match.group('value_null'):
+ key = pair_match.group("key").replace(r"\"", '"').replace("\\\\", "\\")
+ if pair_match.group("value_null"):
value = None
else:
- value = pair_match.group('value').replace(
- r'\"', '"').replace("\\\\", "\\")
+ value = (
+ pair_match.group("value")
+ .replace(r"\"", '"')
+ .replace("\\\\", "\\")
+ )
result[key] = value
pos += pair_match.end()
@@ -405,16 +437,17 @@ def _serialize_hstore(val):
both be strings (except None for values).
"""
+
def esc(s, position):
- if position == 'value' and s is None:
- return 'NULL'
+ if position == "value" and s is None:
+ return "NULL"
elif isinstance(s, util.string_types):
- return '"%s"' % s.replace("\\", "\\\\").replace('"', r'\"')
+ return '"%s"' % s.replace("\\", "\\\\").replace('"', r"\"")
else:
- raise ValueError("%r in %s position is not a string." %
- (s, position))
-
- return ', '.join('%s=>%s' % (esc(k, 'key'), esc(v, 'value'))
- for k, v in val.items())
-
+ raise ValueError(
+ "%r in %s position is not a string." % (s, position)
+ )
+ return ", ".join(
+ "%s=>%s" % (esc(k, "key"), esc(v, "value")) for k, v in val.items()
+ )