view release on metacpan or search on metacpan
lib/Aniki.pm view on Meta::CPAN
my $result = $self->_fetch_by_sth($sth, $table_name, $columns);
$self->fetch_and_attach_relay_data($table_name, $prefetch, $result->rows);
$txn->rollback if defined $txn; ## for read only
return $result;
}
my $sth = $self->execute($sql, @$bind);
# When the return value is never used, should not create object
# case example: use `FOR UPDATE` query for global locking
unless (defined wantarray) {
$sth->finish();
return;
}
return $self->_fetch_by_sth($sth, $table_name, $columns);
}
sub _fetch_by_sth {
my ($self, $sth, $table_name, $columns) = @_;
lib/Aniki/Filter.pm view on Meta::CPAN
package Aniki::Filter;
use 5.014002;
use namespace::autoclean;
use Mouse v2.4.5;
has global_inflators => (
is => 'ro',
default => sub { [] },
);
has global_deflators => (
is => 'ro',
default => sub { [] },
);
has global_triggers => (
is => 'ro',
default => sub { +{} },
);
has table_inflators => (
is => 'ro',
default => sub { +{} },
);
has table_deflators => (
lib/Aniki/Filter.pm view on Meta::CPAN
);
has table_triggers => (
is => 'ro',
default => sub { +{} },
);
sub _identity { $_[0] }
sub _normalize_column2rx { ref $_[0] eq 'Regexp' ? $_[0] : qr/\A\Q$_[0]\E\z/m }
sub add_global_inflator {
my ($self, $column, $code) = @_;
my $rx = _normalize_column2rx($column);
push @{ $self->global_inflators } => [$rx, $code];
}
sub add_global_deflator {
my ($self, $column, $code) = @_;
my $rx = _normalize_column2rx($column);
push @{ $self->global_deflators } => [$rx, $code];
}
sub add_global_trigger {
my ($self, $event, $code) = @_;
push @{ $self->global_triggers->{$event} } => $code;
}
sub add_table_inflator {
my ($self, $table_name, $column, $code) = @_;
my $rx = _normalize_column2rx($column);
push @{ $self->table_inflators->{$table_name} } => [$rx, $code];
}
sub add_table_deflator {
my ($self, $table_name, $column, $code) = @_;
lib/Aniki/Filter.pm view on Meta::CPAN
my %row = %$row;
my $trigger = $self->get_trigger_callback($event, $table_name);
return $trigger->(\%row);
}
sub get_inflate_callback {
my ($self, $table_name, $column) = @_;
unless (exists $self->{__inflate_callbacks_cache}->{$table_name}->{$column}) {
my $callback;
for my $pair (@{ $self->global_inflators }) {
my ($rx, $code) = @$pair;
$callback = $code if $column =~ $rx;
}
for my $pair (@{ $self->table_inflators->{$table_name} }) {
my ($rx, $code) = @$pair;
$callback = $code if $column =~ $rx;
}
$self->{__inflate_callbacks_cache}->{$table_name}->{$column} = $callback;
}
return $self->{__inflate_callbacks_cache}->{$table_name}->{$column};
}
sub get_deflate_callback {
my ($self, $table_name, $column) = @_;
unless (exists $self->{__deflate_callbacks_cache}->{$table_name}->{$column}) {
my $callback;
for my $pair (@{ $self->global_deflators }) {
my ($rx, $code) = @$pair;
$callback = $code if $column =~ $rx;
}
for my $pair (@{ $self->table_deflators->{$table_name} }) {
my ($rx, $code) = @$pair;
$callback = $code if $column =~ $rx;
}
$self->{__deflate_callbacks_cache}->{$table_name}->{$column} = $callback;
}
return $self->{__deflate_callbacks_cache}->{$table_name}->{$column};
}
sub get_trigger_callback {
my ($self, $event, $table_name) = @_;
unless (exists $self->{__trigger_callback_cache}->{$table_name}->{$event}) {
my @triggers = (
@{ $self->table_triggers->{$table_name}->{$event} || [] },
@{ $self->global_triggers->{$event} || [] },
);
my $trigger = \&_identity;
for my $cb (reverse @triggers) {
my $next = $trigger;
$trigger = sub { $cb->($_[0], $next) };
}
$self->{__trigger_callback_cache}->{$table_name}->{$event} = $trigger;
}
lib/Aniki/Filter/Declare.pm view on Meta::CPAN
}
sub _inflate {
my $filter = shift;
return sub ($&) {## no critic
my ($column, $code) = @_;
if (defined $TARGET_TABLE) {
$filter->add_table_inflator($TARGET_TABLE, $column, $code);
}
else {
$filter->add_global_inflator($column, $code);
}
};
}
sub _deflate {
my $filter = shift;
sub ($&) {## no critic
my ($column, $code) = @_;
if (defined $TARGET_TABLE) {
$filter->add_table_deflator($TARGET_TABLE, $column, $code);
}
else {
$filter->add_global_deflator($column, $code);
}
};
}
sub _trigger {
my $filter = shift;
sub ($&) {## no critic
my ($event, $code) = @_;
if (defined $TARGET_TABLE) {
$filter->add_table_trigger($TARGET_TABLE, $event, $code);
}
else {
$filter->add_global_trigger($event, $code);
}
};
}
sub _instance {
my $filter = shift;
return sub { $filter };
}
1;
lib/Aniki/Filter/Declare.pm view on Meta::CPAN
my $name = shift;
return uc $name;
};
deflate name => sub {
my $name = shift;
return lc $name;
};
};
# define inflate/deflate filters in global context. (apply to all tables)
inflate qr/_at$/ => sub {
my $datetime = shift;
return Time::Moment->from_string($datetime.'Z', lenient => 1);
};
deflate qr/_at$/ => sub {
my $datetime = shift;
return $datetime->at_utc->strftime('%F %T') if blessed $datetime and $datetime->isa('Time::Moment');
return $datetime;
};
t/filter/declare/basic.t view on Meta::CPAN
};
deflate foo => sub {
my $value = shift;
return "hoge_deflate_$value";
};
};
inflate bar => sub {
my $value = shift;
return "global_inflate_$value";
};
deflate bar => sub {
my $value = shift;
return "global_deflate_$value";
};
};
my $filter = MyProj::DB::Filter->instance;
subtest table => sub {
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_inflate_foo_value';
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_deflate_foo_value';
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_inflate_foo_value';
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_deflate_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
};
subtest global => sub {
is $filter->inflate_row(hoge => { bar => 'bar_value' })->{bar}, 'global_inflate_bar_value';
is $filter->deflate_row(hoge => { bar => 'bar_value' })->{bar}, 'global_deflate_bar_value';
is $filter->inflate_row(hoge => { bar => 'bar_value' })->{bar}, 'global_inflate_bar_value';
is $filter->deflate_row(hoge => { bar => 'bar_value' })->{bar}, 'global_deflate_bar_value';
is $filter->inflate_row(fuga => { bar => 'bar_value' })->{bar}, 'global_inflate_bar_value';
is $filter->deflate_row(fuga => { bar => 'bar_value' })->{bar}, 'global_deflate_bar_value';
is $filter->inflate_row(fuga => { bar => 'bar_value' })->{bar}, 'global_inflate_bar_value';
is $filter->deflate_row(fuga => { bar => 'bar_value' })->{bar}, 'global_deflate_bar_value';
};
done_testing;
t/filter/deflate/basic.t view on Meta::CPAN
use strict;
use warnings;
use utf8;
use Test::More;
use Aniki::Filter;
subtest 'global deflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_deflator(foo => sub {
my $value = shift;
return "global_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
subtest 'table deflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_deflator(hoge => foo => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
subtest 'table and global deflator' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_deflator(foo => sub {
my $value = shift;
return "global_$value";
});
$filter->add_table_deflator(hoge => foo => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
done_testing();
t/filter/deflate/regex.t view on Meta::CPAN
use strict;
use warnings;
use utf8;
use Test::More;
use Aniki::Filter;
subtest 'global deflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_deflator(qr/foo/ => sub {
my $value = shift;
return "global_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->deflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->deflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
subtest 'table deflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_deflator(hoge => qr/foo/ => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'hoge_foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->deflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->deflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
subtest 'table and global deflator' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_deflator(qr/foo/ => sub {
my $value = shift;
return "global_$value";
});
$filter->add_table_deflator(hoge => qr/foo/ => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->deflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->deflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->deflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'hoge_foo2_value';
is $filter->deflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->deflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->deflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
done_testing();
t/filter/deflate_and_inflate.t view on Meta::CPAN
use Test::More;
use Aniki::Filter;
my @PATTERN = (
[hoge => { foo => 'foo_value' }],
[fuga => { foo => 'foo_value' }],
[hoge => { foo2 => 'foo2_value' }],
[fuga => { foo2 => 'foo2_value' }],
);
subtest 'global' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_inflator(foo => sub {
my $value = shift;
return "global_inflate_$value";
});
$filter->add_global_deflator(foo => sub {
my $value = shift;
return "global_deflate_$value";
});
for my $pattern (@PATTERN) {
my ($table, $row) = @$pattern;
my ($column) = keys %$row;
is $filter->deflate_row($table, $row)->{$column}, $column eq 'foo' ? 'global_deflate_foo_value' : $row->{$column};
is $filter->inflate_row($table, $row)->{$column}, $column eq 'foo' ? 'global_inflate_foo_value' : $row->{$column};
}
};
subtest 'table' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_inflator(hoge => foo => sub {
my $value = shift;
return "hoge_inflate_$value";
});
$filter->add_table_deflator(hoge => foo => sub {
t/filter/inflate/basic.t view on Meta::CPAN
use strict;
use warnings;
use utf8;
use Test::More;
use Aniki::Filter;
subtest 'global inflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_inflator(foo => sub {
my $value = shift;
return "global_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
subtest 'table inflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_inflator(hoge => foo => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
subtest 'table and global inflator' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_inflator(foo => sub {
my $value = shift;
return "global_$value";
});
$filter->add_table_inflator(hoge => foo => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
};
done_testing();
t/filter/inflate/regex.t view on Meta::CPAN
use strict;
use warnings;
use utf8;
use Test::More;
use Aniki::Filter;
subtest 'global inflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_inflator(qr/foo/ => sub {
my $value = shift;
return "global_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->inflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->inflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
subtest 'table inflator only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_inflator(hoge => qr/foo/ => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'hoge_foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'foo2_value';
is $filter->inflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->inflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
subtest 'table and global inflator' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_inflator(qr/foo/ => sub {
my $value = shift;
return "global_$value";
});
$filter->add_table_inflator(hoge => qr/foo/ => sub {
my $value = shift;
return "hoge_$value";
});
is $filter->inflate_row(hoge => { foo => 'foo_value' })->{foo}, 'hoge_foo_value';
is $filter->inflate_row(fuga => { foo => 'foo_value' })->{foo}, 'global_foo_value';
is $filter->inflate_row(hoge => { foo2 => 'foo2_value' })->{foo2}, 'hoge_foo2_value';
is $filter->inflate_row(fuga => { foo2 => 'foo2_value' })->{foo2}, 'global_foo2_value';
is $filter->inflate_row(hoge => { bar => 'bar_value' })->{bar}, 'bar_value';
is $filter->inflate_row(fuga => { bar => 'bar_value' })->{bar}, 'bar_value';
};
done_testing();
t/filter/trigger/basic.t view on Meta::CPAN
use strict;
use warnings;
use utf8;
use Test::More;
use Aniki::Filter;
subtest 'global trigger only' => sub {
my $filter = Aniki::Filter->new();
$filter->add_global_trigger(insert => sub {
my ($row, $next) = @_;
$row->{baz}++;
return $next->($row);
});
is $filter->apply_trigger(insert => hoge => { foo => 'foo_value' })->{baz}, 1;
is $filter->apply_trigger(insert => fuga => { foo => 'foo_value' })->{baz}, 1;
is $filter->apply_trigger(insert => hoge => { foo2 => 'foo2_value' })->{baz}, 1;
is $filter->apply_trigger(insert => fuga => { foo2 => 'foo2_value' })->{baz}, 1;
};
t/filter/trigger/basic.t view on Meta::CPAN
my ($row, $next) = @_;
$row->{baz}++;
return $next->($row);
});
is $filter->apply_trigger(insert => hoge => { foo => 'foo_value' })->{baz}, 1;
is $filter->apply_trigger(insert => fuga => { foo => 'foo_value' })->{baz}, undef;
is $filter->apply_trigger(insert => hoge => { foo2 => 'foo2_value' })->{baz}, 1;
is $filter->apply_trigger(insert => fuga => { foo2 => 'foo2_value' })->{baz}, undef;
};
subtest 'table and global trigger' => sub {
my $filter = Aniki::Filter->new();
$filter->add_table_trigger(hoge => insert => sub {
my ($row, $next) = @_;
$row->{baz}++;
return $next->($row);
});
$filter->add_global_trigger(insert => sub {
my ($row, $next) = @_;
$row->{baz}++;
return $next->($row);
});
is $filter->apply_trigger(insert => hoge => { foo => 'foo_value' })->{baz}, 2;
is $filter->apply_trigger(insert => fuga => { foo => 'foo_value' })->{baz}, 1;
is $filter->apply_trigger(insert => hoge => { foo2 => 'foo2_value' })->{baz}, 2;
is $filter->apply_trigger(insert => fuga => { foo2 => 'foo2_value' })->{baz}, 1;
};