Skip to content

More methods for DB Results like Mojo::Pg::Results and Mojo::mysql::Results

License

Notifications You must be signed in to change notification settings

srchulo/Mojo-DB-Results-Role-MoreMethods

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NAME

Mojo::DB::Results::Role::MoreMethods - More methods for DB Results, like Mojo::Pg::Results and Mojo::mysql::Results

STATUS

Coverage Status

SYNOPSIS

my $db = Mojo::Pg->new(...)

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123})->with_roles('+MoreMethods');
my $name    = $results->get;
my $name    = $results->get(0);
my $name    = $results->get(-3);
my ($name)  = $results->get;

my ($name, $age, $favorite_food)  = $results->get;
my ($name, $age, $favorite_food)  = $results->get(0..2);
my ($name, $favorite_food)        = $results->get(0, 2);
my ($name, $favorite_food)        = $results->get(-3, -1);

my $name   = $results->get_by_name('name');
my ($name) = $results->get_by_name('name');
my ($name, $favorite_food) = $results->get_by_name('name', 'favorite_food');

while (my ($name, $favorite_food) = $results->get('name', 'favorite_food')) {
    say qq{$name's favorite food is $favorite_food};
}

# get the next row as a Mojo::Collection
my $results   = $db->select(people => ['first_name', 'middle_name', 'last_name'])->with_roles('+MoreMethods');
my $full_name = $results->c->join(' ');

# or get collection values by name
my $first_and_last_name = $results->c_by_name('first_name', 'last_name')->join(' ');

# get all rows as collections in a Mojo::Collection
my $full_names = $results->collections->map(sub { $_->join(' ') });

# assert that exactly one row is returned where expected (not 0, not more than one)
my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123})->with_roles('+MoreMethods');
my $name    = $results->one;
my ($name, $age, $favorite_food) = $results->one;
my ($name, $favorite_food)       = $results->one_by_name('name', 'favorite_food');

# Flatten results into one Mojo::Collection with names of all people who like Pizza
my $results = $db->select(people => ['name'] => {favorite_food => 'Pizza'})->with_roles('+MoreMethods');
my $names   = $results->flatten;
say 'Pizza lovers:';
say for $names->each;

# access results by a key
my $results = $db->select(people => '*')->with_roles('+MoreMethods');
my $results_by_name = $results->hashify('name');

# $alice_row is a hash
my $alice_row = $results_by_name->{Alice};

# access results by multiple keys with a multilevel hash
my $results_by_full_name = $results->hashify(['first_name', 'last_name']);

# $alice_smith_row is a hash
my $alice_smith_row = $results_by_full_name->{Alice}{Smith};

# collect results by a key in a Mojo::Collection behind a hash
my $results = $db->select(people => '*')->with_roles('+MoreMethods');
my $collections_by_name = $results->hashify_collect('name');

# $alice_collection is a Mojo::Collection of all rows with the name 'Alice' as hashes
my $alice_collection = $collections_by_name->{Alice};

# collect results by multiple keys in a Mojo::Collection behind a multilevel hash
my $collections_by_full_name = $results->hashify_collect(['first_name', 'last_name']);

# $alice_smith_row is a hash
my $alice_smith_collection = $collections_by_full_name->{Alice}{Smith};

# create a Mojo::Collection of Mojo::Collection's, where all results that share the same key
# are grouped in the same inner Mojo::Collection
my $results = $db->select(people => '*')->with_roles('+MoreMethods');
my $name_collections = $results->collect_by('name');

for my $name_collection ($name_collections->each) {

  say 'Ages for ' . $name_collection->[0]{name};
  for my $row ($name_collection->each) {
    say "$row->{name} is $row->{age} years old";
  }
}

DESCRIPTION

Mojo::DB::Results::Role::MoreMethods is a role that that provides additional methods for results classes like Mojo::Pg::Results or Mojo::mysql::Results.

Mojo::DB::Results::Role::MoreMethods requires a results class that has at least these methods:

  • array
  • arrays
  • columns
  • hash
  • hashes

HOW TO APPLY ROLE

with_roles

# apply Mojo::Pg::Results::Role::MoreMethods
my $pg      = Mojo::Pg->new(...);
my $results = $pg->db->select(people => ['name'] => {id => 123})->with_roles('+MoreMethods');
my $name    = $results->get;

# apply Mojo::mysql::Results::Role::MoreMethods
my $mysql   = Mojo::mysql->new(...);
my $results = $mysql->db->select(people => ['name'] => {id => 123})->with_roles('+MoreMethods');
my $name    = $results->get;

