Skip to content

Commit

Permalink
0.005 - caching
Browse files Browse the repository at this point in the history
  • Loading branch information
rawleyfowler committed Aug 4, 2023
1 parent 8ed4110 commit 70a2e7c
Show file tree
Hide file tree
Showing 10 changed files with 411 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
0.005 2023-08-03
- Alpha release #5
- Add Slick::Cache, Slick::CacheExecutor{,::Redis,::Memcached}
- Add a very basic version of the CLI (WIP)
- Various POD changes

0.004 2023-08-02
- Alpha release #4
- Add error handling for routes and events
Expand Down
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ User-Agents, and much more.
- [x] Database management (auto-enabled)
- [x] Migrations (auto-enabled)
- [ ] CLI
- [ ] Caching via Redis (optional)
- [x] Caching via Redis (optional)
- [x] Caching via Memcached (optional)
- [ ] Sub-routine based caching for routes (optional)
- [ ] RabbitMQ built-ins (optional)
- [ ] AWS S3 support (optional)
- [ ] User-Agents, including Client API exports
Expand Down Expand Up @@ -226,6 +228,44 @@ If you can't do what you want with `SQL::Abstract` helpers, you can certainly do
$s->database('my_postgres')->dbi->execute('DROP TABLE users;');
```

## Caching

Slick supports caching using [`Memcached`](https://memcached.org) or [`Redis`](https://redis.io).

```perl
use 5.036;

use Slick;

my $s = Slick->new;

# See Redis and Cache::Memcached on CPAN for arguments

# Create a Redis instance
$s->cache(
my_redis => type => 'redis', # Slick Arguments
server => '127.0.0.1:6379' # Cache::Memcached arguments
);

# Create a Memcached instance
$s->cache(
my_memcached => type => 'memcached', # Slick Arguments
servers => ['127.0.0.1'] => debug => 1 # Cache::Memcached arguments
);

$s->cache('my_redis')->set( something => 'awesome' );

$s->get(
'/foo' => sub {
my ( $app, $context ) = @_;
my $value = $app->cache('my_redis')->get('something'); # Use your cache
return $context->text($value);
}
);

$s->run;
```

## Deployment

Please follow a standard `Plack` application deployment. Reverse-proxying your application behind
Expand Down
31 changes: 31 additions & 0 deletions examples/cache/app.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use 5.036;

use Slick;

my $s = Slick->new;

# See Redis and Cache::Memcached on CPAN for arguments

# Create a Redis instance
$s->cache(
my_redis => type => 'redis', # Slick Arguments
server => '127.0.0.1:6379' # Cache::Memcached arguments
);

# Create a Memcached instance
$s->cache(
my_memcached => type => 'memcached', # Slick Arguments
servers => ['127.0.0.1'] => debug => 1 # Cache::Memcached arguments
);

$s->cache('my_redis')->set( something => 'awesome' );

$s->get(
'/foo' => sub {
my ( $app, $context ) = @_;
my $value = $app->cache('my_redis')->get('something'); # Use your cache
return $context->text($value);
}
);

$s->run;
41 changes: 39 additions & 2 deletions lib/Slick.pm
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use Slick::Context;
use Slick::Events qw(EVENTS BEFORE_DISPATCH AFTER_DISPATCH);
use Slick::Error;
use Slick::Database;
use Slick::Cache;
use Slick::Methods qw(METHODS);
use Slick::Route;
use Slick::Router;
Expand All @@ -22,7 +23,7 @@ use experimental qw(try);

no warnings qw(experimental::try);

our $VERSION = '0.004';
our $VERSION = '0.005';

with 'Slick::EventHandler';
with 'Slick::RouteManager';
Expand Down Expand Up @@ -68,6 +69,13 @@ has dbs => (
default => sub { return {}; }
);

has caches => (
is => 'ro',
lazy => 1,
isa => HashRef,
default => sub { return {}; }
);

has helpers => (
is => 'rw',
isa => HashRef,
Expand Down Expand Up @@ -181,6 +189,16 @@ sub database {
return $self->dbs->{$name} // undef;
}

sub cache {
my ( $self, $name, @args ) = @_;

if (@args) {
return $self->caches->{$name} = Slick::Cache->new(@args);
}

return $self->caches->{$name} // undef;
}

# Runs the application with the server
sub run {
my ( $self, %args ) = @_;
Expand Down Expand Up @@ -428,10 +446,29 @@ You can overwrite the banner with something else if you like via:
Creates and registers a database to the L<Slick> instance. The connection string should
be a fully-qualified URI based DSN.
$s->datbaase('my_db');
$s->database('my_db');
Retrieves the database if it exists, otherwise returns C<undef>.
=head2 cache
# See Redis and Cache::Memcached on CPAN for arguments
# Create a Redis instance
$s->cache(
my_redis => type => 'redis', # Slick Arguments
server => '127.0.0.1:6379' # Redis arguments
);
# Create a Memcached instance
$s->cache(
my_memcached => type => 'memcached', # Slick Arguments
servers => ['127.0.0.1'] => debug => 1 # Cache::Memcached arguments
);
Retrieves the cache if it exists, otherwise returns C<undef>. Basically L<"database"> but for caches.
Note type is a required argument, it should either be C<'redis'> or C<'memcached'>.
=head2 helper
$s->helper(printer => sub { print "Hi!"; });
Expand Down
153 changes: 153 additions & 0 deletions lib/Slick/Cache.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package Slick::Cache;

use 5.036;

use Moo;
use Carp qw(croak);
use List::Util qw(reduce);
use Scalar::Util qw(reftype);
use Types::Standard qw(Str HashRef);
use Module::Runtime qw(require_module);

has type => (
is => 'ro',
isa => sub {
my $s = shift;
return grep { $_ eq $s } qw(redis memcached);
},
required => 1
);

has _executor => (
is => 'ro',
isa => sub {
my $s = shift;
return blessed($s)
&& ( blessed($s) =~ /Slick\:\:CacheExecutor.*/x );
},
handles => [qw(get set incr decr raw)]
);

sub BUILD {
my $self = shift;
my $args = shift;

delete $args->{type};

my $package = ucfirst( $self->type );

require_module("Slick::CacheExecutor::$package");
$self->{_executor} =
"Slick::CacheExecutor::$package"->new( [ $args->%* ]->@* );

return $self;
}

1;

=encoding utf8
=head1 NAME
Slick::Cache
=head1 SYNOPSIS
A wrapper around a L<Slick::CacheExecutor> that either implements L<Redis> or L<Cache::Memcached>.
use 5.036;
use Slick;
my $s = Slick->new;
# See Redis and Cache::Memcached on CPAN for arguments
# Create a Redis instance
$s->cache(
my_redis => type => 'redis', # Slick Arguments
server => '127.0.0.1:6379' # Cache::Memcached arguments
);
# Create a Memcached instance
$s->cache(
my_memcached => type => 'memcached', # Slick Arguments
servers => ['127.0.0.1'] => debug => 1 # Cache::Memcached arguments
);
$s->cache('my_redis')->set( something => 'awesome' );
$s->get(
'/foo' => sub {
my ( $app, $context ) = @_;
my $value = $app->cache('my_redis')->get('something'); # Use your cache
return $context->text($value);
}
);
$s->run;
=head1 API
=head2 raw
Returns the underlying L<Redis> or L<Cache::Memcached> objects.
=head2 set
$s->cache('my_cache')->set(something => 'awesome');
Sets a value in the cache. Note, this is a facade for L<Redis>->set or L<Cache::Memcached>->set.
=head2 get
$s->cache('my_cache')->get('something');
Gets a value from the cache, returns C<undef> if it that key does not exist.
Note, this is a facade for L<Redis>->get or L<Cache::Memcached>->get.
=head2 incr
$s->cache('my_cache')->incr('value');
Attempts to increment a value in the cache.
=head2 decr
$s->cache('my_cache')->decr('value');
Attempts to decrement a value in the cache.
=head1 See also
=over2
=item * L<Slick::CacheExecutor>
=item * L<Slick::CacheExecutor::Redis>
=item * L<Slick::CacheExecutor::Memcached>
=item * L<Slick::Context>
=item * L<Slick::Database>
=item * L<Slick::DatabaseExecutor>
=item * L<Slick::DatabaseExecutor::MySQL>
=item * L<Slick::DatabaseExecutor::Pg>
=item * L<Slick::EventHandler>
=item * L<Slick::Events>
=item * L<Slick::Methods>
=item * L<Slick::RouteMap>
=item * L<Slick::Util>
=back
=cut
58 changes: 58 additions & 0 deletions lib/Slick/CacheExecutor.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package Slick::CacheExecutor;

use 5.036;

use Moo::Role;
use Types::Standard qw(Str);
use Carp qw(croak);
use Slick::Util;

has raw => (
is => 'ro',
handles => [qw(get set incr decr)]
);

1;

=encoding utf8
=head1 NAME
Slick::CacheExecutor
=head1 SYNOPSIS
A L<Moo::Role> implemented by all of the caches supported by L<Slick>.
=head1 See also
=over2
=item * L<Slick::DatabaseExecutor>
=item * L<Slick::CacheExecutor::Redis>
=item * L<Slick::CacheExecutor::Memcached>
=item * L<Slick::Context>
=item * L<Slick::Database>
=item * L<Slick::DatabaseExecutor::MySQL>
=item * L<Slick::DatabaseExecutor::Pg>
=item * L<Slick::EventHandler>
=item * L<Slick::Events>
=item * L<Slick::Methods>
=item * L<Slick::RouteMap>
=item * L<Slick::Util>
=back
=cut

Loading

0 comments on commit 70a2e7c

Please sign in to comment.