JQ-Lite

 view release on metacpan or  search on metacpan

lib/JQ/Lite/Filters.pm  view on Meta::CPAN

        if (my $reduce = JQ::Lite::Util::_parse_reduce_expression($normalized)) {
            @next_results = ();

            for my $value (@results) {
                my $json = JQ::Lite::Util::_encode_json($value);
                my @items = $self->run_query($json, $reduce->{generator});

                my ($init_values, $init_ok) = JQ::Lite::Util::_evaluate_value_expression($self, $value, $reduce->{init_expr});
                my $acc;
                if ($init_ok) {
                    $acc = @$init_values ? $init_values->[0] : undef;
                }
                else {
                    my @init_outputs = $self->run_query(JQ::Lite::Util::_encode_json($value), $reduce->{init_expr});
                    $acc = @init_outputs ? $init_outputs[0] : undef;
                }

                for my $element (@items) {
                    my %existing = %{ $self->{_vars} || {} };
                    local $self->{_vars} = { %existing, $reduce->{var_name} => $element };

                    my ($updated_values, $updated_ok) = JQ::Lite::Util::_evaluate_value_expression($self, $acc, $reduce->{update_expr});
                    my $next;
                    if ($updated_ok) {
                        $next = @$updated_values ? $updated_values->[0] : undef;
                    }
                    else {
                        my @outputs = $self->run_query(JQ::Lite::Util::_encode_json($acc), $reduce->{update_expr});
                        $next = @outputs ? $outputs[0] : undef;
                    }

                    $acc = $next;
                }

                push @next_results, $acc;
            }

            @$out_ref = @next_results;
            return 1;
        }

        # support for .[] iteration
        if ($part eq '.[]') {
            @next_results = map {
                ref $_ eq 'ARRAY' ? @$_
              : ref $_ eq 'HASH'  ? values %$_
              : JQ::Lite::Util::_is_string_scalar($_) ? split(//, "$_")
              : ()
            } @results;
            @$out_ref = @next_results;
            return 1;
        }

        # support for select(...)
        if ($part =~ /^select\((.+)\)$/) {
            my $cond = $1;
            @next_results = ();

            my $has_wildcard_array = index($cond, '[]') != -1;
            my $has_comparison = ($cond =~ /(==|!=|>=|<=|>|<|\band\b|\bor\b|\bcontains\b|\bhas\b|\bmatch\b)/i);
            my $use_streaming_eval = $has_wildcard_array || !$has_comparison;

            # allow built-in filters like match() and test() to run so their errors surface
            $use_streaming_eval ||= ($cond =~ /^\s*(match|test)\s*\(/);

            VALUE: for my $value (@results) {
                my $simple = JQ::Lite::Util::_evaluate_condition($value, $cond) ? 1 : 0;

                if ($use_streaming_eval) {
                    my $json = JQ::Lite::Util::_encode_json($value);
                    my $error;
                    my @cond_results;

                    {
                        local $@;
                        @cond_results = eval { $self->run_query($json, $cond) };
                        $error = $@;
                    }

                    die $error if $error;

                    if (@cond_results) {
                        my $truthy = 0;

                        for my $cond_value (@cond_results) {
                            if (JQ::Lite::Util::_is_truthy($cond_value)) {
                                $truthy++;
                            }
                        }

                        if ($truthy) {
                            push @next_results, (($value) x $truthy);
                        }

                        next VALUE;
                    }
                }

                if ($simple) {
                    push @next_results, $value;
                }
            }

            @$out_ref = @next_results;
            return 1;
        }

        # support for length
        if ($part eq 'length') {
            @next_results = map {
                if (!defined $_) {
                    0;
                }
                elsif (ref $_ eq 'ARRAY') {
                    scalar(@$_);
                }
                elsif (ref $_ eq 'HASH') {
                    scalar(keys %$_);
                }
                elsif (!ref $_ || ref($_) eq 'JSON::PP::Boolean') {
                    length("$_");
                }
                else {
                    0;
                }
            } @results;
            @$out_ref = @next_results;
            return 1;
        }



( run in 0.677 second using v1.01-cache-2.11-cpan-140bd7fdf52 )