File Coverage

blib/lib/IO/Iron/IronCache/Client.pm
Criterion Covered Total %
statement 76 126 60.3
branch 3 6 50.0
condition n/a
subroutine 17 21 80.9
pod 6 6 100.0
total 102 159 64.1


line stmt bran cond sub pod time code
1             package IO::Iron::IronCache::Client;
2              
3             ## no critic (Documentation::RequirePodAtEnd)
4             ## no critic (Documentation::RequirePodSections)
5             ## no critic (Subroutines::RequireArgUnpacking)
6              
7 6     6   111083 use 5.010_000;
  6         31  
8 6     6   32 use strict;
  6         11  
  6         114  
9 6     6   29 use warnings;
  6         10  
  6         216  
10              
11             # Global creator
12 6         563 BEGIN {
13 6     6   1376 use parent qw(IO::Iron::ClientBase); # Inheritance
  6         1045  
  6         35  
14 6     6   350 use parent qw(IO::Iron::IronCache::Policy );
  6         23  
  6         26  
15             }
16              
17             # Global destructor
18       6     END {
19             }
20              
21             # ABSTRACT: IronCache (Online Item-Value Storage) Client.
22              
23             our $VERSION = '0.14'; # VERSION: generated by DZP::OurPkgVersion
24              
25 6     6   41 use Log::Any qw{$log};
  6         42  
  6         1240  
26 6     6   99 use Hash::Util 0.06 qw{lock_keys lock_keys_plus unlock_keys legal_keys};
  6         35  
  6         514  
27 6     6   12 use Carp::Assert::More;
  6         1118  
  6         53  
28 6     6   12 use English '-no_match_vars';
  6         43  
  6         2244  
29 6     6   27 use Params::Validate qw(:all);
  6         889  
  6         2972  
30              
31 6     6   16 use IO::Iron::IronCache::Api ();
  6         128  
  6         41  
32 6     6   12 use IO::Iron::Common ();
  6         198  
  6         993  
33             require IO::Iron::Connection;
34             require IO::Iron::IronCache::Cache;
35              
36             # CONSTANTS for this package
37              
38             # DEFAULTS
39 6     6   5390 use Const::Fast;
  6         50  
  2         6784  
