Skip to content

Instantly share code, notes, and snippets.

/json.diff Secret

Created December 30, 2014 23:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/7409f3d24ae26208d533 to your computer and use it in GitHub Desktop.
Save anonymous/7409f3d24ae26208d533 to your computer and use it in GitHub Desktop.
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