From 770af39e803b9f3bbbe02dc73ec2fe0c5154d895 Mon Sep 17 00:00:00 2001 From: Brian Duggan Date: Fri, 26 Apr 2013 16:29:24 -0400 Subject: [PATCH] rose, dbi, etc --- Tuba.conf | 7 +++++ lib/Tuba.pm | 21 ++++++++------- lib/Tuba/DB.pm | 24 ++++++++++++++++++ lib/Tuba/Image.pm | 17 +++++++++++++ lib/Tuba/Plugin/Db.pm | 55 ++++++++++++++++++++++++++++++++++++++++ lib/Tuba/Plugin/Debug.pm | 48 +++++++++++++++++++++++++++++++++++ 6 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 lib/Tuba/DB.pm create mode 100644 lib/Tuba/Image.pm create mode 100644 lib/Tuba/Plugin/Db.pm create mode 100644 lib/Tuba/Plugin/Debug.pm diff --git a/Tuba.conf b/Tuba.conf index f260b37f..d679cd3a 100644 --- a/Tuba.conf +++ b/Tuba.conf @@ -3,4 +3,11 @@ hypnotoad : workers : 5 listen : - http://*:8080 +database : + dbname : gcis + schema : gcis_metadata + host : + port : + username : + password : diff --git a/lib/Tuba.pm b/lib/Tuba.pm index c78181a0..ac791e18 100644 --- a/lib/Tuba.pm +++ b/lib/Tuba.pm @@ -11,11 +11,10 @@ Tuba provides a RESTful API to GCIS data. =cut package Tuba; +use Mojo::Base qw/Mojolicious/; our $VERSION = 0.01; -use Mojo::Base qw/Mojolicious/; - sub demo { my $c = shift; my $path = $c->req->url->path; @@ -27,19 +26,21 @@ sub demo { }; sub startup { - my $self = shift; + my $app = shift; - $self->plugin( 'yaml_config' => { file => './Tuba.conf' } ); + $app->plugin( 'yaml_config' => { file => './Tuba.conf' } ); + unshift @{$app->plugins->namespaces}, 'Tuba::Plugin'; + $app->plugin( 'db', ( $app->config('database') || die "no database config" ) ); - $self->secret('aePhoox5Iegh6toeay3ooV9n'); + $app->secret('aePhoox5Iegh6toeay3ooV9n'); - $self->hook(before_dispatch => sub { + $app->hook(before_dispatch => sub { # Remove path when behind a proxy (see Mojolicious::Guides::Cookbook). my $c = shift; push @{$c->req->url->base->path}, shift @{$c->req->url->path} if @{ $c->req->url->path }; - }) if $self->mode eq 'production'; + }) if $app->mode eq 'production'; - my $r = $self->routes; + my $r = $app->routes; $r->get('/' => sub { my $c = shift; @@ -58,7 +59,7 @@ sub startup { $c->stash(placeholders => \@placeholders); } => 'index'); - $r->post('calculate_url' => sub { + $r->post('/calculate_url' => sub { my $c = shift; my $for = $c->param('_route_name'); my $route = $c->app->routes->lookup($for) or return $c->render_not_found; @@ -68,6 +69,7 @@ sub startup { $c->render_json({path => $rendered}); } => 'calculate_url'); + $r->post( '/image/metadata/:image_id')->to('Image#metadata')->name('image_metadata'); $r->get( '/report/:report_id/chapter/:chapter_id/figure/:figure_id' => { report_id => 'nca2013' } => \&demo => 'figure'); $r->get( '/report/:report_id/figure/:figure_token' => { report_id => 'nca2013' } => \&demo => 'figure_token'); $r->get( '/activity/:activity_type/report/:report_id/:entity_type/:entity_id' => \&demo => 'activity'); @@ -94,6 +96,7 @@ sub startup { $r->get( '/role/:role_name' => \&demo => 'role'); $r->get( '/software/:software_name' => \&demo => 'software'); + $app->plugin('debug') if $app->mode eq 'development'; } 1; diff --git a/lib/Tuba/DB.pm b/lib/Tuba/DB.pm new file mode 100644 index 00000000..eba20f34 --- /dev/null +++ b/lib/Tuba/DB.pm @@ -0,0 +1,24 @@ +=head1 NAME + +Tuba::DB -- Rose::DB derived class for Tuba objects. + +=cut + +package Tuba::DB; +use Tuba::Plugin::Db; +use base 'Rose::DB'; +use strict; +use warnings; + +Tuba::DB->register_db( + domain => "default", + type => "default", + driver => 'Pg', +); + +sub dbi_connect { + Tuba::Plugin::Db->connection->dbh; +} + +1; + diff --git a/lib/Tuba/Image.pm b/lib/Tuba/Image.pm new file mode 100644 index 00000000..708d077f --- /dev/null +++ b/lib/Tuba/Image.pm @@ -0,0 +1,17 @@ +=head1 NAME + +Tuba::Image : Controller class for images. + +=cut + +package Tuba::Image; + +use Mojo::Base qw/Mojolicious::Controller/; + +sub metadata { + my $c = shift; + $c->render_text("testing"); +} + +1; + diff --git a/lib/Tuba/Plugin/Db.pm b/lib/Tuba/Plugin/Db.pm new file mode 100644 index 00000000..edc368c2 --- /dev/null +++ b/lib/Tuba/Plugin/Db.pm @@ -0,0 +1,55 @@ +package Tuba::Plugin::Db; +use Mojo::Base qw/Mojolicious::Plugin/; +use DBIx::Connector; +use DBIx::Simple; +use SQL::Abstract; +use SQL::Interp; +use Rose::DB::Object::Loader; +use Tuba::DB; + +{ +my $dbix; + +sub register { + my ($self, $app, $conf) = @_; + my $dbname = $conf->{dbname} or die "no dbname in config file"; + + $app->log->info("Registering database $dbname"); + + my $dsn = "dbi:Pg:dbname=$dbname"; + $dsn .= ":host=$conf->{host}" if $conf->{host}; + $dsn .= ":port=$conf->{port}" if $conf->{port}; + + $dbix = DBIx::Connector->new( $dsn, ($conf->{user} || ''), + ( $conf->{password} || '' ), + { RaiseError => 1, AutoCommit => 1 } ); + + $app->helper( db => sub { $dbix } ); + $app->helper( dbs => sub { DBIx::Simple->new( shift->db->dbh ) } ); + + my $rose_db = Tuba::DB->new(); + my $loader = Rose::DB::Object::Loader->new( class_prefix => 'Tuba::Obj', db_schema => $conf->{schema} ); + my @made = $loader->make_classes(db_class => 'Tuba::DB' ); + $app->log->info("Loaded ".@made." classes"); + + my %orm; # Map table names to class names. + for (@made) { + if ($_->isa("Rose::DB::Object::Manager")) { + $orm{$_->object_class->meta->table}{mng} = $_; + } else { + $orm{$_->meta->table}{obj} = $_; + } + } + $app->helper(orm => sub { \%orm }); + + 1; +} + +sub connection { + $dbix; +} +} + + +1; + diff --git a/lib/Tuba/Plugin/Debug.pm b/lib/Tuba/Plugin/Debug.pm new file mode 100644 index 00000000..1837ec76 --- /dev/null +++ b/lib/Tuba/Plugin/Debug.pm @@ -0,0 +1,48 @@ +=head1 NAME + +Tuba::Plugin::Debug - helpful diagnostics + +=head1 DESCRIPTION + +This plugin is if the server is in debug mode; it provides +extra routes to aid in debugging. + +=cut + +package Tuba::Plugin::Debug; +use Mojo::Base qw/Mojolicious::Plugin/; +use Data::Dumper; + +sub _render_debug { + my $c = shift; + + die "no database handle\n\n$DBI::errstr\n" unless $c->db->dbh; + my @output; + + my $got = $c->db->dbh->selectall_arrayref('select 42') or die $DBI::errstr; + push @output, "db said @{$got->[0]}"; + + my ($flat) = $c->dbs->query('select 42')->flat; + push @output, "db said $flat"; + + my $orm = $c->orm; + for my $table (sort keys %$orm) { + push @output, "$table : ".join ' ', $orm->{$table}{obj}->meta->columns; + } + + $c->res->headers->content_type('text/plain'); + $c->render_text(join "\n", @output); +} + +sub register { + my ($self, $app, $conf) = @_; + return if $app->mode eq 'production'; + return unless $ENV{TUBA_DEBUG}; + + $app->routes->get('/debug' => \&_render_debug); + + 1; +} + +1; +