diff --git a/.gitignore b/.gitignore index 46faee4..f54ec1b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ sql/ qi.conf qi.mysql +modeltest \ No newline at end of file diff --git a/lib/Qi.pm b/lib/Qi.pm index a7a68cc..4a1a97b 100644 --- a/lib/Qi.pm +++ b/lib/Qi.pm @@ -1,6 +1,10 @@ package Qi; +use warnings; use Mojo::Base 'Mojolicious'; use Mojo::Pg; +use SQL::Abstract; + +use Data::Dumper qw(Dumper); # This method will run once at server start sub startup { @@ -10,7 +14,10 @@ sub startup { my $config = $self->plugin('Config'); #Model - $self->helper(pg => sub { state $pg = Mojo::Pg->new(shift->config('pg')) }); + $self->helper(pg => sub { state $pg = Mojo::Pg->new(shift->config('pg')) }); + #$self->helper(sql => sub{ state $sql = SQL::Abstract->new}); + $self->helper(assets => sub { state $assets = Qi::Model::Assets->new(pg => shift->pg) }); + $self->helper(locations => sub { state $locations = Qi::Model::Locations->new(pg => shift->pg) }); # Documentation browser under "/perldoc" $self->plugin('PODRenderer'); @@ -20,9 +27,23 @@ sub startup { # Normal route to controller $r->get('/')->to('example#welcome'); + + ######## API ######### + my $api = $r->under('/api'); + + #Assets + $api->get('/assets')->to('assets#get')->name('get_assets'); # get assets + $api->post('/assets')->to('assets#insert')->name('post_asset'); # insert asset + $api->put('/assets')->to('assets#update')->name('update_asset'); # update asset + $api->delete('/assets')->to('assets#remove')->name('remove_asset'); # remove asset + + #Locations + $api->get('/locations')->to('locations#get')->name('get_locations'); #get locations + + # Migrate to latest version if necessary - my $path = $self->home->rel_file('migrations/Qi.sql'); + my $path = $self->home->rel_file('migrations/qi.sql'); $self->pg->migrations->name('qi')->from_file($path)->migrate; } diff --git a/lib/Qi/Controller/Assets.pm b/lib/Qi/Controller/Assets.pm new file mode 100644 index 0000000..292b407 --- /dev/null +++ b/lib/Qi/Controller/Assets.pm @@ -0,0 +1,48 @@ +package Qi::Controller::Assets; +use Mojo::Base 'Mojolicious::Controller'; +use Qi::Model::Assets; + +sub get { + my $self = shift; + my $json = $self->req->json; #this is optional. Not specifying an asset returns all assets + $self->render( + json => { + table => 'assets', #repond with the table + (($json) ? 'asset' : 'assets') => $self->assets->select($json) #respond with a specified asset or all assets + } + ); +} + +sub insert { + my $self = shift; + $self->render( + json => { + table => 'assets', + tag => $self->assets->insert($self->req->json)->{tag} #respond with the tag that was inserted + } + ); +} + +sub update { + my $self = shift; + my $json = $self->req->json; + $self->render( + json => { + table => 'assets', + tag => $self->assets->update($json)->{tag} #respond with tag of updated entry (if tag is updated, the new tag will be returned) + } + ); +} + +sub remove { + my $self = shift; + my $json = $self->req->json; + $self->render( + json => { + table => 'assets', + tag => $self->assets->delete($json)->{tag} #respond with tag that was deleted + } + ); +} + +1; diff --git a/lib/Qi/Controller/Example.pm b/lib/Qi/Controller/Example.pm deleted file mode 100644 index 19227f9..0000000 --- a/lib/Qi/Controller/Example.pm +++ /dev/null @@ -1,12 +0,0 @@ -package Qi::Controller::Example; -use Mojo::Base 'Mojolicious::Controller'; - -# This action will render a template -sub welcome { - my $self = shift; - - # Render template "example/welcome.html.ep" with message - $self->render(msg => 'Welcome to the Mojolicious real-time web framework!'); -} - -1; diff --git a/lib/Qi/Controller/Locations.pm b/lib/Qi/Controller/Locations.pm new file mode 100644 index 0000000..a86a185 --- /dev/null +++ b/lib/Qi/Controller/Locations.pm @@ -0,0 +1,16 @@ +package Qi::Controller::Locations; +use Mojo::Base 'Mojolicious::Controller'; +use Qi::Model::Locations; + +sub get { + my $self = shift; + my $json = $self->req->json; #this is optional. Not specifying an asset returns all assets + $self->render( + json => { + table => 'locations', #repond with the table + (($json) ? 'location' : 'locations') => $self->locations->select($json) #respond with a specified asset or all assets + } + ); +} + +1; \ No newline at end of file diff --git a/lib/Qi/Model/Assets.pm b/lib/Qi/Model/Assets.pm new file mode 100644 index 0000000..85efe88 --- /dev/null +++ b/lib/Qi/Model/Assets.pm @@ -0,0 +1,19 @@ +package Qi::Model::Assets; +use Mojo::Base 'Qi::Model::Crud'; + +has table => 'assets'; +has primary_key => 'tag'; + +#sub update_timestamp { +# my ($self, $tag) = @_; +# $self->sql +# my $results = eval { +# #my $sql = 'update ? set add_stamp= (now) where tag=?'; +# #$self->pg->db->query($sql, $self->table, $tag)->hash; +# $self->update({data => {add_stamp => \'now()'}, where => {tag => $tag}}) +# +# } +# if ($@){ warn "there's an error";} +# else {warn "Success!";} +#} +1; \ No newline at end of file diff --git a/lib/Qi/Model/Crud.pm b/lib/Qi/Model/Crud.pm new file mode 100644 index 0000000..4effbaf --- /dev/null +++ b/lib/Qi/Model/Crud.pm @@ -0,0 +1,50 @@ +package Qi::Model::Crud; +use Mojo::Base -base; +use SQL::Abstract; +use Mojo::Collection; + +has sql => sub { state $sql = SQL::Abstract->new }; + +#### self Methods #### +#has 'sql'; # $self->sql for SQL::Abstract +has 'pg'; # $self->pg for Mojo::Pg +has 'table' => sub {die "Forgot to define table"}; +has 'primary_key' => sub {die "Forgot to define primary_key"}; + + +# **sql** is optional + +sub select { + my ($self, $request) = @_; + my($stmt, @bind) = $self->sql->select($self->table , '*', $request); #select * from $self->table **where $request** + if($request) { #if there is a where clause + $self->pg->db->query($stmt, @bind)->hash; #respond with 1 row + } + else { #if no where clause + $self->pg->db->query($stmt, @bind)->hashes; #respond with all rows + } +} + +sub insert { + my ($self, $request) = @_; + my($stmt, @bind) = $self->sql->insert($self->table, $request, {returning => $self->primary_key}); #insert into $self->table $request + $self->pg->db->query($stmt, @bind)->hash; #respond with primary key +} + +sub update { + my ($self, $request) = @_; + my($stmt, @bind) = $self->sql->update($self->table, $request->{data}, $request->{where}); #update $self->table set $request->{data} where $request->{where} + $stmt = $stmt . ' returning ' . $self->primary_key; + $self->pg->db->query($stmt, @bind)->hash; +} + +sub delete { + my ($self, $request) = @_; + my($stmt, @bind) = $self->sql->delete($self->table, $request); #delete from $self->table where $request + warn $request; + $stmt = $stmt . ' returning ' . $self->primary_key; + warn $stmt; + $self->pg->db->query($stmt, @bind)->hash; +} + +1; \ No newline at end of file diff --git a/lib/Qi/Model/Locations.pm b/lib/Qi/Model/Locations.pm new file mode 100644 index 0000000..e8f4d98 --- /dev/null +++ b/lib/Qi/Model/Locations.pm @@ -0,0 +1,7 @@ +package Qi::Model::Locations; +use Mojo::Base 'Qi::Model::Crud'; + +has table => 'locations'; +has primary_key => 'location_id'; + +1; \ No newline at end of file diff --git a/migrations/qi.sql b/migrations/qi.sql index 7de5912..7f220c4 100644 --- a/migrations/qi.sql +++ b/migrations/qi.sql @@ -40,7 +40,7 @@ CREATE TABLE if not exists assets ( revenue_percentage varchar(10) DEFAULT NULL, comments varchar(512) DEFAULT NULL, change_stamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - add_stamp timestamp NOT NULL + add_stamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE if not exists barcode_map ( @@ -51,7 +51,7 @@ CREATE TABLE if not exists barcode_map ( ); CREATE TABLE if not exists buyers ( - buyer_id serial NOT NULL DEFAULT '0', + buyer_id serial NOT NULL, name varchar(255) DEFAULT NULL, PRIMARY KEY ("buyer_id") ); @@ -94,7 +94,7 @@ CREATE TABLE if not exists sessions ( ); CREATE TABLE if not exists sold_via ( - sold_via_id serial NOT NULL DEFAULT '0', + sold_via_id serial NOT NULL, name varchar(255) DEFAULT NULL, PRIMARY KEY ("sold_via_id") ); @@ -113,7 +113,7 @@ CREATE TABLE if not exists users ( PRIMARY KEY ("user_id") ); -DROP VIEW asset_vw; +DROP VIEW if exists asset_vw; CREATE VIEW asset_vw AS select @@ -135,7 +135,7 @@ CREATE VIEW asset_vw AS -- 1 down -drop table if exists asset_types; +drop table if exists asset_types CASCADE; drop table if exists assets; drop table if exists barcode_map; drop table if exists buyers; diff --git a/script/Qi b/script/qi similarity index 100% rename from script/Qi rename to script/qi diff --git a/t/basic.t b/t/basic.t index 92a65a4..0907152 100644 --- a/t/basic.t +++ b/t/basic.t @@ -4,6 +4,45 @@ use Test::More; use Test::Mojo; my $t = Test::Mojo->new('Qi'); -$t->get_ok('/')->status_is(200)->content_like(qr/Mojolicious/i); +$t->get_ok('/')->status_is(200); + +$t = $t->post_ok('/api/assets' => {Accept =>'application/json' , dataType => 'json'} => json => {tag => '000000A' , add_stamp => '2016-08-10 16:21:21'}) + ->status_is(200) + ->json_has({table => 'assets'}) + ->json_has({tag => '000000A'}); + +$t = $t->put_ok('/api/assets' => {Accept =>'application/json' , dataType => 'json'} => json => { data => { tag => '000000B'} , where => {tag => '000000A'}}) + ->status_is(200) + ->json_has({table => 'assets'}) + ->json_has({tag => '000000B'}); + +$t = $t->get_ok('/api/assets' => {Accept =>'application/json'}) + ->status_is(200) + ->json_has({table => 'assets'}) + ->json_has({'assets'}); + +$t->get_ok('/api/assets' => {Accept => 'application/json' , dataType => 'json'} => json => {tag => '000000B'}) + ->status_is(200) + ->json_has({table => 'assets'}) + ->json_has({'asset'}); + +$t->delete_ok('/api/assets' => {Accept => 'application/json' , dataType => 'json'} => json => {tag => '000000B'}) + ->status_is(200) + ->json_has({table => 'assets'}) + ->json_has({tag => '000000B'}); + +$t = $t->get_ok('/api/locations' => {Accept =>'application/json'}) + ->status_is(200) + ->json_has({table => 'locations'}) + ->json_has({'locations'}); + +$t = $t->get_ok('/api/locations' => {Accept =>'application/json'}) + ->status_is(200) + ->json_has({table => 'locations'}) + ->json_has({'locations'}); + + + + done_testing();