diff --git a/lib/Mojolicious/Plugin/Yancy.pm b/lib/Mojolicious/Plugin/Yancy.pm index 7846d3a3..f345869d 100644 --- a/lib/Mojolicious/Plugin/Yancy.pm +++ b/lib/Mojolicious/Plugin/Yancy.pm @@ -87,8 +87,10 @@ C configuration as needed. my $be = $c->yancy->backend; -Get the currently-configured Yancy backend object. See L -for the methods you can call on a backend object and their purpose. +Get the Yancy backend object. By default, gets the backend configured +while loading the Yancy plugin. Requests can override the backend by +setting the C stash value. See L for the +methods you can call on a backend object and their purpose. =head2 yancy.plugin @@ -586,7 +588,13 @@ sub register { # Load the backend and schema $config = { %$config }; $app->helper( 'yancy.backend' => sub { - state $backend = load_backend( $config->{backend}, $config->{schema} || $config->{openapi}{definitions} ); + my ( $c ) = @_; + state $default_backend = load_backend( $config->{backend}, $config->{schema} || $config->{openapi}{definitions} ); + if ( my $backend = $c->stash( 'backend' ) ) { + $c->app->log->debug( 'Using override backend from stash: ' . ref $backend ); + return $backend; + } + return $default_backend; } ); if ( $config->{schema} || $config->{read_schema} ) { $config->{schema} = $config->{schema} ? dclone( $config->{schema} ) : {}; diff --git a/lib/Yancy/Plugin/Editor.pm b/lib/Yancy/Plugin/Editor.pm index 98898b22..1b13a231 100644 --- a/lib/Yancy/Plugin/Editor.pm +++ b/lib/Yancy/Plugin/Editor.pm @@ -167,6 +167,8 @@ has moniker => 'editor'; has route =>; has includes => sub { [] }; has menu_items => sub { +{} }; +has backend =>; +has schema =>; sub _helper_name { my ( $self, $name ) = @_; @@ -176,6 +178,9 @@ sub _helper_name { sub register { my ( $self, $app, $config ) = @_; + $self->backend( $config->{backend} ); + $self->schema( $config->{schema} ); + for my $key ( grep exists $config->{ $_ }, qw( moniker ) ) { $self->$key( $config->{ $key } ); } @@ -184,6 +189,7 @@ sub register { derp 'api_controller configuration is deprecated. Use editor.default_controller instead'; } + # XXX: Throw an error if there is already a route here my $route = $config->{route} // $app->routes->any( '/yancy' ); $route->to( return_to => $config->{return_to} // '/' ); @@ -232,7 +238,7 @@ sub register { $self->_openapi_spec_add_mojo( $spec, $config ); my $openapi = $app->plugin( OpenAPI => { - route => $route->any( '/api' )->name( 'yancy.api' ), + route => $route->any( '/api' )->to( backend => $self->backend )->name( 'yancy.api' ), spec => $spec, default_response_name => '_Error', } ); diff --git a/t/lib/Yancy/Backend/Test.pm b/t/lib/Yancy/Backend/Test.pm index 8303c78d..b830a787 100644 --- a/t/lib/Yancy/Backend/Test.pm +++ b/t/lib/Yancy/Backend/Test.pm @@ -16,15 +16,13 @@ our @SCHEMA_ADDED_COLLS; sub new { my ( $class, $url, $schema ) = @_; - my ( $path ) = $url =~ m{^[^:]+://[^/]+(?:/(.+))?$}; - if ( $path ) { - %DATA = %{ from_json( path( ( $ENV{MOJO_HOME} || () ), $path )->slurp ) }; - } elsif ( %Yancy::Backend::Test::SCHEMA ) { - # M::P::Y relies on "read_schema" to give back the "real" schema. - # If given the micro thing, this is needed to make it actually - # operate like it would with a real database - $schema = \%Yancy::Backend::Test::SCHEMA; + if ( $url ) { + my ( $path ) = $url =~ m{^[^:]+://[^/]+(?:/(.+))?$}; + if ( $path ) { + %DATA = %{ from_json( path( ( $ENV{MOJO_HOME} || () ), $path )->slurp ) }; + } } + $schema //= \%SCHEMA; return bless { init_arg => $url, schema => $schema }, $class; } @@ -193,7 +191,8 @@ sub _is_type { sub read_schema { my ( $self, @table_names ) = @_; - my $cloned = dclone $self->collections; + my $schema = %SCHEMA ? \%SCHEMA : $self->schema; + my $cloned = dclone $schema; delete @$cloned{@SCHEMA_ADDED_COLLS}; # ones not in the "database" at all # zap all things that DB can't know about for my $c ( values %$cloned ) { diff --git a/t/plugin/editor.t b/t/plugin/editor.t index 23203dcd..4644b871 100644 --- a/t/plugin/editor.t +++ b/t/plugin/editor.t @@ -47,4 +47,60 @@ subtest 'menu' => sub { ; }; +subtest 'non-default backend' => sub { + my $new_schema = { + pets => { + required => [qw( name type )], + properties => { + id => { + type => 'integer', + readOnly => 1, + }, + name => { + type => 'string', + }, + type => { + type => 'string', + enum => [qw( cat dog bird rat snake )], + }, + }, + }, + }; + + my $ted = { + name => 'Theodore', + type => 'cat', + }; + my $franklin = { + name => 'Franklin', + type => 'cat', + }; + + my $new_backend = Yancy::Backend::Test->new( undef, $new_schema ); + $ted->{id} = $new_backend->create( pets => $ted ); + $franklin->{id} = $new_backend->create( pets => $franklin ); + + my $app = Mojolicious->new; + $app->plugin( Yancy => { %backend_conf } ); + $app->yancy->plugin( Editor => { + backend => $new_backend, + schema => $new_schema, + moniker => 'pets', + require_user => undef, + route => $app->routes->get( '/pets/editor' ), + } ); + + my $t = Test::Mojo->new( $app ); + $t->get_ok( '/yancy/api' )->status_is( 200 ) + ->json_has( '/definitions/people', 'got original schema at original url' ) + ->or( sub { diag explain shift->tx->res->json } ) + ->get_ok( '/pets/editor/api' )->status_is( 200 ) + ->json_has( '/definitions/pets', 'got new schema at new url' ) + ->or( sub { diag explain shift->tx->res->json } ) + ->get_ok( '/pets/editor/api/pets/' . $ted->{id} )->status_is( 200 ) + ->json_is( $ted ) + ->or( sub { diag explain shift->tx->res->json } ) + ; +}; + done_testing;