diff --git a/cpanfile b/cpanfile index 4f5f6f9a..8012599b 100644 --- a/cpanfile +++ b/cpanfile @@ -3,6 +3,7 @@ requires "Digest" => "0"; requires "Exporter" => "0"; requires "File::Spec::Functions" => "0"; requires "FindBin" => "0"; +requires "Lingua::EN::Inflect::Phrase" => "0"; requires "JSON::Validator" => "5.00"; requires "Mojolicious" => "9"; requires "Mojolicious::Plugin::I18N" => "1.6"; diff --git a/lib/Yancy/Backend/Dbic.pm b/lib/Yancy/Backend/Dbic.pm index 998c6323..43eb4440 100644 --- a/lib/Yancy/Backend/Dbic.pm +++ b/lib/Yancy/Backend/Dbic.pm @@ -305,6 +305,11 @@ sub read_schema { my $default = ref $c->{default_value} eq 'SCALAR' ? ${ $c->{default_value} } : $c->{default_value }; + + if ( $default && $default =~ m#[\w]+\s*\(.*\)# && ! exists $fix_default{$default} ) { + $default = undef; + } + $schema{ $schema_name }{ properties }{ $column } = { $self->_map_type( $c ), $is_auto ? ( readOnly => true ) : (), @@ -394,6 +399,9 @@ sub _map_type { elsif ( $db_type =~ /(?:blob|bytea)/i ) { %conf = ( %conf, type => 'string', format => 'binary' ); } + elsif ( $db_type =~ /(?:uuid)/i ) { + %conf = ( %conf, type => 'string', format => 'uuid' ); + } else { # Default to string %conf = ( %conf, type => 'string' ); diff --git a/lib/Yancy/Controller/Yancy.pm b/lib/Yancy/Controller/Yancy.pm index 5596c346..eb21377d 100644 --- a/lib/Yancy/Controller/Yancy.pm +++ b/lib/Yancy/Controller/Yancy.pm @@ -2,6 +2,7 @@ package Yancy::Controller::Yancy; our $VERSION = '1.089'; # ABSTRACT: Basic controller for displaying content +use Lingua::EN::Inflect::Phrase; =head1 SYNOPSIS use Mojolicious::Lite; @@ -206,7 +207,7 @@ L =cut use Mojo::Base 'Mojolicious::Controller'; -use Mojo::JSON qw( to_json ); +use Mojo::JSON qw( to_json from_json ); use Yancy::Util qw( derp is_type ); use POSIX qw( ceil ); @@ -1262,18 +1263,66 @@ sub _get_list_args { $opt->{order_by} = $order_by; } + if ( my $join = $c->param( 'join' ) ) { + $opt->{ join } = $join; + my $json_join_param = eval { from_json ( $join ) }; + if ( $json_join_param ) { + $opt-> { join } = $json_join_param ; + } + } + if ( my $join = $c->stash( 'join' ) ) { $opt->{ join } = $join; } + # use Data::Dumper; + + my $joins = []; + if ( $opt->{ join } ) { + # $c->app->log->info( sprintf "join is: %s" , Dumper $opt->{ join } ); + my %joins ; + _get_unique_relations ( $opt-> { join } , \%joins ); + if ( keys %joins) { + $joins = [ keys %joins ]; + } + } + + # $c->app->log->info( sprintf "joins is: %s" , Dumper $joins ); + my $schema = $c->schema; + my $model = $schema->model; + + my $related_props = {} ; + # enumerate all the properties of all the joins and store in related_props + # keyed by 'join_name.property_name' + foreach my $join ( @$joins) { + # derieve the schema_name from join name. + my $schema_name = Mojo::Util::camelize ( Lingua::EN::Inflect::Phrase::to_S ( $join ) ); + eval { + my $join_schema = $model -> schema($schema_name); # may raise exception if $schema_name is not derieved properly. + my $schema_properties = $join_schema->{json_schema}->{properties} ; + # popuplate related_props with 'join_name.property_name' + map { $related_props->{"$join.$_"} = $schema_properties->{$_} } keys %{$schema_properties} ; + } + } + my $props = $schema->json_schema->{properties}; my %param_filter = (); for my $key ( @{ $c->req->params->names } ) { - next unless exists $props->{ $key }; - my $type = $props->{$key}{type} || 'string'; + next unless ( exists $props->{ $key } || exists $related_props->{ $key } ) ; + my $type = $props->{$key}{type} || $related_props->{$key}{type} || 'string'; + my $format = $props->{$key}{format} || $related_props->{$key}{format} // '' ; my $value = $c->param( $key ); - if ( is_type( $type, 'string' ) ) { + + # if the key belongs to main relation prefix with 'me.' + if ($opt->{ join } && $key !~ /\./) { + $key = "me.$key"; + } + + if ( is_type( $type, 'string' ) && $format eq 'uuid' ) { + $param_filter{ $key } = $value ; + } + elsif ( is_type( $type, 'string' ) ) { if ( ( $value =~ tr/*/%/ ) <= 0 ) { $value = "\%$value\%"; } @@ -1312,6 +1361,25 @@ sub _get_list_args { return ( $filter, $opt ); } +sub _get_unique_relations { + my ( $obj, $result) = @_; + unless ( ref $obj) { + $result->{$obj}++; + return; + } + if ( ref $obj eq 'ARRAY' && @$obj > 0 ) { + foreach my $x ( @$obj) { + &_get_unique_relations ( $x , $result); + } + } + if ( ref $obj eq 'HASH' && keys %{$obj} > 0 ) { + foreach my $key ( keys %{$obj} ) { + &_get_unique_relations ( $key , $result); + &_get_unique_relations ( $obj->{$key} , $result); + } + } +} + sub _resolve_filter { my ( $c ) = @_; my $filter = $c->stash( 'filter' );