package LIMS::Model::Roles::DBIxSimple; use Moose::Role; has params => ( is => 'rw', isa => 'HashRef', default => sub { {} } ); has constraints => ( is => 'ro', isa => 'ArrayRef[Str]', traits => ['Array'], default => sub { [] }, handles => { all_constraints => 'elements', # array accessor add_constraint => 'push', }, ); has constraint_title => ( is => 'rw', isa => 'Str' ); # for chart & template titles use DateTime::Format::MySQL; # requires 'lims_dbix'; # LIMS::Model::Base method use Data::Dumper; sub get_cols { my ($self, $table) = @_; my $dbh = $self->lims_dbix; my $meta = $self->get_meta($table); # warn Dumper $meta; my @cols = keys %$meta; # warn Dumper \@cols; return \@cols; } sub get_meta { my ($self, $table) = @_; my $dbh = $self->lims_dbix; my $t = $dbh->query("show columns from $table")->hashes; # warn Dumper $t; my %meta = map { $_->{field} => $_ } @$t; # warn Dumper \%meta; return \%meta; } sub get_enum_opts { my ($self, $table, $col) = @_; my $meta = $self->get_meta($table); my $col_type = $meta->{$col}->{type}; my ($enum) = $col_type =~ /enum\((.*)\)/; # warn $enum; my @opts = sort grep { $_ =~ s/\'//g } split ',', $enum; # warn Dumper \@opts; return \@opts; } sub inflate_mysql_dates_to_datetime { my $self = shift; my $data = shift; # hashref my $cols = shift; # array(ref) of cols to inflate map { $data->{$_} = DateTime::Format::MySQL->parse_date($data->{$_}); } grep $data->{$_}, @$cols; } sub inflate_mysql_timestamp_to_datetime { my $self = shift; my $data = shift; # hashref my $cols = shift; # array(ref) of cols to inflate map { $data->{$_} = DateTime::Format::MySQL->parse_datetime($data->{$_}); } grep $data->{$_}, @$cols; } sub get_sql_with_constraint { my $self = shift; my $entry = shift; # sql lib entry my $time_column = shift; # to set duration on my $default_constraint_type = shift || ''; # optional - to override return # set constraint & constraint_title params: $self->_set_search_constraints($time_column, $default_constraint_type); my $constraint = join ' AND ', $self->all_constraints; # list format my $sql = $self->sql_lib->retr($entry); $sql =~ s/%CONSTRAINT%/$constraint/; # warn $sql; return $sql; } =begin my $type = $vars->{constraint_type}; my $method = "_build_${type}_sql"; my $sql = $self->$method($vars); and have sub _build_lastyear_sql { ... } and such you'll always have a constraint_type and you can dispatch by that, e.g. simply use it to call a method named "handle_${constraint_type}_query" the nice thing about dispatching to different methods per constraint type means you can do things like put them into reusable roles and such =cut # sets __PACKAGE__->constraint & __PACKAGE__constraint_title: sub _set_search_constraints { my $self = shift; my $time_column = shift; # warn $time_column; my $default_constraint_type = shift || ''; # optional - to override return my $vars = $self->params; # warn Dumper $vars; my $constraint_type # undef on 1st call, unless default set in model method = $vars->{constraint_type} || $default_constraint_type || ''; my ($constraint, $title); # for checkboxes it's safe to examine $constraint_type, for textboxes & # selects, need to test for defined query param as it's possible to submit an # empty field, where constraint_type is defined but equivalent param is undef if ( $constraint_type eq 'all_data' ) { $constraint = qq!year($time_column) IS NOT NULL!; # ie everything $title = 'all requests'; } elsif ( $constraint_type eq 'this_year' ) { my $this_year = DateTime->now->year; $constraint = qq!year($time_column) = $this_year!; $title = 'year ' . $this_year; } elsif ( $constraint_type eq 'one_month' ) { $constraint = qq!$time_column between date_sub(curdate(), interval 1 month) and curdate()!; $title = 'last 1 month'; } elsif ( $constraint_type eq 'year_since' && $vars->{year} ) { # check var sent $constraint = qq!year($time_column) >= $vars->{year}!; $title = 'all from ' . $vars->{year}; } # textboxes & select fields: elsif ( my $days = $vars->{days} ) { # $constraint_type eq 'days' $constraint = qq!$time_column between date_sub(curdate(), interval $days day) and curdate()!; $title = 'previous ' . $days . ' days'; } elsif ( my $year = $vars->{year} ) { # $constraint_type eq 'year' $constraint = qq!year($time_column) = $year!; $title = 'year ' . $vars->{year}; } # need both 'from' & 'to' dates: elsif ( $vars->{date_from} && $vars->{date_to} ) { # $constraint_type eq 'date_range' # NB: silently fails if date is invalid: my $start_date = LIMS::Local::Utils::date_to_mysql($vars->{date_from}); my $end_date = LIMS::Local::Utils::date_to_mysql($vars->{date_to}); # need to ensure no date conversion error: if ($start_date && $end_date) { $constraint = qq!$time_column between '$start_date' and '$end_date'!; $title = 'between ' . $vars->{date_from} . ' & ' . $vars->{date_to}; } } # set default to previous calendar year if no form constraint or invalid date: $constraint ||= qq!$time_column between date_sub(curdate(), interval 1 year) and curdate()!; $title ||= 'last 365 days'; # set package accessors: $self->add_constraint($constraint); $self->constraint_title($title); } 1;