# apply using any results class
my $pg      = Mojo::Pg->new(...);
my $results = $pg->db->select(people => ['name'] => {id => 123})->with_roles('Mojo::DB::Results::Role::MoreMethods');
my $name    = $results->get;

You may use "with_roles" in Mojo::Base to apply Mojo::DB::Results::Role::MoreMethods to your results classes.

These roles are also available to take advantage of with_role's shorthand + notation when using Mojo::Pg::Results or Mojo::mysql::Results:

These two roles are essentially just aliases for Mojo::DB::Results::Role::MoreMethods. They are just empty roles with only this line:

with 'Mojo::DB::Results::Role::MoreMethods';

Mojo::DB::Role::ResultsRoles

# example from Mojo::DB::Role::ResultsRoles

use Mojo::Pg;
my $pg = Mojo::Pg->new(...)->with_roles('Mojo::DB::Role::ResultsRoles');
push @{$pg->results_roles}, 'Mojo::DB::Results::Role::MoreMethods';
my $results = $pg->db->query(...);
# $results does Mojo::DB::Results::Role::MoreMethods

Mojo::DB::Role::ResultsRoles allows roles to be applied to the results objects returned by database APIs like Mojo::Pg or Mojo::mysql. See its documentation for more information.

You may take advantage of with_role's shorthand + notation when using Mojo::Pg or Mojo::mysql objects:

# short hand with_roles syntax supported for Mojo::Pg and Mojo::mysql objects
push @{$pg->results_roles}, '+MoreMethods';

METHODS

get

Be sure to call finish, such as "finish" in Mojo::Pg::Results or "finish" in Mojo::mysql::Results, if you are not fetching all of the possible rows.

"get" will fetch the next row from sth.

SCALAR CONTEXT

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# return the first column
my $name = $results->get;

# same as above but specifying index
my $name = $results->get(0);

# negative indexes may be used
my $name = $results->get(-3);

# any column may be gotten with an index
my $age = $results->get(1);

When "get" is called in scalar context with no index, it will fetch the next row from sth and return the first column requested in your query. If an index is specified, the value corresponding to the column at that index in the query will be used instead. A negative index may be used just like indexing into Perl arrays.

WHILE LOOPS

# THIS IS WRONG DO NOT DO THIS.
while (my $name = $results->get) {
  # broken loop...
}

Because "get" in scalar context may return undef, an empty string or a 0 as values for a column, it cannot be reliably used in while loops (unless used in "LIST CONTEXT"). If you expect one row to be returned, considering using "one" instead.

If you would like to use while loops with "get", consider using a while loop in "LIST CONTEXT":

while (my ($name) = $results->get) {
  say $name;
}

LIST CONTEXT

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# return the first column
my ($name) = $results->get;

# same as above but specifying index
my ($name) = $results->get(0);

# multiple indexes may be used
my ($name, $favorite_food) = $results->get(0, 2);

# negative indexes may be used
my ($name, $favorite_food) = $results->get(-3, -1);

# get all column values
my ($name, $age, $favorite_food) = $results->get;
my @person = $results->get;

# iterate
while (my ($name, $age, $favorite_food) = $results->get) {
  say qq{$name is $age years old and their favorite food is $favorite_food};
}

When "get" is called in list context with no index, it will fetch the next row from sth and return all values for the row as a list. Individual column values may be requested by providing indexes. Negative indexes may also be used just like indexing into Perl arrays.

OPTIONS

You may provide options to "get" by providing an options hashref as the first argument.

die

# dies if no next row exists
my $name = $results->get({die => 1});
my $name = $results->get({die => 1}, 0);

Dies unless there is a next row to be retrieved. See "get_or_die" for this same behavior without needing to provide the die option.

The "die" option does nothing if "one" is provided, as "one" is a superset of the functionality of "die".

one

# dies unless exactly one row was returned in the results
my $name = $results->get({one => 1});
my $name = $results->get({one => 1}, 0);

Dies unless exactly one row was returned in the results. See "one" for this same behavior without needing to provide the one option.

get_by_name

Be sure to call finish, such as "finish" in Mojo::Pg::Results or "finish" in Mojo::mysql::Results, if you are not fetching all of the possible rows.

"get_by_name" will fetch the next row from sth.

SCALAR CONTEXT

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# return the name column
my $name = $results->get_by_name('name');

"get_by_name" called in scalar context will fetch the next row from sth and returns the individual value for the column corresponding to the provided name.

WHILE LOOPS

# THIS IS WRONG DO NOT DO THIS.
while (my $name = $results->get_by_name('name')) {
  # broken loop...
}

Because "get_by_name" in scalar context may return undef, an empty string or a 0 as values for a column, it cannot be reliably used in while loops (unless used in "LIST CONTEXT"). If you expect one row to be returned, considering using "one_by_name" instead.

