FAQ
Hello,

I am trying to make something work nice, but it doesn't want to =) Probably,
it's just by design, or I am missing something.

I have text column in DB used to store everything not fit into row
initially. To do this - I am storing serialized hash in JSON format.

In Result class I have something like this:

__PACKAGE__->table("users");
__PACKAGE__->add_columns(
[...]
"data",
{
data_type => "TEXT",
default_value => undef,
is_nullable => 1,
size => 65535,
},
);

use JSON::XS;
use Hash::AsObject;

__PACKAGE__->inflate_column(
'data',
{
inflate => sub {
Hash::AsObject->new(decode_json( shift() ))
},
deflate => sub {
encode_json shift
},
},
);


It works well for retrieving values from DB:
$test = $user->data->{test}; # return 1

But to save data in db I want to do following:
$user->data->{test} = 1;
$user->update();

This doesn't work. It successfully assign 1 to $user->data->{test}, but it
never passes to deflator and never stores in the DB.

But in the same time this works without any problems:
$user->data({ 'test' => 1 });
$user->update;


Question: is it possible to make it work with $user->data->{test} = 1;
notation? I.e. I do not want to create new methods in results class, not
want to extract hash from field first and then save it?

Regards,
Pavel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20100825/136e68bc/attachment.htm

Search Discussions

  • Mark Hedges at Aug 26, 2010 at 5:10 am

    On Wed, 25 Aug 2010, Pavel A. Karoukin wrote:

    use JSON::XS;
    use Hash::AsObject;

    __PACKAGE__->inflate_column(
        'data',
        {
          inflate => sub {
            Hash::AsObject->new(decode_json( shift() ))
          },
          deflate => sub {
            encode_json shift
          },
        },
    );


    It works well for retrieving values from DB:
    $test = $user->data->{test}; # return 1

    But to save data in db I want to do following:
    $user->data->{test} = 1;
    $user->update();

    This doesn't work. It successfully assign 1 to $user->data->{test}, but it never passes to
    deflator and never stores in the DB.
    $user->test(1);
    $user->update();
    # ???

    Mark
  • Peter Rabbitson at Aug 26, 2010 at 8:33 am

    Pavel A. Karoukin wrote:
    Hello,

    I am trying to make something work nice, but it doesn't want to =)
    Probably, it's just by design, or I am missing something.

    Question: is it possible to make it work with $user->data->{test} = 1;
    notation? I.e. I do not want to create new methods in results class, not
    want to extract hash from field first and then save it?
    Absolutely impossible, since the whole idea of InflateColumn is:
    *) A plain scalar value supplied to new/update is assumed to be an
    already-deflated value to be placed directly in the database
    *) Any type of reference (blessed or not) is a candidate for deflation
    and passed on to the deflator

    However you may find that FilterColumn does exactly what you want to
    do.

    Cheers
  • Pavel A. Karoukin at Aug 26, 2010 at 1:41 pm

    On Thu, Aug 26, 2010 at 3:33 AM, Peter Rabbitson <rabbit+dbic@rabbit.uswrote:

    Pavel A. Karoukin wrote:
    Hello,

    I am trying to make something work nice, but it doesn't want to =)
    Probably, it's just by design, or I am missing something.

    Question: is it possible to make it work with $user->data->{test} = 1;
    notation? I.e. I do not want to create new methods in results class, not
    want to extract hash from field first and then save it?
    Absolutely impossible, since the whole idea of InflateColumn is:
    *) A plain scalar value supplied to new/update is assumed to be an
    already-deflated value to be placed directly in the database
    *) Any type of reference (blessed or not) is a candidate for deflation
    and passed on to the deflator

    However you may find that FilterColumn does exactly what you want to
    do.
    Peter,

    Thank you for pointing to FilterColumn. I've tried it with almost same
    result tho.. Probably I am doing something wrong?

    I.e. I replaced __PACKAGE__inflate_column with:

    __PACKAGE__->filter_column(
    'data' => {
    filter_to_storage => '__data_to_storage',
    filter_from_storage => '__data_from_storage',
    },
    );


    sub __data_to_storage {
    my ($self, $data) = @_;
    return encode_json($data);
    }

    sub __data_from_storage {
    my ($self, $data) = @_;
    return decode_json($data);
    }


    And now in my controller code trying this:

    $c->user->data->{test}; # return "yes" as stored in DB in JSON format
    $c->user->data->{test} = "no"; # now this contain "no", but not stored in
    DB yet
    $c->user->update(); # I thought it should pass $c->user->date to
    __data_to_storage(), but it never do this. Why?

    So so far it behaive the same way as InflateColumn =(

    Regads,
    Pavel
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20100826/8e95541f/attachment.htm
  • Peter Rabbitson at Aug 26, 2010 at 2:11 pm

    Pavel A. Karoukin wrote:
    On Thu, Aug 26, 2010 at 3:33 AM, Peter Rabbitson wrote:

    Pavel A. Karoukin wrote:
    Hello,

    I am trying to make something work nice, but it doesn't want to =)
    Probably, it's just by design, or I am missing something.

    Question: is it possible to make it work with $user->data->{test} = 1;
    notation? I.e. I do not want to create new methods in results
    class, not
    want to extract hash from field first and then save it?
    Absolutely impossible, since the whole idea of InflateColumn is:
    *) A plain scalar value supplied to new/update is assumed to be an
    already-deflated value to be placed directly in the database
    *) Any type of reference (blessed or not) is a candidate for deflation
    and passed on to the deflator

    However you may find that FilterColumn does exactly what you want to
    do.


    Peter,

    Thank you for pointing to FilterColumn. I've tried it with almost same
    result tho.. Probably I am doing something wrong?

    And now in my controller code trying this:

    $c->user->data->{test}; # return "yes" as stored in DB in JSON format
    $c->user->data->{test} = "no"; # now this contain "no", but not stored
    in DB yet
    $c->user->update(); # I thought it should pass $c->user->date to
    __data_to_storage(), but it never do this. Why?
    I misunderstood your initial question, sorry. For what you are doing both
    IC and FC will work. However the data column stores a *reference* to a
    hash. By doing hash->{key} = val you are not changing the reference, so
    as far as DBIC is concerned the value of the column did not change.
    What you need to do is manually invoke[1] or replace the entire hashref
    with another hashref.

    [1] http://search.cpan.org/~frew/DBIx-Class-0.08123/lib/DBIx/Class/Row.pm#make_column_dirty

    Cheers
  • Pavel A. Karoukin at Aug 26, 2010 at 2:46 pm

    On Thu, Aug 26, 2010 at 9:11 AM, Peter Rabbitson <rabbit+dbic@rabbit.uswrote:

    Pavel A. Karoukin wrote:
    On Thu, Aug 26, 2010 at 3:33 AM, Peter Rabbitson <rabbit+dbic@rabbit.us<rabbit%2Bdbic@rabbit.us>
    <mailto:rabbit%2Bdbic@rabbit.us wrote:

    Pavel A. Karoukin wrote:
    Hello,

    I am trying to make something work nice, but it doesn't want to =)
    Probably, it's just by design, or I am missing something.

    Question: is it possible to make it work with $user->data->{test} =
    1;
    notation? I.e. I do not want to create new methods in results
    class, not
    want to extract hash from field first and then save it?
    Absolutely impossible, since the whole idea of InflateColumn is:
    *) A plain scalar value supplied to new/update is assumed to be an
    already-deflated value to be placed directly in the database
    *) Any type of reference (blessed or not) is a candidate for deflation
    and passed on to the deflator

    However you may find that FilterColumn does exactly what you want to
    do.


    Peter,

    Thank you for pointing to FilterColumn. I've tried it with almost same
    result tho.. Probably I am doing something wrong?

    And now in my controller code trying this:

    $c->user->data->{test}; # return "yes" as stored in DB in JSON format
    $c->user->data->{test} = "no"; # now this contain "no", but not stored
    in DB yet
    $c->user->update(); # I thought it should pass $c->user->date to
    __data_to_storage(), but it never do this. Why?
    I misunderstood your initial question, sorry. For what you are doing both
    IC and FC will work. However the data column stores a *reference* to a
    hash. By doing hash->{key} = val you are not changing the reference, so
    as far as DBIC is concerned the value of the column did not change.
    What you need to do is manually invoke[1] or replace the entire hashref
    with another hashref.

    [1]
    http://search.cpan.org/~frew/DBIx-Class-0.08123/lib/DBIx/Class/Row.pm#make_column_dirty
    Thank you Peter! That's something I had in mind but I didn't know about
    possibility column being dirty! I will try to rework it somehow to make call
    to make_column_dirty() automatically inside of "something" =)

    Regards,
    Pavel
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20100826/0b7fd186/attachment.htm

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupdbix-class @
categoriesperl, catalyst
postedAug 26, '10 at 3:25a
activeAug 26, '10 at 2:46p
posts6
users3
websitedbix-class.org
irc#dbix-class

People

Translate

site design / logo © 2021 Grokbase