40              
41             # Service specific!
42             const my $DEFAULT_API_VERSION => '1';
43             const my $DEFAULT_HOST => 'cache-aws-us-east-1.iron.io';
44              
45             sub new {
46 2     2 1 9 my $class = shift;
47             my %params = validate(
48             @_,
49             {
50 20         159 map { $_ => { type => SCALAR, optional => 1 }, } IO::Iron::Common::IRON_CLIENT_PARAMETERS(), ## no critic (ValuesAndExpressions::ProhibitCommaSeparatedStatements)
  2         56  
51             }
52             );
53              
54 2         929 $log->tracef( 'Entering new(%s, %s)', $class, \%params );
55 2         6 my $self = IO::Iron::ClientBase->new();
56              
57             # Add more keys to the self hash.
58             my @self_keys = (
59             'caches', # References to all objects created of class IO::Iron::IronCache::Cache. Not in use!
60             'policy', # The policies of this client.
61 2         18 legal_keys( %{$self} ),
  2         16  
62             );
63 2         9 unlock_keys( %{$self} );
  2         20  
64 2         8 lock_keys_plus( %{$self}, @self_keys );
  2         100  
65 2         61 my $config = IO::Iron::Common::get_config(%params);
66 2         567 $log->debugf( 'The config: %s', $config );
67 2 50       7 $self->{'project_id'} = defined $config->{'project_id'} ? $config->{'project_id'} : undef;
68 2         11 $self->{'caches'} = [];
69 2         19 assert_nonblank( $self->{'project_id'}, 'self->{project_id} is not defined or is blank' );
70              
71 2         8 unlock_keys( %{$self} );
  2         18  
72 2         2 bless $self, $class;
73 2         23 lock_keys( %{$self}, @self_keys );
  2         119  
74              
75             # Set up the policies
76             # We have to do this after blessing the object
77             # because get_policies has late bindings.
78 2         25 $self->{'policy'} = $self->get_policies( 'policies' => $config->{'policies'} );
79              
80             # Set up the connection client
81             my $connection = IO::Iron::Connection->new(
82             {
83             'project_id' => $config->{'project_id'},
84             'token' => $config->{'token'},
85             'host' => defined $config->{'host'} ? $config->{'host'} : $DEFAULT_HOST,
86             'protocol' => $config->{'protocol'},
87             'port' => $config->{'port'},
88             'api_version' => defined $config->{'api_version'} ? $config->{'api_version'} : $DEFAULT_API_VERSION,
89             'timeout' => $config->{'timeout'},
90 2 50       20 'connector' => $params{'connector'},
    50          
91             }
92             );
93 2         22 $self->{'connection'} = $connection;
94             $log->debugf(
95             'IronCache client created with config: (project_id=%s; token=%s; host=%s; timeout=%s).',
96             $config->{'project_id'},
97 2         431 $config->{'token'}, $config->{'host'}, $config->{'timeout'}
98             );
99 2         1641 $log->tracef( 'Exiting new: %s', $self );
100 0         0 return $self;
101             }
102              
103             sub get_caches {
104 0     0 1 0 my $self = shift;
105 0         0 validate(
106             @_,
107             {
108             # No parameters
109             }
110             );
111 0         0 $log->tracef('Entering get_caches()');
112              
113 0         0 my @caches;
114 0         0 my $connection = $self->{'connection'};
115 0         0 my ( $http_status_code, $response_message ) =
116             $connection->perform_iron_action( IO::Iron::IronCache::Api::IRONCACHE_LIST_CACHES(), {} );
117 0         0 $self->{'last_http_status_code'} = $http_status_code;
118 0         0 foreach my $cache_info ( @{$response_message} ) {
  0         0  
119 0         0 my $get_cache_name = $cache_info->{'name'};
120             my $cache = IO::Iron::IronCache::Cache->new(
121             {
122             'ironcache_client' => $self, # Pass a reference to the parent object.
123             'name' => $get_cache_name,
124             'connection' => $self->{'connection'},
125 0         0 'policy' => $self->{'policy'},
126             }
127             );
128 0         0 push @caches, $cache;
129             }
130              
131             #push @{$self->{'caches'}}, @caches; # Store only created caches!
132 0         0 $log->debugf( 'Created caches: %s', \@caches );
133              
134 0         0 $log->tracef( 'Exiting get_caches: %s', \@caches );
135 0         0 return @caches;
136             }
137              
138             sub get_info_about_cache {
139 0     0 1 0 my $self = shift;
140 0         0 my %params = validate(
141             @_,
142             {
143             'name' => { type => SCALAR, }, # cache name.
144             }
145             );
146 0         0 $log->tracef( 'Entering get_info_about_cache(%s)', \%params );
147              
148 0         0 my $connection = $self->{'connection'};
149             my ( $http_status_code, $response_message ) =
150             $connection->perform_iron_action( IO::Iron::IronCache::Api::IRONCACHE_GET_INFO_ABOUT_A_CACHE(),
151 0         0 { '{Cache Name}' => $params{'name'}, } );
152 0         0 $self->{'last_http_status_code'} = $http_status_code;
153 0         0 my $info = $response_message;
154              
155             # info:
156             # {'id':'523566104a734c39bf00041e','project_id':'51bdf5fb2267d84ced002c99',
157             # 'name':'TEST_CACHE_01','size':0,'data_size':0}
158             # Fetched info about cache:{created_at => '0001-01-01T00:00:00Z',data_size => 0,id => '53083eb79ef7915a7f005bc0'
159             # ,name => 'name',project_id => '51bdf5fb2267d84ced002c99',size => 1,updated_at => '0001-01-01T00:00:00Z'}
160 0         0 $log->tracef( 'Exiting get_info_about_cache: %s', $info );
161 0         0 return $info;
162             }
163              
164             sub get_cache {
165 0     0 1 0 my $self = shift;
166 0         0 my %params = validate(
167             @_,
168             {
169             'name' => { type => SCALAR, }, # cache name.
170             }
171             );
172 0         0 $log->tracef( 'Entering get_cache(%s)', \%params );
173              
174 0         0 my $connection = $self->{'connection'};
175             my ( $http_status_code, $response_message ) =
176             $connection->perform_iron_action( IO::Iron::IronCache::Api::IRONCACHE_GET_INFO_ABOUT_A_CACHE(),
177 0         0 { '{Cache Name}' => $params{'name'}, } );
178 0         0 $self->{'last_http_status_code'} = $http_status_code;
179 0         0 my $get_cache_name = $response_message->{'name'};
180             my $cache = IO::Iron::IronCache::Cache->new(
181             {
182             'ironcache_client' => $self, # Pass a reference to the parent object.
183             'name' => $get_cache_name,
184             'connection' => $self->{'connection'},
185 0         0 'policy' => $self->{'policy'},
186             }
187             );
188 0         0 push @{ $self->{'caches'} }, $cache;
  0         0  
189 0         0 $log->debugf( 'Created a new IO::Iron::IronCache::Cache object (name=%s).', $get_cache_name );
190 0         0 $log->tracef( 'Exiting get_cache: %s', $cache );
191 2         72 return $cache;
192             }
193              
194             sub create_cache {
195 2     2 1 47 my $self = shift;
196             my %params = validate(
197             @_,
198             {
199             'name' => {
200             type => SCALAR,
201             callbacks => {
202 2     2   21 'RFC 3986 reserved character check' => sub { return !IO::Iron::Common::contains_rfc_3986_res_chars(shift) },
203             }
204             }, # cache name.
205             }
206 2         25 );
207 2         497 $log->tracef( 'Entering create_cache(%s)', \%params );
208              
209 1         23 $self->validate_cache_name( 'name' => $params{'name'} );
210             my $cache = IO::Iron::IronCache::Cache->new(
211             {
212             'ironcache_client' => $self, # Pass a reference to the parent object.
213             'name' => $params{'name'},
214             'connection' => $self->{'connection'},
215 1         5 'policy' => $self->{'policy'},
216             }
217             );
218 1         9 push @{ $self->{'caches'} }, $cache;
  1         4  
219              
220 1         76 $log->debugf( 'Created a new IO::Iron::IronCache::Cache object (name=%s.)', $params{'name'} );
221 1         401 $log->tracef( 'Exiting get_cache: %s', $cache );
222 0           return $cache;
223             }
224              
225             sub delete_cache {
226 0     0 1   my $self = shift;
227 0           my %params = validate(
228             @_,
229             {
230             'name' => { type => SCALAR, }, # cache name.
231             }
232             );
233 0           $log->tracef( 'Entering delete_cache(%s)', \%params );
234              
235 0           my $connection = $self->{'connection'};
236             my ($http_status_code) = $connection->perform_iron_action(
237             IO::Iron::IronCache::Api::IRONCACHE_DELETE_A_CACHE(),
238             {
239 0           '{Cache Name}' => $params{'name'},
240             }
241             );
242 0           $self->{'last_http_status_code'} = $http_status_code;
243 0           @{ $self->{'caches'} } = grep { $_->name() ne $params{'name'} } @{ $self->{'caches'} };
  0            
  0            
  0            
244              
245 0           $log->debugf( 'Deleted cache (name=%s.)', $params{'name'} );
246 0           $log->tracef( 'Exiting delete_cache: %d', 1 );
247             return 1;
248             }
249              
250             1;
251              
252             __END__
253              
254             =pod
255              
256             =encoding UTF-8
257              
258             =head1 NAME
259              
260             IO::Iron::IronCache::Client - IronCache (Online Item-Value Storage) Client.
261              
262             =head1 VERSION
263              
264             version 0.14
265              
266             =head1 SYNOPSIS
267              
268             require IO::Iron::IronCache::Client;
269             require IO::Iron::IronCache::Item;
270             my $ironcache_client = IO::Iron::IronCache::Client->new();
271             # or
272             use IO::Iron qw(ironcache);
273             $ironcache_client = ironcache();
274              
275             # Operate with caches.
276             my @iron_caches = $ironcache_client->get_caches();
277             my $iron_cache = $ironcache_client->create_cache('name' => 'My_Iron_Cache');
278             # Or get an existing cache.
279             $iron_cache = $ironcache_client->get_cache('name' => 'My_Iron_Cache');
280             my $cache_deleted = $ironcache_client->delete_cache('name' => 'My_Iron_Cache');
281             my $info = $ironcache_client->get_info_about_cache('name' => 'My_Iron_Cache');
282              
283             # Operate with items.
284             my $iron_cache_item_put = IO::Iron::IronCache::Item->new(
285             'value' => "10",
286             'expires_in' => 60, # Expires in 60 seconds.
287             #'replace' => 1, # Only set the item if the item is already in the cache.
288             #'add' => 1 # Only set the item if the item is not already in the cache.
289             #'cas' => '12345' # Only set the item if there is already an item with matching key and cas.
290             );
291             my $item_put_ok = $iron_cache->put('key' => 'my_item', 'item' => $iron_cache_item_put);
292             my $item_put_new_value = $iron_cache->increment('key' => 'my_item', 'increment' => 15);
293             my $iron_cache_item_get = $iron_cache->get('key' => 'my_item');
294             my $item_deleted_ok = $iron_cache->delete('key' => 'my_item');
295             my $items_cleared_ok = $iron_cache->clear();
296              
297             =head1 DESCRIPTION
298              
299             IO::Iron::IronCache is a client for the IronCache online key-value store at L<http://www.iron.io/|http://www.iron.io/>.
300             IronCache is a cloud based key-value store with a REST API.
301             IO::Iron::IronCache::Client creates a Perl object for interacting with IronCache.
302             All IronCache functions are available.
303              
304             The class IO::Iron::IronCache::Client instantiates the 'project', IronCache access configuration.
305              
306             =head2 IronCache Key-Value Store
307              
308             L<http://www.iron.io/|http://www.iron.io/>
309              
310             IronCache is a key-value store online, usable on the principle of
311             "Software as a Service", i.e. SaaS. It is available to Internet connecting
312             applications via its REST interface. Built with distributed
313             cloud applications in mind, it provides on-demand key-value storage,
314             value persistance/expiry as requested and cloud-optimized performance.
315             [see L<http://www.iron.io/|http://www.iron.io/>]
316              
317             =head2 Using the IronCache Client Library
318              
319             IO::Iron::IronCache::Client is a normal Perl package meant to be used as an object.
320              
321             require IO::Iron::IronCache::Client;
322             my $iron_cache_client = IO::Iron::IronCache::Client->new();
323              
324             Please see L<IO::Iron|IO::Iron> for further parameters and general usage.
325              
326             After creating the client, the client can create a new cache (storage), get or
327             delete an old one or get all the existing caches within
328             the same project.
329              
330             The client has all the methods which interact with
331             the caches; the cache (object of class IO::Iron::IronCache::Cache)
332             has methods which involve items inside the cache.
333              
334             When failed to do the requested action, the methods return an exception
335             using Perl package Exception::Class. Calling program should trap these
336             with e.g. Perl package Try::Tiny.
337              
338             # Create the cache client.
339             require IO::Iron::IronCache::Client;
340             my $ironcache_client = IO::Iron::IronCache::Client->new();
341             # Or
342             $ironcache_client = IO::Iron::IronCache::Client->new(
343             config => 'iron_cache.json
344             );
345              
346             # Operate with caches.
347             # Get all the existing caches as objects of
348             # class IO::Iron::IronCache::Cache.
349             my @iron_caches = $ironcache_client->get_caches();
350              
351             # Create a new cache object by its name.
352             # Returns object of class IO::Iron::IronCache::Cache.
353             my $iron_cache = $ironcache_client->create_cache('name' => 'My_Iron_Cache');
354             # Or get an existing cache.
355             $iron_cache = $ironcache_client->get_cache('name' => 'My_Iron_Cache');
356              
357             # Delete a cache by its name. Return 1 for success.
358             my $cache_deleted = $ironcache_client->delete_cache('name' => 'My_Iron_Cache');
359              
360             # Get info about a cache.
361             my $info_hash = $ironcache_client->get_info_about_cache('name' => 'My_Iron_Cache');
362              
363             # Operate with items.
364             # Create an item.
365             my $iron_cache_item_put = IO::Iron::IronCache::Item->new(
366             'value' => "10",
367             'expires_in' => 60, # Expires in 60 seconds.
368             #'replace' => 1, # Only set the item if the item is already in the cache.
369             #'add' => 1, # Only set the item if the item is not already in the cache.
370             #'cas' => '12345', # Only set the item if there is already an item with matching key and cas.
371             );
372             my $item_put = $iron_cache->put('key' => 'my_item_key', 'item' => $iron_cache_item_put);
373             my $item_put_new_value = $iron_cache->increment('key' => 'my_item_key', 'increment' => 15);
374             my $iron_cache_item_get = $iron_cache->get('key' => 'my_item_key');
375             my $item_deleted = $iron_cache->delete('key' => 'my_item_key');
376              
377             # Empty the cache (delete all items inside). Return 1 for success.
378             my $items_cleared_ok = $iron_cache->clear();
379              
380             An IO::Iron::IronCache::Cache object gives access to a single cache.
381             With it you can do all the normal things one would with a key-value store.
382              
383             Items are objects of the class IO::Iron::IronCache::Item. It contains
384             the following attributes:
385              
386             =over 8
387              
388             =item - value, Free text. If you want to put an object or a hash here, it needs to be serialized first; use e.g. JSON, Storable or YAML to stringify it. Then give the resulting string here.
389              
390             =item - expires_in, How long in seconds to keep the item in the cache before it is deleted. By default, items do not expire. Maximum is 2,592,000 seconds (30 days).
391              
392             =item - replace, If set to true, only set the item if the item is already in the cache. If the item is not in the cache, do not create it.
393              
394             =item - add, If set to true, only set the item if the item is not already in the cache. If the item is in the cache, do not overwrite it.
395              
396             =item - cas: If set, the new item will only be placed in the cache if there is an existing item with a matching key and cas value. An item's cas value is automatically generated and is included when the item is retrieved.
397              
398             -item - N.B. The item key is not stored in the object.
399              
400             =back
401              
402             Cas value changes every time the item value is updated to cache.
403             It can be used to verify that the value has not been changed since the
404             last get operation.
405              
406             $iron_cache_item_key = 'my_item_key';
407             my $iron_cache_item_put_1 = IO::Iron::IronCache::Item->new(
408             'value' => "10",
409             'expires_in' => 60, # Expires in 60 seconds.
410             'replace' => 1,
411             );
412             # Or
413             my $iron_cache_item_put_2 = IO::Iron::IronCache::Item->new(
414             'value' => "10",
415             'expires_in' => 60, # Expires in 60 seconds.
416             'add' => 1,
417             );
418              
419             IO::Iron::IronCache::Cache objects are created by the client
420             (object of IO::Iron::IronCache::Client) or they can be created by the user.
421             If an item is put to a cache which doesn't exist yet,
422             IronCache creates a new cache automatically.
423              
424             While it is possible
425             to create a cache object from IO::Iron::IronCache::Cache, user should not
426             normally do this. When the cache object is created
427             by the Client, it gets the Client's REST connection parameters.
428             Otherwise these will need to be set manually.
429              
430             With an IO::Iron::IronCache::Cache object you can put items to the cache,
431             or get existing items from it.
432              
433             Get cache id. Not really needed for anything.
434             Just internal reference for Iron Cache.
435              
436             my $cache_id = $iron_cache->id();
437              
438             Get cache name.
439              
440             my $cache_name = $iron_cache->name();
441              
442             Put an item into the cache. Returns 1 if successful.
443              
444             my $item_put = $iron_cache->put('key' => $iron_cache_item_key, 'item' => $iron_cache_item_put);
445              
446             If the item is an integer value, you can simply increment it by another
447             value. If the value is negative, the value in the cache will be
448             decreased. Returns the new value.
449              
450             my $item_put_new_value = $iron_cache->increment('key' => $iron_cache_item_key, 'increment' => 15);
451              
452             Get an item from the cache by its name. Returns an object of the class
453             IO::Iron::IronCache::Item if successful.
454              
455             my $iron_cache_item_get = $iron_cache->get('key' => $iron_cache_item_key);
456              
457             Delete an item in the cache by its name. Returns 1 if successful.
458              
459             my $item_deleted_ok = $iron_cache->delete('key' => $iron_cache_item_key);
460              
461             Clear the cache (delete all items inside). Return 1 for success.
462              
463             my $items_cleared_ok = $iron_cache->clear();
464              
465             =head3 Exceptions
466              
467             Please see L<IO::Iron|IO::Iron> for documentation on
468             exceptions.
469              
470             =head3 Policies
471              
472             Please see L<IO::Iron|IO::Iron> for documentation on
473             policies (limitations to names).
474              
475             =for stopwords IronCache API SaaS optimized serialized JSON Storable YAML
476              
477             =for stopwords stringify cas Cas Params IronHTTPCallException Mikko Koivunalho
478              
479             =for stopwords perldoc CPAN AnnoCPAN tradename licensable MERCHANTABILITY
480              
481             =head1 REQUIREMENTS
482              
483             See L<IO::Iron|IO::Iron> for requirements.
484              
485             =head1 SUBROUTINES/METHODS
486              
487             =head2 new
488              
489             Creator function.
490              
491             =head2 get_caches
492              
493             Return objects of class IO::Iron::IronCache::Cache representing all the caches
494             within this project.
495              
496             =over 8
497              
498             =item Params: [None]
499              
500             =item Return: List of IO::Iron::IronCache::Cache objects.
501              
502             =back
503              
504             =head2 get_info_about_cache
505              
506             =over 8
507              
508             =item Params: cache name.
509              
510             =item Return: Ref to a hash containing info about cache.
511             Contains at least items I<id>, I<project_id>, I<name> and I<size>.
512              
513             =back
514              
515             =head2 get_cache
516              
517             Return a IO::Iron::IronCache::Cache object representing
518             a particular key-value cache. The cache object is linked to the
519             creating IO::Iron::IronCache::Client object.
520              
521             =over 8
522              
523             =item Params: cache name. Cache must exist. If not, fails with an exception.
524              
525             =item Return: IO::Iron::IronCache::Cache object.
526              
527             =item Exception: IronHTTPCallException if fails. (IronHTTPCallException: status_code=<HTTP status code> response_message=<response_message>)
528              
529             =back
530              
531             =head2 create_cache
532              
533             Return a IO::Iron::IronCache::Cache object representing
534             a particular message cache. This call doesn't actually
535             access IronCache API because, if an item is put to a
536             cache which doesn't exist yet, IronCache creates a new cache
537             automatically. create_cache only creates
538             a new IO::Iron::IronCache::Cache object which is linked to its
539             creator IO::Iron::IronCache::Client object.
540              
541             =over 8
542              
543             =item Params: cache name.
544              
545             =item Return: IO::Iron::IronCache::Cache object.
546              
547             =back
548              
549             =head2 delete_cache
550              
551             Delete an IronCache cache.
552              
553             =over 8
554              
555             =item Params: cache name. Cache must exist. If not, fails with an exception.
556              
557             =item Return: 1 == success.
558              
559             =item Exception: IronHTTPCallException if fails. (IronHTTPCallException: status_code=<HTTP status code> response_message=<response_message>)
560              
561             =back
562              
563             =head1 AUTHOR
564              
565             Mikko Koivunalho <mikko.koivunalho@iki.fi>
566              
567             =head1 BUGS
568              
569             Please report any bugs or feature requests to bug-io-iron@rt.cpan.org or through the web interface at:
570             http://rt.cpan.org/Public/Dist/Display.html?Name=IO-Iron
571              
572             =head1 COPYRIGHT AND LICENSE
573              
574             This software is copyright (c) 2023 by Mikko Koivunalho.
575              
576             This is free software; you can redistribute it and/or modify it under
577             the same terms as the Perl 5 programming language system itself.
578              
579             The full text of the license can be found in the
580             F<LICENSE> file included with this distribution.
581              
582             =cut