If you would like to use while loops with "get_by_name", consider using a while loop in "LIST CONTEXT":

while (my ($name) = $results->get_by_name('name')) {
  say $name;
}

LIST CONTEXT

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# return the name column
my ($name) = $results->get_by_name('name');

# multiple names may be used
my ($name, $favorite_food) = $results->get('name', 'favorite_food');

# get all column values
my ($name, $age, $favorite_food) = $results->get_by_name('name', 'age', 'favorite_food');

# iterate
while (my ($name, $age, $favorite_food) = $results->get_by_name('name', 'age', 'favorite_food')) {
  say qq{$name is $age years old and their favorite food is $favorite_food};
}

"get_by_name" fetches the next row from sth and returns the list of values corresponding to the list of column names provided.

OPTIONS

You may provide options to "get_by_name" by providing an options hashref as the first argument.

die

# dies if no next row exists
my $name = $results->get_by_name({die => 1});
my $name = $results->get_by_name({die => 1}, 0);

Dies unless there is a next row to be retrieved. See "get_by_name_or_die" for this same behavior without needing to provide the die option.

The "die" option does nothing if "one" is provided, as "one" is a superset of the functionality of "die".

one

# dies unless exactly one row was returned in the results
my $name = $results->get({one => 1});
my $name = $results->get({one => 1}, 0);

Dies unless exactly one row was returned in the results. See "one_by_name" for this same behavior without needing to provide the one option.

c

Be sure to call finish, such as "finish" in Mojo::Pg::Results or "finish" in Mojo::mysql::Results, if you are not fetching all of the possible rows.

"c" will fetch the next row from sth.

my $results   = $db->select(people => ['first_name', 'middle_name', 'last_name']);
my $full_name = $results->c->join(' ');

# iterate
while (my $c = $results->c) {
  my $full_name = $c->join(' ');
  say "Full name is $full_name";
}

"c" fetches the next row from sth and returns the row as a Mojo::Collection. If there is no next row available, undef is returned.

You may provide indexes to get just those values in the Mojo::Collection, just as you can do with "get":

my $results   = $db->select(people => ['first_name', 'middle_name', 'last_name']);
my $full_name = $results->c(0, 2)->join(' ');

# prints "$first_name $last_name"
say $full_name;

OPTIONS

You may provide options to "c" by providing an options hashref as the first argument.

die

# dies if no next row exists
my $person = $results->c({die => 1});
my $person = $results->c({die => 1}, 0, 2);

Dies unless there is a next row to be retrieved. See "c_or_die" for this same behavior without needing to provide the die option.

The "die" option does nothing if "one" is provided, as "one" is a superset of the functionality of "die".

one

# dies unless exactly one row was returned in the results
my $person = $results->c({one => 1});
my $person = $results->c({one => 1}, 0, 2);

Dies unless exactly one row was returned in the results. See "one_c" for this same behavior without needing to provide the one option.

c_by_name

Be sure to call finish, such as "finish" in Mojo::Pg::Results or "finish" in Mojo::mysql::Results, if you are not fetching all of the possible rows.

"c_by_name" will fetch the next row from sth.

my $results   = $db->select(people => ['first_name', 'middle_name', 'last_name']);
my $full_name = $results->c_by_name('first_name', 'middle_name', 'last_name')->join(' ');

# iterate
while (my $c = $results->c_by_name('first_name', 'middle_name', 'last_name')) {
  my $full_name = $c->join(' ');
  say "Full name is $full_name";
}

"c_by_name" fetches the next row from sth and returns the values corresponding to the provided columns for the next row as a Mojo::Collection. If there is no next row available, undef is returned.

OPTIONS

You may provide options to "c_by_name" by providing an options hashref as the first argument.

die

# dies if no next row exists
my $person = $results->c_by_name({die => 1}, 'first_name', 'middle_name', 'last_name');

Dies unless there is a next row to be retrieved. See "c_by_name_or_die" for this same behavior without needing to provide the die option.

The "die" option does nothing if "one" is provided, as "one" is a superset of the functionality of "die".

one

# dies unless exactly one row was returned in the results
my $person = $results->c({one => 1}, 'first_name', 'middle_name', 'last_name');

Dies unless exactly one row was returned in the results. See "one_c_by_name" for this same behavior without needing to provide the one option.

collections

my $results    = $db->select(people => ['first_name', 'middle_name', 'last_name']);
my $full_names = $results->collections->map(sub { $_->join(' ') });

"collections" returns a Mojo::Collection of Mojo::Collections. Each inner Mojo::Collection corresponds to one array returned by the results.

