-
-
Save anonymous/7409f3d24ae26208d533 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/lib/Mojo/Pg/Database.pm b/lib/Mojo/Pg/Database.pm | |
index 64932b3..d3b17a2 100644 | |
--- a/lib/Mojo/Pg/Database.pm | |
+++ b/lib/Mojo/Pg/Database.pm | |
@@ -4,6 +4,7 @@ use Mojo::Base 'Mojo::EventEmitter'; | |
use DBD::Pg ':async'; | |
use IO::Handle; | |
use Mojo::IOLoop; | |
+use Mojo::JSON 'encode_json'; | |
use Mojo::Pg::Results; | |
use Mojo::Pg::Transaction; | |
use Scalar::Util 'weaken'; | |
@@ -44,6 +45,10 @@ sub dollar_only { ++$_[0]->{dollar_only} and return $_[0] } | |
sub is_listening { !!keys %{shift->{listen} || {}} } | |
+sub json { | |
+ shift->val(map { encode_json $_} @_); | |
+} | |
+ | |
sub listen { | |
my ($self, $name) = @_; | |
@@ -70,6 +75,8 @@ sub query { | |
my ($self, $query) = (shift, shift); | |
my $cb = ref $_[-1] eq 'CODE' ? pop : undef; | |
+ my @values = $self->{values} ? (@{delete $self->{values}}, @_) : @_; | |
+ | |
# Dollar only | |
my $dbh = $self->dbh; | |
local $dbh->{pg_placeholder_dollaronly} = 1 if delete $self->{dollar_only}; | |
@@ -77,14 +84,14 @@ sub query { | |
# Blocking | |
unless ($cb) { | |
my $sth = $dbh->prepare($query); | |
- $sth->execute(@_); | |
+ $sth->execute(@values); | |
$self->_notifications; | |
return Mojo::Pg::Results->new(sth => $sth); | |
} | |
# Non-blocking | |
my $sth = $dbh->prepare($query, {pg_async => PG_ASYNC}); | |
- push @{$self->{waiting}}, {args => [@_], cb => $cb, sth => $sth}; | |
+ push @{$self->{waiting}}, {args => \@values, cb => $cb, sth => $sth}; | |
$self->$_ for qw(_next _watch); | |
} | |
@@ -100,6 +107,12 @@ sub unlisten { | |
return $self; | |
} | |
+sub val { | |
+ my $self = shift; | |
+ push @{$self->{values}}, @_; | |
+ return $self; | |
+} | |
+ | |
sub _next { | |
return unless my $next = shift->{waiting}[0]; | |
$next->{sth}->execute(@{$next->{args}}) unless $next->{executed}++; | |
@@ -251,9 +264,8 @@ Execute a statement and discard its result. | |
Activate C<pg_placeholder_dollaronly> for next L</"query"> call and allow C<?> | |
to be used as an operator. | |
- use Mojo::JSON 'decode_json'; | |
$db->dollar_only->query('select * from foo where bar ? $1', 'baz') | |
- ->hashes->map(sub { decode_json($_->{bar})->{baz} })->join("\n")->say; | |
+ ->hashes->map(sub { $_->{bar}{baz} })->join("\n")->say; | |
=head2 is_listening | |
@@ -261,6 +273,12 @@ to be used as an operator. | |
Check if L</"dbh"> is listening for notifications. | |
+=head2 json | |
+ | |
+ $db = $db->json(@values); | |
+ | |
+Enqueue JSON placeholder values for next L</"query"> call. | |
+ | |
=head2 listen | |
$db = $db->listen('foo'); | |
@@ -308,6 +326,12 @@ results. You can also append a callback to perform operation non-blocking. | |
Stop listening for notifications. | |
+=head2 val | |
+ | |
+ $db = $db->val(@values); | |
+ | |
+Enqueue placeholder values for next L</"query"> call. | |
+ | |
=head1 SEE ALSO | |
L<Mojo::Pg>, L<Mojolicious::Guides>, L<http://mojolicio.us>. | |
diff --git a/lib/Mojo/Pg/Results.pm b/lib/Mojo/Pg/Results.pm | |
index bc594cd..8f395d1 100644 | |
--- a/lib/Mojo/Pg/Results.pm | |
+++ b/lib/Mojo/Pg/Results.pm | |
@@ -2,6 +2,7 @@ package Mojo::Pg::Results; | |
use Mojo::Base -base; | |
use Mojo::Collection; | |
+use Mojo::JSON 'decode_json'; | |
use Mojo::Util 'tablify'; | |
has 'sth'; | |
@@ -12,7 +13,7 @@ sub arrays { Mojo::Collection->new(@{shift->sth->fetchall_arrayref}) } | |
sub columns { shift->sth->{NAME} } | |
-sub hash { shift->sth->fetchrow_hashref } | |
+sub hash { $_[0]->_decode($_[0]->sth->fetchrow_hashref) } | |
sub hashes { Mojo::Collection->new(@{shift->sth->fetchall_arrayref({})}) } | |
@@ -20,6 +21,18 @@ sub rows { shift->sth->rows } | |
sub text { tablify shift->arrays } | |
+sub _decode { | |
+ my ($self, $hash) = @_; | |
+ | |
+ my $types = $self->sth->{pg_type}; | |
+ my @json | |
+ = grep { $types->[$_] eq 'json' || $types->[$_] eq 'jsonb' } 0 .. $#$types; | |
+ my $names = $self->columns; | |
+ map { $hash->{$names->[$_]} = decode_json $hash->{$names->[$_]} } @json; | |
+ | |
+ return $hash; | |
+} | |
+ | |
1; | |
=encoding utf8 | |
diff --git a/t/database.t b/t/database.t | |
index 020feec..f2b8a2f 100644 | |
--- a/t/database.t | |
+++ b/t/database.t | |
@@ -148,6 +148,11 @@ eval { $db->dollar_only->query('select ? as test', 23) }; | |
like $@, qr/called with 1 bind variables when 0 are needed/, 'right error'; | |
is $db->query('select ? as test', 23)->hash->{test}, 23, 'right result'; | |
+# JSON roundtrip | |
+$db = $pg->db; | |
+is_deeply $db->json({bar => 'baz'})->query('select ?::json as foo')->hash, | |
+ {foo => {bar => 'baz'}}, 'right structure'; | |
+ | |
# Fork safety | |
$dbh = $pg->db->dbh; | |
my ($connections, $current) = @_; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment