Array-Join

 view release on metacpan or  search on metacpan

lib/Array/Join/OO.pm  view on Meta::CPAN

sub _cross_product {
    map { my $a = $_; map [ $a, $_ ], $_[1]->@* } $_[0]->@*
}

sub _merge {
    my ($item_a, $item_b, $opts) = @_;

    $item_a = Clone::clone($item_a);
    $item_b = Clone::clone($item_b);

    if (ref $opts->{merge} eq "CODE") {
	return $opts->{merge}->($item_a, $item_b, $opts);
    }
    elsif (ref $opts->{merge} eq "ARRAY") {
	my @names = $opts->{merge}->@*;
	$item_a->{CORE::join ".", $names[0], $_} = delete $item_a->{$_} for CORE::keys $item_a->%*;
	$item_b->{CORE::join ".", $names[1], $_} = delete $item_b->{$_} for CORE::keys $item_b->%*;
	return Hash::Merge::merge($item_a, $item_b);
    }
    elsif ($opts->{merge} && $opts->{merge} =~ /_PRECEDENT$/) {
	local $Hash::Merge::behavior = $opts->{merge};
	return Hash::Merge::merge($item_a, $item_b);	
    }
    elsif ($opts->{merge}) {
	return Hash::Merge::merge($item_a, $item_b);
    }
    else {
	return [ $item_a, $item_b ]
    }
}

1;

=head1 NAME

Array::Join::OO - SQL-like joins over two arrays of hashrefs

=head1 SYNOPSIS

    use Array::Join::OO;

    my $join = Array::Join::OO->new(
        \@left,
        \@right,
        {
            on   => [
                sub { $_[0]{id} },
                sub { $_[0]{id} },
            ],
            type  => 'inner',   # inner | left | right | outer
            merge => 'LEFT_PRECEDENT',
        }
    );

    my @rows = $join->join;

=head1 DESCRIPTION

C<Array::Join::OO> performs SQL-style joins over two Perl arrays.
Each array element is typically a hashref. Join keys are produced
by user-supplied callbacks.

The module supports C<inner>, C<left>, C<right>, and C<outer> joins
and multiple merge strategies for combining matching rows.

Multiple rows per key are supported; all matching combinations
are returned (Cartesian product).

=head1 CONSTRUCTOR

=head2 new( \@array_a, \@array_b, \%options )

Creates a join object.

Exactly two array references must be provided.

The options hash must contain an C<on> key with exactly two
code references, one per array.

=head3 Options

=over 4

=item * on => [ sub {...}, sub {...} ]

Required. Two callbacks that extract a join key from items in
the left and right arrays respectively.

=item * type => 'inner' | 'left' | 'right' | 'outer'

Join type. Defaults to C<inner>.

=item * merge => STR | ARRAY | CODE

Controls how matching rows are combined.

See L</MERGE STRATEGIES>.

=item * as => ...

Alias for C<merge>.

=back

=head1 METHODS

=head2 join

    my @rows = $join->join;

Executes the join and returns a list of merged rows.

For non-inner joins, missing rows are represented as empty hashrefs.

=head2 keys

    my $keys = $join->keys;

Returns a sorted arrayref of join keys used by the join.

=head2 lookups

    my $lookups = $join->lookups;

Returns a deep clone of the internal lookup tables.
This data is read-only.

=head1 MERGE STRATEGIES

The C<merge> option controls how matching rows are combined.

=head2 CODE reference

    merge => sub {
        my ($left, $right, $opts) = @_;
        ...
    }

Receives cloned copies of both rows and must return a single value.

=head2 ARRAY reference

    merge => [ 'left', 'right' ]

All keys in each hash are renamed with the given prefixes
(e.g. C<left.id>, C<right.id>) before merging.



( run in 1.727 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )