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::Artifact::Table::Data;
use FusqlFS::Version;
our $VERSION = $FusqlFS::Version::VERSION;
use parent 'FusqlFS::Artifact';

sub init
{
    my $self = shift;

    $self->{query_cache} = {};
    $self->{field_quote} = '"';
}

sub list
{
    my $self = shift;
    my ($table) = @_;
    my @primary_key = $self->get_key_fields($table);
    return undef unless @primary_key;

    my $sth = $self->cexpr('SELECT %s FROM %s %s', $self->concat(@primary_key), $self->{field_quote}.$table.$self->{field_quote}, $self->limit);
    return $self->all_col($sth)||[];
}

sub where_clause
{
    my $self = shift;
    my ($table, $name) = @_;
    my @binds = $self->asplit($name);
    my @primary_key = $self->get_key_fields($table);
    return unless @primary_key && $#primary_key == $#binds;

    return $self->pairs(' AND ', @primary_key), @binds;
}

=item pairs

Composes fields into pairs, suitable for UPDATE query or the like.

Input: $glue, @fields.
Output: $sql_clause.

=cut
sub pairs
{
    my ($self, $glue, @fields) = @_;
    my $q = $self->{field_quote};
    return join($glue, map { "$q$_$q = ?" } @fields);
}

sub get
{
    my $self = shift;
    my ($table, $name) = @_;
    my ($where_clause, @binds) = $self->where_clause($table, $name);
    my $qtable = $self->{field_quote}.$table.$self->{field_quote};
    return unless $where_clause || @binds;

    $self->{query_cache}->{$table} ||= {};
    $self->{query_cache}->{$table}->{$where_clause} ||= $where_clause?
                $self->expr('SELECT * FROM %s WHERE %s LIMIT 1', $qtable, $where_clause):
                $self->expr('SELECT * FROM %s %s', $qtable, $self->limit);

    my $sth = $self->{query_cache}->{$table}->{$where_clause};
    my $result = $self->all_row($sth, @binds);
    return unless $result && @$result;

    $result = $result->[0] if scalar(@$result) == 1;
    return $self->dump($result);
}

sub drop
{
    my $self = shift;
    my ($table, $name) = @_;
    my ($where_clause, @binds) = $self->where_clause($table, $name);
    my $qtable = $self->{field_quote}.$table.$self->{field_quote};
    return unless $where_clause;

    $self->cdo('DELETE FROM %s WHERE %s', [$qtable, $where_clause], @binds);
}

sub store
{
    my $self = shift;
    my ($table, $name, $data) = @_;
    my ($where_clause, @binds) = $self->where_clause($table, $name);
    my $qtable = $self->{field_quote}.$table.$self->{field_quote};
    return unless $where_clause || @binds;

    $data = $self->load($data);
    return unless $data;

    my $template = $self->pairs(', ', keys %$data);
    $self->cdo('UPDATE %s SET %s WHERE %s', [$qtable, $template, $where_clause], values %$data, @binds);
}

sub create
{
    my $self = shift;
    my ($table, $name) = @_;
    my @primary_key = $self->get_key_fields($table);
    my $qtable = $self->{field_quote}.$table.$self->{field_quote};
    return unless @primary_key;

    my $pholders = '?,' x scalar(@primary_key);
    chop $pholders;
    $self->cdo('INSERT INTO %s (%s) VALUES (%s)', [$qtable, join(', ', @primary_key), $pholders], $self->asplit($name));
}

sub rename
{
    my $self = shift;
    my ($table, $name, $newname) = @_;
    my @primary_key = $self->get_key_fields($table);
    return unless @primary_key;

    my %data = map { shift(@primary_key) => $_ } $self->asplit($newname);
    $self->store($table, $name, \%data);
}

sub get_key_fields {
    my @fields = @{$FusqlFS::Artifact::instance->{namemap}->{$_[1]} || []};
    @fields = $_[0]->get_primary_key($_[1]) unless @fields;
    return @fields;
}

sub get_primary_key { }

1;