1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
package Catmandu::Store::Hash;
use namespace::clean;
use Catmandu::Sane;
use Catmandu::Util qw(:is);
use Moo;
with 'Catmandu::Store';
has _hashes => (is => 'ro' , lazy => 1, init_arg => undef, default => sub { +{} });
has init_data => (is => 'ro');
sub BUILD {
my $self = $_[0];
if (defined $self->init_data && is_array_ref($self->init_data) ) {
for (@{$self->init_data}) {
$self->bag->add($_);
}
}
}
package Catmandu::Store::Hash::Bag;
use namespace::clean;
use Catmandu::Sane;
use Catmandu::Hits;
use Moo;
use Clone qw(clone);
with 'Catmandu::Bag';
has _hash => (is => 'rw', lazy => 1 , init_arg => undef, builder => '_build_hash');
has _head => (is => 'rw', init_arg => undef, clearer => '_clear_head');
has _tail => (is => 'rw', init_arg => undef, clearer => '_clear_tail');
sub _build_hash {
my $self = $_[0];
$self->store->_hashes->{$self->name} ||= {};
}
sub generator {
my $self = $_[0];
sub {
state $node = $self->_head;
state $data;
$node || return;
$data = $node->[1];
$node = $node->[2];
$data;
};
}
sub get {
my ($self, $id) = @_;
my $node = $self->_hash->{$id} || return;
clone($node->[1]);
}
sub add {
my ($self, $data) = @_;
my $id = $data->{_id};
my $node = $self->_hash->{$id};
if ($node) {
$node->[1] = clone($data);
} elsif (my $tail = $self->_tail) {
$tail->[2] = $node = [$tail, clone($data), undef];
$self->_hash->{$id} = $node;
$self->_tail($node);
} else {
$node = [undef, clone($data), undef];
$self->_hash->{$id} = $node;
$self->_head($node);
$self->_tail($node);
}
$data;
}
sub delete {
my ($self, $id) = @_;
my $node = $self->_hash->{$id} || return;
if ($node->[0]) {
$node->[0][2] = $node->[2];
} else {
$self->_head($node->[2]);
}
if ($node->[2]) {
$node->[2][0] = $node->[0];
} else {
$self->_tail($node->[0]);
}
delete $self->_hash->{$id};
}
sub delete_all {
my $self = $_[0];
$self->_clear_head;
$self->_clear_tail;
$self->_hash($self->store->_hashes->{$self->name} = {});
}
1;
=head1 NAME
Catmandu::Store::Hash - An in-memory Catmandu::Store
=head1 SYNOPSIS
use Catmandu::Store::Hash;
my $store = Catmandu::Store::Hash->new();
my $obj1 = $store->bag->add({ name => 'Patrick' });
printf "obj1 stored as %s\n" , $obj1->{_id};
# Force an id in the store
my $obj2 = $store->bag->add({ _id => 'test123' , name => 'Nicolas' });
my $obj3 = $store->bag->get('test123');
$store->bag->delete('test123');
$store->bag->delete_all;
# All bags are iterators
$store->bag->each(sub { ... });
$store->bag->take(10)->each(sub { ... });
=head1 DESCRIPTION
A Catmandu::Store::Hash is an in-memory L<Catmandu::Store> backed by a hash
for fast retrieval combined with a doubly linked list for fast traversal.
=head1 METHODS
=head2 new()
Create a new Catmandu::Store::Hash
=head2 bag($name)
Create or retieve a bag with name $name. Returns a Catmandu::Bag.
=head1 SEE ALSO
L<Catmandu::Bag>, L<Catmandu::Searchable>
=cut
|