Search code examples
perlpostgresqldbix-class

JSON data and DBIx::Class - how can I store data directly?


I have a Postgres database with a JSON column, for which I'd like to do something like this:

use lib './lib';
use Digest::MD5 qw(md5 md5_hex);
use Data::Dump qw/dump/;

use Foo; # isa 'DBIx::Class::Schema';

$f = Foo->connect('dbi:Pg:database=mydb');

my $i = $f->resultset('People')->create({ id => md5_hex(rand() . 'some string') });
$i->insert;
$i->data({ name => 'john', surname => 'doe', birthday => '04/07/1976'});

#--------------------------------
# this is the important bit
# assigning to the HoH directly
#--------------------------------
$i->data->{books} = ['1984', 'Wuthering heights'];
$i->update;

Foo::People looks like this:

__PACKAGE__->add_columns(
  "id",
  { data_type => "varchar", is_nullable => 0, size => 32 },
  "data",
  { data_type => "json", is_nullable => 1, accessor  => '_data', },
);

__PACKAGE__->set_primary_key(qw/id/);

use JSON::XS;
use Data::Dump qw/dump/;

sub data {
    my ($self, $value) = @_;
    if(@_ > 1) {
        my $value = encode_json($value);
        $self->_data($value);
    }
    $value = decode_json($self->_data());
    return $value;
}

However this does not work - the only thing that does is store the hash in a temporary value, change it, and then store it again, like this:

my $v = $i->data;
$v->{books} = ['1984', 'Wuthering heights'];
$i->data($v)    
$i->update;

Is there a more concise way to do this?


Solution

  • What you're looking for is an InflateColumn like https://metacpan.org/pod/DBIx::Class::InflateColumn::Serializer::JSYNC.

    You can also easily write one yourself.

    Don't forget that DBIC just generates column accessors for you when you call add_column and their names are configurable so can rename them an call them from your own aceessor method.

    Or you use Moo(se) method modifiers.