File Coverage

lib/Redis/SQLite.pm
Criterion Covered Total %
statement 219 286 76.5
branch 48 70 68.5
condition 24 32 75.0
subroutine 31 42 73.8
pod 36 38 94.7
total 358 468 76.5


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Redis::SQLite - Redis-Compatible module which writes to SQLite.
5              
6             =cut
7              
8             =head1 SYNOPSIS
9              
10             =for example begin
11              
12             #!/usr/bin/perl -w
13              
14             use Redis::SQLite;
15             use strict;
16              
17             my $db = Redis::SQLite->new();
18              
19             $db->set( "foo", "bar" );
20              
21             print $db->get( "foo" ) . "\n";
22              
23             =for example end
24              
25              
26             =head1 DESCRIPTION
27              
28             This package is an implementation of the L Perl-client API, which
29             stores all data in an SQLite database rather than in RAM.
30              
31             It is B a drop-in replacement, because it doesn't implement all the
32             features you'd expect from the real Redis module. Just enough to be useful.
33              
34             =cut
35              
36             =head1 COMPATIBILITY
37              
38             This module is designed to be source compatible with the L module,
39             providing you're only operating upon either sets or simple strings.
40              
41             Specifically we do not support:
42              
43             =over 8
44              
45             =item HASH
46              
47             For example C, C, C, etc.
48              
49             =item Lists
50              
51             For example C, C, etc.
52              
53             =item Scripting
54              
55             Perl is itself a wonderful scripting language, so we've no need for Lua support.
56              
57             =item ZSET
58              
59             For example C, C, C, etc.
60              
61             =back
62              
63             All of the set-related primitives are supported, with the exception of C,
64             and the basic commands for working with string-based keys are also present, such
65             as:
66              
67             =over 8
68              
69             =item append
70              
71             =item del
72              
73             =item exists
74              
75             =item get
76              
77             =item set
78              
79             =item etc..
80              
81             =back
82              
83             =cut
84              
85             =head1 METHODS
86              
87             =cut
88              
89              
90             package Redis::SQLite;
91              
92              
93              
94 14     14   411725 use strict;
  14         17  
  14         339  
95 14     14   43 use warnings;
  14         14  
  14         291  
96 14     14   18421 use DBI;
  14         162656  
  14         31716  
