use strict; use warnings; use Test::More; use lib 't/lib'; use Fey::ORM::Test; use Fey::Literal::String; use Fey::Placeholder; use Fey::Test; Fey::ORM::Test::define_live_classes(); Fey::ORM::Test::insert_user_data(); { package Message; use Fey::ORM::Table; has_one Schema->Schema()->table('User'); has_one 'parent_message' => ( table => Schema->Schema()->table('Message') ); } { my $parent = Message->insert( message => 'parent body', user_id => 1, ); is( $parent->user()->user_id(), 1, 'user() for parent message returns expected user object' ); is( $parent->user(), $parent->user(), 'user() attribute is cached' ); is( $parent->parent_message(), undef, 'parent message has no parent itself' ); my $child = Message->insert( message => 'child body', parent_message_id => $parent->message_id(), user_id => 1, ); my $parent_from_attr = $child->parent_message(); is( $parent_from_attr->message_id(), $parent->message_id(), 'parent_message() attribute created via has_one returns expected message' ); } { package Message; __PACKAGE__->meta()->remove_has_one('user'); has_one 'user' => ( table => Schema->Schema()->table('User'), cache => 0, ); } { my $message = Message->insert( message => 'message body', user_id => 1, ); is( $message->user()->user_id(), 1, 'user() for parent message returns expected user object' ); isnt( $message->user(), $message->user(), 'user() attribute is not cached' ); } { my $schema = Schema->Schema(); $schema->remove_foreign_key($_) for $schema->foreign_keys_between_tables( 'Message', 'User' ); $schema->remove_foreign_key($_) for $schema->foreign_keys_between_tables( 'Message', 'Message' ); # These definitions invert the source/target labeling of the # corresponding FKs in Fey::Test. The goal is to test that has_one # figures out the proper "direction" of the FK. my $fk1 = Fey::FK->new( source_columns => [ $schema->table('User')->column('user_id') ], target_columns => [ $schema->table('Message')->column('user_id') ], ); my $fk2 = Fey::FK->new( source_columns => [ $schema->table('Message')->column('message_id') ], target_columns => [ $schema->table('Message')->column('parent_message_id') ], ); $schema->add_foreign_key($_) for $fk1, $fk2; package Message; __PACKAGE__->meta()->remove_has_one('user'); has_one $schema->table('User'); __PACKAGE__->meta()->remove_has_one('parent_message'); has_one 'parent_message' => ( table => $schema->table('Message') ); } inverted_fk_tests(); { # This next set of tests is the same as the last, except this time we # explicitly provide the Fey::FK object, and test that it gets inverted. package Message; my $schema = Schema->Schema(); __PACKAGE__->meta()->remove_has_one('user'); my ($fk) = $schema->foreign_keys_between_tables( $schema->tables( 'Message', 'User' ) ); has_one user => ( table => $schema->table('User'), fk => $fk, ); __PACKAGE__->meta()->remove_has_one('parent_message'); ($fk) = $schema->foreign_keys_between_tables( $schema->tables( 'Message', 'Message' ) ); has_one 'parent_message' => ( table => $schema->table('Message'), fk => $fk, ); } inverted_fk_tests(); { package User; use Fey::ORM::Table; my $select = Schema->SQLFactoryClass()->new_select() ->select( Schema->Schema()->table('Message') ) ->from( Schema->Schema()->table('Message') )->where( Schema->Schema()->table('Message')->column('user_id'), '=', Fey::Placeholder->new() ) ->order_by( Schema->Schema()->table('Message')->column('message_id'), 'DESC' )->limit(1); has_one 'most_recent_message' => ( table => Schema->Schema()->table('Message'), select => $select, bind_params => sub { $_[0]->user_id() }, ); } { my $user = User->new( user_id => 1 ); my $message = $user->most_recent_message(); isa_ok( $message, 'Message', 'most_recent_message() returns Message object' ); my ($most_recent_message_id) = ( Schema->DBIManager()->default_source()->dbh() ->selectcol_arrayref('SELECT MAX(message_id) FROM Message') ) ->[0]; is( $message->message_id(), $most_recent_message_id, 'message object is the most recently inserted message' ); is( $message->user_id(), $user->user_id(), 'message belongs to the user' ); } sub inverted_fk_tests { local $Test::Builder::Level = $Test::Builder::Level + 1; my $parent = Message->insert( message => 'parent body', user_id => 1, ); is( $parent->user()->user_id(), 1, 'user() for parent message returns expected user object' ); is( $parent->parent_message(), undef, 'parent message has no parent itself' ); my $child = Message->insert( message => 'child body', parent_message_id => $parent->message_id(), user_id => 1, ); my $parent_from_attr = $child->parent_message(); is( $parent_from_attr->message_id(), $parent->message_id(), 'parent_message() attribute created via has_one returns expected message' ); } done_testing();