The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl 

use strict;
use warnings;
use File::Basename;
use lib File::Basename::dirname(__FILE__)."/../../../lib";
use lib File::Basename::dirname(__FILE__)."/../..";
use UR;
use URT::DataSource::SomeSQLite;
use Test::More tests => 19;

# This test does a query that joins three tables.
# The get() is done on an is-many property, and its reverse_as is a delegated
# property through a third class

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

$dbh->do('create table car (car_id integer not null primary key, model varchar not null)');
$dbh->do('create table driver (driver_id integer not null primary key, name varchar not null)');
$dbh->do('create table car_driver (car_id integer not null references car(car_id), driver_id integer not null references driver(driver_id))');

$dbh->do("insert into car values (1,'batmobile')");
$dbh->do("insert into car values (2,'race car')");
$dbh->do("insert into car values (3,'mach 5')");
$dbh->do("insert into car values (4,'junked car')");

$dbh->do("insert into driver values (1,'batman')");
$dbh->do("insert into driver values (2,'mario')");
$dbh->do("insert into driver values (3,'speed racer')");
$dbh->do("insert into driver values (4,'superman')");

# batman drives the batmobile
$dbh->do("insert into car_driver values (1,1)");

# mario and speed racer drive the race car
$dbh->do("insert into car_driver values (2,2)");
$dbh->do("insert into car_driver values (2,3)");

# speed racer also drives the mach 5
$dbh->do("insert into car_driver values (3,3)");

# superman doesn't drive anything
# no one drives the junked car

UR::Object::Type->define(
    class_name => 'URT::Car',
    data_source => 'URT::DataSource::SomeSQLite',
    table_name => 'car',
    id_by => [
        car_id => { is => 'Integer' },
    ],
    has => [
        model => { is => 'String', },
    ],
    has_many => [
        car_drivers  => { is => 'URT::CarDriver', reverse_as => 'car' },
        drivers      => { is => 'URT::Driver', via => 'car_drivers', to => 'driver' },  # regular many-to-many property def'n
        driver_names => { is => 'String', via => 'drivers', to => 'name' },
    ],
);

UR::Object::Type->define(
    class_name => 'URT::Driver',
    data_source => 'URT::DataSource::SomeSQLite',
    table_name => 'driver',
    id_by => [
        driver_id => { is => 'Integer' },
    ],
    has => [
        name => { is => 'String' },
    ],
    has_many => [
        cars       => { is => 'URT::Car', reverse_as => 'drivers' }, # not the usual way to make a many-to-many property def'n
        car_models => { is => 'String', via => 'cars', to => 'model' },
    ],
);

UR::Object::Type->define(
    class_name => 'URT::CarDriver',
    data_source => 'URT::DataSource::SomeSQLite',
    table_name => 'car_driver',
    id_by => [
        car_id   => { is => 'Integer' },
        driver_id => { is => 'Integer' },
    ],
    has => [
        car    => { is => 'URT::Car', id_by => 'car_id' },
        driver => { is => 'URT::Driver', id_by => 'driver_id' },
    ],
);


my $query_count = 0;
ok(URT::DataSource::SomeSQLite->create_subscription(
                    method => 'query',
                    callback => sub { $query_count++ }),
   'Created a subscription for query');

$query_count = 0;
my $driver = URT::Driver->get(name => 'batman');
ok($driver, 'got the batman driver');
is($query_count, 1, 'Made 1 query');

$query_count = 0;
my @cars = $driver->cars();
is(scalar(@cars), 1, 'batman drives 1 car');
is($query_count, 1, 'Made 1 query');
is($cars[0]->model, 'batmobile', 'It is the right car');

$query_count = 0;
@cars = $driver->cars();
is(scalar(@cars), 1, 'trying again, batman drives 1 car');
TODO: {
    local $TODO = "query cache doesn't track properties like drivers.id";
    is($query_count, 0, 'Made no queries');
}
is($cars[0]->model, 'batmobile', 'It is the right car');


$query_count = 0;
my @models = $driver->car_models();
is(scalar(@models), 1, 'batman has 1 car model');
is_deeply(\@models, ['batmobile'], 'Got the right car');
is($query_count, 0, 'Made 0 queries');



$driver = URT::Driver->get(name => 'speed racer');
ok($driver, 'Got speed racer');

$query_count = 0;
@models = $driver->car_models();
is(scalar(@models), 2, 'speed racer drives 2 cars');
@models = sort @models;
is_deeply(\@models, ['mach 5', 'race car'], 'Got the right cars');
is($query_count, 1, 'Made 1 query');



$driver = URT::Driver->get(name => 'superman');
ok($driver, 'Got superman');

$query_count = 0;
@models = $driver->car_models();
is(scalar(@models), 0, 'superman drives 0 cars');
TODO: {
    local $TODO = "UR::BX::Template->resolve needs to support meta opt -hints to make this work";
    is($query_count, 1, 'Made 1 query');
}