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

org.dizitart.no2.repository.RepositoryOperations Maven / Gradle / Ivy

/*
 * Copyright (c) 2017-2020. 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.repository;

import org.dizitart.no2.NitriteConfig;
import org.dizitart.no2.collection.*;
import org.dizitart.no2.common.mapper.NitriteMapper;
import org.dizitart.no2.common.tuples.Pair;
import org.dizitart.no2.exceptions.*;
import org.dizitart.no2.filters.*;

import java.lang.reflect.Field;

import static org.dizitart.no2.common.Constants.DOC_ID;
import static org.dizitart.no2.common.util.ObjectUtils.isCompatibleTypes;
import static org.dizitart.no2.common.util.StringUtils.isNullOrEmpty;

/**
 * @author Anindya Chatterjee
 * @since 4.0
 */
public class RepositoryOperations {
    private final NitriteConfig nitriteConfig;
    private final NitriteMapper nitriteMapper;
    private final NitriteCollection collection;
    private final Class type;
    private AnnotationScanner annotationScanner;
    private ObjectIdField objectIdField;
    private EntityDecoratorScanner entityDecoratorScanner;

    public RepositoryOperations(Class type, NitriteCollection collection, NitriteConfig nitriteConfig) {
        this.type = type;
        this.nitriteConfig = nitriteConfig;
        this.nitriteMapper = nitriteConfig.nitriteMapper();
        this.collection = collection;
        this.annotationScanner = new AnnotationScanner(type, collection, nitriteMapper);
        validateCollection();
    }

    public RepositoryOperations(EntityDecorator entityDecorator, NitriteCollection collection, NitriteConfig nitriteConfig) {
        this.type = entityDecorator.getEntityType();
        this.nitriteConfig = nitriteConfig;
        this.nitriteMapper = nitriteConfig.nitriteMapper();
        this.collection = collection;
        this.entityDecoratorScanner = new EntityDecoratorScanner(entityDecorator, collection, nitriteMapper);
        validateCollection();
    }

    public void scanIndexes() {
        if (annotationScanner != null) {
            annotationScanner.performScan();
            objectIdField = annotationScanner.getObjectIdField();
        } else if (entityDecoratorScanner != null) {
            entityDecoratorScanner.readEntity();
            objectIdField = entityDecoratorScanner.getObjectIdField();
        }
    }

    public void createIndexes() {
        if (annotationScanner != null) {
            annotationScanner.createIndices();
            annotationScanner.createIdIndex();
        } else if (entityDecoratorScanner != null) {
            entityDecoratorScanner.createIndices();
            entityDecoratorScanner.createIdIndex();
        }
    }

    public void serializeFields(Document document) {
        if (document != null) {
            for (Pair pair : document) {
                String key = pair.getFirst();
                Object value = pair.getSecond();
                Object serializedValue;
                serializedValue = nitriteMapper.tryConvert(value, Document.class);
                document.put(key, serializedValue);
            }
        }
    }

    public  Document[] toDocuments(T[] others) {
        if (others == null || others.length == 0) return null;
        Document[] documents = new Document[others.length];
        for (int i = 0; i < others.length; i++) {
            documents[i] = toDocument(others[i], false); // this method is for insert only
        }
        return documents;
    }

    public  Document toDocument(T object, boolean update) {
        Document document = (Document) nitriteMapper.tryConvert(object, Document.class);
        if (document == null) {
            throw new ObjectMappingException("Failed to map object to document");
        }

        if (objectIdField != null) {
            Field idField = objectIdField.getField();

            if (idField.getType() == NitriteId.class) {
                try {
                    idField.setAccessible(true);
                    if (idField.get(object) == null) {
                        NitriteId id = document.getId();
                        idField.set(object, id);
                        document.put(objectIdField.getIdFieldName(), nitriteMapper.tryConvert(id, Comparable.class));
                    } else if (!update) {
                        // if it is an insert, then we should not allow to insert the document with user
                        // provided id
                        throw new InvalidIdException("Auto generated id should not be set manually");
                    }
                } catch (IllegalAccessException iae) {
                    throw new InvalidIdException("Auto generated id value cannot be accessed");
                }
            }

            Object idValue = document.get(objectIdField.getIdFieldName());
            if (idValue == null) {
                throw new InvalidIdException("Id cannot be null");
            }
            if (idValue instanceof String && isNullOrEmpty((String) idValue)) {
                throw new InvalidIdException("Id value cannot be empty string");
            }
        }
        return document;
    }

    public Filter createUniqueFilter(Object object) {
        if (objectIdField == null) {
            throw new NotIdentifiableException("No id value found for the object");
        }

        Field idField = objectIdField.getField();
        idField.setAccessible(true);
        try {
            Object value = idField.get(object);
            if (value == null) {
                throw new InvalidIdException("Id value cannot be null");
            }
            return objectIdField.createUniqueFilter(value, nitriteMapper);
        } catch (IllegalAccessException iae) {
            throw new InvalidIdException("Id field is not accessible");
        }
    }

    public void removeNitriteId(Document document) {
        document.remove(DOC_ID);
        if (objectIdField != null) {
            Field idField = objectIdField.getField();
            if (idField != null && !objectIdField.isEmbedded() && idField.getType() == NitriteId.class) {
                document.remove(idField.getName());
            }
        }
    }

    public  Filter createIdFilter(I id) {
        if (objectIdField != null) {
            if (id == null) {
                throw new InvalidIdException("Id cannot be null");
            }
            if (!isCompatibleTypes(id.getClass(), objectIdField.getField().getType())) {
                throw new InvalidIdException("A value of invalid type is provided as id");
            }

            return objectIdField.createUniqueFilter(id, nitriteMapper);
        } else {
            throw new NotIdentifiableException(type.getName() + " does not have any id field");
        }
    }

    public Filter asObjectFilter(Filter filter) {
        if (filter instanceof NitriteFilter) {
            NitriteFilter nitriteFilter = (NitriteFilter) filter;
            nitriteFilter.setObjectFilter(true);
            nitriteFilter.setNitriteConfig(nitriteConfig);

            if (filter instanceof FieldBasedFilter) {
                return createObjectFilter((FieldBasedFilter) filter);
            }
            return nitriteFilter;
        }
        return filter;
    }

    public  Cursor find(Filter filter, FindOptions findOptions, Class type) {
        DocumentCursor documentCursor = collection.find(asObjectFilter(filter), findOptions);
        return new ObjectCursor<>(nitriteMapper, documentCursor, type);
    }

    private void validateCollection() {
        if (collection == null) {
            throw new ValidationException("Repository has not been initialized properly");
        }
    }

    private Filter createObjectFilter(FieldBasedFilter fieldBasedFilter) {
        if (objectIdField != null && objectIdField.getIdFieldName().equals(fieldBasedFilter.getField())) {
            if (fieldBasedFilter instanceof EqualsFilter) {
                return objectIdField.createUniqueFilter(fieldBasedFilter.getValue(), nitriteMapper);
            } else if (fieldBasedFilter instanceof ComparableFilter) {
                Object fieldValue = fieldBasedFilter.getValue();
                Object converted = nitriteMapper.tryConvert(fieldValue, Document.class);
                if (converted instanceof Document) {
                    throw new InvalidOperationException("Cannot compare object of type " + fieldValue.getClass());
                }
            }
        }
        return fieldBasedFilter;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy