Red.git | t/ | 77-red-type.rakutest


#!/usr/bin/env raku

use Test;
use Red;
use Red::Type;
use Red::AST::Value;
use Red::AST::Unary;
use JSON::Fast;

my $*RED-FALLBACK       = False;
my $*RED-DEBUG          = $_ with %*ENV<RED_DEBUG>;
my $*RED-DEBUG-RESPONSE = $_ with %*ENV<RED_DEBUG_RESPONSE>;
my @conf                = (%*ENV<RED_DATABASE> // "SQLite").split(" ");
my $driver              = @conf.shift;
my $*RED-DB             = database $driver, |%( @conf.map: { do given .split: "=" { .[0] => val .[1] } } );

class Point {
   has $.x;
   has $.y;
}

class DBPoint does Red::Type {
   method inflator {
     -> $_ --> Point {
       my $value = do if $_ ~~ Str {
         .&from-json
       } else {
         .<>
       }
       Point.new: :x($value<x>), :y($value<y>)
     }
   }
   method deflator {
     -> Point $_ {
       my $value = %( :x( .x ), :y( .y ) );
       $value .= &to-json unless $*RED-DB.^name.ends-with: "Pg";
       $value
     }
   }
   method red-type-column-type    { "jsonb" }
   method red-type-accepts(Point) { True }
   method red-type-db-methods {
    role :: {
      method x { Red::AST::Cast.new: Red::AST::JsonItem.new(self, ast-value "x"), "integer" }
      method y { Red::AST::Cast.new: Red::AST::JsonItem.new(self, ast-value "y"), "integer" }
    }
   }
}

model Place {
   has UInt    $.id    is serial;
   has DBPoint $.point is column;
}

schema(Place).drop.create;

Place.^create: :point(Point.new: :x($_), :10y) for ^10;
my $p = Place.^all.head;

isa-ok $p, Place;
isa-ok $p.point, Point;
is $p.point.x, 0;
is $p.point.y, 10;

is Place.^all.grep(*.point.x >= 5).Seq>>.point>>.raku, (5 .. 9).map: { Point.new(:x($_), :10y).raku };

done-testing