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 App-csv2sqlite
#
# This software is copyright (c) 2012 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 App::csv2sqlite;
{
  $App::csv2sqlite::VERSION = '0.004';
}
# git description: v0.003-3-g85d53f9

BEGIN {
  $App::csv2sqlite::AUTHORITY = 'cpan:RWSTAUNER';
}
# ABSTRACT: Import CSV files into a SQLite database

use Moo 1;

use DBI 1.6 ();
use DBD::SQLite 1 ();
use DBIx::TableLoader::CSV 1.102 (); # catch csv errors and close transactions; file_encoding
use Getopt::Long 2.34 ();

sub new_from_argv {
  my ($class, $args) = @_;
  $class->new( $class->getopt($args) );
}

around BUILDARGS => sub {
  my ($orig, $self, @args) = @_;
  my $args = $self->$orig(@args);

  if( my $enc = delete $args->{encoding} ){
    ($args->{loader_options} ||= {})->{file_encoding} ||= $enc;
  }

  return $args;
};

has csv_files => (
  is         => 'ro',
  coerce     => sub { ref $_[0] eq 'ARRAY' ? $_[0] : [ $_[0] ] },
);

has csv_options => (
  is         => 'ro',
  default    => sub { +{} },
);

has loader_options => (
  is         => 'ro',
  default    => sub { +{} },
);

has dbname => (
  is         => 'ro',
);

has dbh => (
  is         => 'lazy',
);

sub _build_dbh {
  my ($self) = @_;
  # TODO: does the dbname need to be escaped in some way?
  my $dbh = DBI->connect('dbi:SQLite:dbname=' . $self->dbname, undef, undef, {
    RaiseError => 1,
    PrintError => 0,
    sqlite_unicode => $self->encoding ? 1 : 0,
  });
  return $dbh;
}

sub encoding {
  return $_[0]->loader_options->{file_encoding};
}

sub help { Getopt::Long::HelpMessage(2); }


sub getopt {
  my ($class, $args) = @_;
  my $opts = {};

  {
    local @ARGV = @$args;
    my $p = Getopt::Long::Parser->new(
      config => [qw(pass_through auto_help auto_version)],
    );
    $p->getoptions($opts,
      'csv_files|csv-file|csvfile|csv=s@',
      # TODO: 'named_csv_files=s%'
      # or maybe --csv and --named should be subs that append to an array ref to keep order?
      'csv_options|csv-opt|csvopt|o=s%',
      # TODO: tableloader options like 'drop' or maybe --no-create
      'loader_options|loader-opt|loaderopt|l=s%',
      'dbname|database=s',
      'encoding|enc|e=s',
    ) or $class->help;
    $args = [@ARGV];
  }

  # last arguments
  $opts->{dbname} ||= pop @$args;

  # first argument
  if( @$args ){
    push @{ $opts->{csv_files} ||= [] }, @$args;
  }

  return $opts;
}

sub load_tables {
  my ($self) = @_;

  # TODO: option for wrapping the whole loop in a transaction rather than each table

  foreach my $file ( @{ $self->csv_files } ){
    my %opts = (
      %{ $self->loader_options },
      csv_opts => { %{ $self->csv_options } },
      file => $file,
    );

    # TODO: This could work but i hate the escaping thing.
    # Allow table=file (use "=file" for files with an equal sign).
    #if( $file =~ /^([^=:]*)[=:](.+)$/ ){ $opts{name} = $1 if $1; $opts{file} = $2; }

    DBIx::TableLoader::CSV->new(
      %opts,
      dbh  => $self->dbh,
    )->load;
  }

  return;
}

sub run {
  my $class = shift || __PACKAGE__;
  my $args = @_ ? shift : [@ARGV];

  my $self = $class->new_from_argv($args);
  $self->load_tables;
}

1;

__END__

=pod

=encoding utf-8

=for :stopwords Randy Stauner ACKNOWLEDGEMENTS TODO CSV csv sqlite csv2sqlite --csv
--csv-file --csv-opt --dbname cpan testmatrix url annocpan anno bugtracker
rt cpants kwalitee diff irc mailto metadata placeholders metacpan

=head1 NAME

App::csv2sqlite - Import CSV files into a SQLite database

=head1 VERSION

version 0.004

=head1 SYNOPSIS

  csv2sqlite doggies.csv kitties.csv pets.sqlite

  # configure CSV parsing as necessary:
  csv2sqlite -o sep_char=$'\t' plants.tab plants.sqlite

=head1 DESCRIPTION

Import CSV files into a SQLite database
(using L<DBIx::TableLoader::CSV>).

Each csv file specified on the command line
will became a table in the resulting sqlite database.

=head1 OPTIONS

=over 4

=item --csv-file (or --csv)

The csv files to load

=item --csv-opt (or -o)

A hash of key=value options to pass to L<Text::CSV>

=item --dbname (or --database)

The file path for the SQLite database

=item --encoding (or -e)

The encoding of the csv files (a shortcut for C<< --loader-opt file_encoding=$enc >>);
(Strings will be stored in the database in UTF-8.)

=item --loader-opt (or -l)

A hash of key=value options to pass to L<DBIx::TableLoader::CSV>

=back

=for Pod::Coverage new_from_argv
help
getopt
load_tables
run
csv_files
csv_options
loader_options
dbname
dbh
BUILDARGS
encoding

=head1 TODO

=over 4

=item *

specific L<DBIx::TableLoader> options?

=item *

confirm using a pre-existing database?

=item *

more tests

=item *

allow specifying table names for csv files

=back

=head1 SUPPORT

=head2 Perldoc

You can find documentation for this module with the perldoc command.

  perldoc App::csv2sqlite

=head2 Websites

The following websites have more information about this module, and may be of help to you. As always,
in addition to those websites please use your favorite search engine to discover more resources.

=over 4

=item *

Search CPAN

The default CPAN search engine, useful to view POD in HTML format.

L<http://search.cpan.org/dist/App-csv2sqlite>

=item *

RT: CPAN's Bug Tracker

The RT ( Request Tracker ) website is the default bug/issue tracking system for CPAN.

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-csv2sqlite>

=item *

CPAN Ratings

The CPAN Ratings is a website that allows community ratings and reviews of Perl modules.

L<http://cpanratings.perl.org/d/App-csv2sqlite>

=item *

CPAN Testers

The CPAN Testers is a network of smokers who run automated tests on uploaded CPAN distributions.

L<http://www.cpantesters.org/distro/A/App-csv2sqlite>

=item *

CPAN Testers Matrix

The CPAN Testers Matrix is a website that provides a visual overview of the test results for a distribution on various Perls/platforms.

L<http://matrix.cpantesters.org/?dist=App-csv2sqlite>

=item *

CPAN Testers Dependencies

The CPAN Testers Dependencies is a website that shows a chart of the test results of all dependencies for a distribution.

L<http://deps.cpantesters.org/?module=App::csv2sqlite>

=back

=head2 Bugs / Feature Requests

Please report any bugs or feature requests by email to C<bug-app-csv2sqlite at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-csv2sqlite>. You will be automatically notified of any
progress on the request by the system.

=head2 Source Code


L<https://github.com/rwstauner/App-csv2sqlite>

  git clone https://github.com/rwstauner/App-csv2sqlite.git

=head1 AUTHOR

Randy Stauner <rwstauner@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2012 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