On Aug 13, 2010, at 10:45 AM, Dan wrote:
> Unfortunately still getting the same result:
>
> http://paste.pocoo.org/show/249801/
>
> The test snippet shows that the modified set is not actually saved to
> the database.
that code snippet is not complete (doesn't create a Session, doesn't add Post
to it, doesn't commit() or flush() the session but then removes it so I guess
maybe its a scoped_session, don't know) so I don't actually know what you're
doing. The test case below adds your assertion, uses the Session properly,
and works fine. The previous test I pasted also works (if I bothered to write
out a full test for it, you can be sure I ran it).
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
Base = declarative_base()
metadata = Base.metadata
engine = create_engine('sqlite://', echo=True)
from sqlalchemy import types
class DenormalizedText(types.TypeDecorator):
"""
Stores denormalized primary keys that can be
accessed as a set.
:param coerce: coercion function that ensures correct
type is returned
:param separator: separator character
"""
impl = types.Text
def __init__(self, coerce=int, separator=" ", **kwargs):
self.coerce = coerce
self.separator = separator
super(DenormalizedText, self).__init__(**kwargs)
def bind_processor(self, dialect):
def process(value):
if value is not None:
items = [str(item).strip() for item in value]
value = self.separator.join(item for item in items if item)
return value
return process
def result_processor(self, dialect, coltype):
def process(value):
if not value:
return set()
return set(self.coerce(item) \
for item in value.split(self.separator))
return process
def copy_value(self, value):
return set(value)
def is_mutable(self):
return True
class Post(Base):
__tablename__ = "posts"
id = Column(Integer, primary_key=True)
votes = Column(DenormalizedText)
def __init__(self, *args, **kwargs):
super(Post, self).__init__(*args, **kwargs)
self.votes = self.votes or set()
Base.metadata.create_all(engine)
session = sessionmaker(engine)()
post = Post()
assert post.votes == set([])
session.add(post)
session.commit()
post.votes.add(1)
assert 1 in post.votes
session.commit()
post_id = post.id
# close out transaction, session entirely, even
# though commit expires everything anyway
session.close()
post = session.query(Post).get(post_id)
assert 1 in post.votes
>
> On Aug 13, 3:29 pm, Michael Bayer <[email protected]> wrote:
>> On Aug 13, 2010, at 10:24 AM, Dan wrote:
>>
>>
>>
>>
>>
>>> On Aug 13, 3:17 pm, Michael Bayer <[email protected]> wrote:
>>>> On Aug 13, 2010, at 10:01 AM, Dan wrote:
>>
>>>>> I have created a custom type in order to store denormalized PKs in a
>>>>> TEXT field. The idea is that the text is converted back and forth from
>>>>> a set of integers:
>>
>>>>> http://paste.pocoo.org/show/249784/
>>
>>>> this is unrelated, but the code is incorrect there, should be
>>
>>>> def process(value):
>>>> if value is not None:
>>>> items = [str(item).strip() for item in value]
>>>> value = self.separator.join(item for item in items if item)
>>
>>>> otherwise, you must implement copy_value() on your type. Here, the value
>>>> isn't being copied so there's nothing to compare to.
>>
>>> Yes, sorry for the typo. Realized myself once I'd posted.
>>
>>>> Usually you're supposed to mixin MutableType which will raise
>>>> notimplemented for copy_value(). I guess still more docs are needed
>>>> since you were misled by the is_mutable() method.
>>
>>> I've tried the same thing with the MutableType mixin with the same
>>> result, i.e:
>>
>>> class DenormalizedText(types.TypeDecorator, types.MutableType):
>>
>> MutableType would be first. But again this only just so the
>> NotImplementedError lets you know copy_value() is needed. I could make
>> the default copy_value() raise if is_mutable() is true...though it pains me
>> to add more method calls...
>>
>> from sqlalchemy import *
>>
>> from sqlalchemy.ext.declarative import declarative_base
>> from sqlalchemy.orm import *
>>
>> Base = declarative_base()
>> metadata = Base.metadata
>> engine = create_engine('sqlite://', echo=True)
>>
>> from sqlalchemy import types
>>
>> class DenormalizedText(types.TypeDecorator):
>> """
>> Stores denormalized primary keys that can be
>> accessed as a set.
>>
>> :param coerce: coercion function that ensures correct
>> type is returned
>>
>> :param separator: separator character
>> """
>>
>> impl = types.Text
>>
>> def __init__(self, coerce=int, separator=" ", **kwargs):
>>
>> self.coerce = coerce
>> self.separator = separator
>>
>> super(DenormalizedText, self).__init__(**kwargs)
>>
>> def bind_processor(self, dialect):
>>
>> def process(value):
>> if value is not None:
>> items = [str(item).strip() for item in value]
>> value = self.separator.join(item for item in items if item)
>> return value
>> return process
>>
>> def result_processor(self, dialect, coltype):
>> def process(value):
>> if not value:
>> return set()
>> return set(self.coerce(item) \
>> for item in value.split(self.separator))
>> return process
>>
>> def copy_value(self, value):
>> return set(value)
>>
>> def is_mutable(self):
>>
>> return True
>>
>> class Post(Base):
>> __tablename__ = "posts"
>> id = Column(Integer, primary_key=True)
>> votes = Column(DenormalizedText)
>>
>> def __init__(self, *args, **kwargs):
>> super(Post, self).__init__(*args, **kwargs)
>> self.votes = self.votes or set()
>>
>> Base.metadata.create_all(engine)
>>
>> session = sessionmaker(engine)()
>>
>> post = Post()
>> post.votes.add(3)
>>
>> session.add(post)
>> session.commit()
>>
>> print "-----------------------"
>> post.votes.add(5)
>> session.commit()
>>
>>
>>
>>> --
>>> 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
>>> athttp://groups.google.com/group/sqlalchemy?hl=en.
>
> --
> 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.
>
--
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.