The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl

use strict;
use warnings;
no warnings 'redefine';
use 5.010;

use Module::Load;
use Getopt::Long;
use Pod::Usage;

my $dir;
my $driver;
my $help;
my $sql;
my $code;
BEGIN {
	GetOptions(
        'dir=s'    => \$dir,
        'driver=s' => \$driver,
        'help'     => \$help,
        'sql'      => \$sql,
        'perl'     => \$code,
    );

    if (not defined $dir) {
	    pod2usage(1);
	    exit 0;
    }
}

use lib "$dir";
use ActiveRecord::Simple;

*ActiveRecord::Simple::dbh = sub { return { Driver => { Name => $driver } } };
*ActiveRecord::Simple::_smart_saving_used = sub { undef };

if ($sql) {
	MODULE:
    for my $module (list($dir)) {
        my $module_content = slurp_file($module);
        next MODULE if $module_content !~ m/ActiveRecord\:\:Simple/;

        my ($class) = $module_content =~ m/^package\s+(.+);\n/;
        load $class;

        say $class->as_sql;

        #my $table_name  = $class->_get_table_name  if $class->can('_get_table_name');
        #my $columns     = $class->_get_columns     if $class->can('_get_columns');
        #my $primary_key = $class->_get_primary_key if $class->can('_get_primary_key');
        #my $relations   = $class->_get_relations   if $class->can('_get_relations');
        #
        #my $sql = "CREATE TABLE \"$table_name\" (\n";
        #my @cols;
        #for my $col (@$columns) {
	    #    my $cs = q/"/ . $col . q/" [TYPE]/;
	    #    $cs .= " PRIMARY KEY" if defined $primary_key && $col eq $primary_key;
	    #    push @cols, "  $cs";
        #}
        #my $colstring = join ",\n", @cols;
        #$sql .= $colstring;
        #$sql .= "\n);";
        #
        #my $arself = bless {}, 'ActiveRecord::Simple';
        #$arself->{SQL} = $sql;
        #$arself->_quote_sql_stmt();
        # 
        #say $arself->{SQL};
    }
}

if ($code) {

	my $sql;
	for my $sql_file (list($dir, '.sql')) {
		$sql .= slurp_file($sql_file);
	}

	my @tables_sql = $sql =~ m/CREATE\s+TABLE(.+?);/igs;
	for my $table_sql (@tables_sql) {
		my ($table_name) = $table_sql =~ m/^(.+?)\s+/s;
		$table_name =~ s/^\s+|\s+$//g;
		$table_name =~ s/`|"//g;

        my $class_name = camelize($table_name);
        my $class_content = "package $class_name;\n\nuse strict;\nuse warnings;\n";
        $class_content .= "use base 'ActiveRecord::Simple';\n\n";

        my ($fields_sql) = $table_sql =~ m/\((.+)\)/igs;

        my @columns; my $primary_key;
        for my $field (split /\n/, $fields_sql) {
        	$field =~ s/^\s+|\s+$//g;
        	next if $field eq '';

        	my ($column) = $field =~ m/^(.+?)\s+/;
        	$column =~ s/`|"//g;
        	push @columns, $column;

        	$primary_key = $column if $field =~ /PRIMARY\s+KEY/i;
        }

        $class_content .= "__PACKAGE__->table_name('$table_name');\n" if $table_name;
        my $columns_str = join q/, /, map { q/'/ . $_ . q/'/ } @columns;
        $class_content .= "__PACKAGE__->columns([$columns_str]);\n";
        $class_content .= "__PACKAGE__->primary_key('$primary_key');\n" if $primary_key;
        $class_content .= "\n1;\n";

        open my $fh, '>', "$class_name\.pm";
        print {$fh} $class_content;
        close $fh;

        say "Created $class_name\.pm";
	}
}

sub camelize {
	my ($str) = @_;

    return unless $str;

	return join q//, map { ucfirst $_ } split q/_/, $str;
}

sub list {
	my ($dir, $type) = @_;

	$type ||= '.pm';

    opendir my $dh, "$dir";
    my @list = grep { $_ !~ /^\./ } readdir $dh;
    close $dh;

    my @classes;
    for my $item (@list) {
        if ($item =~ /$type$/) {
        	push @classes, "$dir/$item";
        }

        if (-d "$dir/$item") {
        	push @classes, list("$dir/$item");
        }
    }

    return @classes;
}

sub slurp_file {
	my ($file_path) = @_;

	return if !-e $file_path;
	open my $fh, "$file_path";
	my $text = do { local $/; <$fh> };
	close $fh;

	return $text;
}

__END__

=head1 NAME

arsimple

=head1 OPTIONS

=over 8

=item B<-dir>

Set a directory with ARSimple-based classes or .sql files

=item B<-sql>

Get SQL from the code

=item B<-code>

Get code from the SQL

=item B<-driver>

Database driver name (Pg, mysql or SQLite)

=item B<-help>

This text

=back