File Coverage

blib/lib/AnyEvent/KVStore/Hash.pm
Criterion Covered Total %
statement 44 52 84.6
branch 7 12 58.3
condition 3 8 37.5
subroutine 11 11 100.0
pod 5 5 100.0
total 70 88 79.5


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             AnyEvent::KVStore::Hash -- A simple, hash-based Key/value store
4              
5             =cut
6              
7             package AnyEvent::KVStore::Hash;
8 3     3   190801 use 5.010;
  3         24  
9 3     3   21 use strict;
  3         6  
  3         123  
10 3     3   20 use warnings;
  3         5  
  3         185  
11 3     3   1861 no autovivification;
  3         4103  
  3         17  
12 3     3   900 use Moo;
  3         10712  
  3         23  
13 3     3   3637 use Types::Standard qw(HashRef);
  3         188919  
  3         51  
14             with 'AnyEvent::KVStore::Driver';
15              
16             =head1 VERSION
17              
18             0.1.2
19              
20             =cut
21              
22             our $VERSION = '0.1.2';
23              
24             =head1 SYNOPSIS
25              
26             use AnyEvent::KVStore;
27             my $store = AnyEvent::KVStore->new(module => 'hash', config => {});
28             $store->write('foo', 'bar');
29             $store->watch('f', sub { my ($k, $v) = @_; warn "Setting $k to $v"; });
30             $store->write('far', 'over there');
31              
32             =head2 DESCRIPTION
33              
34             L ships with a very simple, non-blocking key-value store for
35             testing, proofs of concepts, and other purposes. This has all the advantages
36             and disadvantages of just storing the data in a hash table, but comes with
37             callback features on write. You can use this as a glorified enriched hashtable
38             or you can use other modules in this framework to connect to shared key/value
39             stores.
40              
41             Each kvstore here has its own keyspace and watch list.
42              
43             =head2 Watch Behavior
44              
45             C allows for unlimited watches to be set up, and
46             because this key/value store is private, the callbacks are handled synchronous
47             to the writes. If you want asynchronous callbacks, you can use the
48             C function from L.
49              
50             Watches are currently indexed by the first letter of the prefix, or if no
51             prefix is given, an empty string. Watches are then checked (and executed)
52             in order of:
53              
54             =over
55              
56             =item First empty prefix watches
57              
58             These are run (there is no checking) in order of creation
59              
60             =item Then the first letter of the key is used to match prefixes.
61              
62             The prefixes are checked and run un order of creation here too. This may, in
63             the future, change to be more alphabetically ordered.
64              
65             =back
66              
67             This behavior is subect to change.
68              
69             =cut
70              
71             has _store => (is => 'ro', isa => HashRef, default => sub { {} });
72              
73             has _watches => (is => 'ro', isa => HashRef, default => sub { {} });
74              
75             =head1 METHODS
76              
77             Unless otherwise noted, these do exactly what the documentation in
78             C and C suggest.
79              
80             =head2 read
81              
82             =head2 exists
83              
84             =head2 list
85              
86             =head2 write
87              
88             =head2 watch
89              
90             In this module, watches are run synchronously, not via AnyEvent's event loop.
91              
92             If you wish to use AnyEvent's event loop, use condition variables with
93             callbacks set and C them.
94              
95             =cut
96              
97             sub read($$) {
98 6     6 1 124 my ($self, $key) = @_;
99 6         47 return $self->_store->{$key};
100             }
101              
102             sub exists($$) {
103 4     4 1 129 my ($self, $key) = @_;
104 4         15 my $href = $self->_store;
105 4         29 return exists $href->{$key};
106             }
107              
108             sub list($$) {
109 2     2 1 44 my ($self, $prefix) = @_;
110 2 50 33     20 return grep { $_ =~ /^$prefix/ } keys %{$self->_store}
  0         0  
  0         0  
111             if defined $prefix and $prefix ne '';
112 2         5 return keys %{$self->_store};
  2         25  
113             }
114              
115             sub write($$$) {
116 6     6 1 134 my ($self, $key, $value) = @_;
117             # check watches
118 6 50       43 if (exists $self->_watches->{''}){
119 0         0 for my $w (@{$self->_watches->{''}}){
  0         0  
120 0         0 $w->{cb}($key, $value);
121             }
122             }
123 6         17 my $first_letter = substr($key, 0, 1);
124 6 100       29 if (exists $self->_watches->{$first_letter}){
125 4         9 for my $w (@{$self->_watches->{$first_letter}}){
  4         16  
126 4 50       109 $w->{cb}($key, $value) if $key =~ /^$w->{pfx}/;
127             }
128             }
129 6 50       2058 if (not defined $value) {
130 0         0 delete $self->_store->{$key};
131 0         0 return 1;
132             }
133 6         33 $self->_store->{$key} = $value;
134 6         35 return 1;
135             }
136              
137             sub watch($$&) {
138 2     2 1 799 my ($self, $pfx, $cb) = @_;
139 2         5 my $first;
140 2 50 33     20 if ($pfx eq '' or not defined $pfx){
141 0         0 $first = '';
142             } else {
143 2         7 $first = substr($pfx, 0, 1);
144             }
145 2   50     28 $self->_watches->{$first} //= [];
146 2         4 push @{$self->_watches->{$first}}, {pfx => $pfx, cb => $cb};
  2         22  
147 2         8 return 1;
148             }
149              
150             =head1 MORE INFORMATION
151              
152             For information on Copyright, Licensing, Contributing, Bug trackers, etc. see
153             the documentation of C, which this module is distributed as
154             a part of.
155              
156             =cut
157              
158             1;