our
%defaults
;
use
constant
DEFAULT_MAX_SLURP_SIZE
=> 16 * 1024;
our
$VERSION
=
'0.20'
;
sub
init
{
if
(
scalar
(
@_
)) {
my
%args
= (
ref
(
$_
[0]) eq
'HASH'
) ? %{
$_
[0]} :
@_
;
if
((
$args
{
'expires_in'
} && !
$args
{
'cache_duration'
})) {
$args
{
'cache_duration'
} =
$args
{
'expires_in'
};
}
%defaults
= (
%defaults
,
%args
);
$defaults
{
'cache_duration'
} ||=
'1 hour'
;
}
return
\
%defaults
}
sub
new {
my
$class
=
shift
;
my
%args
;
if
(
ref
(
$_
[0]) eq
'HASH'
) {
%args
= %{
$_
[0]};
}
elsif
((
scalar
(
@_
) % 2) == 0) {
%args
=
@_
;
}
elsif
(
scalar
(
@_
) == 1) {
$args
{
'directory'
} =
shift
;
}
if
(!
defined
(
$class
)) {
if
((
scalar
keys
%args
) > 0) {
carp(__PACKAGE__,
' use ->new() not ::new() to instantiate'
);
return
;
}
$class
= __PACKAGE__;
}
elsif
(
$class
eq __PACKAGE__) {
croak(
"$class: abstract class"
);
}
elsif
(Scalar::Util::blessed(
$class
)) {
return
bless
{ %{
$class
},
%args
},
ref
(
$class
);
}
croak(
"$class: where are the files?"
)
unless
(
$args
{
'directory'
} ||
$defaults
{
'directory'
});
croak(
"$class: "
,
$args
{
'directory'
} ||
$defaults
{
'directory'
},
' is not a directory'
)
unless
(-d (
$args
{
'directory'
} ||
$defaults
{
'directory'
}));
return
bless
{
no_entry
=> 0,
id
=>
'entry'
,
cache_duration
=>
'1 hour'
,
max_slurp_size
=> DEFAULT_MAX_SLURP_SIZE,
%defaults
,
%args
},
$class
;
}
sub
set_logger
{
my
$self
=
shift
;
my
$args
=
$self
->_get_params(
'logger'
,
@_
);
if
(
defined
(
$args
->{
'logger'
})) {
$self
->{
'logger'
} =
$args
->{
'logger'
};
return
$self
;
}
Carp::croak(
'Usage: set_logger(logger => $logger)'
)
}
sub
_open {
my
$self
=
shift
;
my
$sep_char
= (
$self
->{
'sep_char'
} ?
$self
->{
'sep_char'
} :
'!'
);
my
%args
= (
sep_char
=>
$sep_char
,
((
ref
(
$_
[0]) eq
'HASH'
) ? %{
$_
[0]} :
@_
)
);
my
$table
=
$self
->{
'table'
} ||
ref
(
$self
);
$table
=~ s/.*:://;
$self
->_trace(
"_open $table"
);
return
if
(
$self
->{
$table
});
my
$dbh
;
my
$dir
=
$self
->{
'directory'
} ||
$defaults
{
'directory'
};
my
$dbname
=
$self
->{
'dbname'
} ||
$defaults
{
'dbname'
} ||
$table
;
my
$slurp_file
= File::Spec->catfile(
$dir
,
"$dbname.sql"
);
$self
->_debug(
"_open: try to open $slurp_file"
);
if
(-r
$slurp_file
) {
DBI->
import
();
$dbh
= DBI->
connect
(
"dbi:SQLite:dbname=$slurp_file"
,
undef
,
undef
, {
sqlite_open_flags
=> SQLITE_OPEN_READONLY,
});
$dbh
->
do
(
'PRAGMA synchronous = OFF'
);
$dbh
->
do
(
'PRAGMA cache_size = 65536'
);
$self
->_debug(
"read in $table from SQLite $slurp_file"
);
$self
->{
'type'
} =
'DBI'
;
}
else
{
my
$fin
;
(
$fin
,
$slurp_file
) = File::pfopen::pfopen(
$dir
,
$dbname
,
'csv.gz:db.gz'
,
'<'
);
if
(
defined
(
$slurp_file
) && (-r
$slurp_file
)) {
Gzip::Faster->
import
();
close
(
$fin
);
$fin
= File::Temp->new(
SUFFIX
=>
'.csv'
,
UNLINK
=> 0);
print
$fin
gunzip_file(
$slurp_file
);
$slurp_file
=
$fin
->filename();
$self
->{
'temp'
} =
$slurp_file
;
}
else
{
(
$fin
,
$slurp_file
) = File::pfopen::pfopen(
$dir
,
$dbname
,
'psv'
,
'<'
);
if
(
defined
(
$fin
)) {
$args
{
'sep_char'
} =
'|'
;
}
else
{
(
$fin
,
$slurp_file
) = File::pfopen::pfopen(
$dir
,
$dbname
,
'csv:db'
,
'<'
);
}
}
if
(
my
$filename
=
$self
->{
'filename'
} ||
$defaults
{
'filename'
}) {
$self
->_debug(
"Looking for $filename in $dir"
);
$slurp_file
= File::Spec->catfile(
$dir
,
$filename
);
}
if
(
defined
(
$slurp_file
) && (-r
$slurp_file
)) {
close
(
$fin
)
if
(
defined
(
$fin
));
$sep_char
=
$args
{
'sep_char'
};
$self
->_debug(__LINE__,
' of '
, __PACKAGE__,
": slurp_file = $slurp_file, sep_char = $sep_char"
);
if
(
$args
{
'column_names'
}) {
$dbh
= DBI->
connect
(
"dbi:CSV:db_name=$slurp_file"
,
undef
,
undef
,
{
csv_sep_char
=>
$sep_char
,
csv_tables
=> {
$table
=> {
col_names
=>
$args
{
'column_names'
},
},
},
}
);
}
else
{
$dbh
= DBI->
connect
(
"dbi:CSV:db_name=$slurp_file"
,
undef
,
undef
, {
csv_sep_char
=>
$sep_char
});
}
$dbh
->{
'RaiseError'
} = 1;
$self
->_debug(
"read in $table from CSV $slurp_file"
);
$dbh
->{csv_tables}->{
$table
} = {
allow_loose_quotes
=> 1,
blank_is_undef
=> 1,
empty_is_undef
=> 1,
binary
=> 1,
f_file
=>
$slurp_file
,
escape_char
=>
'\\'
,
sep_char
=>
$sep_char
,
auto_diag
=> 0,
};
if
(((-s
$slurp_file
) <=
$self
->{
'max_slurp_size'
}) && !
$args
{
'column_names'
}) {
if
((-s
$slurp_file
) == 0) {
$self
->{
'data'
} = {};
}
else
{
Text::xSV::Slurp->
import
();
$self
->_trace(
'slurp in'
);
my
@data
= @{xsv_slurp(
shape
=>
'aoh'
,
text_csv
=> {
sep_char
=>
$sep_char
,
allow_loose_quotes
=> 1,
blank_is_undef
=> 1,
empty_is_undef
=> 1,
binary
=> 1,
escape_char
=>
'\\'
,
},
file
=>
$slurp_file
)};
if
(
$self
->{
'no_entry'
}) {
my
$i
= 0;
$self
->{
'data'
} = ();
foreach
my
$d
(
@data
) {
$self
->{
'data'
}[
$i
++] =
$d
;
}
}
else
{
@data
=
grep
{
$_
->{
$self
->{
'id'
}} !~ /^\s*
foreach
my
$d
(
@data
) {
$self
->{
'data'
}->{
$d
->{
$self
->{
'id'
}}} =
$d
;
}
}
}
}
$self
->{
'type'
} =
'CSV'
;
}
else
{
$slurp_file
= File::Spec->catfile(
$dir
,
"$dbname.xml"
);
if
(-r
$slurp_file
) {
if
((-s
$slurp_file
) <=
$self
->{
'max_slurp_size'
}) {
XML::Simple->
import
();
my
$xml
= XMLin(
$slurp_file
);
my
@keys
=
keys
%{
$xml
};
my
$key
=
$keys
[0];
my
@data
;
if
(
ref
(
$xml
->{
$key
}) eq
'ARRAY'
) {
@data
= @{
$xml
->{
$key
}};
}
else
{
@data
= @{
$xml
};
}
$self
->{
'data'
} = ();
if
(
$self
->{
'no_entry'
}) {
my
$i
= 0;
foreach
my
$d
(
@data
) {
$self
->{
'data'
}->{
$i
++} =
$d
;
}
}
else
{
foreach
my
$d
(
@data
) {
$self
->{
'data'
}->{
$d
->{
$self
->{
'id'
}}} =
$d
;
}
}
}
else
{
$dbh
= DBI->
connect
(
'dbi:XMLSimple(RaiseError=>1):'
);
$dbh
->{
'RaiseError'
} = 1;
$self
->_debug(
"read in $table from XML $slurp_file"
);
$dbh
->func(
$table
,
'XML'
,
$slurp_file
,
'xmlsimple_import'
);
}
}
else
{
Carp::croak(
"Can't find a $dbname file for the table $table in $dir"
);
}
$self
->{
'type'
} =
'XML'
;
}
}
$self
->{
$table
} =
$dbh
;
my
@statb
=
stat
(
$slurp_file
);
$self
->{
'_updated'
} =
$statb
[9];
return
$self
;
}
sub
selectall_hashref {
my
$self
=
shift
;
my
@rc
=
$self
->selectall_hash(
@_
);
return
\
@rc
;
}
sub
selectall_hash
{
my
$self
=
shift
;
my
$params
=
$self
->_get_params(
undef
,
@_
);
my
$table
=
$self
->{table} ||
ref
(
$self
);
$table
=~ s/.*:://;
$self
->_open()
if
((!
$self
->{
$table
}) && (!
$self
->{
'data'
}));
if
(
$self
->{
'data'
}) {
if
(
scalar
(
keys
%{
$params
}) == 0) {
$self
->_trace(
"$table: selectall_hash fast track return"
);
if
(
ref
(
$self
->{
'data'
}) eq
'HASH'
) {
return
values
%{
$self
->{
'data'
}};
}
return
@{
$self
->{
'data'
}};
}
elsif
((
scalar
(
keys
%{
$params
}) == 1) &&
defined
(
$params
->{
'entry'
}) && !
$self
->{
'no_entry'
}) {
return
$self
->{
'data'
}->{
$params
->{
'entry'
}};
}
}
my
$query
;
my
$done_where
= 0;
if
((
$self
->{
'type'
} eq
'CSV'
) && !
$self
->{no_entry}) {
$query
=
"SELECT * FROM $table WHERE entry IS NOT NULL AND entry NOT LIKE '#%'"
;
$done_where
= 1;
}
else
{
$query
=
"SELECT * FROM $table"
;
}
my
@query_args
;
foreach
my
$c1
(
sort
keys
(%{
$params
})) {
my
$arg
=
$params
->{
$c1
};
if
(
ref
(
$arg
)) {
$self
->_fatal(
"selectall_hash $query: argument is not a string"
);
croak(
"$query: argument is not a string: "
,
ref
(
$arg
));
}
if
(!
defined
(
$arg
)) {
my
@call_details
=
caller
(0);
Carp::croak(
"$query: value for $c1 is not defined in call from "
,
$call_details
[2],
' of '
,
$call_details
[1]);
}
my
$keyword
;
if
(
$done_where
) {
$keyword
=
'AND'
;
}
else
{
$keyword
=
'WHERE'
;
$done_where
= 1;
}
if
(
$arg
=~ /\@/) {
$query
.=
" $keyword $c1 LIKE ?"
;
}
else
{
$query
.=
" $keyword $c1 = ?"
;
}
push
@query_args
,
$arg
;
}
if
(!
$self
->{no_entry}) {
$query
.=
' ORDER BY '
.
$self
->{
'id'
};
}
if
(!
wantarray
) {
$query
.=
' LIMIT 1'
;
}
if
(
defined
(
$query_args
[0])) {
$self
->_debug(
"selectall_hash $query: "
,
join
(
', '
,
@query_args
));
}
else
{
$self
->_debug(
"selectall_hash $query"
);
}
my
$key
;
my
$c
;
if
(
$c
=
$self
->{cache}) {
$key
=
$query
;
if
(
wantarray
) {
$key
.=
' array'
;
}
if
(
defined
(
$query_args
[0])) {
$key
.=
' '
.
join
(
', '
,
@query_args
);
}
if
(
my
$rc
=
$c
->get(
$key
)) {
$self
->_debug(
'cache HIT'
);
return
@{
$rc
};
}
$self
->_debug(
'cache MISS'
);
}
else
{
$self
->_debug(
'cache not used'
);
}
if
(
my
$sth
=
$self
->{
$table
}->prepare(
$query
)) {
$sth
->execute(
@query_args
) ||
croak(
"$query: @query_args"
);
my
@rc
;
while
(
my
$href
=
$sth
->fetchrow_hashref()) {
return
$href
if
(!
wantarray
);
push
@rc
,
$href
;
}
if
(
$c
&&
wantarray
) {
$c
->set(
$key
, \
@rc
,
$self
->{
'cache_duration'
});
}
return
@rc
;
}
$self
->_warn(
"selectall_hash failure on $query: @query_args"
);
croak(
"$query: @query_args"
);
}
sub
fetchrow_hashref {
my
$self
=
shift
;
my
$params
;
if
(!
$self
->{
'no_entry'
}) {
$params
=
$self
->_get_params(
'entry'
,
@_
);
}
else
{
$params
=
$self
->_get_params(
undef
,
@_
);
}
my
$table
=
$params
->{
'table'
} ||
$self
->{
'table'
} ||
ref
(
$self
);
$table
=~ s/.*:://;
if
(
$self
->{
'data'
} && (!
$self
->{
'no_entry'
}) && (
scalar
keys
(%{
$params
}) == 1) &&
defined
(
$params
->{
'entry'
})) {
$self
->_debug(
'Fast return from slurped data'
);
return
$self
->{
'data'
}->{
$params
->{
'entry'
}};
}
my
$query
=
'SELECT * FROM '
;
if
(
my
$t
=
delete
$params
->{
'table'
}) {
$query
.=
$t
;
}
else
{
$query
.=
$table
;
}
my
$done_where
= 0;
$self
->_open()
if
(!
$self
->{
$table
});
if
((
$self
->{
'type'
} eq
'CSV'
) && !
$self
->{no_entry}) {
$query
.=
' WHERE '
.
$self
->{
'id'
} .
' IS NOT NULL AND '
.
$self
->{
'id'
} .
" NOT LIKE '#%'"
;
$done_where
= 1;
}
my
@query_args
;
foreach
my
$c1
(
sort
keys
(%{
$params
})) {
if
(
my
$arg
=
$params
->{
$c1
}) {
my
$keyword
;
if
(
ref
(
$arg
)) {
$self
->_fatal(
"selectall_hash $query: argument is not a string"
);
croak(
"$query: argument is not a string: "
,
ref
(
$arg
));
}
if
(
$done_where
) {
$keyword
=
'AND'
;
}
else
{
$keyword
=
'WHERE'
;
$done_where
= 1;
}
if
(
$arg
=~ /\@/) {
$query
.=
" $keyword $c1 LIKE ?"
;
}
else
{
$query
.=
" $keyword $c1 = ?"
;
}
push
@query_args
,
$arg
;
}
elsif
(!
defined
(
$arg
)) {
my
@call_details
=
caller
(0);
Carp::croak(
"$query: value for $c1 is not defined in call from "
,
$call_details
[2],
' of '
,
$call_details
[1]);
}
}
$query
.=
' LIMIT 1'
;
if
(
defined
(
$query_args
[0])) {
my
@call_details
=
caller
(0);
$self
->_debug(
"fetchrow_hashref $query: "
,
join
(
', '
,
@query_args
),
' called from '
,
$call_details
[2],
' of '
,
$call_details
[1]);
}
else
{
$self
->_debug(
"fetchrow_hashref $query"
);
}
my
$key
;
if
(
defined
(
$query_args
[0])) {
if
(
wantarray
) {
$key
=
'array '
;
}
$key
=
"fetchrow $query "
.
join
(
', '
,
@query_args
);
}
else
{
$key
=
"fetchrow $query"
;
}
my
$c
;
if
(
$c
=
$self
->{cache}) {
if
(
my
$rc
=
$c
->get(
$key
)) {
if
(
wantarray
) {
return
@{
$rc
};
}
return
$rc
;
}
}
my
$sth
=
$self
->{
$table
}->prepare(
$query
) or
die
$self
->{
$table
}->errstr();
$sth
->execute(
@query_args
) || croak(
"$query: @query_args"
);
my
$rc
=
$sth
->fetchrow_hashref();
if
(
$c
) {
if
(
$rc
) {
$self
->_debug(
"stash $key=>$rc in the cache for "
,
$self
->{
'cache_duration'
});
$self
->_debug(
"returns "
, Data::Dumper->new([
$rc
])->Dump());
}
else
{
$self
->_debug(
"Stash $key=>undef in the cache for "
,
$self
->{
'cache_duration'
});
}
$c
->set(
$key
,
$rc
,
$self
->{
'cache_duration'
});
}
return
$rc
;
}
sub
execute
{
my
$self
=
shift
;
my
$args
=
$self
->_get_params(
'query'
,
@_
);
Carp::croak(__PACKAGE__,
': Usage: execute(query => $query)'
)
unless
defined
$args
->{
'query'
};
my
$table
=
$self
->{table} ||
ref
(
$self
);
$table
=~ s/.*:://;
$self
->_open()
unless
$self
->{
$table
};
my
$query
=
$args
->{
'query'
};
$query
.=
" FROM $table"
unless
$query
=~ /\sFROM\s/i;
$self
->_debug(
"execute $query"
);
my
$sth
=
$self
->{
$table
}->prepare(
$query
);
$sth
->execute() or croak(
$query
);
my
@results
;
while
(
my
$row
=
$sth
->fetchrow_hashref()) {
return
$row
unless
wantarray
;
push
@results
,
$row
;
}
return
@results
;
}
sub
updated {
my
$self
=
shift
;
return
$self
->{
'_updated'
};
}
sub
AUTOLOAD {
our
$AUTOLOAD
;
my
(
$column
) =
$AUTOLOAD
=~ /::(\w+)$/;
return
if
(
$column
eq
'DESTROY'
);
my
$self
=
shift
or
return
;
my
$table
=
$self
->{table} ||
ref
(
$self
);
$table
=~ s/.*:://;
my
%params
;
if
(
ref
(
$_
[0]) eq
'HASH'
) {
%params
= %{
$_
[0]};
}
elsif
((
scalar
(
@_
) % 2) == 0) {
%params
=
@_
;
}
elsif
(
scalar
(
@_
) == 1) {
if
(
$self
->{
'no_entry'
}) {
Carp::croak(
ref
(
$self
),
"::($_[0]): "
,
$self
->{
'id'
},
' is not a column'
);
}
$params
{
'entry'
} =
shift
;
}
$self
->_open()
if
(!
$self
->{
$table
});
my
$query
;
my
$done_where
= 0;
my
$distinct
=
delete
(
$params
{
'distinct'
}) ||
delete
(
$params
{
'unique'
});
if
(
wantarray
&& !
$distinct
) {
if
(((
scalar
keys
%params
) == 0) && (
my
$data
=
$self
->{
'data'
})) {
return
map
{
$_
->{
$column
} }
values
%{
$data
};
}
if
((
$self
->{
'type'
} eq
'CSV'
) && !
$self
->{no_entry}) {
$query
=
"SELECT $column FROM $table WHERE "
.
$self
->{
'id'
} .
" IS NOT NULL AND entry NOT LIKE '#%'"
;
$done_where
= 1;
}
else
{
$query
=
"SELECT $column FROM $table"
;
}
}
else
{
if
(
my
$data
=
$self
->{
'data'
}) {
$self
->_debug(
'AUTOLOAD using slurped data'
);
if
(
$self
->{
'no_entry'
}) {
$self
->_debug(
'no_entry is set'
);
my
(
$key
,
$value
) =
%params
;
if
(
defined
(
$key
)) {
$self
->_debug(
"key = $key, value = $value, column = $column"
);
foreach
my
$row
(@{
$data
}) {
if
(
defined
(
$row
->{
$key
}) && (
$row
->{
$key
} eq
$value
) && (
my
$rc
=
$row
->{
$column
})) {
if
(
defined
(
$rc
)) {
$self
->_trace(__LINE__,
": AUTOLOAD $key: return '$rc' from slurped data"
);
}
else
{
$self
->_trace(__LINE__,
": AUTOLOAD $key: return undef from slurped data"
);
}
return
$rc
}
}
$self
->_debug(
'not found in slurped data'
);
}
}
elsif
(((
scalar
keys
%params
) == 1) &&
defined
(
my
$key
=
$params
{
'entry'
})) {
my
$rc
;
if
(
defined
(
my
$hash
=
$data
->{
$key
})) {
if
(!
exists
(
$hash
->{
$column
})) {
Carp::croak(__PACKAGE__,
": There is no column $column in $table"
);
}
$rc
=
$hash
->{
$column
};
}
if
(
defined
(
$rc
)) {
$self
->_trace(__LINE__,
": AUTOLOAD $key: return '$rc' from slurped data"
);
}
else
{
$self
->_trace(__LINE__,
": AUTOLOAD $key: return undef from slurped data"
);
}
return
$rc
}
elsif
((
scalar
keys
%params
) == 0) {
if
(
wantarray
) {
if
(
$distinct
) {
my
%h
=
map
{
$_
, 1 }
map
{
$_
->{
$column
} }
values
%{
$data
};
return
keys
%h
;
}
return
map
{
$_
->{
$column
} }
values
%{
$data
}
}
foreach
my
$v
(
values
%{
$data
}) {
return
$v
->{
$column
}
}
}
else
{
my
(
$key
,
$value
) =
%params
;
foreach
my
$row
(
values
%{
$data
}) {
if
(
defined
(
$row
->{
$key
}) && (
$row
->{
$key
} eq
$value
) && (
my
$rc
=
$row
->{
$column
})) {
if
(
defined
(
$rc
)) {
$self
->_trace(__LINE__,
": AUTOLOAD $key: return '$rc' from slurped data"
);
}
else
{
$self
->_trace(__LINE__,
": AUTOLOAD $key: return undef from slurped data"
);
}
return
$rc
}
}
}
return
}
if
((
$self
->{
'type'
} eq
'CSV'
) && !
$self
->{no_entry}) {
$query
=
"SELECT DISTINCT $column FROM $table WHERE "
.
$self
->{
'id'
} .
" IS NOT NULL AND entry NOT LIKE '#%'"
;
$done_where
= 1;
}
else
{
$query
=
"SELECT DISTINCT $column FROM $table"
;
}
}
my
@args
;
while
(
my
(
$key
,
$value
) =
each
%params
) {
$self
->_debug(__PACKAGE__,
": AUTOLOAD adding key/value pair $key=>$value"
);
if
(
defined
(
$value
)) {
if
(
$done_where
) {
$query
.=
" AND $key = ?"
;
}
else
{
$query
.=
" WHERE $key = ?"
;
$done_where
= 1;
}
push
@args
,
$value
;
}
else
{
$self
->_debug(
"AUTOLOAD params $key isn't defined"
);
if
(
$done_where
) {
$query
.=
" AND $key IS NULL"
;
}
else
{
$query
.=
" WHERE $key IS NULL"
;
$done_where
= 1;
}
}
}
if
(
wantarray
) {
$query
.=
" ORDER BY $column"
;
}
else
{
$query
.=
' LIMIT 1'
;
}
if
(
scalar
(
@args
) &&
$args
[0]) {
$self
->_debug(
"AUTOLOAD $query: "
,
join
(
', '
,
@args
));
}
else
{
$self
->_debug(
"AUTOLOAD $query"
);
}
my
$cache
;
my
$key
;
if
(
$cache
=
$self
->{cache}) {
if
(
wantarray
) {
$key
=
'array '
;
}
if
(
defined
(
$args
[0])) {
$key
=
"fetchrow $query "
.
join
(
', '
,
@args
);
}
else
{
$key
=
"fetchrow $query"
;
}
if
(
my
$rc
=
$cache
->get(
$key
)) {
$self
->_debug(
'cache HIT'
);
if
(
wantarray
) {
return
@{
$rc
};
}
return
$rc
;
}
$self
->_debug(
'cache MISS'
);
}
else
{
$self
->_debug(
'cache not used'
);
}
my
$sth
=
$self
->{
$table
}->prepare(
$query
) || croak(
$query
);
$sth
->execute(
@args
) || croak(
$query
);
if
(
wantarray
) {
my
@rc
=
map
{
$_
->[0] } @{
$sth
->fetchall_arrayref()};
if
(
$cache
) {
$cache
->set(
$key
, \
@rc
,
$self
->{
'cache_duration'
});
}
return
@rc
;
}
my
$rc
=
$sth
->fetchrow_array();
if
(
$cache
) {
return
$cache
->set(
$key
,
$rc
,
$self
->{
'cache_duration'
});
}
return
$rc
;
}
sub
DESTROY {
if
(
defined
($^V) && ($^V ge
'v5.14.0'
)) {
return
if
${^GLOBAL_PHASE} eq
'DESTRUCT'
;
}
my
$self
=
shift
;
if
(
$self
->{
'temp'
}) {
unlink
delete
$self
->{
'temp'
};
}
if
(
my
$table
=
delete
$self
->{
'table'
}) {
$table
->finish();
}
}
sub
_log
{
my
(
$self
,
$level
,
@messages
) =
@_
;
if
(
my
$logger
=
$self
->{
'logger'
}) {
if
(
ref
(
$logger
) eq
'CODE'
) {
$logger
->({
class
=>
ref
(
$self
) // __PACKAGE__,
function
=> (
caller
(2))[3],
line
=> (
caller
(1))[2],
level
=>
$level
,
message
=> \
@messages
});
}
elsif
(!
ref
(
$logger
)) {
if
(
open
(
my
$fout
,
'>>'
,
$logger
)) {
print
$fout
uc
(
$level
),
': '
,
ref
(
$self
) // __PACKAGE__,
' '
, (
caller
(2))[3], (
caller
(1))[2],
join
(
' '
,
@messages
),
"\n"
;
close
$fout
;
}
}
else
{
$logger
->
$level
(
@messages
);
}
}
}
sub
_fatal {
my
$self
=
shift
;
$self
->_log(
'fatal'
,
@_
);
}
sub
_trace {
my
$self
=
shift
;
$self
->_log(
'trace'
,
@_
);
}
sub
_debug {
my
$self
=
shift
;
$self
->_log(
'debug'
,
@_
);
}
sub
_get_params
{
shift
;
my
$default
=
shift
;
return
$_
[0]
if
(
ref
$_
[0] eq
'HASH'
);
my
%rc
;
my
$num_args
=
scalar
@_
;
if
((
$num_args
== 1) && (
defined
$default
)) {
return
{
$default
=>
shift
};
}
elsif
(
$num_args
== 1) {
Carp::croak(
'Usage: '
, __PACKAGE__,
'->'
, (
caller
(1))[3],
'()'
);
}
elsif
((
$num_args
== 0) && (
defined
(
$default
))) {
Carp::croak(
'Usage: '
, __PACKAGE__,
'->'
, (
caller
(1))[3],
"($default => \$val)"
);
}
elsif
((
$num_args
% 2) == 0) {
%rc
=
@_
;
}
elsif
(
$num_args
== 0) {
return
;
}
else
{
Carp::croak(
'Usage: '
, __PACKAGE__,
'->'
, (
caller
(1))[3],
'()'
);
}
return
\
%rc
;
}
1;