+ return \@result;
+}
+
+sub _apply_value_filters {
+ my ($key, $value, $type, $op) = @_;
+
+ return ($key, $value) unless $key && $value && $type && $op && (ref($value) eq 'HASH');
+
+ if (($type eq 'date') && ($op eq 'le')) {
+ my $date = delete $value->{le};
+ $value->{lt} = $date->add(days => 1);
+ }
+
+ return ($key, $value);
+}
+
+sub _dispatch_custom_filters {
+ my ($class, $with_objects, $key, $value) = @_;
+
+ # the key should by now have no filters left
+ # if it has, catch it here:
+ die 'unrecognized filters' if $key =~ /:/;
+
+ my @tokens = split /\./, $key;
+ my $last_token = pop @tokens;
+ my $curr_class = $class->object_class;
+
+ for my $token (@tokens) {
+ eval {
+ $curr_class = $curr_class->meta->relationship($token)->class;
+ 1;
+ } or do {
+ require Carp;
+ Carp::croak("Could not resolve the relationship '$token' in '$key' while building the filter request");
+ }
+ }
+
+ my $manager = $curr_class->meta->convention_manager->auto_manager_class_name;
+ my $obj_path = join '.', @tokens;
+ my $obj_prefix = join '.', @tokens, '';
+
+ if ($manager->can('filter')) {
+ ($key, $value, my $obj) = $manager->filter($last_token, $value, $obj_prefix);
+ _add_uniq($with_objects, $obj) if $obj;
+ } else {
+ _add_uniq($with_objects, $obj_path) if $obj_path;
+ }
+
+ return ($key, $value);
+}
+
+sub _add_uniq {
+ my ($array, $what) = @_;
+
+ $array //= [];
+ @$array = (uniq @$array, listify($what));
+}
+
+sub _collapse_indirect_filters {
+ my ($flattened) = @_;
+
+ die 'flattened filter array length is uneven, should be possible to use as hash' if @$flattened % 2;
+
+ my (%keys_to_delete, %keys_to_move, @collapsed);
+
+ # search keys matching /::$/;
+ for (my $i = 0; $i < scalar @$flattened; $i += 2) {
+ my ($key, $value) = ($flattened->[$i], $flattened->[$i+1]);
+
+ next unless $key =~ /^(.*\b)::$/;
+
+ $keys_to_delete{$key}++;
+ $keys_to_move{$1} = $1 . '::' . $value;
+ }
+
+ for (my $i = 0; $i < scalar @$flattened; $i += 2) {
+ my ($key, $value) = ($flattened->[$i], $flattened->[$i+1]);
+
+ if ($keys_to_move{$key}) {
+ push @collapsed, $keys_to_move{$key}, $value;
+ next;
+ }
+ if (!$keys_to_delete{$key}) {
+ push @collapsed, $key, $value;
+ }
+ }
+
+ return \@collapsed;