File Coverage

blib/lib/Dancer2/Plugin/Redis.pm
Criterion Covered Total %
statement 53 99 53.5
branch 9 50 18.0
condition 0 18 0.0
subroutine 16 27 59.2
pod 7 7 100.0
total 85 201 42.2


line stmt bran cond sub pod time code
1             package Dancer2::Plugin::Redis;
2 4     4   3349663 use strictures 1;
  4         67  
  4         226  
3             # ABSTRACT: Perl Dancer2 plugin for interaction with key-value-store Redis.
4             #
5             # This file is part of Dancer2-Plugin-Redis
6             #
7             # This software is Copyright (c) 2018 by BURNERSK .
8             #
9             # This is free software, licensed under:
10             #
11             # The MIT (X11) License
12             #
13              
14             BEGIN {
15 4     4   619 our $VERSION = '0.008'; # VERSION: generated by DZP::OurPkgVersion
16             }
17              
18 4     4   28 use Carp qw( carp croak );
  4         10  
  4         182  
19 4     4   26 use Dancer2::Core::Types qw( Maybe InstanceOf );
  4         8  
  4         29  
20 4     4   7080 use Dancer2::Plugin 0.200000;
  4         56071  
  4         47  
21 4     4   16945 use Redis;
  4         135096  
  4         149  
22 4     4   34 use Safe::Isa;
  4         18  
  4         498  
23 4     4   34 use Try::Tiny;
  4         11  
  4         276  
24 4     4   38 use Type::Tiny;
  4         11  
  4         5953  
25              
26              
27             ############################################################################
28              
29             my $TYPE_SERIALIZATIONOBJECT = Type::Tiny->new(
30             name => 'SerializationObject',
31             constraint => sub { $_->$_call_if_object( 'does' => 'Dancer2::Plugin::Redis::SerializationRole' ) },
32             message => sub { qq{$_ does not consume a SerializationRole} },
33             );
34              
35             has _serialization => (
36             is => 'lazy',
37             isa => Maybe [ $TYPE_SERIALIZATIONOBJECT ],
38             );
39              
40             sub _build__serialization {
41 3     3   71 my ($dsl1) = @_;
42 3         64 my $conf = $dsl1->config;
43 3         119 my $serialization;
44              
45             # Setup serialization.
46 3 50       20 if ( my $serialization_module = delete $conf->{serialization}{module} ) {
47 0 0       0 $serialization_module =~ s/^/Dancer2::Plugin::Redis::Serialization::/
48             if $serialization_module !~ m/^Dancer2::Plugin::Redis::Serialization::/;
49 0 0       0 croak qq{Invalid serialization module: $serialization_module}
50             if $serialization_module !~ m/^Dancer2::Plugin::Redis::Serialization::[a-zA-Z][a-zA-Z0-9_]*$/;
51             try {
52 0 0   0   0 eval "require $serialization_module" or croak $@;
53 0         0 $serialization = "$serialization_module"->new( %{ $conf->{serialization} } );
  0         0  
54             }
55             catch {
56 0     0   0 $dsl1->error(qq{Unable to set up serialization '$serialization_module': $_});
57 0         0 };
58             }
59 3         91 return $serialization;
60             };
61              
62             has _redis => (
63             is => 'lazy',
64             isa => InstanceOf ['Redis', 't::TestApp::RedisMock'],
65             );
66              
67             sub _build__redis {
68 4     4   84 my ($dsl2) = @_;
69 4         106 my $conf = $dsl2->config;
70              
71 4 50       144 if ( $conf->{test_mock} ) {
72 4         1380 require t::TestApp::RedisMock;
73 4         16391 return t::TestApp::RedisMock->new;
74             }
75              
76 0         0 my %opts;
77              
78             # Build Redis->new settings.
79 0         0 for (qw( server sock password reconnect every name debug )) {
80 0 0       0 $opts{$_} = $conf->{$_} if exists $conf->{$_};
81             }
82              
83             # Cleanup settings.
84 0 0       0 delete $opts{server} if $opts{sock}; # prefer UNIX/Linux sockets.
85 0 0       0 delete $opts{sock} if $opts{server};
86 0 0 0     0 delete $opts{password} if exists $opts{password} && ( !defined $opts{password} || $opts{password} eq '' );
      0        
87 0 0       0 delete $opts{name} unless $opts{name};
88              
89             # Validate reconnect settings.
90 0 0 0     0 if ( ( exists $opts{reconnect} || exists $opts{every} ) && ( !$opts{reconnect} || !$opts{every} ) ) {
      0        
      0        
91 0         0 $dsl2->error(q{Incomplete Redis configuration for 'reconnect' and 'every', skipping...});
92 0         0 delete $opts{reconnect};
93 0         0 delete $opts{every};
94             }
95              
96             # Validate on_connect settings.
97 0 0       0 if ( exists $conf->{on_connect} ) {
98 0 0       0 if ( !exists &{ $conf->{on_connect} } ) {
  0         0  
99 0         0 $dsl2->error(q{Invalid Redis configuration for 'on_connect', skipping...});
100             }
101             else {
102 0         0 $opts{on_connect} = \&{ $conf->{on_connect} };
  0         0  
103             }
104             }
105              
106             # Validate connection settings.
107             $dsl2->error(q{Incomplete Redis configuration: required is either 'server' or 'sock'})
108 0 0 0     0 if !$opts{server} && !$opts{sock};
109              
110 0         0 return Redis->new(%opts);
111             }
112              
113             ############################################################################
114              
115             sub _plugin {
116 0     0   0 shift->redis_plugin;
117             }
118              
119             sub redis_plugin {
120 1     1 1 32245 my ($dsl) = @_;
121 1         22 return $dsl;
122             }
123              
124             ############################################################################
125              
126             sub _get {
127 0     0   0 shift->redis_get(@_);
128             }
129              
130             sub redis_get {
131 5     5 1 2069090 my ( $dsl, $key ) = @_;
132 5 50       27 croak q{Redis key is required} unless $key;
133 5         108 my $data = $dsl->_redis->get($key);
134 5 50       1729 if ( my $serialization = $dsl->_serialization ) {
135 0         0 $data = $serialization->decode($data);
136             }
137 5         186 return $data;
138             }
139              
140             ############################################################################
141              
142             sub _mget {
143 0     0   0 shift->redis_mget(@_);
144             }
145              
146             sub redis_mget {
147 0     0 1 0 my ( $dsl, @keys ) = @_;
148 0 0       0 croak q{Redis key is required} unless scalar @keys;
149 0         0 my @data = $dsl->_redis->mget(@keys);
150 0 0       0 if ( my $serialization = $dsl->_serialization ) {
151 0         0 $data[$_] = $serialization->decode( $data[$_] ) for ( 0 .. scalar @data );
152             }
153 0         0 return @data;
154             }
155              
156             ############################################################################
157              
158             sub _set {
159 0     0   0 shift->redis_set(@_);
160             }
161              
162             sub redis_set {
163 3     3 1 76557 my ( $dsl, $key, $data ) = @_;
164 3 50       14 croak q{Redis key is required} unless $key;
165 3 50       65 if ( my $serialization = $dsl->_serialization ) {
166 0         0 $data = $serialization->encode($data);
167             }
168 3         308 return $dsl->_redis->set( $key => $data );
169             }
170              
171             ############################################################################
172              
173             sub _mset {
174 0     0   0 shift->redis_mset(@_);
175             }
176              
177             sub redis_mset {
178 0     0 1 0 my ( $dsl, %key_data ) = @_;
179 0 0       0 croak q{Redis key is required} unless scalar %key_data;
180 0 0       0 if ( my $serialization = $dsl->_serialization ) {
181 0         0 $key_data{$_} = $serialization->encode( $key_data{$_} ) for ( keys %key_data );
182             }
183 0         0 return $dsl->_redis->mset(%key_data);
184             }
185              
186             ############################################################################
187              
188             sub _expire {
189 0     0   0 shift->redis_expire(@_);
190             }
191              
192             sub redis_expire {
193 1     1 1 13595 my ( $dsl, $key, $timeout ) = @_;
194 1 50       5 croak q{Redis key is required} unless $key;
195 1 50       4 return $dsl->_redis->persist($key) unless $timeout;
196 1         19 return $dsl->_redis->expire( $key => $timeout );
197             }
198              
199             ############################################################################
200              
201             sub _del {
202 0     0   0 shift->redis_del(@_);
203             }
204              
205             sub redis_del {
206 1     1 1 14750 my ( $dsl, $key ) = @_;
207 1 50       6 croak q{Redis key is required} unless $key;
208 1         21 return $dsl->_redis->del($key);
209             }
210              
211             ############################################################################
212              
213             plugin_keywords 'redis_plugin', 'redis_get', 'redis_mget', 'redis_set',
214             'redis_mset', 'redis_expire', 'redis_del';
215              
216              
217             ############################################################################
218              
219              
220             1;
221              
222             __END__