From e9a5b7e7065011ef690a53408320dfeadee6960d Mon Sep 17 00:00:00 2001 From: Ryan Henszey Date: Tue, 23 Apr 2013 21:24:49 -0500 Subject: [PATCH] Added support for varying ID types (int/long) for repositories. --- .../AbstractElasticsearchRepository.java | 316 +++++++++++++ .../ElasticsearchRepositoryFactory.java | 33 +- ...MappingElasticsearchEntityInformation.java | 9 +- .../support/NumberKeyedRepository.java | 51 +++ .../SimpleElasticsearchRepository.java | 298 +----------- .../data/elasticsearch/DoubleIDEntity.java | 68 +++ .../data/elasticsearch/IntegerIDEntity.java | 70 +++ .../repositories/DoubleIDRepository.java | 25 + .../repositories/IntegerIDRepository.java | 24 + .../support/DoubleIDRepositoryTest.java | 429 ++++++++++++++++++ .../support/IntegerIDRepositoryTest.java | 429 ++++++++++++++++++ 11 files changed, 1461 insertions(+), 291 deletions(-) create mode 100644 src/main/java/org/springframework/data/elasticsearch/repository/support/AbstractElasticsearchRepository.java create mode 100644 src/main/java/org/springframework/data/elasticsearch/repository/support/NumberKeyedRepository.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/DoubleIDEntity.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/IntegerIDEntity.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/repositories/DoubleIDRepository.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/repositories/IntegerIDRepository.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/repository/support/DoubleIDRepositoryTest.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/repository/support/IntegerIDRepositoryTest.java diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/AbstractElasticsearchRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/AbstractElasticsearchRepository.java new file mode 100644 index 000000000..700260343 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/AbstractElasticsearchRepository.java @@ -0,0 +1,316 @@ +/* + * Copyright 2013 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.elasticsearch.repository.support; + +import org.elasticsearch.index.query.QueryBuilder; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.domain.*; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.query.*; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.elasticsearch.index.query.QueryBuilders.inQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.springframework.data.elasticsearch.core.query.Query.DEFAULT_PAGE; + +/** + * Elasticsearch specific repository implementation. Likely to be used as target within {@link ElasticsearchRepositoryFactory} + * + * + * @author Rizwan Idrees + * @author Mohsin Husen + * @author Ryan Henszey + */ +public abstract class AbstractElasticsearchRepository implements ElasticsearchRepository { + + + protected ElasticsearchOperations elasticsearchOperations; + protected Class entityClass; + protected ElasticsearchEntityInformation entityInformation; + + public AbstractElasticsearchRepository() { + } + + public AbstractElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) { + Assert.notNull(elasticsearchOperations); + this.setElasticsearchOperations(elasticsearchOperations); + } + + public AbstractElasticsearchRepository(ElasticsearchEntityInformation metadata, ElasticsearchOperations elasticsearchOperations) { + this(elasticsearchOperations); + Assert.notNull(metadata); + this.entityInformation = metadata; + setEntityClass(this.entityInformation.getJavaType()); + createIndex(); + putMapping(); + } + + private void createIndex(){ + elasticsearchOperations.createIndex(getEntityClass()); + } + + private void putMapping(){ + elasticsearchOperations.putMapping(getEntityClass()); + } + + @Override + public T findOne(ID id) { + GetQuery query = new GetQuery(); + query.setId(stringIdRepresentation(id)); + return elasticsearchOperations.queryForObject(query, getEntityClass()); + } + + @Override + public Iterable findAll() { + int itemCount = (int) this.count(); + if (itemCount == 0) { + return new PageImpl(Collections. emptyList()); + } + return this.findAll(new PageRequest(0, Math.max(1, itemCount))); + } + + @Override + public Page findAll(Pageable pageable) { + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(matchAllQuery()) + .withPageable(pageable) + .build(); + return elasticsearchOperations.queryForPage(query, getEntityClass()); + } + + @Override + public Iterable findAll(Sort sort) { + int itemCount = (int) this.count(); + if (itemCount == 0) { + return new PageImpl(Collections. emptyList()); + } + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(matchAllQuery()) + .withPageable(new PageRequest(0,itemCount, sort)) + .build(); + return elasticsearchOperations.queryForPage(query, getEntityClass()); + } + + @Override + public Iterable findAll(Iterable ids) { + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(inQuery(entityInformation.getIdAttribute(), ids)) + .build(); + return elasticsearchOperations.queryForPage(query, getEntityClass()); + } + + @Override + public long count() { + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(matchAllQuery()).build(); + return elasticsearchOperations.count(query,getEntityClass()); + } + + @Override + public S save(S entity) { + Assert.notNull(entity, "Cannot save 'null' entity."); + elasticsearchOperations.index(createIndexQuery(entity)); + elasticsearchOperations.refresh(entityInformation.getIndexName(), true); + return entity; + } + + public List save(List entities) { + Assert.notNull(entities, "Cannot insert 'null' as a List."); + Assert.notEmpty(entities,"Cannot insert empty List."); + List queries = new ArrayList(); + for(S s:entities){ + queries.add(createIndexQuery(s)); + } + elasticsearchOperations.bulkIndex(queries); + elasticsearchOperations.refresh(entityInformation.getIndexName(), true); + return entities; + } + + @Override + public S index(S entity) { + return save(entity); + } + + @Override + public Iterable save(Iterable entities) { + Assert.notNull(entities, "Cannot insert 'null' as a List."); + if (!(entities instanceof Collection)) { + throw new InvalidDataAccessApiUsageException("Entities have to be inside a collection"); + } + List queries = new ArrayList(); + for(S s: entities){ + queries.add(createIndexQuery(s)); + } + elasticsearchOperations.bulkIndex(queries); + elasticsearchOperations.refresh(entityInformation.getIndexName(), true); + return entities; + } + + @Override + public boolean exists(ID id) { + return findOne(id) != null; + } + + @Override + public Iterable search(QueryBuilder query) { + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(query).build(); + int count = (int) elasticsearchOperations.count(searchQuery, getEntityClass()); + if(count == 0){ + return new PageImpl(Collections.emptyList()); + } + searchQuery.setPageable(new PageRequest(0, count)); + return elasticsearchOperations.queryForPage(searchQuery, getEntityClass()); + } + + @Override + public Page search(QueryBuilder query, Pageable pageable) { + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(query) + .withPageable(pageable) + .build(); + return elasticsearchOperations.queryForPage(searchQuery, getEntityClass()); + } + + @Override + public Page search(SearchQuery query){ + return elasticsearchOperations.queryForPage(query, getEntityClass()); + } + + @Override + public Page searchSimilar(T entity) { + return searchSimilar(entity, DEFAULT_PAGE); + } + + @Override + public Page searchSimilar(T entity, Pageable pageable) { + Assert.notNull(entity, "Cannot search similar records for 'null'."); + Assert.notNull(entity, "Pageable cannot be 'null'"); + MoreLikeThisQuery query = new MoreLikeThisQuery(); + query.setId(stringIdRepresentation(extractIdFromBean(entity))); + query.setPageable(pageable); + return elasticsearchOperations.moreLikeThis(query, getEntityClass()); + } + + + @Override + public void delete(ID id) { + Assert.notNull(id, "Cannot delete entity with id 'null'."); + elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),stringIdRepresentation(id)); + elasticsearchOperations.refresh(entityInformation.getIndexName(),true); + } + + @Override + public void delete(T entity) { + Assert.notNull(entity, "Cannot delete 'null' entity."); + delete(extractIdFromBean(entity)); + elasticsearchOperations.refresh(entityInformation.getIndexName(), true); + } + + @Override + public void delete(Iterable entities) { + Assert.notNull(entities, "Cannot delete 'null' list."); + for (T entity : entities) { + delete(entity); + } + } + + @Override + public void deleteAll() { + DeleteQuery deleteQuery = new DeleteQuery(); + deleteQuery.setQuery(matchAllQuery()); + elasticsearchOperations.delete(deleteQuery, getEntityClass()); + elasticsearchOperations.refresh(entityInformation.getIndexName(),true); + } + + private IndexQuery createIndexQuery(T entity){ + IndexQuery query = new IndexQuery(); + query.setObject(entity); + query.setId(stringIdRepresentation(extractIdFromBean(entity))); + query.setVersion(extractVersionFromBean(entity)); + return query; + } + + @SuppressWarnings("unchecked") + private Class resolveReturnedClassFromGenericType() { + ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass()); + return (Class) parameterizedType.getActualTypeArguments()[0]; + } + + private ParameterizedType resolveReturnedClassFromGenericType(Class clazz) { + Object genericSuperclass = clazz.getGenericSuperclass(); + if (genericSuperclass instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; + Type rawtype = parameterizedType.getRawType(); + if (SimpleElasticsearchRepository.class.equals(rawtype)) { + return parameterizedType; + } + } + return resolveReturnedClassFromGenericType(clazz.getSuperclass()); + } + + public Class getEntityClass() { + if (!isEntityClassSet()) { + try { + this.entityClass = resolveReturnedClassFromGenericType(); + } catch (Exception e) { + throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e); + } + } + return entityClass; + } + + private boolean isEntityClassSet() { + return entityClass != null; + } + + public final void setEntityClass(Class entityClass) { + Assert.notNull(entityClass, "EntityClass must not be null."); + this.entityClass = entityClass; + } + + public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) { + Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null."); + this.elasticsearchOperations = elasticsearchOperations; + } + + + protected ID extractIdFromBean(T entity) { + if (entityInformation != null) { + return entityInformation.getId(entity); + } + return null; + } + + protected abstract String stringIdRepresentation(ID id); + + private Long extractVersionFromBean(T entity){ + if (entityInformation != null) { + return entityInformation.getVersion(entity); + } + return null; + } + +} diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java index acde9e30c..3d4f4119a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java @@ -15,6 +15,11 @@ */ package org.springframework.data.elasticsearch.repository.support; +import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT; + +import java.io.Serializable; +import java.lang.reflect.Method; + import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery; @@ -28,18 +33,15 @@ import org.springframework.data.repository.query.QueryLookupStrategy; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.util.Assert; -import java.io.Serializable; -import java.lang.reflect.Method; - -import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT; - /** * Factory to create {@link ElasticsearchRepository} * * @author Rizwan Idrees * @author Mohsin Husen + * @author Ryan Henszey */ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport { + private final ElasticsearchOperations elasticsearchOperations; private final ElasticsearchEntityInformationCreator entityInformationCreator; @@ -59,8 +61,27 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport { @Override @SuppressWarnings({ "rawtypes", "unchecked" }) protected Object getTargetRepository(RepositoryMetadata metadata) { - SimpleElasticsearchRepository repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations); + + ElasticsearchEntityInformation entityInformation = getEntityInformation(metadata.getDomainType()); + + AbstractElasticsearchRepository repository; + + //Probably a better way to store and look these up. + if(Integer.class.isAssignableFrom(entityInformation.getIdType()) || + Long.class.isAssignableFrom(entityInformation.getIdType()) || + Double.class.isAssignableFrom(entityInformation.getIdType())){ + //logger.debug("Using NumberKeyedRepository for " + metadata.getRepositoryInterface()); + repository = new NumberKeyedRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations); + } + else if (entityInformation.getIdType() == String.class){ + //logger.debug("Using SimpleElasticsearchRepository for " + metadata.getRepositoryInterface()); + repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations); + } + else { + throw new IllegalArgumentException("Unsuppored ID type " + entityInformation.getIdType()); + } repository.setEntityClass(metadata.getDomainType()); + return repository; } diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java index 3ce4842de..c24bb1de5 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java @@ -15,6 +15,8 @@ */ package org.springframework.data.elasticsearch.repository.support; +import java.io.Serializable; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; @@ -23,8 +25,6 @@ import org.springframework.data.mapping.model.BeanWrapper; import org.springframework.data.repository.core.support.AbstractEntityInformation; import org.springframework.util.Assert; -import java.io.Serializable; - /** * Elasticsearch specific implementation of {@link org.springframework.data.repository.core.support.AbstractEntityInformation} * @@ -33,6 +33,7 @@ import java.io.Serializable; * * @author Rizwan Idrees * @author Mohsin Husen + * @author Ryan Henszey */ public class MappingElasticsearchEntityInformation extends AbstractEntityInformation implements ElasticsearchEntityInformation { @@ -41,6 +42,7 @@ public class MappingElasticsearchEntityInformation e private final ElasticsearchPersistentEntity entityMetadata; private final String indexName; private final String type; + private Class idClass; public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity entity) { this(entity, null, null); @@ -51,6 +53,7 @@ public class MappingElasticsearchEntityInformation e this.entityMetadata = entity; this.indexName = indexName; this.type = type; + this.idClass = entity.getIdProperty().getType(); } @SuppressWarnings("unchecked") @@ -67,7 +70,7 @@ public class MappingElasticsearchEntityInformation e @SuppressWarnings("unchecked") @Override public Class getIdType() { - return (Class) String.class; + return (Class)idClass; } @Override diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/NumberKeyedRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/NumberKeyedRepository.java new file mode 100644 index 000000000..adeb6b774 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/NumberKeyedRepository.java @@ -0,0 +1,51 @@ +/* + * Copyright 2013 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.elasticsearch.repository.support; + +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; + +/** + * Elasticsearch specific repository implementation. Likely to be used as target within {@link ElasticsearchRepositoryFactory} + * + * + * @author Rizwan Idrees + * @author Mohsin Husen + * @author Ryan Henszey + */ +public class NumberKeyedRepository extends AbstractElasticsearchRepository { + + + public NumberKeyedRepository() { + super(); + } + + public NumberKeyedRepository(ElasticsearchEntityInformation metadata,ElasticsearchOperations elasticsearchOperations) { + super(metadata, elasticsearchOperations); + } + + public NumberKeyedRepository(ElasticsearchOperations elasticsearchOperations) { + super(elasticsearchOperations); + } + + + + @Override + protected String stringIdRepresentation(ID id) { + return String.valueOf(id); + } + + +} diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java index 2b90ed987..1ef1e5223 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java @@ -15,299 +15,33 @@ */ package org.springframework.data.elasticsearch.repository.support; -import org.elasticsearch.index.query.QueryBuilder; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.domain.*; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; -import org.springframework.data.elasticsearch.core.query.*; -import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; -import org.springframework.util.Assert; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import static org.elasticsearch.index.query.QueryBuilders.inQuery; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -import static org.springframework.data.elasticsearch.core.query.Query.DEFAULT_PAGE; /** * Elasticsearch specific repository implementation. Likely to be used as target within {@link ElasticsearchRepositoryFactory} * - * @param * * @author Rizwan Idrees * @author Mohsin Husen + * @author Ryan Henszey */ -public class SimpleElasticsearchRepository implements ElasticsearchRepository { +public class SimpleElasticsearchRepository extends AbstractElasticsearchRepository { + + public SimpleElasticsearchRepository() { + super(); + } + public SimpleElasticsearchRepository(ElasticsearchEntityInformation metadata,ElasticsearchOperations elasticsearchOperations) { + super(metadata, elasticsearchOperations); + } - private ElasticsearchOperations elasticsearchOperations; - private Class entityClass; - private ElasticsearchEntityInformation entityInformation; + public SimpleElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) { + super(elasticsearchOperations); + } - public SimpleElasticsearchRepository() { - } - - public SimpleElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) { - Assert.notNull(elasticsearchOperations); - this.setElasticsearchOperations(elasticsearchOperations); - } - - public SimpleElasticsearchRepository(ElasticsearchEntityInformation metadata, ElasticsearchOperations elasticsearchOperations) { - this(elasticsearchOperations); - Assert.notNull(metadata); - this.entityInformation = metadata; - setEntityClass(this.entityInformation.getJavaType()); - createIndex(); - putMapping(); - } - - private void createIndex(){ - elasticsearchOperations.createIndex(getEntityClass()); - } - - private void putMapping(){ - elasticsearchOperations.putMapping(getEntityClass()); - } - - @Override - public T findOne(String id) { - GetQuery query = new GetQuery(); - query.setId(id); - return elasticsearchOperations.queryForObject(query, getEntityClass()); - } - - @Override - public Iterable findAll() { - int itemCount = (int) this.count(); - if (itemCount == 0) { - return new PageImpl(Collections. emptyList()); - } - return this.findAll(new PageRequest(0, Math.max(1, itemCount))); - } - - @Override - public Page findAll(Pageable pageable) { - SearchQuery query = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()) - .withPageable(pageable) - .build(); - return elasticsearchOperations.queryForPage(query, getEntityClass()); - } - - @Override - public Iterable findAll(Sort sort) { - int itemCount = (int) this.count(); - if (itemCount == 0) { - return new PageImpl(Collections. emptyList()); - } - SearchQuery query = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()) - .withPageable(new PageRequest(0,itemCount, sort)) - .build(); - return elasticsearchOperations.queryForPage(query, getEntityClass()); - } - - @Override - public Iterable findAll(Iterable ids) { - SearchQuery query = new NativeSearchQueryBuilder() - .withQuery(inQuery(entityInformation.getIdAttribute(), ids)) - .build(); - return elasticsearchOperations.queryForPage(query, getEntityClass()); - } - - @Override - public long count() { - SearchQuery query = new NativeSearchQueryBuilder() - .withQuery(matchAllQuery()).build(); - return elasticsearchOperations.count(query,getEntityClass()); - } - - @Override - public S save(S entity) { - Assert.notNull(entity, "Cannot save 'null' entity."); - elasticsearchOperations.index(createIndexQuery(entity)); - elasticsearchOperations.refresh(entityInformation.getIndexName(), true); - return entity; - } - - public List save(List entities) { - Assert.notNull(entities, "Cannot insert 'null' as a List."); - Assert.notEmpty(entities,"Cannot insert empty List."); - List queries = new ArrayList(); - for(S s:entities){ - queries.add(createIndexQuery(s)); - } - elasticsearchOperations.bulkIndex(queries); - elasticsearchOperations.refresh(entityInformation.getIndexName(), true); - return entities; - } - - @Override - public S index(S entity) { - return save(entity); - } - - @Override - public Iterable save(Iterable entities) { - Assert.notNull(entities, "Cannot insert 'null' as a List."); - if (!(entities instanceof Collection)) { - throw new InvalidDataAccessApiUsageException("Entities have to be inside a collection"); - } - List queries = new ArrayList(); - for(S s: entities){ - queries.add(createIndexQuery(s)); - } - elasticsearchOperations.bulkIndex(queries); - elasticsearchOperations.refresh(entityInformation.getIndexName(), true); - return entities; - } - - @Override - public boolean exists(String id) { - return findOne(id) != null; - } - - @Override - public Iterable search(QueryBuilder query) { - SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(query).build(); - int count = (int) elasticsearchOperations.count(searchQuery, getEntityClass()); - if(count == 0){ - return new PageImpl(Collections.emptyList()); - } - searchQuery.setPageable(new PageRequest(0, count)); - return elasticsearchOperations.queryForPage(searchQuery, getEntityClass()); - } - - @Override - public Page search(QueryBuilder query, Pageable pageable) { - SearchQuery searchQuery = new NativeSearchQueryBuilder() - .withQuery(query) - .withPageable(pageable) - .build(); - return elasticsearchOperations.queryForPage(searchQuery, getEntityClass()); - } - - @Override - public Page search(SearchQuery query){ - return elasticsearchOperations.queryForPage(query, getEntityClass()); - } - - @Override - public Page searchSimilar(T entity) { - return searchSimilar(entity, DEFAULT_PAGE); - } - - @Override - public Page searchSimilar(T entity, Pageable pageable) { - Assert.notNull(entity, "Cannot search similar records for 'null'."); - Assert.notNull(entity, "Pageable cannot be 'null'"); - MoreLikeThisQuery query = new MoreLikeThisQuery(); - query.setId(extractIdFromBean(entity)); - query.setPageable(pageable); - return elasticsearchOperations.moreLikeThis(query, getEntityClass()); - } - - - @Override - public void delete(String id) { - Assert.notNull(id, "Cannot delete entity with id 'null'."); - elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),id); - elasticsearchOperations.refresh(entityInformation.getIndexName(),true); - } - - @Override - public void delete(T entity) { - Assert.notNull(entity, "Cannot delete 'null' entity."); - delete(extractIdFromBean(entity)); - elasticsearchOperations.refresh(entityInformation.getIndexName(), true); - } - - @Override - public void delete(Iterable entities) { - Assert.notNull(entities, "Cannot delete 'null' list."); - for (T entity : entities) { - delete(entity); - } - } - - @Override - public void deleteAll() { - DeleteQuery deleteQuery = new DeleteQuery(); - deleteQuery.setQuery(matchAllQuery()); - elasticsearchOperations.delete(deleteQuery, getEntityClass()); - elasticsearchOperations.refresh(entityInformation.getIndexName(),true); - } - - private IndexQuery createIndexQuery(T entity){ - IndexQuery query = new IndexQuery(); - query.setObject(entity); - query.setId(extractIdFromBean(entity)); - query.setVersion(extractVersionFromBean(entity)); - return query; - } - - @SuppressWarnings("unchecked") - private Class resolveReturnedClassFromGenericType() { - ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass()); - return (Class) parameterizedType.getActualTypeArguments()[0]; - } - - private ParameterizedType resolveReturnedClassFromGenericType(Class clazz) { - Object genericSuperclass = clazz.getGenericSuperclass(); - if (genericSuperclass instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass; - Type rawtype = parameterizedType.getRawType(); - if (SimpleElasticsearchRepository.class.equals(rawtype)) { - return parameterizedType; - } - } - return resolveReturnedClassFromGenericType(clazz.getSuperclass()); - } - - public Class getEntityClass() { - if (!isEntityClassSet()) { - try { - this.entityClass = resolveReturnedClassFromGenericType(); - } catch (Exception e) { - throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e); - } - } - return entityClass; - } - - private boolean isEntityClassSet() { - return entityClass != null; - } - - public final void setEntityClass(Class entityClass) { - Assert.notNull(entityClass, "EntityClass must not be null."); - this.entityClass = entityClass; - } - - public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) { - Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null."); - this.elasticsearchOperations = elasticsearchOperations; - } - - - private String extractIdFromBean(T entity) { - if (entityInformation != null) { - return entityInformation.getId(entity); - } - return null; - } - - private Long extractVersionFromBean(T entity){ - if (entityInformation != null) { - return entityInformation.getVersion(entity); - } - return null; - } + @Override + protected String stringIdRepresentation(String id) { + return id; + } } diff --git a/src/test/java/org/springframework/data/elasticsearch/DoubleIDEntity.java b/src/test/java/org/springframework/data/elasticsearch/DoubleIDEntity.java new file mode 100644 index 000000000..bb4f415d9 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/DoubleIDEntity.java @@ -0,0 +1,68 @@ +/* + * Copyright 2013 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.elasticsearch; + +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Version; +import org.springframework.data.elasticsearch.annotations.Document; + + +@Document(indexName = "double-keyed-entity", type = "double-keyed-entity") +public class DoubleIDEntity { + + + @Id + private Double id; + private String type; + private String message; + @Version + private Long version; + + public Double getId() { + return id; + } + + public void setId(Double id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/IntegerIDEntity.java b/src/test/java/org/springframework/data/elasticsearch/IntegerIDEntity.java new file mode 100644 index 000000000..6e67902ab --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/IntegerIDEntity.java @@ -0,0 +1,70 @@ +/* + * Copyright 2013 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.elasticsearch; + +import java.math.BigInteger; + +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Version; +import org.springframework.data.elasticsearch.annotations.Document; + + +@Document(indexName = "integer-keyed-entity", type = "integer-keyed-entity") +public class IntegerIDEntity { + + + @Id + private Integer id; + private String type; + private String message; + @Version + private Long version; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/DoubleIDRepository.java b/src/test/java/org/springframework/data/elasticsearch/repositories/DoubleIDRepository.java new file mode 100644 index 000000000..258103524 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/DoubleIDRepository.java @@ -0,0 +1,25 @@ +/* + * Copyright 2013 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.elasticsearch.repositories; + +import org.springframework.data.elasticsearch.DoubleIDEntity; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +public interface DoubleIDRepository extends ElasticsearchRepository { + + + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/IntegerIDRepository.java b/src/test/java/org/springframework/data/elasticsearch/repositories/IntegerIDRepository.java new file mode 100644 index 000000000..449f66b23 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/IntegerIDRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2013 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.elasticsearch.repositories; + +import org.springframework.data.elasticsearch.IntegerIDEntity; +import org.springframework.data.elasticsearch.SampleEntity; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +public interface IntegerIDRepository extends ElasticsearchRepository { + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/support/DoubleIDRepositoryTest.java b/src/test/java/org/springframework/data/elasticsearch/repository/support/DoubleIDRepositoryTest.java new file mode 100644 index 000000000..a37a02f12 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/repository/support/DoubleIDRepositoryTest.java @@ -0,0 +1,429 @@ +/* + * Copyright 2013 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.elasticsearch.repository.support; + +import static org.elasticsearch.index.query.QueryBuilders.fieldQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Resource; + +import org.apache.commons.lang.math.RandomUtils; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.elasticsearch.DoubleIDEntity; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.data.elasticsearch.core.query.SearchQuery; +import org.springframework.data.elasticsearch.repositories.DoubleIDRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:/simple-repository-test.xml") +public class DoubleIDRepositoryTest { + + + @Resource + private DoubleIDRepository repository; + + + @Before + public void before(){ + repository.deleteAll(); + } + + @Test + public void shouldDoBulkIndexDocument(){ + //given + Double documentId1 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity1 = new DoubleIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("some message"); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("some message"); + sampleEntity2.setVersion(System.currentTimeMillis()); + + //when + repository.save(Arrays.asList(sampleEntity1, sampleEntity2)); + //then + DoubleIDEntity entity1FromElasticSearch = repository.findOne(documentId1); + assertThat(entity1FromElasticSearch, is(notNullValue())); + + DoubleIDEntity entity2FromElasticSearch = repository.findOne(documentId2); + assertThat(entity2FromElasticSearch, is(notNullValue())); + } + + @Test + public void shouldSaveDocument(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + //when + repository.save(sampleEntity); + //then + DoubleIDEntity entityFromElasticSearch = repository.findOne(documentId); + assertThat(entityFromElasticSearch, is(notNullValue())); + } + + @Test + public void shouldFindDocumentById(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + DoubleIDEntity entityFromElasticSearch = repository.findOne(documentId); + //then + assertThat(entityFromElasticSearch, is(notNullValue())); + assertThat(sampleEntity, is((equalTo(sampleEntity)))); + } + + @Test + public void shouldReturnCountOfDocuments(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + Long count = repository.count(); + //then + assertThat(count, is(greaterThanOrEqualTo(1L))); + } + + @Test + public void shouldFindAllDocuments(){ + //when + Iterable results = repository.findAll(); + //then + assertThat(results, is(notNullValue())); + } + + @Test + public void shouldDeleteDocument(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + repository.delete(documentId); + //then + DoubleIDEntity entityFromElasticSearch = repository.findOne(documentId); + assertThat(entityFromElasticSearch, is(nullValue())); + } + + @Test + public void shouldSearchDocumentsGivenSearchQuery(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some test message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(termQuery("message", "test")) + .build(); + //when + Page page = repository.search(query); + //then + assertThat(page, is(notNullValue())); + assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1))); + } + + @Test + public void shouldSearchDocumentsGivenElasticsearchQuery(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + Page page = repository.search(termQuery("message", "world"), new PageRequest(0,50)); + //then + assertThat(page, is(notNullValue())); + assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1))); + } + + @Test + @Ignore + public void shouldFindAllByIdQuery(){ + //todo : find solution for findAll(Iterable ids) + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + //when + Iterable sampleEntities=repository.findAll(Arrays.asList(documentId,documentId2)); + + //then + assertNotNull("sample entities cant be null..", sampleEntities); + } + + @Test + public void shouldSaveIterableEntities(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity1 = new DoubleIDEntity(); + sampleEntity1.setId(documentId); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + + Iterable sampleEntities = Arrays.asList(sampleEntity1,sampleEntity2); + //when + repository.save(sampleEntities); + //then + Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0, 50)); + assertNotNull(entities); + } + + @Test + public void shouldReturnTrueGivenDocumentWithIdExists(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + //when + boolean exist = repository.exists(documentId); + + //then + assertEquals(exist, true); + } + + @Test + public void shouldReturnResultsForGivenSearchQuery(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(fieldQuery("id",documentId)) + .build(); + Page sampleEntities= repository.search(searchQuery); + //then + assertThat(sampleEntities.getTotalElements(), equalTo(1L)); + } + + @Test + public void shouldDeleteAll(){ + //when + repository.deleteAll(); + //then + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(matchAllQuery()) + .build(); + Page sampleEntities= repository.search(searchQuery); + assertThat(sampleEntities.getTotalElements(), equalTo(0L)); + } + + @Test + public void shouldDeleteEntity(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + repository.delete(sampleEntity); + //then + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(fieldQuery("id", documentId)) + .build(); + Page sampleEntities= repository.search(searchQuery); + assertThat(sampleEntities.getTotalElements(),equalTo(0L)); + } + + @Test + public void shouldReturnIterableEntities(){ + //given + Double documentId1 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity1 = new DoubleIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity1); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + //when + Iterable sampleEntities = repository.search(fieldQuery("id",documentId1)); + //then + assertNotNull("sample entities cant be null..", sampleEntities); + } + + @Test + public void shouldDeleteIterableEntities(){ + //given + Double documentId1 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity1 = new DoubleIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + Iterable sampleEntities = Arrays.asList(sampleEntity2,sampleEntity2); + //when + repository.delete(sampleEntities); + //then + assertThat(repository.findOne(documentId1),is(nullValue())); + assertThat(repository.findOne(documentId2),is(nullValue())); + } + + @Test + public void shouldIndexEntity(){ + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setVersion(System.currentTimeMillis()); + sampleEntity.setMessage("some message"); + //when + repository.index(sampleEntity); + //then + Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50)); + assertThat(entities.getTotalElements(),equalTo(1L)); + } + + @Test + public void shouldSortByGivenField(){ + //todo + //given + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("A. hello world."); + repository.save(sampleEntity); + + Double documentId2 = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity2 = new DoubleIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("B.hello world."); + repository.save(sampleEntity2); + //when + Iterable sampleEntities=repository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"message"))); + //then + assertThat(sampleEntities,is(notNullValue())); + } + + + @Test + public void shouldReturnSimilarEntities(){ + //given + String sampleMessage = "So we build a web site or an application and want to add search to it, " + + "and then it hits us: getting search working is hard. We want our search solution to be fast," + + " we want a painless setup and a completely free search schema, we want to be able to index data simply using JSON over HTTP, " + + "we want our search server to be always available, we want to be able to start with one machine and scale to hundreds, " + + "we want real-time search, we want simple multi-tenancy, and we want a solution that is built for the cloud."; + + + + List sampleEntities = createSampleEntitiesWithMessage(sampleMessage, 30); + repository.save(sampleEntities); + + //when + Page results = repository.searchSimilar(sampleEntities.get(0)); + + //then + assertThat(results.getTotalElements(), is(greaterThanOrEqualTo(1L))); + } + + private static List createSampleEntitiesWithMessage(String message, int numberOfEntities){ + List sampleEntities = new ArrayList(); + for(int i = 0; i < numberOfEntities; i++){ + Double documentId = RandomUtils.nextDouble(); + DoubleIDEntity sampleEntity = new DoubleIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage(message); + sampleEntity.setVersion(System.currentTimeMillis()); + sampleEntities.add(sampleEntity); + } + return sampleEntities; + } + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/support/IntegerIDRepositoryTest.java b/src/test/java/org/springframework/data/elasticsearch/repository/support/IntegerIDRepositoryTest.java new file mode 100644 index 000000000..2b7349264 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/repository/support/IntegerIDRepositoryTest.java @@ -0,0 +1,429 @@ +/* + * Copyright 2013 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.elasticsearch.repository.support; + +import static org.elasticsearch.index.query.QueryBuilders.fieldQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.annotation.Resource; + +import org.apache.commons.lang.math.RandomUtils; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.data.elasticsearch.IntegerIDEntity; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.data.elasticsearch.core.query.SearchQuery; +import org.springframework.data.elasticsearch.repositories.IntegerIDRepository; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:/simple-repository-test.xml") +public class IntegerIDRepositoryTest { + + + @Resource + private IntegerIDRepository repository; + + + @Before + public void before(){ + repository.deleteAll(); + } + + @Test + public void shouldDoBulkIndexDocument(){ + //given + Integer documentId1 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity1 = new IntegerIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("some message"); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("some message"); + sampleEntity2.setVersion(System.currentTimeMillis()); + + //when + repository.save(Arrays.asList(sampleEntity1, sampleEntity2)); + //then + IntegerIDEntity entity1FromElasticSearch = repository.findOne(documentId1); + assertThat(entity1FromElasticSearch, is(notNullValue())); + + IntegerIDEntity entity2FromElasticSearch = repository.findOne(documentId2); + assertThat(entity2FromElasticSearch, is(notNullValue())); + } + + @Test + public void shouldSaveDocument(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + //when + repository.save(sampleEntity); + //then + IntegerIDEntity entityFromElasticSearch = repository.findOne(documentId); + assertThat(entityFromElasticSearch, is(notNullValue())); + } + + @Test + public void shouldFindDocumentById(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + IntegerIDEntity entityFromElasticSearch = repository.findOne(documentId); + //then + assertThat(entityFromElasticSearch, is(notNullValue())); + assertThat(sampleEntity, is((equalTo(sampleEntity)))); + } + + @Test + public void shouldReturnCountOfDocuments(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + Long count = repository.count(); + //then + assertThat(count, is(greaterThanOrEqualTo(1L))); + } + + @Test + public void shouldFindAllDocuments(){ + //when + Iterable results = repository.findAll(); + //then + assertThat(results, is(notNullValue())); + } + + @Test + public void shouldDeleteDocument(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + repository.delete(documentId); + //then + IntegerIDEntity entityFromElasticSearch = repository.findOne(documentId); + assertThat(entityFromElasticSearch, is(nullValue())); + } + + @Test + public void shouldSearchDocumentsGivenSearchQuery(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("some test message"); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + SearchQuery query = new NativeSearchQueryBuilder() + .withQuery(termQuery("message", "test")) + .build(); + //when + Page page = repository.search(query); + //then + assertThat(page, is(notNullValue())); + assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1))); + } + + @Test + public void shouldSearchDocumentsGivenElasticsearchQuery(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + Page page = repository.search(termQuery("message", "world"), new PageRequest(0,50)); + //then + assertThat(page, is(notNullValue())); + assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1))); + } + + @Test + @Ignore + public void shouldFindAllByIdQuery(){ + //todo : find solution for findAll(Iterable ids) + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + //when + Iterable sampleEntities=repository.findAll(Arrays.asList(documentId,documentId2)); + + //then + assertNotNull("sample entities cant be null..", sampleEntities); + } + + @Test + public void shouldSaveIterableEntities(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity1 = new IntegerIDEntity(); + sampleEntity1.setId(documentId); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + + Iterable sampleEntities = Arrays.asList(sampleEntity1,sampleEntity2); + //when + repository.save(sampleEntities); + //then + Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0, 50)); + assertNotNull(entities); + } + + @Test + public void shouldReturnTrueGivenDocumentWithIdExists(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + + //when + boolean exist = repository.exists(documentId); + + //then + assertEquals(exist, true); + } + + @Test + public void shouldReturnResultsForGivenSearchQuery(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(fieldQuery("id",documentId)) + .build(); + Page sampleEntities= repository.search(searchQuery); + //then + assertThat(sampleEntities.getTotalElements(), equalTo(1L)); + } + + @Test + public void shouldDeleteAll(){ + //when + repository.deleteAll(); + //then + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(matchAllQuery()) + .build(); + Page sampleEntities= repository.search(searchQuery); + assertThat(sampleEntities.getTotalElements(), equalTo(0L)); + } + + @Test + public void shouldDeleteEntity(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("hello world."); + sampleEntity.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity); + //when + repository.delete(sampleEntity); + //then + SearchQuery searchQuery = new NativeSearchQueryBuilder() + .withQuery(fieldQuery("id", documentId)) + .build(); + Page sampleEntities= repository.search(searchQuery); + assertThat(sampleEntities.getTotalElements(),equalTo(0L)); + } + + @Test + public void shouldReturnIterableEntities(){ + //given + Integer documentId1 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity1 = new IntegerIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity1); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + //when + Iterable sampleEntities = repository.search(fieldQuery("id",documentId1)); + //then + assertNotNull("sample entities cant be null..", sampleEntities); + } + + @Test + public void shouldDeleteIterableEntities(){ + //given + Integer documentId1 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity1 = new IntegerIDEntity(); + sampleEntity1.setId(documentId1); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity2); + + Iterable sampleEntities = Arrays.asList(sampleEntity2,sampleEntity2); + //when + repository.delete(sampleEntities); + //then + assertThat(repository.findOne(documentId1),is(nullValue())); + assertThat(repository.findOne(documentId2),is(nullValue())); + } + + @Test + public void shouldIndexEntity(){ + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setVersion(System.currentTimeMillis()); + sampleEntity.setMessage("some message"); + //when + repository.index(sampleEntity); + //then + Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50)); + assertThat(entities.getTotalElements(),equalTo(1L)); + } + + @Test + public void shouldSortByGivenField(){ + //todo + //given + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage("A. hello world."); + repository.save(sampleEntity); + + Integer documentId2 = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity2 = new IntegerIDEntity(); + sampleEntity2.setId(documentId2); + sampleEntity2.setMessage("B.hello world."); + repository.save(sampleEntity2); + //when + Iterable sampleEntities=repository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"message"))); + //then + assertThat(sampleEntities,is(notNullValue())); + } + + + @Test + public void shouldReturnSimilarEntities(){ + //given + String sampleMessage = "So we build a web site or an application and want to add search to it, " + + "and then it hits us: getting search working is hard. We want our search solution to be fast," + + " we want a painless setup and a completely free search schema, we want to be able to index data simply using JSON over HTTP, " + + "we want our search server to be always available, we want to be able to start with one machine and scale to hundreds, " + + "we want real-time search, we want simple multi-tenancy, and we want a solution that is built for the cloud."; + + + + List sampleEntities = createSampleEntitiesWithMessage(sampleMessage, 30); + repository.save(sampleEntities); + + //when + Page results = repository.searchSimilar(sampleEntities.get(0)); + + //then + assertThat(results.getTotalElements(), is(greaterThanOrEqualTo(1L))); + } + + private static List createSampleEntitiesWithMessage(String message, int numberOfEntities){ + List sampleEntities = new ArrayList(); + for(int i = 0; i < numberOfEntities; i++){ + Integer documentId = RandomUtils.nextInt(); + IntegerIDEntity sampleEntity = new IntegerIDEntity(); + sampleEntity.setId(documentId); + sampleEntity.setMessage(message); + sampleEntity.setVersion(System.currentTimeMillis()); + sampleEntities.add(sampleEntity); + } + return sampleEntities; + } + +}