Red.git | t/ | 01-tdd.rakutest
use Test;
use Red::Cli::Table;
plan :skip-all("Different driver setted ($_)") with %*ENV<RED_DATABASE>;
my $*RED-FALLBACK = False;
use-ok "Red";
use Red;
use Red::ResultSeq;
use Red::AST::Infixes;
my $*RED-DB = database "Mock";
my $*RED-DRY-RUN = True;
my $*RED-DEBUG = so %*ENV<RED_DEBUG>;
#isa-ok model {}.HOW, MetamodelX::Red::Model;
can-ok model {}.HOW, "columns";
can-ok model {}.HOW, "is-dirty";
can-ok model {}.HOW, "clean-up";
can-ok model {}.HOW, "dirty-columns";
given model { has $!a is column }.new: :42a {
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.^clean-up;
ok not .^is-dirty;
dies-ok { .a };
}
given model { has $.a is column }.new: :42a {
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.^clean-up;
ok not .^is-dirty;
is .a, 42;
dies-ok { .a = 42 };
ok not .^is-dirty;
}
given model { has $.a is rw is column }.new {
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.^clean-up;
ok not .^is-dirty;
.a = 42;
is .a, 42;
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.^clean-up;
#.a(:clean) = 13;
#is .a, 13;
#ok not .^is-dirty;
}
given model { has $.a is rw is column; has $.b is rw is column }.new {
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a $!b >;
.^clean-up;
ok not .^is-dirty;
.a = 42;
is .a, 42;
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.b = 13;
is .b, 13;
is .^dirty-columns.keys.sort, < $!a $!b >;
.^clean-up;
ok not .^is-dirty;
}
given model :: { has UInt $.a is rw is id; has Int $.b is rw is column }.new {
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a $!b >;
.^save;
ok not .^is-dirty;
.a = 42;
is .a, 42;
ok .^is-dirty;
is .^dirty-columns.keys.sort, < $!a >;
.b = 13;
is .b, 13;
is .^dirty-columns.keys.sort, < $!a $!b >;
.^save;
ok not .^is-dirty;
}
given model {
has $.a is column;
has $!b is column;
has $!c is column{:id, :name<column_c>, :!nullable};
} {
my $*RED-INTERNAL = True;
use Red::Column;
use Red::AST::Value;
isa-ok .a, Red::Column;
is .a.name, "a";
isa-ok .b, Red::Column;
is .b.name, "b";
isa-ok .c, Red::Column;
is .c.name, "column_c";
ok .c.id;
ok not .c.nullable;
use Red::AST;
my $a = 42;
is
(.a == 42).raku,
Red::AST::Eq.new(Red::AST::Cast.new(.a, "num"), ast-value(42)).raku
;
is
(42 == .a).raku,
Red::AST::Eq.new(ast-value(42), Red::AST::Cast.new(.a, "num")).raku
;
is
(.a == $a).raku,
Red::AST::Eq.new(Red::AST::Cast.new(.a, "num"), ast-value(42), :bind-right).raku
;
is
($a == .a).raku,
Red::AST::Eq.new(ast-value(42), Red::AST::Cast.new(.a, "num"), :bind-left).raku
;
is
(.a != 42).raku,
Red::AST::Ne.new(Red::AST::Cast.new(.a, "num"), ast-value(42)).raku
;
is
(42 != .a).raku,
Red::AST::Ne.new(ast-value(42), Red::AST::Cast.new(.a, "num")).raku
;
is
(.a != $a).raku,
Red::AST::Ne.new(Red::AST::Cast.new(.a, "num"), ast-value(42), :bind-right).raku
;
is
($a != .a).raku,
Red::AST::Ne.new(ast-value(42), Red::AST::Cast.new(.a, "num"), :bind-left).raku
;
my $b = "lorem ipsum";
is
(.a eq "lorem ipsum").raku,
Red::AST::Eq.new(Red::AST::Cast.new(.a, "str"), ast-value("lorem ipsum")).raku
;
is
("lorem ipsum" eq .a).raku,
Red::AST::Eq.new(ast-value("lorem ipsum"), Red::AST::Cast.new(.a, "str")).raku
;
is
(.a eq $b).raku,
Red::AST::Eq.new(Red::AST::Cast.new(.a, "str"), ast-value("lorem ipsum"), :bind-right).raku
;
is
($b eq .a).raku,
Red::AST::Eq.new(ast-value("lorem ipsum"), Red::AST::Cast.new(.a, "str"), :bind-left).raku
;
is
(.a ne "lorem ipsum").raku,
Red::AST::Ne.new(Red::AST::Cast.new(.a, "str"), ast-value("lorem ipsum")).raku
;
is
("lorem ipsum" ne .a).raku,
Red::AST::Ne.new(ast-value("lorem ipsum"), Red::AST::Cast.new(.a, "str")).raku
;
is
(.a ne $b).raku,
Red::AST::Ne.new(Red::AST::Cast.new(.a, "str"), ast-value("lorem ipsum"), :bind-right).raku
;
is
($b ne .a).raku,
Red::AST::Ne.new(ast-value("lorem ipsum"), Red::AST::Cast.new(.a, "str"), :bind-left).raku
;
}
given model A {} {
isa-ok .^rs, Red::DefaultResultSeq;
}
#class B::ResultSeq does Red::ResultSeq { has $.works = True }
#given model B {} {
# isa-ok .^rs, B::ResultSeq;
# ok .^rs.works;
#}
lives-ok {
class MyResultSet does Red::ResultSeq {has $.is-it-custom = True}
given model C is rs-class(MyResultSet) {} {
isa-ok .^rs, MyResultSet;
ok .^rs.is-it-custom
}
}
given model D is rs-class<MyResultSet> {} {
isa-ok .^rs, MyResultSet;
ok .^rs.is-it-custom
}
#`{{{
eval-lives-ok q[
use Red;
class B::ResultSeq {}
model B {}
];
eval-lives-ok q[
class MyResultSet {}
model C is rs-class(MyResultSet) {}
];
eval-lives-ok q[
class MyResultSet {}
model D is rs-class<MyResultSet> {}
];
}}}
given model BlaBleBli {} {
is .^table, "bla_ble_bli";
}
given model BlaBleBli2 is table<not_that> {} {
is .^table, "not_that";
}
model Person { ... }
model Post {
has Int $.id is column{ :id };
has Int $.author-id is column{ :references{ .id }, :model-name<Person> };
has Person $.author is relationship{ .author-id };
}
model Person {
has Int $.id is column{ :id };
has Str $.name is column;
has Post @.posts is relationship{ .author-id };
}
my $*RED-INTERNAL = True;
is Post.^id>>.name, < $!id >;
is Post.new(:42id).^id-values, < 42 >;
is Post.^new-with-id(42).id, < 42 >;
isa-ok Person.new(:42id).posts, Post::ResultSeq;
isa-ok Post.new(:123author-id).author, Person;
is-deeply Post.author-id.ref, Person.id;
lives-ok { Post.^all.grep: *.author.name eq "Bla" }
is-deeply Post.author.^table, Person.^table;
model Person2 { ... }
model Post2 {
has Int $.id is column{ :id };
has Int $.author-id is referencing( *.id, :model<Person2> );
has Person2 $.author is relationship{ .author-id };
}
model Person2 {
has Int $.id is column{ :id };
has Str $.name is column;
has Post2 @.posts is relationship{ .author-id };
}
is-deeply Post2.author-id.ref, Person2.id;
lives-ok { Post2.^all.grep: *.author.name eq "Bla" }
is Post2.author.^table, Person2.^table;
is Post2.author.^name, "post2_author";
my $alias1 = Post2.^alias;
is $alias1.^name, "Post2_1";
is $alias1, $alias1.id.class;
isnt $alias1, Post2;
is Post2, Post2.id.class;
is $alias1.id.attr, Post2.id.attr;
is $alias1.id.attr-name, Post2.id.attr-name;
is $alias1.id.id, Post2.id.id;
is-deeply $alias1.id.references, Post2.id.references;
is $alias1.id.nullable, Post2.id.nullable;
is $alias1.id.name, Post2.id.name;
is $alias1, $alias1.author-id.class;
is Post2, Post2.author-id.class;
is $alias1.author-id.attr, Post2.author-id.attr;
is $alias1.author-id.attr-name, Post2.author-id.attr-name;
is-deeply $alias1.author-id.references, Post2.author-id.references;
is $alias1.author-id.nullable, Post2.author-id.nullable;
is $alias1.author-id.name, Post2.author-id.name;
my $alias2 = Post2.^alias: "me";
is $alias2.^name, "me";
is $alias2, $alias2.id.class;
is Post2, Post2.id.class;
is $alias2.id.attr, Post2.id.attr;
is $alias2.id.attr-name, Post2.id.attr-name;
is $alias2.id.id, Post2.id.id;
is-deeply $alias2.id.references, Post2.id.references;
is $alias2.id.nullable, Post2.id.nullable;
is $alias2.id.name, Post2.id.name;
is $alias2, $alias2.author-id.class;
is Post2, Post2.author-id.class;
is $alias2.author-id.attr, Post2.author-id.attr;
is $alias2.author-id.attr-name, Post2.author-id.attr-name;
is $alias2.author-id.id, Post2.author-id.id;
is-deeply $alias2.author-id.references, Post2.author-id.references;
is $alias2.author-id.nullable, Post2.author-id.nullable;
is $alias2.author-id.name, Post2.author-id.name;
is $alias1.^name, "Post2_1";
is Post2.^name, "Post2";
is Post2.author-id.as("bla").name, "bla";
is Post2.author-id.as("bla").attr-name, "bla";
ok not Post2.author-id.as("bla").id;
ok Post2.author-id.as("bla").nullable;
ok not Post2.author-id.as("bla", :!nullable).nullable;
is (Post2.id == 42).tables.elems, 1;
is (Post2.author-id == Person2.id).tables.elems, 2;
given model {
has $.a is unique<a-and-b aonly-a>;
has $.b is unique<a-and-b>;
} {
is .^constraints<unique>.elems, 2;
}
isa-ok Person2.new.posts, Post2::ResultSeq;
isa-ok Person2.posts, Post2::ResultSeq;
isa-ok Person2.posts.do-it, Seq;
isa-ok Person2.posts.do-it.head, Post2;
my $seq = Person2.posts.map: *.id;
isa-ok $seq, Post2::ResultSeq;
#isa-ok $seq.head, Int;
is $seq.filter.raku, Person2.posts.filter.raku;
given my model {
has Int $.int-u is column{ :id };
has Str $.str-u is column;
has Bool $.bool-u is column;
has Int $.int-d is column = 42;
has Str $.str-d is column = "answer";
has Bool $.bool-d is column = False;
} {
my $a = .new: :143int-u;
my $b = .new;
my $c = .new: :1int-u, :str-u<bla>, :!bool-u, :2int-u, :str-u<ble>, :bool-d;
use Red::AST::Insert;
my $a-i = Red::AST::Insert.new: $a;
is $a-i.values.keys.sort, <int_u str_u bool_u int_d str_d bool_d>.sort;
is $a.^id-filter.right.value, 143;
is $a.int-d, 42;
is $a.str-d, "answer";
is $a.bool-d, False;
}
model Post3_1 {
has Int $.id is id;
has Int $.author-id is referencing({ .id }, :model<Person3>);
has $.author is relationship({ .author-id }, :model<Person3>)
}
model Post3_2 {
has Int $.id is id;
has Int $.author-id is referencing{:model<Person3>, :column<id>};
has $.author is relationship{:column<author-id>, :model<Person3>}
}
model Person3 {
has Int $.id is id;
has Str $.name is column;
has @.posts is relationship{:column<author-id>, :model<Post3_2>}
}
is-deeply Post3_1.author-id.ref, Person3.id;
is-deeply Post3_2.author-id.ref, Person3.id;
is-deeply Post3_2.author-id.ref, Post3_1.author-id.ref;
lives-ok { Post3_2.^all.grep: *.author.name eq "Bla" }
is-deeply Post3_1.author.^table, Person3.^table;
is-deeply Post3_2.author.^table, Person3.^table;
is-deeply Post3_1.author.^table, Post3_2.author.^table;
model X is rw {
has Int $.int is column{:nullable}
has Str $.str is column{:nullable}
has Str(Int) $.coerce is column{:nullable}
}
my X $x .= new;
dies-ok { $x.int = "Hi" }, "Dies when setting wrong typed value";
lives-ok { $x.int = 42 };
dies-ok { $x.str = 42 }, "Dies when setting wrong typed value";
lives-ok { $x.str = "Hi" };
lives-ok { $x.coerce = "42" };
lives-ok { $x.coerce = 42 };
lives-ok {
$x.int = Nil;
$x.str = Nil;
$x.coerce = Nil;
}
is $x.int, Int;
is $x.str, Str;
is $x.coerce, Str(Int);
my CX::Red::Bool $cx-red-bool .= new: :value;
ok $cx-red-bool.value;
is $cx-red-bool.message, "<red bool control exception>";
$cx-red-bool .= new: :!value;
ok !$cx-red-bool.value;
is $cx-red-bool.message, "<red bool control exception>";
lives-ok {
ok X.^describe;
isa-ok X.^describe, Red::Cli::Table;
#ok X.^diff-to-db;
#ok X.^diff-from-db;
model Y is table<x> is rw {
has Int $.int is column{:nullable}
has Str $.str is column{:nullable}
}
ok X.^diff: Y
}
done-testing;