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.py97
1 files changed, 60 insertions, 37 deletions
diff --git a/lib/sqlalchemy/dialects/postgresql/hstore.py b/lib/sqlalchemy/dialects/postgresql/hstore.py
index ee5dec168..d7a161274 100644
--- a/lib/sqlalchemy/dialects/postgresql/hstore.py
+++ b/lib/sqlalchemy/dialects/postgresql/hstore.py
@@ -10,9 +10,8 @@ from .base import ARRAY
from ... import types as sqltypes
from ...sql import functions as sqlfunc
from ...sql.operators import custom_op
-from ...exc import SQLAlchemyError
-__all__ = ('HStoreSyntaxError', 'HSTORE', 'hstore')
+__all__ = ('HSTORE', 'hstore')
# 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
@@ -33,28 +32,23 @@ HSTORE_DELIMITER_RE = re.compile(r"""
""", re.VERBOSE)
-class HStoreSyntaxError(SQLAlchemyError):
- """Indicates an error unmarshalling an hstore value."""
- def __init__(self, hstore_str, pos):
- self.hstore_str = hstore_str
- self.pos = pos
+def _parse_error(hstore_str, pos):
+ """format an unmarshalling error."""
- ctx = 20
- hslen = len(hstore_str)
+ 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:]
- if len(residual) > ctx:
- residual = residual[:-1] + '[...]'
+ if len(parsed_tail) > ctx:
+ parsed_tail = '[...]' + parsed_tail[1:]
+ if len(residual) > ctx:
+ residual = residual[:-1] + '[...]'
- super(HStoreSyntaxError, self).__init__(
- "After %r, could not parse residual at position %d: %r" %
- (parsed_tail, pos, residual)
- )
+ return "After %r, could not parse residual at position %d: %r" % (
+ parsed_tail, pos, residual)
def _parse_hstore(hstore_str):
@@ -66,7 +60,7 @@ def _parse_hstore(hstore_str):
accepts as input, the documentation makes no guarantees that will always
be the case.
- Throws HStoreSyntaxError if parsing fails.
+
"""
result = {}
@@ -90,7 +84,7 @@ def _parse_hstore(hstore_str):
pair_match = HSTORE_PAIR_RE.match(hstore_str[pos:])
if pos != len(hstore_str):
- raise HStoreSyntaxError(hstore_str, pos)
+ raise ValueError(_parse_error(hstore_str, pos))
return result
@@ -131,11 +125,21 @@ class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
:class:`.HSTORE` provides for a wide range of operations, including:
- * :meth:`.HSTORE.comparatopr_factory.has_key`
+ * Index operations::
+
+ data_table.c.data['some key'] == 'some value'
+
+ * Containment operations::
+
+ data_table.c.data.has_key('some key')
- * :meth:`.HSTORE.comparatopr_factory.has_all`
+ data_table.c.data.has_all(['one', 'two', 'three'])
- * :meth:`.HSTORE.comparatopr_factory.defined`
+ * Concatenation::
+
+ data_table.c.data + {"k1": "v1"}
+
+ For a full list of special methods see :class:`.HSTORE.comparator_factory`.
For usage with the SQLAlchemy ORM, it may be desirable to combine
the usage of :class:`.HSTORE` with the :mod:`sqlalchemy.ext.mutable`
@@ -158,11 +162,20 @@ class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
session.commit()
+ .. versionadded:: 0.8
+
+ .. seealso::
+
+ :class:`.hstore` - render the Postgresql ``hstore()`` function.
+
+
"""
__visit_name__ = 'HSTORE'
class comparator_factory(sqltypes.TypeEngine.Comparator):
+ """Define comparison operations for :class:`.HSTORE`."""
+
def has_key(self, other):
"""Boolean expression. Test for presence of a key. Note that the
key may be a SQLA expression.
@@ -251,15 +264,6 @@ class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
return op, sqltypes.Text
return op, other_comparator.type
- #@util.memoized_property
- #@property
- #def _expression_adaptations(self):
- # return {
- # operators.getitem: {
- # sqltypes.String: sqltypes.String
- # },
- # }
-
def bind_processor(self, dialect):
def process(value):
if isinstance(value, dict):
@@ -278,11 +282,30 @@ class HSTORE(sqltypes.Concatenable, sqltypes.TypeEngine):
class hstore(sqlfunc.GenericFunction):
- """Construct an hstore on the server side using the hstore function.
+ """Construct an hstore value within a SQL expression using the
+ Postgresql ``hstore()`` function.
+
+ The :class:`.hstore` function accepts one or two arguments as described
+ in the Postgresql documentation.
+
+ E.g.::
+
+ from sqlalchemy.dialects.postgresql import array, hstore
+
+ select([hstore('key1', 'value1')])
+
+ select([
+ hstore(
+ array(['key1', 'key2', 'key3']),
+ array(['value1', 'value2', 'value3'])
+ )
+ ])
+
+ .. versionadded:: 0.8
+
+ .. seealso::
- The single argument or a pair of arguments are evaluated as SQLAlchemy
- expressions, so both may contain columns, function calls, or any other
- valid SQL expressions which evaluate to text or array.
+ :class:`.HSTORE` - the Postgresql ``HSTORE`` datatype.
"""
type = HSTORE