97              
98              
99             our $VERSION = '0.2';
100              
101              
102             =head2 new
103              
104             Constructor. The only (optional) argument is C which will
105             change the default SQLite database-file location, if unspecified
106             C<~/.predis.db> will be used.
107              
108             =cut
109              
110             sub new
111             {
112 13     13 1 13744 my ( $proto, %supplied ) = (@_);
113 13   33     81 my $class = ref($proto) || $proto;
114              
115 13         24 my $self = {};
116 13         25 bless( $self, $class );
117              
118             # Get the user's home-directory
119             my $home =
120 13   0     50 $ENV{ 'HOME' } || $ENV{ 'USERPROFILE' } || ( getpwuid($<) )[7] || "C:/";
121              
122             # Create ~/.predis.db unless an alternative path was specified.
123 13   33     61 my $file = $supplied{ 'path' } || "$home/.predis.db";
124              
125 13         18 my $create = 1;
126 13 50       197 $create = 0 if ( -e $file );
127              
128 13         128 $self->{ 'db' } =
129             DBI->connect( "dbi:SQLite:dbname=$file", "", "", { AutoCommit => 1 } );
130              
131             #
132             # Populate the database tables, if it was missing.
133             #
134 13 50       113538 if ($create)
135             {
136 13         75 $self->{ 'db' }->do(
137             "CREATE TABLE string (id INTEGER PRIMARY KEY, key UNIQUE, val );");
138 13         4133880 $self->{ 'db' }
139             ->do("CREATE TABLE sets (id INTEGER PRIMARY KEY, key, val );");
140             }
141              
142             #
143             # This is potentially risky, but improves the throughput by several
144             # orders of magnitude.
145             #
146 13 50       312786 if ( !$ENV{ 'SAFE' } )
147             {
148 13         140 $self->{ 'db' }->do("PRAGMA synchronous = OFF");
149 13         753 $self->{ 'db' }->do("PRAGMA journal_mode = MEMORY");
150             }
151              
152 13         365 return $self;
153             }
154              
155              
156             =head2 append
157              
158             Append the given string to the contents of the existing key, creating it
159             if didn't previously exist.
160              
161             =cut
162              
163             sub append
164             {
165 2     2 1 8 my ( $self, $key, $data ) = (@_);
166              
167 2         7 my $r = $self->get($key);
168 2         6 $r .= $data;
169 2         7 $self->set( $key, $r );
170             }
171              
172              
173             =head2 exists
174              
175             Does the given key exist?
176              
177             =cut
178              
179             sub exists
180             {
181 21     21 1 1891 my ( $self, $key ) = (@_);
182              
183 21         94 my $sql = $self->{ 'db' }->prepare("SELECT key FROM string WHERE key=?");
184 21         1757 $sql->execute($key);
185 21   100     191 my $x = $sql->fetchrow_array() || undef;
186 21         42 $sql->finish();
187              
188 21 100       34 if ($x)
189             {
190 12         143 return 1;
191             }
192              
193 9         36 $sql = $self->{ 'db' }->prepare("SELECT key FROM sets WHERE key=?");
194 9         741 $sql->execute($key);
195 9   100     57 $x = $sql->fetchrow_array() || undef;
196 9         16 $sql->finish();
197              
198 9 100       16 if ($x)
199             {
200 1         11 return 1;
201             }
202              
203 8         73 return 0;
204             }
205              
206              
207             =head2 get
208              
209             Get the value of a string-key. Returns C if the key didn't exist,
210             or contain data.
211              
212             =cut
213              
214             sub get
215             {
216 50     50 1 428 my ( $self, $key ) = (@_);
217              
218 50 100       127 if ( !$self->{ 'get' } )
219             {
220             $self->{ 'get' } =
221 6         39 $self->{ 'db' }->prepare("SELECT val FROM string WHERE key=?");
222             }
223 50         4886 $self->{ 'get' }->execute($key);
224 50         2928 my $x = $self->{ 'get' }->fetchrow_array();
225 50         134 $self->{ 'get' }->finish();
226 50         186 return ($x);
227             }
228              
229              
230              
231             =head2 getset
232              
233             Update the value of a key, and return the previous value if any.
234              
235             =cut
236              
237             sub getset
238             {
239 1     1 1 2 my ( $self, $key, $val ) = (@_);
240              
241 1         3 my $old = $self->get($key);
242 1         3 $self->set( $key, $val );
243              
244 1         4 return ($old);
245             }
246              
247              
248             =head2 getrange
249              
250             Return the chunk of the key's value between the given offsets.
251              
252             =cut
253              
254             sub getrange
255             {
256 0     0 1 0 my ( $self, $key, $start, $end ) = (@_);
257              
258 0         0 my $val = $self->get($key);
259 0         0 my $s = $start;
260 0         0 my $e = $end;
261              
262 0 0       0 if ( $s < 0 )
263             {
264 0         0 $s = length($val) + $s;
265             }
266 0 0       0 if ( $e < 0 )
267             {
268 0         0 $e = length($val) + $e;
269             }
270              
271 0         0 return ( substr( $val, $s, ( $e - $s + 1 ) ) );
272             }
273              
274              
275              
276             =head2 strlen
277              
278             Return the length of the given value of the given key.
279              
280             =cut
281              
282             sub strlen
283             {
284 4     4 1 5 my ( $self, $key ) = (@_);
285              
286 4         14 my $data = $self->get($key);
287 4 50       12 if ( defined($data) )
288             {
289 4         15 return ( length($data) );
290             }
291 0         0 return 0;
292             }
293              
294              
295             =head2 rename
296              
297             Rename a string key. Deleting the target if it exists.
298              
299             =cut
300              
301             sub rename
302             {
303 0     0 1 0 my ( $self, $key, $new_name ) = (@_);
304              
305 0         0 $self->del($new_name);
306              
307 0         0 my $val = $self->get($key);
308 0         0 $self->set( $new_name, $val );
309              
310 0         0 $self->del($key);
311             }
312              
313              
314             =head2 renamenx
315              
316             Attempt to rename the given key, if the destination exists then
317             nothing happens.
318              
319             =cut
320              
321             sub renamenx
322             {
323 0     0 1 0 my ( $self, $key, $new_name ) = (@_);
324              
325 0 0       0 return 0 if ( $self->exists($new_name) );
326              
327             # Get the value and save it.
328 0         0 my $val = $self->get($key);
329 0         0 $self->set( $new_name, $val );
330              
331             # Remove the original
332 0         0 $self->del($key);
333              
334 0         0 return "OK";
335             }
336              
337              
338             =head2 set
339              
340             Set the value of a string-key.
341              
342             =cut
343              
344             sub set
345             {
346 54     54 1 5712 my ( $self, $key, $val ) = (@_);
347              
348 54 100       115 if ( !$self->{ 'ins' } )
349             {
350             $self->{ 'ins' } =
351 7         46 $self->{ 'db' }
352             ->prepare("INSERT OR REPLACE INTO string (key,val) VALUES( ?,? )");
353             }
354 54         19059 $self->{ 'ins' }->execute( $key, $val );
355 54         345 $self->{ 'ins' }->finish();
356              
357             }
358              
359              
360             =head2 setnx
361              
362             Store the given value in the named key, unless that key exists.
363              
364             =cut
365              
366             sub setnx
367             {
368 1     1 1 3 my ( $self, $key, $val ) = (@_);
369              
370 1 50       5 return 0 if ( $self->exists($key) );
371              
372 0         0 $self->set( $key, $val );
373 0         0 return 1;
374             }
375              
376              
377             =head2 setrange
378              
379             Insert some new data at the given offset of the specific key's value.
380              
381             If the current length of the key's value is too short it is NULL-padded
382             first.
383              
384             =cut
385              
386             sub setrange
387             {
388 0     0 1 0 my ( $self, $key, $offset, $data ) = (@_);
389              
390 0         0 my $val = $self->get($key);
391              
392 0 0       0 while ( ( $val ? length($val) : 0 ) < $offset )
393             {
394 0         0 $val .= chr(0x00);
395             }
396              
397              
398 0         0 substr( $val, $offset, length($data), $data );
399 0         0 $self->set( $key, $val );
400 0         0 return ( length($val) );
401             }
402              
403              
404             =head2 type
405              
406             Return the type of the named key.
407              
408             =cut
409              
410             sub type
411             {
412 5     5 1 11 my ( $self, $key ) = (@_);
413              
414              
415 5         32 my $sql = $self->{ 'db' }->prepare("SELECT key FROM string WHERE key=?");
416 5         560 $sql->execute($key);
417 5   100     114 my $x = $sql->fetchrow_array() || undef;
418 5         24 $sql->finish();
419              
420 5 100       46 return 'string' if ($x);
421              
422 3         24 $sql = $self->{ 'db' }->prepare("SELECT key FROM sets WHERE key=?");
423 3         343 $sql->execute($key);
424 3   100     28 $x = $sql->fetchrow_array() || undef;
425 3         13 $sql->finish();
426              
427 3 100       20 return 'set' if ($x);
428              
429 2         27 return undef;
430             }
431              
432              
433             =head2 incr
434              
435             Increment and return the value of an (integer) string-key.
436              
437             =cut
438              
439             sub incr
440             {
441 9     9 1 19 my ( $self, $key ) = (@_);
442              
443 9         17 return ( $self->incrby( $key, 1 ) );
444             }
445              
446              
447              
448             =head2 incrby
449              
450             Increment and return the value of an (integer) string-key.
451              
452             =cut
453              
454             sub incrby
455             {
456 12     12 1 734 my ( $self, $key, $amt ) = (@_);
457              
458 12 50       24 $amt = 1 if ( !defined($amt) );
459              
460 12   100     21 my $cur = $self->get($key) || 0;
461 12         20 $cur += $amt;
462 12         19 $self->set( $key, $cur );
463              
464 12         40 return ($cur);
465             }
466              
467              
468             =head2 decr
469              
470             Decrement and return the value of an (integer) string-key.
471              
472             =cut
473              
474             sub decr
475             {
476 4     4 1 6 my ( $self, $key ) = (@_);
477              
478 4         9 return ( $self->decrby( $key, 1 ) );
479             }
480              
481              
482              
483             =head2 decrby
484              
485             Decrement and return the value of an (integer) string-key.
486              
487             =cut
488              
489             sub decrby
490             {
491 12     12 1 27 my ( $self, $key, $amt ) = (@_);
492              
493 12 50       21 $amt = 1 if ( !defined($amt) );
494              
495 12   100     27 my $cur = $self->get($key) || 0;
496 12         22 $cur -= $amt;
497 12         19 $self->set( $key, $cur );
498              
499 12         54 return ($cur);
500             }
501              
502              
503             =head2 del
504              
505             Delete a given key, regardless of whether it holds a string or a set.
506              
507             =cut
508              
509             sub del
510             {
511 7     7 1 1853 my ( $self, $key ) = (@_);
512              
513             # strings
514 7         43 my $str = $self->{ 'db' }->prepare("DELETE FROM string WHERE key=?");
515 7         754 $str->execute($key);
516 7         25 $str->finish();
517              
518             # Deleted a string-keyu
519 7 100       60 return 1 if ( $str->rows > 0 );
520              
521             # sets
522 5         22 my $set = $self->{ 'db' }->prepare("DELETE FROM sets WHERE key=?");
523 5         431 $set->execute($key);
524 5         16 $set->finish();
525              
526             # Deleted a set-key.
527 5 100       35 return 1 if ( $set->rows > 0 );
528              
529             # Deleted nothing.
530 4         57 return 0;
531             }
532              
533              
534             =head2 keys
535              
536             Return the names of each known key.
537              
538             These can be optionally filtered by a (perl) regular expression, for example:
539              
540             =for example begin
541              
542             $redis->set( "foo", 1 );
543             $redis->set( "moo", 1 );
544              
545             $redis->keys( "^f" ); # -> [ "foo" ]
546             $redis->keys( "oo\$" ); # -> [ "foo", "moo" ]
547              
548             =for example end
549              
550             =cut
551              
552             sub keys
553             {
554 33     33 1 9780 my ( $self, $pattern ) = (@_);
555              
556             # Get all keys into this hash
557 33         43 my %known;
558              
559             # We run the same query against two tables.
560 33         67 foreach my $table (qw! string sets !)
561             {
562             # Get the names of the key.
563 66         398 my $str = $self->{ 'db' }->prepare("SELECT key FROM $table");
564 66         6035 $str->execute();
565 66         525 while ( my ($name) = $str->fetchrow_array )
566             {
567 117         417 $known{ $name } += 1;
568             }
569 66         713 $str->finish();
570             }
571              
572             # The keys we've found
573 33         111 my @keys = keys %known;
574              
575 33 100       97 if ($pattern)
576             {
577 4         5 my @ret;
578 4         6 foreach my $ent (@keys)
579             {
580 30 100       99 push( @ret, $ent ) if ( $ent =~ /$pattern/ );
581             }
582 4         29 return (@ret);
583             }
584             else
585             {
586 29         180 return (@keys);
587             }
588             }
589              
590              
591             =head2 randomkey
592              
593             Return the name of a random key.
594              
595             =cut
596              
597             sub randomkey
598             {
599 1     1 1 3 my ($self) = (@_);
600              
601             # Get all keys into this hash
602 1         1 my %known;
603              
604             # We run the same query against two tables.
605 1         2 foreach my $table (qw! string sets !)
606             {
607             # Get the names of the key.
608 2         12 my $str = $self->{ 'db' }->prepare("SELECT key FROM $table");
609 2         145 $str->execute();
610 2         15 while ( my ($name) = $str->fetchrow_array )
611             {
612 9         31 $known{ $name } += 1;
613             }
614 2         19 $str->finish();
615             }
616              
617             # The keys we've found
618 1         6 my @keys = CORE::keys %known;
619              
620 1         8 return ( $keys[rand @keys] );
621             }
622              
623              
624             =head2 smembers
625              
626             Return the members of the given set.
627              
628             =cut
629              
630             sub smembers
631             {
632 13     13 1 19 my ( $self, $key ) = (@_);
633              
634 13 100       28 if ( !$self->{ 'smembers' } )
635             {
636             $self->{ 'smembers' } =
637 3         17 $self->{ 'db' }->prepare("SELECT val FROM sets WHERE key=?");
638             }
639 13         549 $self->{ 'smembers' }->execute($key);
640              
641 13         16 my @vals;
642 13         78 while ( my ($name) = $self->{ 'smembers' }->fetchrow_array )
643             {
644 42         204 push( @vals, $name );
645             }
646 13         22 $self->{ 'smembers' }->finish();
647              
648 13         44 return (@vals);
649             }
650              
651              
652             =head2 smove
653              
654             Move a member from a given set to a new one.
655              
656             =cut
657              
658             sub smove
659             {
660 2     2 1 4 my ( $self, $src, $dst, $ent ) = (@_);
661              
662             # Get the value from the original set
663 2         11 my $sql = $self->{ 'db' }
664             ->prepare("UPDATE sets SET key=? WHERE ( key=? AND val=?)");
665              
666 2         213 $sql->execute( $dst, $src, $ent );
667 2         7 $sql->finish();
668              
669 2 100       8 if ( $sql->rows > 0 )
670             {
671 1         11 return 1;
672             }
673 1         10 return 0;
674              
675             }
676              
677              
678             =head2 sismember
679              
680             Is the given item a member of the set?
681              
682             =cut
683              
684             sub sismember
685             {
686 22     22 1 5282 my ( $self, $set, $key ) = (@_);
687              
688             my $sql =
689 22         104 $self->{ 'db' }->prepare("SELECT val FROM sets WHERE key=? AND val=?");
690 22         1983 $sql->execute( $set, $key );
691              
692 22   100     197 my $x = $sql->fetchrow_array() || undef;
693 22         44 $sql->finish();
694              
695 22 100 66     72 if ( defined($x) && ( $x eq $key ) )
696             {
697 11         142 return 1;
698             }
699 11         133 return 0;
700             }
701              
702              
703             =head2 sadd
704              
705             Add a member to a set.
706              
707             =cut
708              
709             sub sadd
710             {
711 65     65 1 872 my ( $self, $key, $val ) = (@_);
712              
713 65 100       128 if ( !$self->{ 'sadd' } )
714             {
715             $self->{ 'sadd' } =
716 7         41 $self->{ 'db' }->prepare(
717             "INSERT INTO sets (key,val) SELECT ?,? WHERE NOT EXISTS( SELECT key, val FROM sets WHERE key=? AND val=? );"
718             );
719              
720             }
721 65         7552 $self->{ 'sadd' }->execute( $key, $val, $key, $val );
722 65         223 $self->{ 'sadd' }->finish();
723              
724 65 50       217 if ( $self->{ 'sadd' }->rows > 0 )
725             {
726 65         148 return 1;
727             }
728 0         0 return 0;
729              
730             }
731              
732              
733             =head2 srem
734              
735             Remove a member from a set.
736              
737             =cut
738              
739             sub srem
740             {
741 9     9 1 373 my ( $self, $key, $val ) = (@_);
742              
743 9 100       20 if ( !$self->{ 'srem' } )
744             {
745             $self->{ 'srem' } =
746 3         15 $self->{ 'db' }->prepare("DELETE FROM sets WHERE (key=? AND val=?)");
747             }
748 9         647 $self->{ 'srem' }->execute( $key, $val );
749 9         29 $self->{ 'srem' }->finish();
750              
751 9 50       37 if ( $self->{ 'srem' }->rows > 0 )
752             {
753 9         16 return 1;
754             }
755 0         0 return 0;
756             }
757              
758              
759             =head2 spop
760              
761             Remove a given number of elements from the named set, and return them.
762              
763             =cut
764              
765             sub spop
766             {
767 4     4 1 10 my ( $self, $key, $count ) = (@_);
768              
769 4 100       12 $count = 1 if ( !defined($count) );
770              
771 4         4 my @res;
772              
773 4   100     16 while ( ( $count > 0 ) && ( $count <= $self->scard($key) ) )
774             {
775 5         10 my $rand = $self->srandmember($key);
776 5         8 push( @res, $rand );
777 5         9 $self->srem( $key, $rand );
778              
779 5         14 $count -= 1;
780             }
781              
782 4         8 return (@res);
783             }
784              
785              
786              
787             =head2 srandmember
788              
789             Fetch the value of a random member from a set.
790              
791             =cut
792              
793             sub srandmember
794             {
795 6     6 1 1377 my ( $self, $key ) = (@_);
796              
797 6 100       12 if ( !$self->{ 'srandommember' } )
798             {
799             $self->{ 'srandommember' } =
800 2 50       11 $self->{ 'db' }->prepare(
801             "SELECT val FROM sets where key=? ORDER BY RANDOM() LIMIT 1") or
802             die "Failed to prepare";
803             }
804 6         693 $self->{ 'srandommember' }->execute($key);
805 6   50     94 my $x = $self->{ 'srandommember' }->fetchrow_array() || "";
806 6         20 $self->{ 'srandommember' }->finish();
807              
808 6         16 return ($x);
809             }
810              
811              
812             =head2 sunion
813              
814             Return the values which are present in each of the sets named, duplicates
815             will only be returned one time.
816              
817             For example:
818              
819             =for example begin
820              
821             $redis->sadd( "one", 1 );
822             $redis->sadd( "one", 2 );
823             $redis->sadd( "one", 3 );
824              
825             $redis->sadd( "two", 2 );
826             $redis->sadd( "two", 3 );
827             $redis->sadd( "two", 4 );
828              
829             $redis->sunion( "one", "two" ); # -> [ 1,2,3,4 ]
830              
831             =for example end
832              
833             =cut
834              
835             sub sunion
836             {
837 2     2 1 4 my ( $self, @keys ) = (@_);
838              
839              
840 2         2 my %result;
841              
842 2         4 foreach my $key (@keys)
843             {
844 4         7 my @vals = $self->smembers($key);
845 4         7 foreach my $val (@vals)
846             {
847 12         20 $result{ $val } += 1;
848             }
849             }
850              
851 2         10 return ( CORE::keys(%result) );
852             }
853              
854              
855             =head2 sunionstore
856              
857             Store the values which are present in each of the named sets in a new set.
858              
859             =cut
860              
861             sub sunionstore
862             {
863 1     1 1 3 my ( $self, $dest, @keys ) = (@_);
864              
865             # Get the union
866 1         3 my @union = $self->sunion(@keys);
867              
868             # Delete the current contents of the destination.
869 1         5 $self->del($dest);
870              
871             # Now store the members
872 1         2 foreach my $ent (@union)
873             {
874 6         8 $self->sadd( $dest, $ent );
875             }
876              
877             # Return the number of entries added
878 1         4 return ( scalar @union );
879             }
880              
881              
882             =head2 sinter
883              
884             Return only those members who exist in each of the named sets.
885              
886             =for example begin
887              
888             $redis->sadd( "one", 1 );
889             $redis->sadd( "one", 2 );
890             $redis->sadd( "one", 3 );
891              
892             $redis->sadd( "two", 2 );
893             $redis->sadd( "two", 3 );
894             $redis->sadd( "two", 4 );
895              
896             $redis->sinter( "one", "two" ); # -> [ 2,3 ]
897              
898             =for example end
899              
900             =cut
901              
902             sub sinter
903             {
904 3     3 1 7 my ( $self, @names ) = (@_);
905              
906 3         3 my %seen;
907              
908 3         5 foreach my $key (@names)
909             {
910 6         11 my @vals = $self->smembers($key);
911 6         8 foreach my $val (@vals)
912             {
913 20         30 $seen{ $val } += 1;
914             }
915             }
916              
917 3         3 my @result;
918              
919 3         8 foreach my $key ( CORE::keys(%seen) )
920             {
921 15 100       24 if ( $seen{ $key } == scalar @names )
922             {
923 5         8 push( @result, $key );
924             }
925             }
926 3         14 return (@result);
927             }
928              
929              
930              
931             =head2 sinterstore
932              
933             Store those members who exist in all the named sets in a new set.
934              
935             =cut
936              
937             sub sinterstore
938             {
939 1     1 1 4 my ( $self, $dest, @names ) = (@_);
940              
941             # Get the values that intersect
942 1         3 my @update = $self->sinter(@names);
943              
944             # Delete the current contents of the destination.
945 1         5 $self->del($dest);
946              
947             # Now store the members
948 1         2 foreach my $ent (@update)
949             {
950 2         5 $self->sadd( $dest, $ent );
951             }
952              
953             # Return the number of entries added
954 1         4 return ( scalar @update );
955             }
956              
957              
958             =head2 scard
959              
960             Count the number of entries in the given set.
961              
962             =cut
963              
964             sub scard
965             {
966 26     26 1 310 my ( $self, $key ) = (@_);
967              
968 26 100       58 if ( !$self->{ 'scard' } )
969             {
970             $self->{ 'scard' } =
971 6         35 $self->{ 'db' }->prepare("SELECT COUNT(id) FROM sets where key=?");
972             }
973 26         1244 $self->{ 'scard' }->execute($key);
974 26   100     292 my $count = $self->{ 'scard' }->fetchrow_array() || 0;
975 26         69 $self->{ 'scard' }->finish();
976              
977 26         132 return ($count);
978             }
979              
980              
981              
982             =head2 bitcount
983              
984             Count the number of set bits in the content of the given key.
985              
986             =cut
987              
988             sub bitcount
989             {
990 0     0 1   my ( $self, $key ) = (@_);
991              
992 0           my $val = $self->get($key);
993              
994             # Use a lookup-table for each byte.
995 0           my @bitcounts = ( 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2,
996             2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3,
997             2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4,
998             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4,
999             2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,
1000             4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,
1001             4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
1002             6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1003             2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,
1004             3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,
1005             4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4,
1006             4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,
1007             4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,
1008             5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7,
1009             6, 7, 7, 8
1010             );
1011              
1012 0           my $sum = 0;
1013              
1014 0           foreach my $char ( split( //, $val ) )
1015             {
1016 0           $sum += $bitcounts[ord($char)];
1017             }
1018              
1019 0           return ($sum);
1020             }
1021              
1022              
1023             =head2 ping
1024              
1025             This would usually check if the Redis connection was alive, and the
1026             server was present, in this implementation we always return true.
1027              
1028             =cut
1029              
1030             sub ping
1031             {
1032 0     0 1   return 1;
1033             }
1034              
1035              
1036             =head2 echo
1037              
1038             Return the parameters given.
1039              
1040             =cut
1041              
1042             sub echo
1043             {
1044 0     0 1   my ( $self, $arg ) = (@_);
1045              
1046 0           return ($arg);
1047             }
1048              
1049             our $AUTOLOAD;
1050              
1051             sub AUTOLOAD
1052             {
1053 0     0     my $command = $AUTOLOAD;
1054 0           $command =~ s/.*://;
1055 0           warn "NOT IMPLEMENTED:$command";
1056              
1057 0           return 1;
1058             }
1059              
1060              
1061             =head2 mget
1062              
1063             Return the values of multiple-keys. If a given key doesn't exist
1064             then C will be returned for that entry.
1065              
1066             =cut
1067              
1068             sub mget
1069             {
1070 0     0 1   my ( $self, @keys ) = (@_);
1071              
1072 0           my @ret;
1073              
1074 0           foreach my $key (@keys)
1075             {
1076 0 0         if ( $self->exists($key) )
1077             {
1078 0           push( @ret, $self->get($key) );
1079             }
1080             else
1081             {
1082 0           push( @ret, undef );
1083             }
1084             }
1085              
1086 0           return (@ret);
1087             }
1088              
1089              
1090             =head2 mget
1091              
1092             Update the values of multiple-keys.
1093              
1094             =cut
1095              
1096             sub mset
1097             {
1098 0     0 0   my ( $self, @keys ) = (@_);
1099              
1100 0           while ( scalar @keys )
1101             {
1102 0           my ( $key, $val ) = splice( @keys, 0, 2 );
1103              
1104 0           $self->set( $key, $val );
1105             }
1106             }
1107              
1108              
1109              
1110             =head2 mgetnx
1111              
1112             Update the values of multiple-keys, only if all the keys don't already exist.
1113              
1114             =cut
1115              
1116             sub msetnx
1117             {
1118 0     0 0   my ( $self, @keys ) = (@_);
1119              
1120 0           my %hash;
1121              
1122             # Update so we can test the keys.
1123 0           while ( scalar @keys )
1124             {
1125 0           my ( $key, $val ) = splice( @keys, 0, 2 );
1126 0           $hash{ $key } = $val;
1127             }
1128              
1129             # Does any key already exist? If so we should do nothing.
1130 0           foreach my $key ( CORE::keys %hash )
1131             {
1132 0 0         return 0 if ( $self->exists($key) );
1133             }
1134              
1135 0           foreach my $key ( CORE::keys %hash )
1136             {
1137 0           $self->set( $key, $hash{ $key } );
1138             }
1139 0           return 1;
1140              
1141             }
1142              
1143             1;
1144              
1145              
1146              
1147             =head1 AUTHOR
1148              
1149             Steve Kemp
1150              
1151             http://www.steve.org.uk/
1152              
1153             =cut
1154              
1155              
1156              
1157             =head1 LICENSE
1158              
1159             Copyright (c) 2016 by Steve Kemp. All rights reserved.
1160              
1161             This module is free software;
1162             you can redistribute it and/or modify it under
1163             the same terms as Perl itself.
1164             The LICENSE file contains the full text of the license.
1165              
1166             =cut