The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use 5.010;

package FusqlFS::Backend::MySQL::Table::Indices;
use FusqlFS::Version;
our $VERSION = $FusqlFS::Version::VERSION;
use parent 'FusqlFS::Artifact::Table::Lazy';

=head1 NAME

FusqlFS::Backend::MySQL::Table::Indices - 

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 EXPOSED STRUCTURE

=cut

sub init
{
    my $self = shift;
    $self->{template} = { '.order' => [] };
}

sub list
{
    my $self = shift;
    my ($table) = @_;
    my $data = $self->all_row('SHOW INDEX FROM `%s`', [$table]);
    return unless $data;

    my %keys = map { $_->{Key_name} => 1 } @$data;
    return [ keys %keys, @{$self->SUPER::list($table)} ];
}

sub get
{
    my $self = shift;
    my ($table, $name) = @_;
    unless ($self->SUPER::get($table, $name))
    {
        my $data = $self->all_row('SHOW INDEX FROM `%s` WHERE `Key_name` = ?', [$table], $name);
        return unless $data && @$data;

        my $result = { '.order' => [] };
        foreach my $item (@$data)
        {
            my $colname = $item->{Sub_part}? $self->ajoin($item->{Column_name}, $item->{Sub_part}): $item->{Column_name};
            push @{$result->{'.order'}}, $item->{Column_name};

            $result->{$colname}   = \"tables/$table/struct/$item->{Column_name}";
            $result->{'.unique'}  = 1 unless $item->{Non_unique};
            $result->{'.type'}    = $item->{Index_type};
            $result->{'.primary'} = 1 if $item->{Key_name} =~ /^PRI/;
        }

        return $result;
    }
}

sub rename
{
    my $self = shift;
    my ($table, $name, $newname) = @_;
    my $data = $self->get($table, $name) or return;
    $self->SUPER::rename($table, $name, $newname) or
        $self->drop($table, $name) and $self->store($table, $newname, $data);
}

sub drop
{
    my $self = shift;
    my ($table, $name) = @_;
    $self->SUPER::drop($table, $name) or $self->do('ALTER TABLE `%s` DROP INDEX `%s`', [$table, $name]);
}

sub store
{
    my $self = shift;
    my ($table, $name, $data) = @_;
    my $struct = $self->validate($data, {
        '-.primary' => '',
        '-.unique'  => '',
        '-.type'    => '',
        '.order'    => 'ARRAY',
    }, sub{
        my %columns = map { $self->asplit($_, 2) } grep !/^[.]/, keys %{$_[0]};
        my @order   = grep { exists $columns{$_} } @{$_->{'.order'}};

        my %order = map { $_ => 1 } @order;
        foreach (keys %columns)
        {
            push @order, $_ unless exists $order{$_};
        }
        my $columns = join(',', map {
            my $colname = "`$_`";
            $colname .= "($columns{$_})" if $columns{$_};
            $colname;
        } @order);
        $_->{'columns'} = $columns;
    }) or return;

    $self->drop($table, $name) and $self->do('ALTER TABLE `%s` ADD %s KEY %s %s (%s)',
    [
        $table,
        $struct->{'.primary'}? 'PRIMARY': ($struct->{'.unique'}? 'UNIQUE': ''),
        $struct->{'.primary'}? '': "`$name`",
        $struct->{'.type'}? 'USING '.$struct->{'.type'}: '',
        $struct->{'columns'},
    ]);
}

1;