NAME
LINQ::Util - useful utilities to make working with LINQ collections easier
SYNOPSIS
use feature qw( say );
use LINQ qw( LINQ )';
use LINQ::Util qw( fields );
my $collection = LINQ( [
{ name => 'Alice', age => 30, dept => 'IT' },
{ name => 'Bob' , age => 29, dept => 'IT' },
{ name => 'Carol', age => 32, dept => 'Marketing' },
{ name => 'Dave', age => 33, dept => 'Accounts' },
] );
my $name_and_dept = $collection->select( fields( 'name', 'dept' ) );
for ( $name_and_dept->to_list ) {
printf( "Hi, I'm %s from %s\n", $_->name, $_->dept );
}
DESCRIPTION
LINQ::Util provides a collection of auxiliary functions to make working with LINQ collections a little more intuitive and perhaps avoid passing a bunch of sub { ... }
arguments to select
and where
.
FUNCTIONS
fields( SPEC )
-
Creates a coderef (actually a blessed object overloading
&{}
) which takes a hashref or object as input, selects just the fields/keys given in the SPEC, and returns an object with those fields.A simple example would be:
my $selector = fields( 'name' ); my $object = $selector->( { name => 'Bob', age => 29 } );
In this example,
$object
would be a blessed object with aname
method which returns "Bob".Fields can be renamed:
my $selector = fields( 'name', -as => 'moniker' ); my $object = $selector->( { name => 'Bob', age => 29 } ); say $object->moniker; # ==> "Bob"
A coderef can be used as a field:
my $selector = fields( sub { uc( $_->{'name'} ) }, -as => 'moniker', ); my $object = $selector->( { name => 'Bob', age => 29 } ); say $object->moniker; # ==> "BOB"
An asterisk field selects all the input fields:
my $selector = fields( sub { uc( $_->{'name'} ) }, -as => 'moniker', '*', ); my $object = $selector->( { name => 'Bob', age => 29 } ); say $object->moniker; # ==> "BOB" say $object->name; # ==> "Bob" say $object->age; # ==> 29
The aim of the
fields
function is to allow the LINQselect
method to function more like an SQL SELECT, where you give a list of fields you wish to select. field( NAME )
-
Conceptually similar to
fields()
but for a single field. Returns the field value instead of a hashref of field values.my $field = field('name'); say $field->( $_ ) for ( { name => 'Alice' }, { name => 'Bob' }, );
If called in list context with extra arguments after the field name, a list will be returned, including the extra arguments unchanged.
my $people = LINQ( [ { name => 'Alice', age => 30, dept => 3 }, { name => 'Bob' , age => 29, dept => 3 }, { name => 'Carol', age => 32, dept => 4 }, { name => 'Dave', age => 33, dept => 1 }, ] ); my $depts = LINQ( [ { id => 3, name => 'IT' }, { id => 4, name => 'Marketing' }, { id => 1, name => 'Accounts' }, ] ); my $joiner = sub { my ( $person, $dept ) = @_; return { person_name => $person->{name}, person_age => $person->{age}, dept_name => $dept->{name}, }; }; my $joined = $people->join( $depts, field 'dept', field 'id', $joiner ); print Dumper( $joined->to_array );
check_fields( SPEC )
-
If
fields()
can be compared to SQL SELECT, thencheck_fields()
can be compared to SQL WHERE. Likefields()
it assumes your data is hashrefs or blessed objects with attributes.# Select people called Bob. $people ->where( check_fields( 'name', -is => 'Bob' ) ) ->select( fields( 'name', 'age', 'dept' ) );
Different operators can be used. Whether performing string or numeric comparison, ">", "<", ">=", "<=", "==", and "!=" are used. (And the
-is
parameter is used to provide the right hand side of the comparison, even for comparisons like "!=".)$people ->where( check_fields( 'name', -cmp => '>', -is => 'Bob' ) );
check_fields()
will probably guess correctly whether you want numeric or string comparison, but if you need to specify, you can:$people ->where( check_fields( 'phone', -is => '012345679', -string ); $people ->where( check_fields( 'age', -is => '33', -numeric );
String comparisons can be made case-insensitive:
$people ->where( check_fields( 'name', -is => 'Bob', -nocase ) );
You can use
-in
to find a value in an arrayref. These comparisons are always stringy and case-sensitive.$people ->where( check_fields( 'name', -in => ['Alice', 'Bob'] ) );
You can invert any comparison using
-nix
.$people ->where( check_fields( 'name', -nix, -in => ['Alice', 'Bob'] ) );
You can perform more complex matches using match::simple:
$people ->where( check_fields( 'name', -match => qr/^[RB]ob(ert)?$/i ) );
SQL LIKE is also supported:
$people ->where( check_fields( 'name', -like => 'Bob%', -nocase ) );
You can check multiple fields at once. There's an implied "AND" between the conditions.
$people ->where( check_fields( 'name', -is => 'Bob', 'age', -nix, -is => 33, ) );
You can compare one field to another field using
-to
:# Says all the values which are between the min and max. LINQ( { min => 10, max => 100, value => 50 }, { min => 10, max => 100, value => 5 }, { min => 10, max => 20, value => 50 }, )->where( check_fields( 'value', -cmp => '>=', -to => 'min', -numeric, 'value', -cmp => '<=', -to => 'max', -numeric, ) )->foreach( sub { say $_->value; } );
You can invert a whole
check_fields()
using thenot
method:my $where_not_bob = check_fields( 'name', -is => 'Bob' )->not; $people->where( $where_not_bob );
Generally, you can use
not
,and
, andor
methods to compose more complex conditions. The~
,&
, and|
bitwise operators are also overloaded to compose conditions.my $where_alice = check_fields( 'name', -is => 'Alice' ); my $where_bob = check_fields( 'name', -is => 'Bob' ); my $where_alice_or_bob = $where_alice->or( $where_bob ); # Or... my $where_alice_or_bob = $where_alice | $where_bob; # Or... my $where_alice_or_bob = check_fields( 'name', -is => 'Alice' ) ->or( 'name', -is => 'Bob' );
Like with
fields()
, fields can be a coderef.my $where_bob = check_fields( sub { $_->get_name("givenName") }, -is => 'Bob' );
BUGS
Please report any bugs to http://rt.cpan.org/Dist/Display.html?Queue=LINQ.
SEE ALSO
https://en.wikipedia.org/wiki/Language_Integrated_Query
AUTHOR
Toby Inkster <tobyink@cpan.org>.
COPYRIGHT AND LICENCE
This software is copyright (c) 2021 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
DISCLAIMER OF WARRANTIES
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.