Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Change the type conversion to hash association.
Allow pg types to be dynamic. This is inmportant for e.g. enums
  • Loading branch information
kaare committed Jan 7, 2017
1 parent 6223169 commit c070886
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 42 deletions.
18 changes: 10 additions & 8 deletions lib/DBDish.pm6
Expand Up @@ -19,14 +19,16 @@ role Driver does DBDish::ErrorHandling {
#method new() { nextsame; }
}

role Type {
has Callable %!Conversions{Mu:U};

method set(Mu:U $name, &convert) {
%!Conversions{$name} = &convert;
}
method get(Mu:U $type) {
%!Conversions{$type} || sub (Str :$str, Mu:U :$type-name) { $type-name($str) };
role TypeConverter does Associative {
has Callable %!Conversions{Mu:U} handles <AT-KEY EXISTS-KEY>;

# The role implements the conversion
method convert (::?CLASS:D: Str $datum, Mu:U $typ) {
with %!Conversions{$typ} -> &converter {
converter($datum, $typ);
} else { # Common case
$typ($datum);
}
}
}

Expand Down
16 changes: 7 additions & 9 deletions lib/DBDish/Pg/Connection.pm6
Expand Up @@ -2,7 +2,6 @@ use v6;
need DBDish;

unit class DBDish::Pg::Connection does DBDish::Connection;
use DBDish::Pg::Types;
use DBDish::Pg::Native;
need DBDish::Pg::StatementHandle;
need DBDish::TestMock;
Expand All @@ -14,16 +13,15 @@ has PGconn $!pg_conn is required handles <
pg-port pg-options quote>;
has $.AutoCommit is rw = True;
has $.in_transaction is rw = False;
has $.types;
has %.Converter is DBDish::TypeConverter;
has %.dynamic-types = %oid-to-type;

submethod BUILD(:$!pg_conn, :$!parent!, :$!AutoCommit) {
$!types = DBDish::Pg::Types.new;
$!types.set(Str, sub (Str :$str, Mu:U :$type-name) { $str });
$!types.set(Date, sub (Str :$str, Mu:U :$type-name) { Date.new($str) });
$!types.set(DateTime, sub (Str :$str, Mu:U :$type-name) { DateTime.new($str.split(' ').join('T')) });
$!types.set(Array, sub (Str :$str, Mu:U :$type-name) { $str });
$!types.set(Bool, sub (Str :$str, Mu:U :$type-name) { $str eq 't' });
$!types.set(Buf, &str-to-blob);
%!Converter{Str} = sub (Str $str, Mu:U $type-name) { $str };
%!Converter{Date} = sub (Str $str, Mu:U $type-name) { Date.new($str) };
%!Converter{DateTime} = sub (Str $str, Mu:U $type-name) { DateTime.new($str.split(' ').join('T')) };
%!Converter{Bool} = sub (Str $str, Mu:U $type-name) { $str eq 't' };
%!Converter{Buf} = &str-to-blob;
}

method prepare(Str $statement, *%args) {
Expand Down
2 changes: 1 addition & 1 deletion lib/DBDish/Pg/Native.pm6
Expand Up @@ -15,7 +15,7 @@ sub PQlibVersion(-->uint32) is native(LIB) is export { * }
sub PQfreemem(Pointer) is native(LIB) { * }
sub PQunescapeBytea(str, size_t is rw --> Pointer) is native(LIB) { * }

sub str-to-blob(Str :str($value), Mu:U :$type-name) is export {
sub str-to-blob(Str $value, Mu:U $type-name) is export {
my \ptr = PQunescapeBytea($value, my size_t $elems);
LEAVE { PQfreemem(ptr) if ptr }
with ptr {
Expand Down
10 changes: 4 additions & 6 deletions lib/DBDish/Pg/StatementHandle.pm6
Expand Up @@ -2,7 +2,6 @@ use v6;
need DBDish;

unit class DBDish::Pg::StatementHandle does DBDish::StatementHandle;
use DBDish::Pg::Types;
use DBDish::Pg::Native;

has PGconn $!pg_conn;
Expand All @@ -28,7 +27,7 @@ submethod !get-meta($result) {
@!column-name.push: $result.PQfname($_);
@!column-type.push: do {
my $pt = $result.PQftype($_);
if (my \t = %oid-to-type{$pt}) === Nil {
if (my \t = $!parent.dynamic-types{$pt}) === Nil {
warn "No type map defined for postgresql type $pt at column $_";
Str;
} else { t }
Expand All @@ -42,7 +41,7 @@ submethod BUILD(:$!parent!, :$!pg_conn, # Per protocol
) {
if $!statement_name { # Prepared
with $!pg_conn.PQdescribePrepared($!statement_name) -> $info {
@!param_type.push(%oid-to-type{$info.PQparamtype($_)}) for ^$info.PQnparams;
@!param_type.push($!parent.dynamic-types{$info.PQparamtype($_)}) for ^$info.PQnparams;
self!get-meta($info);
$info.PQclear;
}
Expand Down Expand Up @@ -88,16 +87,15 @@ method _row() {
my $l = ();
if $!Executed && $!field_count && $!current_row < $!row_count {
my $col = 0;
my $types = $!parent.types;
my %Converter := $!parent.Converter;
$l = do for @!column-type -> \ct {
my $value = ct;
unless $!result.PQgetisnull($!current_row, $col) {
my $str = $!result.PQgetvalue($!current_row, $col);
if ct ~~ Array {
$value = _pg-to-array($str, ct.of);
} else {
my $sub = $types.get(ct);
$value = &$sub(:$str, :type-name(ct));
$value = %Converter.convert($str, ct);
}
}
$col++;
Expand Down
4 changes: 0 additions & 4 deletions lib/DBDish/Pg/Types.pm6

This file was deleted.

33 changes: 20 additions & 13 deletions t/06-types.t
@@ -1,26 +1,33 @@
use v6;
use Test;
use DBDish;
plan 9;
need DBDish;

plan 11;

class type-test {
has %.Converter is DBDish::TypeConverter;

class type-test does DBDish::Type {
method test-str(Str $value) {
$value.flip;
}

submethod BUILD {
%!Conversions{Int} = sub (Str $value) { Int($value) };
self.set(Str, self.^find_method('test-str'));
%!Converter{Int} = sub (Str $value, $typ) { Int($value) };
%!Converter{Str} = self.^find_method('test-str');
}
}

ok my $test = type-test.new;
ok my $sub = $test.get(Int);
is $sub('123'), 123;
ok my $res = $test.Converter.convert('123', Int), 'Get the result (Int)';
is $res, 123, 'Check it';

ok my $sub = $test.Converter{Int}, 'Get the converter sub (Int)';
is $sub('123', Int), 123, 'and then convert';
my $int = sub ($) {1};
ok $test.set(Int, $int);
ok $sub = $test.get(Int);
is $sub.WHAT, Sub;
is $sub('123'), 1;
ok $sub = $test.get(Str);
is $test.$sub('test'), 'tset';
ok ($test.Converter{Int} = $int), 'Change the Int converter';
ok $sub = $test.Converter{Int}, 'Get it back';
is $sub.WHAT, Sub, 'Is it a sub?';
is $sub('123'), 1, 'Does it do its job?';

ok $sub = $test.Converter{Str}, 'get the Str method';
is $test.$sub('test'), 'tset', 'and try it';
2 changes: 1 addition & 1 deletion t/34-pg-types.t
Expand Up @@ -49,7 +49,7 @@ is $sth.execute, 1, '1 row';
my ($col1) = $sth.row;
isa-ok $col1, Str;
is $col1, 'test', 'Test';
$dbh.types.set(Str, sub (Str :$str, Str :$type-name) { 'changed' });
$dbh.Converter{Str} = sub (Str $str, Str $type-name) { 'changed' };
is $sth.execute, 1, '1 row';
($col1) = $sth.row;
is $col1, 'changed', 'Changed';
Expand Down

0 comments on commit c070886

Please sign in to comment.