This is similar to "arrays" in Mojo::Pg::Results or "arrays" in Mojo::mysql::Results, but each arrayref is a Mojo::Collection instead.

flatten

# Mojo::Collection with names of all people who like Pizza
my $results = $db->select(people => ['name'] => {favorite_food => 'Pizza'});
my $names   = $results->flatten; # equivalent to $results->arrays->flatten

say 'Pizza lovers:';
say for $names->each;

"flatten" returns a Mojo::Collection with all result arrays flattened to return a Mojo::Collection with all elements. This is equivalent to calling "flatten" in Mojo::Collection on the arrays method.

struct

my $struct = $results->struct;

Fetch next row from the statement handle with the result object's array method, and return it as a struct.

This method is composed from Mojo::DB::Results::Role::Struct.

structs

my $collection = $results->structs;

Fetch all rows from the statement handle with the result object's arrays method, and return them as a Mojo::Collection object containing structs.

This method is composed from Mojo::DB::Results::Role::Struct.

TRANSFORM METHODS

"TRANSFORM METHODS" is a group of methods that build on top of Mojo::Collection::Role::Transform that allow you to transform your results in meaningful and convenient ways. These are:

hashify

# access results by a key
my $results         = $db->select(people => '*');
my $results_by_name = $results->hashify('name');

# $alice_row is a hash
my $alice_row = $results_by_name->{Alice};

# access by multiple keys with a multilevel hash
my $results_by_full_name = $results->hashify(['first_name', 'last_name']);

# $alice_smith_row is a hash
my $alice_smith_row = $results_by_full_name->{Alice}{Smith};

# store the value as a struct instead of a hash
my $results_by_name = $results->hashify({struct => 1}, 'name');
my $alice_struct = $results_by_name->{Alice};

say 'Alice is ' . $alice_struct->age . ' years old';

"hashify" transforms your results into a hash that stores single rows or values (usually a column value) behind a key or multiple keys (usually column values).

"hashify" builds on "hashify" in Mojo::Collection::Role::Transform and adds useful functionality specific to DB results.

OPTIONS

array

my $results         = $db->select(people => '*');
my $results_by_name = $results->hashify({array => 1}, 'name');

my $alice_array = $results_by_name->{Alice};

"array" allows you to store the value as an array instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be an array.

c

my $results         = $db->select(people => '*');
my $results_by_name = $results->hashify({c => 1}, 'name');

my $alice_collection = $results_by_name->{Alice};

"c" allows you to store the value as a Mojo::Collection instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a Mojo::Collection.

hash

my $results         = $db->select(people => '*');
my $results_by_name = $results->hashify({hash => 1}, 'name'); # default

my $alice_hash = $results_by_name->{Alice};

"hash" allows you to store the value as a hash. This is the default and is the same as providing no option hash:

my $results_by_name = $results->hashify('name');

This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a hash.

struct

my $results         = $db->select(people => '*');
my $results_by_name = $results->hashify({struct => 1}, 'name');

my $alice_struct = $results_by_name->{Alice};

"struct" allows you to store the value as a readonly struct provided by Mojo::DB::Results::Role::Struct instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a readonly struct.

KEY

SINGLE KEY

my $results_by_name = $results->hashify('name');
my $alice_row       = $results_by_name->{Alice};

A single key may be used to access values. This key should be the name of a returned column.

MULTIPLE KEYS

my $results_by_full_name = $results->hashify(['first_name', 'last_name']);
my $alice_smith_row      = $results_by_full_name->{Alice}{Smith};

Multiple keys may be used to access values. Multiple keys should be provided as an arrayref of names of returned columns.

SUB

# single key
my $results_by_name = $results->hashify(sub { $_->{name} });
my $alice_row       = $results_by_name->{Alice};

# multiple keys
my $results_by_full_name = $results->hashify(sub { @{ $_ }{qw(first_name last_name)} });
my $alice_smith_row      = $results_by_full_name->{Alice}{Smith};

Providing a subroutine for the key allows you to create the key (or keys) with the returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

If the subroutine returns one key, the hash will be a "SINGLE KEY" hash. If multiple keys are returned as a list, the hash with be a "MULTIPLE KEYS" hash.

VALUE

DEFAULT

# values are hashes
my $results_by_name = $results->hashify('name');
my $alice_hash      = $results_by_name->{Alice};

# values are still hashes
my $results_by_name = $results->hashify({hash => 1}, 'name');
my $alice_hash      = $results_by_name->{Alice};

# values are arrays
my $results_by_name = $results->hashify({array => 1}, 'name');
my $alice_array     = $results_by_name->{Alice};

# values are Mojo::Collection's
my $results_by_name  = $results->hashify({c => 1}, 'name');
my $alice_collection = $results_by_name->{Alice};

