### ----------------------------------------------------
### -- UpRooted
### -- Licenses: Artistic-2.0
### -- Authors: Paweł bbkr Pabian
### -- File: t/10-schema.rakutest
### ----------------------------------------------------
use lib 'lib';

use Test;

use UpRooted::Schema;
use UpRooted::Table;
use UpRooted::Column;
use UpRooted::Relation;

plan 4;

subtest 'UpRooted::Schema' => {

    plan 1;
    
    lives-ok {
        UpRooted::Schema.new( name => 's1' );
    }, 'UpRooted::Schema created';

};

subtest 'UpRooted::Table' => {

    plan 6;

    my $schema = UpRooted::Schema.new( name => 's1' );
    
    throws-like {
        $schema.table( 't1' );
    }, Exception, message => 'UpRooted::Table t1 is not present in UpRooted::Schema s1.', 'UpRooted::Table is not present in UpRooted::Schema';
    
    lives-ok {
        UpRooted::Table.new( :$schema, name => 't1' );
    }, 'UpRooted::Table created';

    ok $schema.table( 't1' ):defined, 'UpRooted::Table is present in UpRooted::Schema';
    
    throws-like {
        UpRooted::Table.new( :$schema, name => 't1' );
    }, Exception, message => 'UpRooted::Table t1 ia already present in UpRooted::Schema s1.', 'UpRooted::Table is already present in UpRooted::Schema';
    
    throws-like {
        $schema.add-table(
            UpRooted::Table.new( schema => UpRooted::Schema.new( name => 's2' ), name => 't2' )
        )
    }, Exception, message => 'UpRooted::Table t2 is from different UpRooted::Schema than s1.', 'UpRooted::Table is from different UpRooted::Schema';

    UpRooted::Table.new( :$schema, name => 't3' );
    UpRooted::Table.new( :$schema, name => 't2' );
    is-deeply $schema.tables.map( { .name } ), ( 't1', 't2', 't3' ), 'All UpRooted::Tables in alphabetical order';

}

subtest 'UpRooted::Column' => {
    
    plan 11;

    my $schema = UpRooted::Schema.new( name => 's1' );
    UpRooted::Table.new( :$schema, name => 't1' );
    
    throws-like {
        $schema.table( 't1' ).column( 'c1' );
    }, Exception, message => 'UpRooted::Column c1 is not present in UpRooted::Table t1.', 'UpRooted::Column is not present in UpRooted::Table';

    lives-ok {
        UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c1', type => 'tEXt', :!is-nullable );
    }, 'UpRooted::Column created';
    
    ok $schema.table( 't1' ).column( 'c1' ):defined, 'UpRooted::Column is present in UpRooted::Table';
    
    is $schema.table( 't1' ).column( 'c1' ).type, 'text', 'UpRooted::Column has known type which was lowercased';
    
    is $schema.table( 't1' ).column( 'c1' ).order, 1, 'Automatic UpRooted::Column order set';
    
    throws-like {
        UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c1', :!is-nullable );
    }, Exception, message => 'UpRooted::Column c1 ia already present in UpRooted::Table t1.', 'UpRooted::Column is already present in UpRooted::Table';

    throws-like {
        $schema.table( 't1' ).add-column(
            UpRooted::Column.new( table => UpRooted::Table.new( :$schema, name => 't2' ), name => 'c2', :is-nullable )
        );
    }, Exception, message => 'UpRooted::Column c2 is from different UpRooted::Table than t1.', 'UpRooted::Column is from different UpRooted::Table';

    UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c3', :!is-nullable, order => 3 );
    
    nok $schema.table( 't1' ).column( 'c3' ).type.defined, 'UpRooted::Column has not known type';
    
    UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c2', :!is-nullable, order => 2 );
    is-deeply $schema.table( 't1' ).columns.map( { .name } ), ( 'c1', 'c2', 'c3' ), 'All UpRooted::Columns in definition order';
    
    is-deeply $schema.table( 't1' ).columns( 'c3', 'c1' ).map( { .name } ), ( 'c3', 'c1' ), 'Subset of UpRooted::Columns in requested order';

    throws-like {
        UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c4', :!is-nullable, order => 1 );
    }, Exception, message => 'UpRooted::Column c4 has order conflict in UpRooted::Table t1.', 'UpRooted::Column has order conflict in UpRooted::Table';

}

subtest 'UpRooted::::Relation' => {
    
    plan 16;

    my $schema = UpRooted::Schema.new( name => 's1' );
    UpRooted::Table.new( :$schema, name => 't1' );
    UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c1', :!is-nullable );
    UpRooted::Column.new( table => $schema.table( 't1' ), name => 'c2', :!is-nullable );
    UpRooted::Table.new( :$schema, name => 't2' );
    UpRooted::Column.new( table => $schema.table( 't2' ), name => 'c3', :!is-nullable );
    UpRooted::Column.new( table => $schema.table( 't2' ), name => 'c4', :is-nullable );

    throws-like {
        $schema.table( 't1' ).child-relation( 'r1' );
    }, Exception, message => 'UpRooted::Relation r1 is not present in UpRooted::Table t1.', 'UpRooted::Relation is not present in UpRooted::Table';
    
    lives-ok {
        UpRooted::Relation.new(
            parent-columns => $schema.table( 't1' ).columns( 'c1' ),
            child-columns => $schema.table( 't2' ).columns( 'c3' ),
            name => 'r1'
        );
    }, 'UpRooted::Relation on single UpRooted::Column created';
    
    ok $schema.table( 't1' ).child-relation( 'r1' ):defined, 'UpRooted::Relation is present in UpRooted::Table';
    
    ok $schema.table( 't1' ).child-relation( 'r1' ).is-blocked.not, 'UpRooted::Relation is not blocked by default';
    $schema.table( 't1' ).child-relation( 'r1' ).is-blocked = True;
    ok $schema.table( 't1' ).child-relation( 'r1' ).is-blocked, 'UpRooted::Relation can be blocked if needed';
    
    with $schema.table( 't1' ).child-relation( 'r1' ) {
        is .parent-table, $schema.table( 't1' ), 'UpRooted::Relation knows parent UpRooted::Table from UpRooted::Columns';
        is .child-table, $schema.table( 't2' ), 'UpRooted::Relation knows child UpRooted::Table from UpRooted::Columns';
        nok .is-nullable, 'UpRooted::Relation is not nullable.';
    }
    
    throws-like {
        UpRooted::Relation.new(
            parent-columns => $schema.table( 't1' ).columns( 'c1' ),
            child-columns => $schema.table( 't2' ).columns( 'c3' ),
            name => 'r1'
        );
    }, Exception, message => 'UpRooted::Relation r1 ia already present in parent UpRooted::Table t1.', 'UpRooted::Relation is already present in UpRooted::Table';
    
    lives-ok {
        UpRooted::Relation.new(
            parent-columns => $schema.table( 't1' ).columns( 'c1', 'c2' ),
            child-columns => $schema.table( 't2' ).columns( 'c3', 'c4' ),
            name => 'r2'
        );
    }, 'UpRooted::Relation on multiple UpRooted::Columns created';
    
    ok $schema.table( 't1' ).child-relation( 'r2' ).is-nullable, 'UpRooted::Relation is nullable.';
    
    is-deeply $schema.table( 't1' ).children-relations.map( { .name } ), ( 'r1', 'r2' ), 'All UpRooted::Relations to child UpRooted::Tables in name order';
    
    throws-like {
        UpRooted::Relation.new(
            parent-columns => $schema.table( 't1' ).columns( 'c1' ),
            child-columns => $schema.table( 't2' ).columns( 'c3', 'c4' ),
            name => 'r3'
        );
    }, Exception, message => 'Parent and child UpRooted::Columns count different in UpRooted::Relation r3.', 'UpRooted::Column count for parent and child UpRooted::Table is different';
    
    throws-like {
        UpRooted::Relation.new(
            parent-columns => [ $schema.table( 't1' ).column( 'c1' ), $schema.table( 't2' ).column( 'c3' ) ],
            child-columns => $schema.table( 't2' ).columns( 'c3', 'c4' ),
            name => 'r3'
        );
    }, Exception, message => 'Parent UpRooted::Columns must be from the same UpRooted::Table in UpRooted::Relation r3.', 'UpRooted::Columns from two different parent UpRooted::Tables';
    
    throws-like {
        UpRooted::Relation.new(
            parent-columns => $schema.table( 't1' ).columns( 'c1', 'c2' ),
            child-columns => [ $schema.table( 't1' ).column( 'c1' ), $schema.table( 't2' ).column( 'c3' ) ],
            name => 'r3'
        );
    }, Exception, message => 'Child UpRooted::Columns must be from the same UpRooted::Table in UpRooted::Relation r3.', 'UpRooted::Columns from two different child UpRooted::Tables';
    
    throws-like {
        $schema.table( 't1' ).add-child-relation(
            UpRooted::Relation.new(
                parent-columns => $schema.table( 't2' ).columns( 'c3' ),
                child-columns => $schema.table( 't2' ).columns( 'c4' ),
                name => 'r3'
            )
        );
    }, Exception, message => 'UpRooted::Relation r3 is from different parent UpRooted::Table than t1.', 'UpRooted::Relation is from different parent UpRooted::Table';

}


