DataLoader

 view release on metacpan or  search on metacpan

lib/DataLoader.pm  view on Meta::CPAN

        croak "cache_hashref must be a HASH ref (tied or plain)";
    }
    if (defined $max_batch_size) {
        $max_batch_size =~ /^\d+$/ or croak "max_batch_size must be a positive integer";
        $max_batch_size > 0 or croak "max_batch_size cannot be zero";
    }

    return bless {
        batch_load_func => $batch_load_func,
        do_batch => $do_batch,
        max_batch_size => $max_batch_size,
        do_cache => $do_cache,
        cache_key_func => $cache_key_func,
        promise_cache => $cache_map,
        queue => [],
    }, $class;
}

=item load ( key )

Loads a key, returning a L<Mojo::Promise> for the value represented by that key.

=cut

# False-positive on Perl::Critic < 1.119 due to @_ size tests
## no critic (RequireArgUnpacking)
sub load {
    my ($self, $key) = @_;

    @_ >= 2 or croak "load: key is required";
    defined $key or croak "load: key must be defined";
    @_ == 2 or croak "load: too many arguments, expected 1";

    my $cache_key = $self->_cache_key($key);

    # If caching and there is a cache-hit, return cached promise
    if ($self->{do_cache} && (my $promise = $self->{promise_cache}{$cache_key})) {
        return $promise;
    }

    # Otherwise, produce a new Promise for this value
    my $promise = Mojo::Promise->new;

    # JS code calls new Promise((resolve, reject) => ...) with the below code
    # but this should be equivalent.
    push @{$self->{queue}}, [$key, $promise];

    # Determine if a dispatch of this queue should be scheduled.
    # A single dispatch should be scheduled per queue at the time when the queue
    # changes from 'empty' to 'full'
    if (@{$self->{queue}} == 1) {
        if ($self->{do_batch}) {
            # Schedule next tick, to allow all batch calls this frame to be batched
            # together.

            # We prefer an idle watcher as it will execute after all Promises are
            # resolved (batching as much as possible). But Mojo::IOLoop's API does
            # not provide this. And we cannot assume AnyEvent can be used.
            # The best we can do is detect the EV backend and use EV::idle.
            if (Mojo::IOLoop->singleton->reactor->isa('Mojo::Reactor::EV')) {
                # Capture the lexical inside the coderef to keep it alive until
                # the callback is finished.
                my $w; $w = EV::idle(sub {
                    $self->_dispatch_queue;
                    undef $w;
                });
            }
            else {
                # We fall back to next_tick, which is less efficient.
                Mojo::IOLoop->next_tick(sub { $self->_dispatch_queue });
            }
        }
        else {
            # Dispatch immediately
            $self->_dispatch_queue;
        }
    }

    # If caching, cache this cv
    if ($self->{do_cache}) {
        $self->{promise_cache}{$cache_key} = $promise;
    }

    return $promise;
}

=item load_many ( @keys )

Loads multiple keys, returning a Promise that resolves a list of values.

Equivalent to C<< DataLoader->all(map { $loader->load($_) } @keys) >>.

=cut

sub load_many {
    my ($self, @keys) = @_;

    return $self->all(map { $self->load($_) } @keys);
}

=item clear ( key )

Clear the value at C<key> from the cache, if it exists. Returns itself for method
chaining.

=cut

sub clear {
    my ($self, $key) = @_;

    my $cache_key = $self->_cache_key($key);
    delete $self->{promise_cache}{$cache_key};

    return $self;
}

=item clear_all ()

Clears the entire cache. To be used when some event results in unknown invalidations
across this particular L<DataLoader>. Returns itself for method chaining.



( run in 1.213 second using v1.01-cache-2.11-cpan-39bf76dae61 )