DBIO-GraphQL
view release on metacpan or search on metacpan
lib/DBIO/GraphQL.pm view on Meta::CPAN
fields => {
nodes => { type => GraphQL::Type::List->new(of => $gql_type) },
total => { type => $Int },
nextCursor => { type => $String },
hasNextPage => { type => $Boolean },
},
);
}
# _encode_cursor / _decode_cursor
#
# Cursors are base64(val1:val2:...), stateless, no extra dependencies.
# Colons inside values are percent-encoded so the separator is unambiguous.
sub _encode_cursor {
my (@vals) = @_;
my $raw = join ':', map { (my $v = $_) =~ s/%/%25/g; $v =~ s/:/%3A/g; $v } @vals;
return encode_base64($raw, ''); # no newline
}
sub _decode_cursor {
my ($cursor) = @_;
my $raw = decode_base64($cursor);
my @vals = map { (my $v = $_) =~ s/%3A/:/gi; $v =~ s/%25/%/g; $v }
split /:/, $raw;
return @vals;
}
# _apply_pagination($rs, $args, $source)
#
# Applies ordering, then either offset (page) or cursor (cursor) pagination.
# Returns ($nodes, $next_cursor, $has_next).
#
# Precedence: cursor pagination wins if both are supplied.
sub _apply_pagination {
my ($rs, $args, $source) = @_;
my @pk_cols = $source->primary_columns;
my $order_by = $args->{orderBy};
if ($order_by && $order_by->{field}) {
my $field = $order_by->{field};
unless ($source->has_column($field)) {
die "DBIO::GraphQL: unknown order column '$field' on source '"
. $source->source_name . "'\n";
}
my $dir = lc($order_by->{direction} // 'ASC');
$rs = $rs->search(undef, {
order_by => { "-$dir" => $field }
});
}
else {
# Default: stable order by PK
$rs = $rs->search(undef, { order_by => [ map { { -asc => $_ } } @pk_cols ] });
}
if (my $cursor_args = $args->{cursor}) {
my $first = $cursor_args->{first} // 10;
my $after = $cursor_args->{after};
if ($after) {
my @decoded = _decode_cursor($after);
if (@pk_cols == 1) {
$rs = $rs->search({ $pk_cols[0] => { '>' => $decoded[0] } });
}
else {
my %after_cond = map { $pk_cols[$_] => { '>' => $decoded[$_] } }
0 .. $#pk_cols;
$rs = $rs->search(\%after_cond);
}
}
my @rows = $rs->search(undef, { rows => $first + 1 })->all;
my $has_next = @rows > $first;
@rows = @rows[0 .. $first - 1] if $has_next;
my $next_cursor;
if ($has_next && @rows) {
my $last_row = $rows[-1];
$next_cursor = _encode_cursor(map { $last_row->get_column($_) } @pk_cols);
}
return (
[ map { { $_->get_columns } } @rows ],
$next_cursor,
$has_next ? 1 : 0,
);
}
if (my $page_args = $args->{page}) {
my $skip = $page_args->{skip} // 0;
my $take = $page_args->{take} // 10;
my @rows = $rs->search(undef, { rows => $take, offset => $skip })->all;
return (
[ map { { $_->get_columns } } @rows ],
undef,
0,
);
}
my @rows = $rs->all;
return (
[ map { { $_->get_columns } } @rows ],
undef,
0,
);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
DBIO::GraphQL - Auto-generate a GraphQL schema from a DBIO schema
=head1 VERSION
version 0.900001
=head1 SYNOPSIS
( run in 0.583 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )