### ----------------------------------------------------
### -- Gherkin::Grammar
### -- Licenses: Artistic-2.0
### -- Authors: Anton Antonov
### -- File: resources/DSL-for-data-wrangling.rakutest
### ----------------------------------------------------
use v6.d;

use Data::ExampleDatasets;
use Data::Reshapers;
use Data::Summarizers;
use DSL::English::DataQueryWorkflows;

#============================================================

proto sub Background($descr) {*}
proto sub ScenarioOutline(@cmdFuncPairs) {*}
proto sub Example($descr) {*}
proto sub Given(Str:D $cmd, |) {*}
proto sub When(Str:D $cmd, |) {*}
proto sub Then(Str:D $cmd, |) {*}

#============================================================

use Test;
plan *;

#============================================================
# Background : Load data
#------------------------------------------------------------
my Str $target;

multi sub Given('target is "raku"') {
    $target = 'Raku::Reshapers';
}

my @dsTitanic;

multi sub Then('titanic dataset exists') {
    @dsTitanic = get-titanic-dataset;
    return @dsTitanic ~~ Array;
}

multi sub Then(
        $cmd where * eq 'the columns of the titanic dataset are "id passengerAge passengerClass passengerSex passengerSurvival"') {
    if $cmd ~~ / \"(<-["]>+)\" / {
        return @dsTitanic.head.keys.sort eq ~$0.split(/\s/)>>.trim.sort.List;
    }
    return False;
}

multi sub Background('Load data') {
    Given('target is "raku"');
    Then('titanic dataset exists') and
    Then('the columns of the titanic dataset are "id passengerAge passengerClass passengerSex passengerSurvival"');
}

is Background('Load data'), True, 'Load data';

#============================================================
# Example : Group and count
#------------------------------------------------------------
my $parseResult1;

multi sub When($cmd where $cmd eq 'group by passengerSex; counts') {
    $parseResult1 = ToDataQueryWorkflowCode("DSL TARGET $target; use @dsTitanic;" ~ $cmd);
    say "Result for:\n```dsl\n$cmd\n```\nis:\n```raku\n$parseResult1\n```";
}

multi sub Then('result is a hash') {
    use MONKEY-SEE-NO-EVAL;
    # The code generated code uses the variables $obj
    my $obj;
    EVAL($parseResult1);
    $obj ~~ Hash;
}

multi sub Example('Group and count') {
    When('group by passengerSex; counts');
    Then('result is a hash');
}

Background('Load data');

is Example('Group and count'), True, 'Group and count';

#============================================================
# Example : Slicing
#------------------------------------------------------------
my $parseResult2;

multi sub When( $cmd where * eq 'take the elements from 12 to 511' ) {
    $parseResult2 = ToDataQueryWorkflowCode("DSL TARGET $target; use @dsTitanic;" ~ $cmd);
    say "Result for pipeline:\n```dsl\n{$cmd.lines>>.trim.join("\n")}\n```\nis:\n```raku\n$parseResult2\n```";
}

multi sub Then( $cmd where *.starts-with('the result length is')) {
    use MONKEY-SEE-NO-EVAL;
    if $cmd ~~ / \"(<-["]>+)\" / {
        my $obj;
        EVAL($parseResult2);
        return $obj.elems == $0.Str.Int;
    }
    return False;
}

multi sub Example('Slicing') {
    When( 'take the elements from 12 to 511' );
    Then( 'the result length is "500"' );
}

Background('Load data');

is Example('Slicing'), True, 'Slicing';

#============================================================
# Example : Long pipeline
#------------------------------------------------------------

multi sub When( 'is executed the pipeline:', Str $cmd) {
    $parseResult1 = ToDataQueryWorkflowCode("DSL TARGET $target;" ~ $cmd);
    say "Result for pipeline:\n```dsl\n{$cmd.lines>>.trim.join("\n")}\n```\nis:\n```raku\n$parseResult1\n```";
}

multi sub Example('Long pipeline') {
    When( 'is executed the pipeline:', '
      use @dsTitanic;
      filter by passengerSurvival is "survived";
      cross tabulate passengerSex vs passengerClass
      ' );
    Then( 'result is a hash' );
}

Background('Load data');

is Example('Long pipeline'), True, 'Long pipeline';

done-testing;


