The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use Test::Clustericious::Cluster 0.26;
use Test::More;
use File::Find qw( find );
use File::Basename qw( dirname );
use Clustericious::Plugin::CommonRoutes ();

plan skip_all => 'requires Rose::Planter 0.34 and DBD::SQLite: '
  unless eval q{ use Rose::Planter 0.34 (); use DBD::SQLite (); 1 };

plan tests => 43;

my $cluster = Test::Clustericious::Cluster->new;
$cluster->create_cluster_ok('SomeService');
my $t = $cluster->t;

$t->get_ok("/api")
  ->status_is(200);

$t->get_ok("/api/bogus_table")
  ->status_is(404);

$t->get_ok("/api/person")
  ->status_is(200)
  ->json_is("/columns/first_name/not_null", 1)
  ->json_is("/columns/first_name/rose_db_type", "varchar")
  ->json_is("/columns/first_name/type", "string")
  ->json_is("/columns/id/not_null", 0)
  ->json_is("/columns/id/rose_db_type", "integer")
  ->json_is("/columns/id/type", "integer")
  ->json_is("/columns/last_name/not_null", 0)
  ->json_is("/columns/last_name/rose_db_type", "varchar")
  ->json_is("/columns/last_name/type", "string")
  ->json_is("/primary_key/0", "id");

find(
    {
        wanted => sub {
            my $name = $File::Find::name;
            return if -d $name || $name =~ /^\./;
            $name =~ s{^.*(Rose/DB/Object/Metadata/Column/.*?\.pm)$}{$1};
            eval qq{ require '$name'; };
            my $class = $name;
            $class =~ s{/}{::}g;
            $class =~ s/\.pm$//;
            return if $class =~ /^Rose::DB::Object::Metadata::Column::(Array|Scalar)$/;
            return if Clustericious::Plugin::CommonRoutes->_dump_api_table_types($class->type) ne 'unknown';
            diag "not sure about type for $class";
        },
        no_chdir => 1,
    },
    dirname($INC{'Rose/DB/Object/Metadata/Column.pm'}) . "/Column",
);

foreach my $type (qw( character text varchar ))
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), 'string', "$type = string");
}

foreach my $type ('numeric', 'float', 'double precision', 'decimal')
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), 'numeric', "$type = numeric");
}

foreach my $type (qw( blob set time interval enum datetime bytea chkpass bitfield date boolean ))
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), $type, "$type = $type");
}

foreach my $type (qw( bigint integer bigserial serial ))
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), 'integer', "$type = integer");
}

foreach my $type ('epoch', 'epoch hires')
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), 'epoch', "$type = epoch");
}

foreach my $type ('timestamp', 'timestamp with time zone')
{
  is(Clustericious::Plugin::CommonRoutes->_dump_api_table_types($type), 'timestamp', "$type = timestamp");
}

__DATA__


@@ etc/SomeService.conf
---
url: <%= cluster->url %>
db:
  database: <%= home %>/database.sqlite
  driver: SQLite


@@ lib/SomeService.pm
package SomeService;

use strict;
use warnings;
use SomeService::DB;
use Capture::Tiny qw( capture_stderr );
use File::Glob qw( bsd_glob );

BEGIN {
  capture_stderr {
    Rose::Planter->plant(
      "SomeService::Objects" => bsd_glob('~/lib/SomeService/Objects/autolib'),
    );
  };
}


use SomeService::Objects;
use SomeService::Routes;

our $VERSION = '1.0';
use base 'Clustericious::App';

1;



@@ lib/SomeService/DB.pm
package SomeService::DB;

use strict;
use warnings;
use File::Glob qw( bsd_glob );
use base qw( Rose::Planter::DB );
use Clustericious::Config;
use DBI;
use Test::More;

my $home = bsd_glob '~';
my $db_filename = "$home/database.sqlite";
my $dbh = DBI->connect("dbi:SQLite:dbname=$db_filename", '', '', { RaiseError => 1, AutoCommit => 1 });

$dbh->do(q{create table person (
  id integer primary key,
  first_name varchar not null,
  last_name varchar
)});

$dbh->do(q{create table employer (
  id integer primary key,
  name varchar not null,
  tax_id integer
)});

$dbh->do(q{ create table employment_contract (
  id integer primary key,
  person_id integer,
  employer_id integer,
  text terms
)});

undef $dbh;

__PACKAGE__->register_databases(
  module_name => 'SomeService',
  conf => Clustericious::Config->new('SomeService'),
);

1;



@@ lib/SomeService/Objects.pm
package SomeService::Objects;

use strict;
use warnings;
use File::Spec;
use Rose::Planter
    loader_params => {
        class_prefix => 'SomeService::Object',
        db_class     => 'SomeService::DB',
    },
    convention_manager_params => {};
;

1;



@@ lib/SomeService/Routes.pm
package SomeService::Routes;

use strict;
use warnings;
use Clustericious::RouteBuilder;
use Clustericious::RouteBuilder::CRUD
    create   => { -as => "do_create" },
    read     => { -as => "do_read" }, 
    delete   => { -as => "do_delete" }, 
    update   => { -as => "do_update" }, 
    list     => { -as => "do_list" }, 
    defaults => { finder => "Rose::Planter" };
use Clustericious::RouteBuilder::Search
    search   => { -as => "do_search" },
    defaults => { finder => "Rose::Planter" };

get '/' => sub { shift->render(text => "hello"); };

post  '/:items/search' => \&do_search;
get   '/:items/search' => \&do_search;
post  '/:table'        => [ table => Rose::Planter->regex_for_tables ] => \&do_create;
get   '/:table/*key'   => [ table => Rose::Planter->regex_for_tables ] => \&do_read;
post  '/:table/*key'   => [ table => Rose::Planter->regex_for_tables ] => \&do_update;
del   '/:table/*key'   => [ table => Rose::Planter->regex_for_tables ] => \&do_delete;
get   '/:table'        => [ table => Rose::Planter->regex_for_tables ] => \&do_list;

1;