RSS Git Download  Clone
Raw Blame History
package Local::DBIx::Simple::Result;

# patched hash() and array() to auto_inflate dates and return in DBIx::Simple
# default scalar (href), or in list context using wantarray()

BEGIN { # fix for DBIx::Simple::Result being in same file as DBIx::Simple & not in @INC:
    require DBIx::Simple;
    $INC{'DBIx/Simple/Result.pm'} = $INC{'DBIx/Simple.pm'};
}

use parent 'DBIx::Simple::Result';

use Scalar::Util qw(looks_like_number);
use DateTime::Format::MySQL;
use Data::Printer alias => 'ddp';
use Data::Dumper;

our $NO_AUTO_DATE_INFLATION; # to suppress auto-date-inflation in caller class

# returns hash or hashref (DBIx::Simple only returns hashref):
sub hash { # warn $NO_AUTO_DATE_INFLATION; # set in calling class if required
    my $self = shift;
    my $href = $self->SUPER::hash(@_); # p $href;
    $self->_autoinflate_dates($href) unless $NO_AUTO_DATE_INFLATION;
    return wantarray ? %$href : $href;
}

# returns array or arrayref (DBIx::Simple only returns arrayref):
sub array {
    my $self = shift;
    my $aref = $self->SUPER::array(@_);
	$self->_autoinflate_dates($aref) unless $NO_AUTO_DATE_INFLATION;
    return wantarray ? @$aref : $aref; 
}

sub _autoinflate_dates {
    my ($self, $data) = @_; # ddp $self; ddp $data;

    my $re = qr!\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?!;

    # uses date(time) regex to determine whether value is a date (ie pattern not col def):
    my $to_datetime = sub {
        my $val = shift || return; # ddp $val;
        if ( my ($date) = $val =~ m!\A($re)\Z! ) {
            $val = length $date > 10 # ie date + time
                ? DateTime::Format::MySQL->parse_datetime($date)
                : DateTime::Format::MySQL->parse_date($date);
        } # warn Dumper $val; ddp stringifies DT object
        return $val;
    };

=begin # alternative method using column data-type (doesn't work for Reporter):
    my $col_types = $self->col_types; # ddp $col_types;

    my $to_datetime = sub {
        my $val = shift || return; # ddp $val;
        return
            lc $col_types->{$val} eq 'timestamp'
                ? DateTime::Format::MySQL->parse_timestamp($val)
                : lc $col_types->{$val} eq 'datetime'
                    ? DateTime::Format::MySQL->parse_datetime($val)
                    : lc $col_types->{$val} eq 'date'
                        ? DateTime::Format::MySQL->parse_date($val)
                        : $val;
    };
=cut
	if ( ref $data eq 'HASH' ) {
		$data->{$_} = &$to_datetime($data->{$_}) for keys %$data; # ddp $data;
	}
	elsif ( ref $data eq 'ARRAY' ) { # ddp $data;
		$_ = &$to_datetime($_) for @$data;
	}
    return $data;
}

sub col_types {
    my $self = shift;

    # decode for MySQL column TYPE (integers):
    my %type_map = (
         1 => 'enum',
         4 => 'integer',
         9 => 'date',
        11 => 'datetime',
        12 => 'varchar',
    );

    my @names = @{ $self->attr('NAME') };  ddp @names;
    my @types = @{ $self->attr('TYPE') };  ddp @types;

    my %h;
    # sqlite returns types as VARCHAR, DATE, etc, MySQL returns integers:
    @h{@names} = ( grep looks_like_number($_), @types )
        ? map $type_map{$_}, @types
        : @types;  ddp %h;
    return \%h;
}

1;