I have the following TypeDecorator type to store a tuple of strings as
a delimited string.  It works fine but I discovered an abnormality
with LIKE.  The right side of a like expression is being passed to the
converter, so it has to be a one-item tuple instead of a string.  This
makes my model unintuitive.  Am I doing something wrong or is this
just a corollary of how TypeDecorator works?


 m.Chemical.synonyms.like((like,))     # Ugly

 q = q.filter(m.UN.synonyms.like(("%" + term + "%",)))     # Ugly


class MultiText(sa.types.TypeDecorator):
    """Store a tuple of string values as a single delimited string.

    Legal values are a tuple of strings, or ``None`` for NULL.
    Lists are not allowed because SQLAlchemy can't recognize in-place
    modifications.

    Note that during SQL queries (e.g., column LIKE "%ABC%"), the
    comparision is against the delimited string.  This may cause unexpected
    results if the control value contains the delimeter as a substring.
    """

    impl = sa.types.Text

    def __init__(self, delimiter, *args, **kw):
        """Constructor.

        The first positional arg is the delimiter, and is required.

        All other positional and keyword args are passed to the underlying
        column type.
        """
        if not isinstance(delimiter, basestring):
            msg = "arg ``delimiter`` must be string, not %r"
            raise TypeError(msg % delimiter)
        self.delimiter = delimiter
        sa.types.TypeDecorator.__init__(self, *args, **kw)

    def process_bind_param(self, value, dialect):
        """Convert a tuple of strings to a single delimited string.

        Exceptions:
            ``TypeError`` if the value is neither a tuple nor ``None``.
            ``TypeError`` if any element is not a string.
            ``ValueError`` if any element contains the delimeter as a substring.
        """
        if value is None:
            return None
        if not isinstance(value, tuple):
            msg = "%s value must be a tuple, not %r"
            tup = self.__class__.__name__, value
            raise TypeError(msg % tup)
        for i, element in enumerate(value):
            if self.delimiter in element:
                msg = "delimiter %r found in index %d of %s: %r"
                tup = (self.delimiter, i, self.__class__.__name, value)
                raise ValueError(msg % tup)
        return self.delimiter.join(value)

    def process_result_value(self, value, dialect):
        """Convert a delimited string to a tuple of strings."""
        if value is None:
            return None
        elif value == "":
            return ()
        elements = value.split(self.delimiter)
        return tuple(elements)

    def copy(self):
        return self.__class__(self.delimiter, self.impl.length)




-- 
Mike Orr <[email protected]>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to