# values are readonly structs
my $results_by_name = $results->hashify({struct => 1}, 'name');
my $alice_struct    = $results_by_name->{Alice};

If no value argument is provided, the default is to use the row as the value according to the type specified in "OPTIONS" ("array", "c", "hash", "struct"). The default is "hash".

COLUMN

# value will be age
my $results_by_name = $results->hashify('name', 'age');
my $alice_age       = $results_by_name->{Alice};

The value can be provided as a column returned in the results and will be used as the final value in the hash.

SUB

# value will be the age squared
my $results_by_name   = $results->hashify('name', sub { $_->{age} * $_->{age} });
my $alice_age_squared = $results_by_name->{Alice};

Providing a subroutine for the value allows you to create the value with the returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

hashify_collect

# group results by a key in a hash
my $results             = $db->select(people => '*');
my $collections_by_name = $results->hashify_collect('name');

# $alice_collection is a Mojo::Collection with all rows with the name Alice as hashes
my $alice_collection = $collections_by_name->{Alice};

# group by multiple keys with a multilevel hash
my $collections_by_full_name = $results->hashify_collect(['first_name', 'last_name']);

# $alice_smith_collection is a Mojo::Collection with all rows with
# the first name Alice and last name Smith as hashes
my $alice_smith_collection = $collections_by_full_name->{Alice}{Smith};

# group the values as structs instead of hashes
my $structs_by_name = $results->hashify_collect({struct => 1}, 'name');
my $alice_structs   = $structs_by_name->{Alice};

$alice_structs->each(sub {
  say 'Alice is ' . $_->age . ' years old';
});

# collect a single column value
my $ages_by_name = $results->hashify_collect('name', 'age');

# contains all ages in one Mojo::Collection for all rows with the name Alice
my $alice_ages = $ages_by_name->{Alice};

# flatten grouped results
my $results               = $db->select(people => '*');
my $column_values_by_name = $results->hashify_collect({flatten => 1}, 'name');

# contains all column values in one Mojo::Collection for all rows with the name Alice
my $alice_all_column_values = $column_values_by_name->{Alice};

"hashify_collect" allows you to group rows behind a key or multiple keys in a hash.

"hashify_collect" builds on "hashify_collect" in Mojo::Collection::Role::Transform and adds useful functionality specific to DB results.

OPTIONS

array

my $results             = $db->select(people => '*');
my $collections_by_name = $results->hashify_collect({array => 1}, 'name');

my $alice_collection = $collections_by_name->{Alice};
my $alice_array      = $alice_collection->first;

"array" allows you to group rows as arrays instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be an array.

flatten

my $results = $db->select(people => ['name', 'age']);

# trivial example returning arrayref to demonstrate flatten
my $age_collections_by_name = $results->hashify_collect({flatten => 1}, 'name', sub { [$_->{age}] });

my $alice_ages_collection = $age_collections_by_name->{Alice};
my $age_sum               = $alice_ages_collection->reduce(sub { $a + $b }, 0);

say "Collective age of Alices is $age_sum years old";

"flatten" flattens all values for a key into the same Mojo::Collection.

"flatten" may be combined with the other type options to specify the type of the rows that will be passed to the "KEY" "SUB" or the "VALUE" "SUB".

If no "VALUE" is specified, all returned column values for a row will be returned in the order they were requested and flattened into the resulting Mojo::Collection. This works regardless of any type option that is specified:

my $results = $db->select(people => ['name', 'age']);

# both contain name and age flattened into the collections
my $collections_by_name = $results->hashify_collect({hash => 1, flatten => 1}, sub { $_->{name} });
my $collections_by_name = $results->hashify_collect({struct => 1, flatten => 1}, sub { $_->name });

Any value returned by a "VALUE" "SUB" should be an arrayref or list of values and all values will be added to the Mojo::Collection:

my $collections_by_name = $results->hashify_collect({flatten => 1}, 'name', sub { $_->{age} }); # flatten not needed in this specific case because it's a list of 1
my $collections_by_name = $results->hashify_collect({flatten => 1}, 'name', sub { [$_->{age}] });

c

my $results             = $db->select(people => '*');
my $collections_by_name = $results->hashify_collect({c => 1}, 'name');

my $alice_collections = $collections_by_name->{Alice};
$alice_collections->each(sub {
  say 'Random column value is ' . $_->shuffle->first;
});

"c" allows you to group rows as Mojo::Collections instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a Mojo::Collection.

hash

my $results             = $db->select(people => '*');
my $collections_by_name = $results->hashify_collect({hash => 1}, 'name'); # default

my $alice_collection = $collections_by_name->{Alice};

