Package org.springframework.data.neo4j.repository

Source Code of org.springframework.data.neo4j.repository.AbstractGraphRepository$Query

/**
* Copyright 2011 the original 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.springframework.data.neo4j.repository;

import org.neo4j.cypherdsl.grammar.Execute;
import org.neo4j.cypherdsl.grammar.Skip;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.index.IndexHits;
import org.neo4j.graphdb.index.ReadableIndex;
import org.neo4j.helpers.collection.ClosableIterable;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.data.domain.*;
import org.springframework.data.geo.Box;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Shape;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.mapping.Neo4jPersistentEntity;
import org.springframework.data.neo4j.mapping.Neo4jPersistentProperty;
import org.springframework.data.neo4j.repository.query.CypherQuery;
import org.springframework.data.neo4j.support.Neo4jTemplate;
import org.springframework.data.neo4j.support.query.CypherQueryEngine;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.List;

import static java.lang.String.format;
import static org.neo4j.helpers.collection.MapUtil.map;

/**
* Repository like finder for Node and Relationship-Entities. Provides finder methods for direct access, access via {@link org.springframework.data.neo4j.core.TypeRepresentationStrategy}
* and indexing.
*
* @param <T> GraphBacked target of this finder, enables the finder methods to return this concrete type
* @param <S> Type of backing state, either Node or Relationship
*/
@Transactional(readOnly = true)
public abstract class AbstractGraphRepository<S extends PropertyContainer, T> implements
        GraphRepository<T>, NamedIndexRepository<T>, SpatialRepository<T>, CypherDslRepository<T> {
    private final LegacyIndexSearcher<S,T> legacyIndexSearcher;
    private final GeoQueries<S,T> geoQueries;

    interface Query<S extends PropertyContainer> {
        IndexHits<S> query(ReadableIndex<S> index);
    }

    protected T createEntity(S node) {
        return template.createEntityFromState(node, clazz, template.getMappingPolicy(clazz));
    }

    public static final ClosableIterable EMPTY_CLOSABLE_ITERABLE = new ClosableIterable() {
        @Override
        public void close() {
        }

        @Override
        public Iterator<?> iterator() {
            return Collections.emptyList().iterator();
        }
    };
    /**
     * Target graphbacked type
     */
    protected final Class<T> clazz;
    protected final Neo4jTemplate template;

    public AbstractGraphRepository(final Neo4jTemplate template, final Class<T> clazz) {
        this.template = template;
        this.clazz = clazz;
        legacyIndexSearcher = new LegacyIndexSearcher<>(template,clazz);
        geoQueries = new GeoQueries<>(legacyIndexSearcher);
    }

    @Override
    @Transactional
    public <U extends T> U save(U entity) {
        return template.save(entity);
    }

    @Override
    @Transactional
    public <U extends T> Iterable<U> save(Iterable<U> entities) {
        for (U entity : entities) {
            save(entity);
        }
        return entities;
    }
   
    /**
     * @return Number of instances of the target type in the graph.
     */
    @Override
    public long count() {
        return template.count(clazz);
    }

    /**
     * @return lazy Iterable over all instances of the target type.
     */
    @Override
    public Result<T> findAll() {
        return template.findAll(clazz);
    }

    /**
     *
     * @param id id
     * @return Entity with the given id or null.
     */
    @Override
    public T findOne(final Long id) {
        try {
            return createEntity(getById(id));
        } catch (DataRetrievalFailureException e) {
            return null;
        }
    }

    /**
     * Index based single finder, uses the default index name for this type (short class name).
     *
     * @param property
     * @param value
     * @return Single Entity with this property and value
     */
    @Override
    public T findByPropertyValue(final String property, final Object value) {
        return findByPropertyValue(null,property,value);
    }
    /**
     * Index based single finder.
     *
     * @param indexName or null for default
     * @param property
     * @param value
     * @return Single Entity with this property and value
     */
    @Override
    @Deprecated
    public T findByPropertyValue(final String indexName, final String property, final Object value) {
        return legacyIndexSearcher.findByPropertyValue(indexName, property, value);

    }

    /**
     * Index based exact finder.
     *
     * @param indexName or null for default index
     * @param property
     * @param value
     * @return Iterable over Entities with this property and value
     */
    @Override
    @Deprecated
    public Result<T> findAllByPropertyValue(final String indexName, final String property, final Object value) {
        return legacyIndexSearcher.findAllByPropertyValue(indexName, property, value);
    }

    /**
     * Index based exact finder, uses the default index name for this type (short class name).
     * @param property
     * @param value
     * @return Iterable over Entities with this property and value
     */
    @Override
    public Result<T> findAllByPropertyValue(final String property, final Object value) {
        return findAllByPropertyValue(null, property, value);
    }

    /**
     * Index based fulltext / query object finder, uses the default index name for this type (short class name).
     *
     * @param key key of the field to query
     *@param query lucene query object or query-string  @return Iterable over Entities with this property and value
     */
    @Override
    @Deprecated
    public Result<T> findAllByQuery(final String key, final Object query) {
        return findAllByQuery(null, key,query);
    }
    /**
     * Index based fulltext / query object finder.
     *
     * @param indexName or null for default index
     * @param property property of the field to query
     *@param query lucene query object or query-string  @return Iterable over Entities with this property and value
     */
    @Override
    @Deprecated
    public Result<T> findAllByQuery(final String indexName, final String property, final Object query) {
        return legacyIndexSearcher.findAllByQuery(indexName, property, query);
    }

    @Override
    @Deprecated
    public Result<T> findAllByRange(final String property, final Number from, final Number to) {
        return findAllByRange(null,property,from,to);
    }
    @Override
    @Deprecated
    public Result<T> findAllByRange(final String indexName, final String property, final Number from, final Number to) {
        return legacyIndexSearcher.findAllByRange(indexName, property, from, to);
    }


    /**
     * Schema (aka Label based) Index based single finder which uses the default label
     * name for this type to find the entity.
     *
     * @param property
     * @param value
     * @return Single Entity with this property and value or null if it does not exist
     */
    @Override
    public T findBySchemaPropertyValue(String property, Object value) {
        return findAllBySchemaPropertyValue(property,value).singleOrNull();
    }

    /**
     * Schema (aka Label based) finder, uses the default label name for this type
     * to lookup entities.
     * @param property
     * @param value
     * @return Iterable over Entities with this property and value
     */
    @Override
    public Result<T> findAllBySchemaPropertyValue(String property, Object value) {
        final String SCHEMA_PROP_MATCH_CLAUSE = "MATCH (entity:`%s`) where entity.`%s` = {propValue} return entity";

        Neo4jPersistentEntity persistentEntity = template.getEntityType(clazz).getEntity();
        Neo4jPersistentProperty persistentProperty = (Neo4jPersistentProperty)persistentEntity.getPersistentProperty(property);
        if (persistentProperty.getIndexInfo() == null || !persistentProperty.getIndexInfo().isLabelBased() ) {
            throw new IllegalArgumentException(format("property %s.%s is not schema indexed",persistentEntity.getName(),property));
        }

        Map<String,Object> params = new HashMap<String,Object>();
        params.put("propValue", value);
        String cypherQuery = format(SCHEMA_PROP_MATCH_CLAUSE,
                persistentProperty.getIndexInfo().getIndexName(), property );
        return template.query(cypherQuery,params).to(clazz);
    }

    protected abstract S getById(long id);

    @Override
    public boolean exists(Long id) {
        try {
            return getById(id)!=null;
        } catch (DataRetrievalFailureException e) {
            return false;
        }
    }

    @Override
    public Class getStoredJavaType(Object entity) {
        return template.getStoredJavaType(entity);
    }

    @Override
    @Transactional
    public void delete(T entity) {
        template.delete(entity);
    }

    @Override
    @Transactional
    public void delete(Long id) {
        delete(findOne(id));
    }

    @Override
    @Transactional
    public void delete(Iterable<? extends T> entities) {
        for (T entity : entities) {
            delete(entity);
        }
    }

    @Override
    @Transactional
    public void deleteAll() {
        delete(findAll());
    }

    @Override
    public Result<T> findAll(Sort sort) {
        CypherQuery cq = new CypherQuery(template.getEntityType(clazz).getEntity(),template, template.isLabelBased());
        return query(cq.toQueryString(sort), Collections.EMPTY_MAP);
    }

    @Override
    public Result<T> query(String query, Map<String, Object> params) {
        return template.query(query, params).to(clazz);
    }

    @Override
    public Page<T> findAll(final Pageable pageable) {
        int count = pageable.getPageSize();
        int offset = pageable.getOffset();
        Result<T> foundEntities = findAll(pageable.getSort());
        final Iterator<T> iterator = foundEntities.iterator();
        final PageImpl<T> page = extractPage(pageable, count, offset, iterator);
        foundEntities.finish();
        return page;
    }

    @Override
    public Iterable<T> findAll(final Iterable<Long> ids) {
        return new Iterable<T>() {
            @Override
            public Iterator<T> iterator() {
                final Iterator<Long> idIterator = ids.iterator();
                return new Iterator<T>() {

                     @Override
                     public boolean hasNext() {
                         return idIterator.hasNext();
                     }

                     @Override
                     public T next() {
                          return template.findOne(idIterator.next(), clazz);
                     }

                     @Override
                     public void remove() {
                          throw new UnsupportedOperationException();
                     }
                };
            }
        };
    }

    private PageImpl<T> extractPage(Pageable pageable, int count, int offset, Iterator<T> iterator) {
        final List<T> result = new ArrayList<T>(count);
        int total=subList(offset, count, iterator, result);
        if (iterator.hasNext()) total++;
        return new PageImpl<T>(result, pageable, total);
    }

    private SliceImpl<T> extractSlice(Pageable pageable, int count, int offset, Iterator<T> iterator) {
        final List<T> result = new ArrayList<T>(count);
        int total=subList(offset, count, iterator, result);
        boolean hasNext = iterator.hasNext();
        return new SliceImpl<>(result, pageable, hasNext);
    }

    private int subList(int skip, int limit, Iterator<T> source, final List<T> list) {
        int count=0;
        while (source.hasNext()) {
            count++;
            T t = source.next();
            if (skip > 0) {
                skip--;
            } else {
                list.add(t);
                limit--;
            }
            if (limit + skip == 0) break;
        }
        return count;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Page<T> query(Execute query, Execute countQuery, Map<String, Object> params, Pageable page) {
        final Execute limitedQuery = ((Skip)query).skip(page.getOffset()).limit(page.getPageSize());
        CypherQueryEngine engine = template.queryEngineFor();
        Page result = engine.query(limitedQuery.toString(), params).to(clazz).as(Page.class);
        if (countQuery == null) {
            return result;
        }
        Long count = engine.query(countQuery.toString(), params).to(Long.class).singleOrNull();
        if (count==null) return result;
        return new PageImpl<T>(result.getContent(),page, count);
    }
    @SuppressWarnings("unchecked")
    @Override
    public Page<T> query(Execute query, Map<String, Object> params, Pageable page) {
        return query(query, null, params, page);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Result<T> query(Execute query, Map<String, Object> params) {
        return template.queryEngineFor().query(query.toString(), params).to(clazz);
    }

    // SpatialRepository

    @Override
    public Result<T> findWithinWellKnownText(final String indexName, String wellKnownText) {
        return geoQueries.findWithinWellKnownText(indexName,wellKnownText);
    }
    @Override
    public Result<T> findWithinDistance(final String indexName, final double lat, double lon, double distanceKm) {
        return geoQueries.findWithinDistance(indexName, lat, lon,distanceKm);
    }

    @Override
    public Result<T> findWithinBoundingBox(final String indexName, final double lowerLeftLat,
                                           final double lowerLeftLon, final double upperRightLat, final double upperRightLon) {
        return geoQueries.findWithinBoundingBox(indexName, lowerLeftLat, lowerLeftLon, upperRightLat, upperRightLon);
    }

    @Override
    public Result<T> findWithinBoundingBox(String indexName, Box box) {
        return geoQueries.findWithinBoundingBox(indexName,box);
    }

    @Override
    public Result<T> findWithinDistance(String indexName, Circle circle) {
        return geoQueries.findWithinDistance(indexName, circle);
    }

    @Override
    public Result<T> findWithinShape(String indexName, Shape shape) {
        return geoQueries.findWithinShape(indexName,shape);
    }
}
TOP

Related Classes of org.springframework.data.neo4j.repository.AbstractGraphRepository$Query

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.