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 )