The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;

use File::Basename;
use lib File::Basename::dirname(__FILE__)."/../../../lib";
use lib File::Basename::dirname(__FILE__)."/../..";
use URT;

use Test::More tests => 17;
use URT::DataSource::SomeSQLite;

# This tests a get() where the filtering property has several levels of indirection
# - A Person has a Job, which has a Location, which has a phone number
# - A Person's phone number for their job can be linked together a couple
#   of different ways
#     1) 
#        a) Location has a phone number
#        b) Job has-a location, id-by the location_id property
#        c) Job has-a phone number via the Location
#        d) Person has-a Job, linked with the job_id property
#        e) Person has-a job_phone, via the Job (which is via the Location)
#     2) a,b same as above
#        c) Person has-a location_id via the Job
#        d) Person has-a Location, id-by the location_id (which is via the Job)
#        e) Person has-a work_phone, via the Location

&setup_classes_and_db();

# This is the way we usually do a doubly-indirect property
my $person = URT::Person->get(job_phone => '456-789-0123');
ok($person, 'get() returned an object');
isa_ok($person, 'URT::Person');
is($person->name, 'Joe', 'Got the right person');
is($person->job_name, 'cleaner', 'With the right job name');
is ($person->job_phone, '456-789-0123', 'the right job_phone');
is ($person->work_phone, '456-789-0123', 'and the right work_phone');

# This one wasn't working before I fixed UR::Object::Property::_get_joins()
$person = URT::Person->get(work_phone => '123-456-7890');

ok($person, 'get() returned an object');
isa_ok($person, 'URT::Person');
is($person->name, 'Bob', 'Got the right person');
is($person->job_name, 'cook', 'With the right job name');
is($person->job_phone, '123-456-7890', 'the right job_phone');
is($person->work_phone, '123-456-7890', 'and the right work_phone');


sub setup_classes_and_db {
    my $dbh = URT::DataSource::SomeSQLite->get_default_handle;

    ok($dbh, 'Got DB handle');

    ok( $dbh->do("create table locations (location_id integer, phone_number varchar, address varchar)"),
       'Created locations table');

    ok( $dbh->do("create table jobs (job_id integer, job_name varchar, location_id integer REFERENCES locations(location_id))"),
       'Created jobs table');

    ok( $dbh->do("create table persons (person_id integer, name varchar, job_id integer REFERENCES jobs(job_id))"),
       'Created persons table');

    # First person 
    $dbh->do("insert into locations (location_id, phone_number, address) values (1,'123-456-7890','123 Fake St')");
    $dbh->do("insert into jobs (job_id, job_name, location_id) values (1, 'cook', 1)");
    $dbh->do("insert into persons (person_id, name, job_id) values(1,'Bob', 1)");

    # second
    $dbh->do("insert into locations (location_id, phone_number, address) values (2,'456-789-0123','987 Main St')");
    $dbh->do("insert into jobs (job_id, job_name, location_id) values (2, 'cleaner', 2)");
    $dbh->do("insert into persons (person_id, name, job_id) values(2,'Joe', 2)");

    ok($dbh->commit(), 'DB commit');
           
    UR::Object::Type->define(
        class_name => 'URT::Location',
        id_by => [
            location_id => { is => 'Integer' },
        ],
        has => [
            phone_number => { is => 'String' },
            address      => { is => 'String' },
        ],
        data_source => 'URT::DataSource::SomeSQLite',
        table_name => 'locations',
    );

    UR::Object::Type->define(
        class_name => 'URT::Job',
        id_by => [
            job_id => { is => 'Integer' },
        ],
        has => [
            job_name => { is => 'String' },
            location => { is => 'URT::Location', id_by => 'location_id' },
            location_phone => { via => 'location', to => 'phone_number' },
        ],
        data_source => 'URT::DataSource::SomeSQLite',
        table_name => 'jobs',
    );

    UR::Object::Type->define(
        class_name => 'URT::Person',
        id_by => [
            person_id => { is => 'Integer' },
        ],
        has => [
            name   => { is => 'String' },

            job_id   => { is => 'Integer' },
            job      => { is => 'URT::Job', id_by => 'job_id' },
            job_name => { via => 'job' },
            job_phone => { via => 'job', to => 'location_phone' },

            work_location_id => { via => 'job', to => 'location_id' },
            work_location    => { is => 'URT::Location', id_by => 'work_location_id' },
            work_phone       => { via => 'work_location', to => 'phone_number' },
        ],
        data_source => 'URT::DataSource::SomeSQLite',
        table_name => 'persons',
    );
}