All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dizitart.no2.internals.SearchService Maven / Gradle / Ivy

There is a newer version: 4.3.0
Show newest version
/*
 *
 * Copyright 2017-2018 Nitrite author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.dizitart.no2.internals;

import org.dizitart.no2.*;
import org.dizitart.no2.exceptions.FilterException;
import org.dizitart.no2.exceptions.InvalidOperationException;
import org.dizitart.no2.store.NitriteMap;

import java.text.Collator;
import java.util.*;

import static org.dizitart.no2.exceptions.ErrorCodes.VE_SEARCH_SERVICE_NULL_NITRITE_SERVICE;
import static org.dizitart.no2.exceptions.ErrorMessage.*;
import static org.dizitart.no2.util.DocumentUtils.getFieldValue;
import static org.dizitart.no2.util.StringUtils.isNullOrEmpty;
import static org.dizitart.no2.util.ValidationUtils.notNull;
import static org.dizitart.no2.util.ValidationUtils.validateLimit;

/**
 * @author Anindya Chatterjee.
 */
class SearchService {
    private NitriteService nitriteService;
    private NitriteMap underlyingMap;

    SearchService(NitriteService nitriteService, NitriteMap mapStore) {
        notNull(nitriteService, errorMessage("nitriteService can not be null", VE_SEARCH_SERVICE_NULL_NITRITE_SERVICE));
        this.nitriteService = nitriteService;
        underlyingMap = mapStore;
    }

    Cursor find() {
        FindResult findResult = new FindResult();
        findResult.setHasMore(false);
        findResult.setTotalCount(underlyingMap.size());
        findResult.setIdSet(underlyingMap.keySet());
        findResult.setUnderlyingMap(underlyingMap);

        return new DocumentCursor(findResult);
    }

    Cursor find(Filter filter) {
        if (filter == null) {
            return find();
        }
        filter.setNitriteService(nitriteService);
        Set result;

        try {
            result = filter.apply(underlyingMap);
        } catch (FilterException fe) {
            throw fe;
        } catch (Throwable t) {
            throw new FilterException(FILTERED_FIND_OPERATION_FAILED, t);
        }

        FindResult findResult = new FindResult();
        findResult.setUnderlyingMap(underlyingMap);
        if (result != null) {
            findResult.setHasMore(false);
            findResult.setTotalCount(result.size());
            findResult.setIdSet(result);
        }

        return new DocumentCursor(findResult);
    }

    Cursor find(FindOptions findOptions) {
        FindResult findResult = new FindResult();
        findResult.setUnderlyingMap(underlyingMap);
        setUnfilteredResultSet(findOptions, findResult);

        return new DocumentCursor(findResult);
    }

    Cursor find(Filter filter, FindOptions findOptions) {
        if (filter == null) {
            return find(findOptions);
        }
        filter.setNitriteService(nitriteService);
        FindResult findResult = new FindResult();
        findResult.setUnderlyingMap(underlyingMap);
        setFilteredResultSet(filter, findOptions, findResult);

        return new DocumentCursor(findResult);
    }

    private void setUnfilteredResultSet(FindOptions findOptions, FindResult findResult) {
        validateLimit(findOptions, underlyingMap.sizeAsLong());

        Set resultSet;
        if (isNullOrEmpty(findOptions.getField())) {
            resultSet = limitIdSet(underlyingMap.keySet(), findOptions);
        } else {
            resultSet = sortIdSet(underlyingMap.keySet(), findOptions);
        }

        findResult.setIdSet(resultSet);
        findResult.setTotalCount(underlyingMap.size());
        findResult.setHasMore(underlyingMap.keySet().size() > (findOptions.getSize() + findOptions.getOffset()));
    }

    private void setFilteredResultSet(Filter filter, FindOptions findOptions, FindResult findResult) {
        Set nitriteIdSet;
        try {
            nitriteIdSet = filter.apply(underlyingMap);
        } catch (FilterException fe) {
            throw fe;
        } catch (Throwable t) {
            throw new FilterException(FILTERED_FIND_WITH_OPTIONS_OPERATION_FAILED, t);
        }

        if (nitriteIdSet == null || nitriteIdSet.isEmpty()) return;

        validateLimit(findOptions, nitriteIdSet.size());
        Set resultSet;

        if (isNullOrEmpty(findOptions.getField())) {
            resultSet = limitIdSet(nitriteIdSet, findOptions);
        } else {
            resultSet = sortIdSet(nitriteIdSet, findOptions);
        }

        findResult.setIdSet(resultSet);
        findResult.setHasMore(nitriteIdSet.size() > (findOptions.getSize() + findOptions.getOffset()));
        findResult.setTotalCount(nitriteIdSet.size());
    }

    private Set sortIdSet(Collection nitriteIdSet, FindOptions findOptions) {
        String sortField = findOptions.getField();
        Collator collator = findOptions.getCollator();

        NavigableMap> sortedMap;
        if (collator != null) {
            sortedMap = new TreeMap<>(collator);
        } else {
            sortedMap = new TreeMap<>();
        }

        Set nullValueIds = new HashSet<>();

        for (NitriteId id : nitriteIdSet) {
            Document document = underlyingMap.get(id);
            if (document == null) continue;

            Object value = getFieldValue(document, sortField);

            if (value != null) {
                if (value.getClass().isArray() || value instanceof Iterable) {
                    throw new InvalidOperationException(UNABLE_TO_SORT_ON_ARRAY);
                }
            } else {
                nullValueIds.add(id);
                continue;
            }

            if (sortedMap.containsKey(value)) {
                List idList = sortedMap.get(value);
                idList.add(id);
                sortedMap.put(value, idList);
            } else {
                List idList = new ArrayList<>();
                idList.add(id);
                sortedMap.put(value, idList);
            }
        }

        List sortedValues;
        if (findOptions.getSortOrder() == SortOrder.Ascending) {
            if (findOptions.getNullOrder() == NullOrder.Default || findOptions.getNullOrder() == NullOrder.First) {
                sortedValues = new ArrayList<>(nullValueIds);
                sortedValues.addAll(flattenList(sortedMap.values()));
            } else {
                sortedValues = flattenList(sortedMap.values());
                sortedValues.addAll(nullValueIds);
            }
        } else {
            if (findOptions.getNullOrder() == NullOrder.Default || findOptions.getNullOrder() == NullOrder.Last) {
                sortedValues = flattenList(sortedMap.descendingMap().values());
                sortedValues.addAll(nullValueIds);
            } else {
                sortedValues = new ArrayList<>(nullValueIds);
                sortedValues.addAll(flattenList(sortedMap.descendingMap().values()));
            }
        }

        return limitIdSet(sortedValues, findOptions);
    }

    private Set limitIdSet(Collection nitriteIdSet, FindOptions findOptions) {
        int offset = findOptions.getOffset();
        int size = findOptions.getSize();
        Set resultSet = new LinkedHashSet<>();

        int index = 0;
        for (NitriteId nitriteId : nitriteIdSet) {
            if (index >= offset) {
                resultSet.add(nitriteId);
                if (index == (offset + size - 1)) break;
            }
            index++;
        }

        return resultSet;
    }

    private  List flattenList(Collection> collection) {
        List finalList = new ArrayList<>();
        for (List list : collection) {
            finalList.addAll(list);
        }
        return finalList;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy