# $Id: db-common.pl 91 2006-08-17 00:39:55Z bradfitz $

use strict;
use File::Spec;
use Carp qw(croak);

sub run_tests {
    my ($n, $code) = @_;

    run_tests_mysql($n, $code);
    run_tests_sqlite($n, $code);
}

sub run_tests_innodb {
    my ($n, $code) = @_;
    run_tests_mysql($n, $code, 1);
}

sub run_tests_mysql {
    my ($n, $code, $innodb) = @_;
  SKIP: {
      local $ENV{USE_MYSQL} = 1;
      my $dbh = eval { mysql_dbh() };
      skip "MySQL not accessible as root on localhost", $n if $@;
      skip "InnoDB not available on localhost's MySQL", $n if $innodb && ! has_innodb($dbh);
      $code->();
  }
}

sub run_tests_sqlite {
    my ($n, $code) = @_;

    # SQLite
  SKIP: {
      my $rv = eval "use DBD::SQLite; 1";
      $rv = 0 if $ENV{SKIP_SQLITE};
      skip "SQLite not installed", $n if !$rv;
      $code->();
  }
}

sub test_client {
    my %opts = @_;
    my $dbs     = delete $opts{dbs};
    my $init    = delete $opts{init};
    my $pfx     = delete $opts{dbprefix};
    croak "'dbs' not an ARRAY" unless ref $dbs eq "ARRAY";
    croak "unknown opts" if %opts;
    $init = 1 unless defined $init;

    if ($init) {
        setup_dbs({ prefix => $pfx }, $dbs);
    }

    return TheSchwartz->new(databases => [
                                          map { {
                                              dsn  => dsn_for($_),
                                              user => "root",
                                              pass => "",
                                              prefix => $pfx,
                                          } } @$dbs
                                          ]);
}

sub has_innodb {
    my $dbh = shift;
    my $tmpname = "test_to_see_if_innoavail";
    $dbh->do("CREATE TABLE IF NOT EXISTS $tmpname (i int) ENGINE=INNODB")
        or return 0;
    my @row = $dbh->selectrow_array("SHOW CREATE TABLE $tmpname");
    my $row = join(' ', @row);
    my $has_it = ($row =~ /=InnoDB/i);
    $dbh->do("DROP TABLE $tmpname");
    return $has_it;
}

sub schema_file {
    return "doc/schema.sql" if $ENV{USE_MYSQL};
    return "t/schema-sqlite.sql";
}

sub db_filename {
    my($dbname) = @_;
    return $dbname . '.db';
}

sub mysql_dbname {
    my($dbname) = @_;
    return 't_sch_' . $dbname;
}

sub dsn_for {
    my $dbname = shift;
    if ($ENV{USE_MYSQL}) {
        return 'dbi:mysql:' . mysql_dbname($dbname);
    } else {
        return 'dbi:SQLite:dbname=' . db_filename($dbname);
    }
}

sub setup_dbs {
    shift if $_[0] =~ /\.sql$/;  # skip filenames (old)

    my $opts = ref $_[0] eq "HASH" ? shift : {};
    my $pfx = delete $opts->{prefix} || "";
    die "unknown opts" if %$opts;

    my(@dbs) = @_;
    my $dbs = ref $dbs[0] ? $dbs[0] : \@dbs;  # support array or arrayref (old)

    my $schema = schema_file();
    teardown_dbs(@$dbs);
    for my $dbname (@$dbs) {
        if ($ENV{USE_MYSQL}) {
            create_mysql_db(mysql_dbname($dbname));
        }
        my $dbh = DBI->connect(dsn_for($dbname),
            'root', '', { RaiseError => 1, PrintError => 0 })
            or die "Couldn't connect: $!\n";
        my @sql = load_sql($schema);
        for my $sql (@sql) {
            $sql =~ s!^\s*create\s+table\s+(\w+)!CREATE TABLE ${pfx}$1!i;
            $sql .= " ENGINE=INNODB\n" if $ENV{USE_MYSQL};
            $dbh->do($sql);
        }
        $dbh->disconnect;
    }
}

sub mysql_dbh {
    return DBI->connect("DBI:mysql:mysql", "root", "", { RaiseError => 1 })
        or die "Couldn't connect to database";
}

sub create_mysql_db {
    my $dbname = shift;
    mysql_dbh()->do("CREATE DATABASE $dbname");
}

sub drop_mysql_db {
    my $dbname = shift;
    mysql_dbh()->do("DROP DATABASE IF EXISTS $dbname");
}

sub teardown_dbs {
    my(@dbs) = @_;
    for my $db (@dbs) {
        if ($ENV{USE_MYSQL}) {
            drop_mysql_db(mysql_dbname($db));
        } else {
            my $file = db_filename($db);
            next unless -e $file;
            unlink $file or die "Can't teardown $db: $!";
        }
    }
}

sub load_sql {
    my($file) = @_;
    open my $fh, $file or die "Can't open $file: $!";
    my $sql = do { local $/; <$fh> };
    close $fh;
    split /;\s*/, $sql;
}

1;
