LittleJack has asked for the wisdom of the Perl Monks concerning the following question:

I don't know if I'm misunderstanding something fundamental here, but here's the situation:

I have a module: package Model::DB::Result::Thing; and it looks basically like this:

package Model::DB::Result::Thing; use warnings; use base 'DBIx::Class::Core'; __PACKAGE__->table("table_in_postgres"); __PACKAGE__->add_columns( "id", { data_type => "integer", is_auto_increment => 1, is_nullable => 0, sequence => "things_id_seq", }, "some_thing", { data_type => "text", is_nullable => 0, }, );
and Model::DB is just
package Model::DB; use strict; use warnings; use base 'DBIx::Class::Schema'; __PACKAGE__->load_namespaces; 1;

All the other parts of my codebase (a legacy Catalyst App) seem happy with it, and I can do some things with it which show that it's connecting to the DB correctly, see below.

What I can't do it seems is get a simple set of results back with all() or search()

What I'm expecting, as per this page https://metacpan.org/release/RIBASUSHI/DBIx-Class-0.082841/view/lib/DBIx/Class/ResultSet.pm is that I do my $thing_rs = $c->model('DB::Thing')->all(); but when I do that and use Data::Dumper I get an integer, the number of rows: $VAR1 = 123;

So I try calling in list context: my @thing_rs = $c->model('DB::Thing')->all(); and I get $VAR1 as the whole MyApp::Model::DB::Thing object, followed by 123 blessed objects like this:

$VAR2 = bless( { '_result_source' => $VAR1->{'_result_source'}, '_in_storage' => 1, '_column_data' => { 'some_thing' => 'foo', 'id' => 99, } }, 'MyApp::Model::DB::Thing' );

What I'm expecting is an array of hashes containing what I see there in the blessed objects, i.e.

[ { 'some_thing' => 'foo', 'id' => 99, }, { 'some_thing' => 'bar', 'id' => 100, }, # etc ]

So I'm kind of stumped. Is something different because it's PostGres? Is my version of DBIxC (0.082840) weird? TIA Monks!

Replies are listed 'Best First'.
Re: Issues with DBIx::Class
by Your Mother (Archbishop) on Mar 23, 2022 at 04:40 UTC

    DBIC defaults to always using objects, whether that’s an iterator, a table, a row, a resultset. You have to do things like $rec->columns otherwise.

    What you probably want is DBIx::Class::ResultSet::HashRef. You include it in your ResultSet class’s hierarchy, not the Result class, and it gives you options to return pure data structures. Docs should get you going.

Re: Issues with DBIx::Class
by 1nickt (Canon) on Mar 23, 2022 at 17:56 UTC

    Besides the module Your Mother suggested, you can use an idiom like:

    for my $result_as_href ( map { $_->get_columns } $rs->all ) { # do something with the hash ref }
    I use this in debugging all the time.

    Hope this helps!

    ,bR>
    The way forward always starts with a minimal test.
      map syntax is wrong, it should be map +{ $_->get_columns }, $rs->all

      Thanks for your help. I'm doing exactly what you said and not getting individual hashrefs in Data::Dumper output.

      Instead I get each column by itself, one line per loop:

      $VAR1 = 'id'; $VAR1 = 99; $VAR1 = 'some_thing'; $VAR1 = 'bar';

      Is there some missing step in your method, or am I missing something again?

        Sorry, I missed a curly brace pair.

        for my $result_as_href ( map { { $_->get_columns } } $rs->all ) { # do something with the hash ref }

        The way forward always starts with a minimal test.
Re: Issues with DBIx::Class
by NERDVANA (Priest) on Mar 24, 2022 at 02:38 UTC
    DBIx::Class has a mis-feature where the ->search method is context-aware. In list context, it runs the query and you get back the rows. In scalar context it returns a resultset which you can continue chaining methods on and decide to run the query later. One workaround is the ->search_rs method which always returns a resultset.

    The ->all method always returns a list (not arrayref) of rows. You got "123" because you tried assigning a list to a scalar, which gives you the size of the list.

    The rows are objects by default. If you want hashrefs, use DBIx::Class::ResultClass::HashRefInflator. You can also use $row->get_columns to dump the key/value pairs from a row object but if you don't want the object in the first place, just use HashRefInflator and get better performance.

    If you are doing a lot of work with DBIx::Class, consider using DBIx::Class::Helper::ResultSet which smooths over some of the rough edges of the DBIx::Class API. With this module installed, you can write:

    for my $hashref ($c->model('DB::Thing')->hri->all) { ... }