"hash" allows you to group the rows as hashes. This is the default and is the same as providing no option hash:

my $collections_by_name = $results->hashify_collect('name');

This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a hash.

struct

my $results             = $db->select(people => '*');
my $collections_by_name = $results->hashify_collect({struct => 1}, 'name');

my $alice_collection = $collections_by_name->{Alice};
say q{First Alice's age is } . $alice_collection->first->age;

"struct" allows you to group the rows as readonly structs provided by Mojo::DB::Results::Role::Struct instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a readonly struct.

KEY

SINGLE KEY

my $collections_by_name = $results->hashify_collect('name');
my $alice_collection    = $collections_by_name->{Alice};

A single key may be used to access collections. This key should be the name of a returned column.

MULTIPLE KEYS

my $collections_by_full_name = $results->hashify_collect(['first_name', 'last_name']);
my $alice_smith_collection   = $collections_by_full_name->{Alice}{Smith};

Multiple keys may be used to access collections. Multiple keys should be provided as an arrayref of names of returned columns.

SUB

# single key
my $collections_by_name = $results->hashify_collect(sub { $_->{name} });
my $alice_collection    = $collections_by_name->{Alice};

# multiple keys
my $collections_by_full_name = $results->hashify_collect(sub { @{ $_ }{qw(first_name last_name)} });
my $alice_smith_collection   = $collections_by_full_name->{Alice}{Smith};

Providing a subroutine for the key allows you to create the key (or keys) with the returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

If the subroutine returns one key, the hash will be a "SINGLE KEY" hash. If multiple keys are returned as a list, the hash with be a "MULTIPLE KEYS" hash.

VALUE

DEFAULT

# collections contain hashes
my $collections_by_name        = $results->hashify_collect('name');
my $alice_collection_of_hashes = $collections_by_name->{Alice};

# collections still contain hashes
my $collections_by_name        = $results->hashify_collect({hash => 1}, 'name');
my $alice_collection_of_hashes = $collections_by_name->{Alice};

# collections contain arrays
my $collections_by_name        = $results->hashify_collect({array => 1}, 'name');
my $alice_collection_of_arrays = $collections_by_name->{Alice};

# collections contain Mojo::Collection's
my $collections_by_name             = $results->hashify_collect({c => 1}, 'name');
my $alice_collection_of_collections = $collections_by_name->{Alice};

# collections contain readonly structs
my $collections_by_name         = $results->hashify_collect({struct => 1}, 'name');
my $alice_collection_of_structs = $collections_by_name->{Alice};

If no value argument is provided, the default is to collect the rows as the value according to the type specified in "OPTIONS" ("array", "c", "hash", "struct"). The default is "hash".

COLUMN

# age will be collected
my $collections_by_name      = $results->hashify_collect('name', 'age');
my $alice_collection_of_ages = $collections_by_name->{Alice};

The value can be provided as a column returned in the results, and this column value for each row will be collected into the corresponding Mojo::Collection based on the key(s).

SUB

# collected value will be the age squared
my $collections_by_name              = $results->hashify_collect('name', sub { $_->{age} * $_->{age} });
my $alice_collection_of_ages_squared = $collections_by_name->{Alice};

Providing a subroutine for the value allows you to create the collected values for each returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

You may return a single value, or a list of values to be collected:

my $collections_by_name = $results->hashify_collect('name', sub { $_->{age}, $_->{favorite_food} });

collect_by

# group results by a key in Mojo::Collection's inside of a Mojo::Collection
my $results             = $db->select(people => '*');
my $collections_by_name = $results->collect_by('name');
say 'First collection contains rows with name', $collections_by_name->first->first->{name};

# group results by multiple keys
my $collections_by_full_name = $results->collect_by(['first_name', 'last_name']);
my $first_collection = $collections_by_name->first;
say
  'First collection contains rows with first name',
  $first_collection->first->{first_name},
  ' and last name ',
  $first_collection->first->{last_name};

# group the values as structs instead of hashes
my $structs_by_name = $results->collect_by({struct => 1}, 'name');

$structs_by_name->first->each(sub {
  say $_->name, ' is ' . $_->age . ' years old';
});

# collect a single column value
my $ages_by_name = $results->collect_by('name', 'age');
say 'First collection contains ages for name', $ages_by_name->first->first->{name};

# flatten grouped results
my $results = $db->select(people => '*');
# each inner Mojo::Collection is flattened
my $column_values_by_name = $results->collect_by({flatten => 1}, 'name');

"collect_by" allows you to group rows/values that share the same key or multiple keys in Mojo::Collections inside of a Mojo::Collection.

"collect_by" builds on "collect_by" in Mojo::Collection::Role::Transform and adds useful functionality specific to DB results.

OPTIONS

array

my $results             = $db->select(people => '*');
my $collections_by_name = $results->collect_by({array => 1}, 'name');

"array" allows you to group rows as arrays instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be an array.

flatten

my $results = $db->select(people => ['name', 'age']);

# trivial example returning arrayref to demonstrate flatten
my $age_collections_by_name = $results->collect_by({flatten => 1}, 'name', sub { [$_->{age}] });

"flatten" flattens all values for each inner Mojo::Collection.

"flatten" may be combined with the other type options to specify the type of the rows that will be passed to the "KEY" "SUB" or the "VALUE" "SUB".

If no "VALUE" is specified, all returned column values for a row will be returned in the order they were requested and flattened into the resulting Mojo::Collection. This works regardless of any type option that is specified:

my $results = $db->select(people => ['name', 'age']);

# both contain name and age flattened into the inner collections
my $collections_by_name = $results->collect_by({hash => 1, flatten => 1}, sub { $_->{name} });
my $collections_by_name = $results->collect_by({struct => 1, flatten => 1}, sub { $_->name });

Any value returned by a "VALUE" "SUB" should be an arrayref or list of values and all values will be added to the inner Mojo::Collections:

my $collections_by_name = $results->collect_by({flatten => 1}, 'name', sub { $_->{age} }); # flatten not needed in this specific case because it's a list of 1
my $collections_by_name = $results->collect_by({flatten => 1}, 'name', sub { [$_->{age}] });

c

my $results             = $db->select(people => '*');
my $collections_by_name = $results->collect_by({c => 1}, 'name');

$collections_by_name->first->first->each(sub {
  say 'Random column value is ' . $_->shuffle->first;
});

"c" allows you to group rows as Mojo::Collections instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a Mojo::Collection.

hash

my $results             = $db->select(people => '*');
my $collections_by_name = $results->collect_by({hash => 1}, 'name'); # default

"hash" allows you to group the rows as hashes. This is the default and is the same as providing no option hash:

my $collections_by_name = $results->collect_by('name');

This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a hash.

struct

my $results             = $db->select(people => '*');
my $collections_by_name = $results->collect_by({struct => 1}, 'name');

my $first_collection = $collections_by_name->first;
say $first_collection->first->name, ' is ', $first_collection->first->age, ' years old';

"struct" allows you to group the rows as readonly structs provided by Mojo::DB::Results::Role::Struct instead of the default "hash". This also means the value provided to the "KEY" "SUB" or the "VALUE" "SUB", if used, will be a readonly struct.

KEY

SINGLE KEY

my $collections_by_name = $results->collect_by('name');

A single key may be used to group rows/values into inner Mojo::Collections. This key should be the name of a returned column.

MULTIPLE KEYS

my $collections_by_full_name = $results->collect_by(['first_name', 'last_name']);

Multiple keys may be used to group rows/values into inner Mojo::Collections. Multiple keys should be provided as an arrayref of names of returned columns.

SUB

# single key
my $collections_by_name = $results->collect_by(sub { $_->{name} });

# multiple keys
my $collections_by_full_name = $results->collect_by(sub { @{ $_ }{qw(first_name last_name)} });

Providing a subroutine for the key allows you to create the key (or keys) with the returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

If the subroutine returns one key, the hash will be a "SINGLE KEY" hash. If multiple keys are returned as a list, the hash with be a "MULTIPLE KEYS" hash.

VALUE

DEFAULT

# collections contain hashes
my $collections_by_name = $results->collect_by('name');

# collections still contain hashes
my $collections_by_name = $results->collect_by({hash => 1}, 'name');

# collections contain arrays
my $collections_by_name = $results->collect_by({array => 1}, 'name');

# collections contain Mojo::Collection's
my $collections_by_name = $results->collect_by({c => 1}, 'name');

# collections contain readonly structs
my $collections_by_name = $results->collect_by({struct => 1}, 'name');

If no value argument is provided, the default is to collect the rows as the value according to the type specified in "OPTIONS" ("array", "c", "hash", "struct"). The default is "hash".

COLUMN

# age will be collected
my $collections_by_name = $results->collect_by('name', 'age');

The value can be provided as a column returned in the results, and this column value for each row will be collected into the corresponding inner Mojo::Collection based on the key(s).

SUB

# collected value will be the age squared
my $collections_by_name = $results->collect_by('name', sub { $_->{age} * $_->{age} });

Providing a subroutine for the value allows you to create the collected values for each returned row. The row is available either as $_ or as the first argument to the subroutine. The type of the row ("array", "c", "hash", "struct") that is passed to the subroutine depends on any "OPTIONS" value that is passed (default is "hash").

You may return a single value, or a list of values to be collected:

my $collections_by_name = $results->collect_by('name', sub { $_->{age}, $_->{favorite_food} });

DIE METHODS

"DIE METHODS" are equivalent to the "get", "get_by_name", "c", and "c_by_name" methods above, however, the die option for these methods is passed as true for you and the method will die if there is no next row to be retrieved.

Additionally, "struct_or_die", "array_or_die", and "hash_or_die" are provided.

get_or_die

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# all of these die if there is no next row to be retrieved

# return the first column
my $name = $results->get_or_die;

# same as above but specifying index
my $name = $results->get_or_die(0);

# negative indexes may be used
my $name = $results->get_or_die(-3);

# any column may be gotten with an index
my $age = $results->get_or_die(1);

Same as "get", but dies if there is no next row to be retrieved.

get_by_name_or_die

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# dies if there is no next row to be retrieved
my $name = $results->get_by_name_or_die('name');

Same as "get_by_name", but dies if there is no next row to be retrieved.

c_or_die

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name']);

# dies if there is no next row to be retrieved
my $full_name = $results->c_or_die->join(' ');

Same as "c", but dies if there is no next row to be retrieved.

c_by_name_or_die

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name']);

# dies if there is no next row to be retrieved
my $full_name = $results->c_by_name_or_die('first_name', 'middle_name', 'last_name')->join(' ');

Same as "c_by_name", but dies if there is no next row to be retrieved.

struct_or_die

my $results = $db->select(people => '*' => {id => 123});

# dies if there is no next row to be retrieved
my $person_struct = $results->struct_or_die;

"struct_or_die" is the same as "struct", but dies if there is no next row to be retrieved.

array_or_die

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name'] => {id => 123});

# dies if there is no next row to be retrieved
my $full_name = join ' ', @{ $results->array_or_die };

"array_or_die" is similar to "array" in Mojo::Pg::Results or "array" in Mojo::mysql::Results, but dies if there is no next row to be retrieved.

hash_or_die

my $results = $db->select(people => '*' => {id => 123});

# dies if there is no next row to be retrieved
my $person = $results->hash_or_die;

"hash_or_die" is similar to "hash" in Mojo::Pg::Results or "hash" in Mojo::mysql::Results, but dies if there is no next row to be retrieved.

ONE METHODS

"ONE METHODS" are equivalent to the "get", "get_by_name", "c", "c_by_name", and "struct" methods above, however, the one option for these methods is passed as true for you and the method will die unless exactly one row was returned.

Additionally, "one_struct", "one_array" and "one_hash" are provided.

one

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# all of these die unless exactly one row was returned

# return the first column
my $name = $results->one;

# same as above but specifying index
my $name = $results->one(0);

# negative indexes may be used
my $name = $results->one(-3);

# any column may be gotten with an index
my $age = $results->one(1);

Same as "get", but dies unless exactly one row was returned.

one_by_name

my $results = $db->select(people => ['name', 'age', 'favorite_food'] => {id => 123});

# dies unless exactly one row was returned
my $name = $results->one_by_name('name');

Same as "get_by_name", but dies unless exactly one row was returned.

one_c

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name'] => {id => 123});

# dies unless exactly one row was returned
my $full_name = $results->one_c->join(' ');

Same as "c", but dies unless exactly one row was returned.

one_c_by_name

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name'] => {id => 123});

# dies unless exactly one row was returned
my $full_name = $results->one_c_by_name('first_name', 'middle_name', 'last_name')->join(' ');

Same as "c_by_name", but dies unless exactly one row was returned

one_struct

my $results = $db->select(people => '*' => {id => 123});

# dies unless exactly one row was returned
my $person_struct = $results->one_struct;

"one_struct" is the same as "struct", but dies unless exactly one row was returned.

one_array

my $results = $db->select(people => ['first_name', 'middle_name', 'last_name'] => {id => 123});

# dies unless exactly one row was returned
my $full_name = join ' ', @{ $results->one_array };

"one_array" is similar to "array" in Mojo::Pg::Results or "array" in Mojo::mysql::Results, but dies unless exactly one row was returned.

one_hash

my $results = $db->select(people => '*' => {id => 123});

# dies unless exactly one row was returned
my $person = $results->one_hash;

"one_hash" is similar to "hash" in Mojo::Pg::Results or "hash" in Mojo::mysql::Results, but dies unless exactly one row was returned.

AUTHOR

Adam Hopkins srchulo@cpan.org

COPYRIGHT

Copyright 2019- Adam Hopkins

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

About

More methods for DB Results like Mojo::Pg::Results and Mojo::mysql::Results

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages