public PaginatedList<ViewDTO> searchPaginatedByType(ViewDTO.Type type,
                                                        SearchQuery query,
                                                        Predicate<ViewDTO> filter,
                                                        SortOrder order,
                                                        String sortField,
                                                        int page,
                                                        int perPage) {
        checkNotNull(sortField);
        return searchPaginatedWithGrandTotal(
                Filters.and(
                        Filters.or(Filters.eq(ViewDTO.FIELD_TYPE, type), Filters.not(Filters.exists(ViewDTO.FIELD_TYPE))),
                        query.toBson()
                ),
                filter,
                order,
                sortField,
                Filters.or(Filters.eq(ViewDTO.FIELD_TYPE, type), Filters.not(Filters.exists(ViewDTO.FIELD_TYPE))),
                page,
                perPage
        );
    }
@Test
    public void searchPaginatedByType() {
        final ImmutableMap<String, SearchQueryField> searchFieldMapping = ImmutableMap.<String, SearchQueryField>builder()
                .put("id", SearchQueryField.create(ViewDTO.FIELD_ID))
                .put("title", SearchQueryField.create(ViewDTO.FIELD_TITLE))
                .put("summary", SearchQueryField.create(ViewDTO.FIELD_DESCRIPTION))
                .build();

        dbService.save(ViewDTO.builder().type(ViewDTO.Type.DASHBOARD).title("View A").searchId("abc123").state(Collections.emptyMap()).owner("franz").build());
        dbService.save(ViewDTO.builder().type(ViewDTO.Type.DASHBOARD).title("View B").searchId("abc123").state(Collections.emptyMap()).owner("franz").build());
        dbService.save(ViewDTO.builder().type(ViewDTO.Type.DASHBOARD).title("View C").searchId("abc123").state(Collections.emptyMap()).owner("franz").build());
        dbService.save(ViewDTO.builder().type(ViewDTO.Type.SEARCH).title("View D").searchId("abc123").state(Collections.emptyMap()).owner("franz").build());
        dbService.save(ViewDTO.builder().type(ViewDTO.Type.SEARCH).title("View E").searchId("abc123").state(Collections.emptyMap()).owner("franz").build());

        final SearchQueryParser queryParser = new SearchQueryParser(ViewDTO.FIELD_TITLE, searchFieldMapping);

        final PaginatedList<ViewDTO> result1 = dbService.searchPaginatedByType(
                ViewDTO.Type.DASHBOARD,
                queryParser.parse("A B D"),
                view -> true, SortOrder.DESCENDING,
                "title",
                1,
                5
        );

        assertThat(result1)
                .hasSize(2)
                .extracting("title")
                .containsExactly("View B", "View A");

        assertThat(result1.grandTotal()).hasValue(3L);

        final PaginatedList<ViewDTO> result2 = dbService.searchPaginatedByType(
                ViewDTO.Type.DASHBOARD,
                queryParser.parse("A B D"),
                view -> view.title().contains("B") || view.title().contains("D"), SortOrder.DESCENDING,
                "title",
                1,
                5
        );

        assertThat(result2)
                .hasSize(1)
                .extracting("title")
                .containsExactly("View B");

        assertThat(result1.grandTotal()).hasValue(3L);

        final PaginatedList<ViewDTO> result3 = dbService.searchPaginatedByType(
                ViewDTO.Type.SEARCH,
                queryParser.parse(""),
                view -> true, SortOrder.ASCENDING,
                "title",
                1,
                5
        );

        assertThat(result3)
                .hasSize(2)
                .extracting("title")
                .containsExactly("View D", "View E");

        assertThat(result3.grandTotal()).hasValue(2L);
    }