package DBIx::Data::Store::CRUD;

use Moose;
use Method::Signatures::Simple;

has raw_store => (is => 'ro', required => 1); # DBIx::Data::Store object

foreach my $type (qw(select insert update delete)) {
  has "${type}_sql" => (is => 'ro', predicate => "has_${type}_sql");
  has "${type}_argument_order" => (is => 'ro', default => sub { [] });
}

has 'insert_command_constructor' => (is => 'ro');

has "select_column_order" => (is => 'ro');

method new_select_command ($args) {
  die "$self->has_select_sql" unless $self->has_select_sql;
  $self->raw_store->new_stream_command(
    $self->select_sql,
    $self->_unwrap_args_for(select => $args),
    $self->select_column_order
  );
}

method _unwrap_args_for ($type, $args) {
  [ @{$args}{@{$self->${\"${type}_argument_order"}}} ]
}

method _new_command ($builder, $type, $args) {
  my $has_meth = "has_${type}_sql";
  die "${self}->${has_meth}" unless $self->$has_meth;
  $self->$builder(
    $self->${\"${type}_sql"},
    $self->_unwrap_args_for($type => $args),
  );
}

method _new_call_command ($type, $args) {
  $self->_new_command(
    sub { shift->raw_store->new_call_command(@_) },
    $type => $args,
  );
}

method new_insert_command ($args) {
  my $builder = $self->insert_command_constructor;
  $builder
    ? $self->_new_command($builder => insert => $args)
    : $self->_new_call_command(insert => $args);
}

method new_update_command ($args) {
  $self->_new_call_command(update => $args);
}

method new_delete_command ($args) {
  $self->_new_call_command(delete => $args);
}

__PACKAGE__->meta->make_immutable;

1;
