The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
#
# This file is part of DBIx-RoboQuery
#
# This software is copyright (c) 2010 by Randy Stauner.
#
# This is free software; you can redistribute it and/or modify it under
# the same terms as the Perl 5 programming language system itself.
#
use strict;
use warnings;

package DBIx::RoboQuery::Util;
{
  $DBIx::RoboQuery::Util::VERSION = '0.032';
}
BEGIN {
  $DBIx::RoboQuery::Util::AUTHORITY = 'cpan:RWSTAUNER';
}
# ABSTRACT: Utility functions for DBIx::RoboQuery

# convenience function used in both modules
# to convert specific hash items to arrayrefs

sub _ensure_arrayrefs {
  my ($hash, @keys) = @_;

  # if no keys were provided, use the defaults
  @keys = $hash->_arrayref_args
    if !@keys;

  foreach my $key ( @keys ){
    if( exists $hash->{$key} ){
      $hash->{$key} = [$hash->{$key}]
        unless ref($hash->{$key}) eq 'ARRAY';
    }
  }
}

# flatten any arrayrefs and return a single list

sub _flatten {
  return map { ref $_ ? @$_ : $_ } @_;
}


sub order_from_sql {
  my ($sql, $opts) = @_;
  # TODO: consider including /|LIMIT \d+/ in suffix unless 'no_limit' provided
  $opts ||= {};

  my $suffix = $opts->{suffix}
    # don't inherit /x from the parent re below
    ? qr/(?-x:$opts->{suffix})?/
    # nothing
    : qr//;

  return
  $sql =~ /\bORDER\s+BY\s+         # start order by clause
    (                            # start capture
      (?:\w+)                  # first column
      (?:\s+(?:ASC|DESC))?     # direction
      (?:\s*,\s*               # comma, possibly spaced
        (?:\w+)              # next column
        (?:\s+(?:ASC|DESC))? # direction
      )*                       # repeat
    )\s*                         # end capture
    $suffix                      # possible query suffix
    \s*;?\s*\Z                   # end of SQL
  /isx
    # ignore direction
    ## no critic ProhibitMutatingListFunctions
    ? map { s/\s+(ASC|DESC)$//; $_ } split(/\s*,\s*/, $1)
    : ();
}

1;

__END__

=pod

=encoding utf-8

=for :stopwords Randy Stauner ACKNOWLEDGEMENTS dbh sql resultset ASC DESC

=head1 NAME

DBIx::RoboQuery::Util - Utility functions for DBIx::RoboQuery

=head1 VERSION

version 0.032

=head1 SYNOPSIS

  use DBIx::RoboQuery::Util ();

=head1 DESCRIPTION

A collection of utility functions for L<DBIx::RoboQuery>.

=head1 FUNCTIONS

=head2 order_from_sql

  # returns qw(fld1)
  @order = order_from_sql("SELECT * FROM table ORDER BY fld1");

  # returns qw(fld1 fld2)
  @order = order_from_sql(
    "SELECT * FROM table ORDER BY fld1 DESC, fld2 FETCH 2 ROWS",
    {suffix => 'FETCH 2 ROWS'}
  );
    # suffix can also be an re: qr/FETCH \d+ ROWS/

Return a list of the column names that make up the sort order
based on the C<ORDER BY> clause of a SQL statement.

Options can be specified in a hashref:

=over 4

=item *

C<suffix>

A string of sql (or a regular expression compiled with qr//)
that follows the C<ORDER BY> clause;
Often C<ORDER BY> is the last clause of the statement.
To anchor the regular expression used to find the ORDER BY clause
to the end of the string,
specify a string or regexp that follows the ORDER BY clause
and completes the statement.

=back

Other modules that could be used instead:

=over 4

=item *

L<SQL::Statement>

=item *

L<SQL::OrderBy>

=back

Currently a flat list of column names is returned.
(Any direction (C<ASC> or C<DESC>) is dropped.)

=head1 EXPORTS

None.
The functions in this module are not intended for public
consumption.

=head1 AUTHOR

Randy Stauner <rwstauner@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2010 by Randy Stauner.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut