Skip to content

Added the String Contains Ignorecase criteria support #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@
<module>querydsl-dynamodb</module>
<module>querydsl-hazelcast</module>
<module>querydsl-elasticsearch</module>
<module>querydsl-elasticsearch2</module>
</modules>

<dependencies>
Original file line number Diff line number Diff line change
@@ -212,6 +212,10 @@ public Object visit(Operation<?> expr, @Nullable BoolQueryBuilder context) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryString("*" + value + "*").field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.STRING_CONTAINS_IC) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryString("*" + value + "*").field(asDBKey(expr, 0)).analyzer("standard").analyzeWildcard(true);

} else if (op == Ops.NOT) {
// Handle the not's child
BoolQueryBuilder subContext = QueryBuilders.boolQuery();
Original file line number Diff line number Diff line change
@@ -117,6 +117,16 @@ public void NotContains() {
//assertQuery(user.friends.contains(u1).not(), u1);
}

@Test
public void Contains_Ignore_Case() {
assertTrue(where(user.firstName.containsIgnoreCase("akk")).fetchCount() > 0);
}

@Test
public void Contains_Ignore_Case_2() {
assertFalse(where(user.firstName.containsIgnoreCase("xyzzz")).fetchCount() > 0);
}

@Test
public void Equals_Ignore_Case() {
assertTrue(where(user.firstName.equalsIgnoreCase("jAaKko")).fetchCount() > 0);
159 changes: 159 additions & 0 deletions querydsl-elasticsearch2/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.querydsl.contrib</groupId>
<artifactId>querydsl-contrib</artifactId>
<version>4.0.4</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>querydsl-elasticsearch2</artifactId>
<name>Querydsl - Elasticsearch 2 support</name>
<description>Elasticsearch 2 support for Querydsl</description>
<packaging>jar</packaging>
<url>${project.homepage}</url>

<scm>
<connection>${project.checkout}</connection>
<developerConnection>${project.checkout}</developerConnection>
<url>${project.githubpage}</url>
</scm>

<properties>
<elasticsearch.version>2.1.0</elasticsearch.version>
<jackson.version>2.6.3</jackson.version>
<osgi.import.package>
org.elasticsearch.*;version="0.0.0",
com.fasterxml.jackson.core.*;version="0.0.0",
${osgi.import.package.root}
</osgi.import.package>
</properties>

<dependencies>

<!-- Elasticsearch -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
</dependency>

<!-- Jackson JSON Mapper -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>

<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.springsource.bundlor</groupId>
<artifactId>com.springsource.bundlor.maven</artifactId>
</plugin>

<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-test-sources</phase>
<goals>
<goal>test-process</goal>
<goal>add-test-sources</goal>
</goals>
<configuration>
<outputDirectory>target/generated-test-sources/java</outputDirectory>
<processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
<options>
<defaultOverwrite>true</defaultOverwrite>
</options>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>extra-jars</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>src/main/apt.xml</descriptor>
<descriptor>src/main/assembly.xml</descriptor>
</descriptors>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>verification</id>
<goals>
<goal>test</goal>
</goals>
<phase>verify</phase>
<configuration>
<systemProperties>
<property>
<name>version</name>
<value>${project.version}</value>
</property>
</systemProperties>
<includes>
<include>com/mysema/query/PackageVerification.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>

</plugins>
</build>

<developers>
<developer>
<id>kevinleturc</id>
<name>Kevin Leturc</name>
<email>[email protected]</email>
<roles>
<role>donator</role>
</roles>
</developer>
<developer>
<id>gkathire</id>
<name>Guru Kathiresan</name>
<email>[email protected]</email>
<roles>
<role>donator</role>
</roles>
</developer>
</developers>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.mysema.query.apt.QuerydslAnnotationProcessor
19 changes: 19 additions & 0 deletions querydsl-elasticsearch2/src/main/apt.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>apt</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/apt</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
25 changes: 25 additions & 0 deletions querydsl-elasticsearch2/src/main/assembly.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>apt-one-jar</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>src/apt</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>src/license</directory>
<outputDirectory>/license</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<unpack>true</unpack>
</dependencySet>
</dependencySets>
</assembly>

Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/*
* Copyright 2014, Mysema Ltd
*
* 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 com.querydsl.elasticsearch2;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Nonnegative;
import javax.annotation.Nullable;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;

import com.google.common.base.Function;
import com.mysema.commons.lang.CloseableIterator;
import com.mysema.commons.lang.IteratorAdapter;
import com.querydsl.core.*;
import com.querydsl.core.support.QueryMixin;
import com.querydsl.core.types.*;

/**
* ElasticsearchQuery provides a general Querydsl query implementation with a pluggable String to Bean transformation
*
* @param <K> result type
* @author Kevin Leturc
*/
public abstract class ElasticsearchQuery<K> implements SimpleQuery<ElasticsearchQuery<K>>, Fetchable<K> {

private final QueryMixin<ElasticsearchQuery<K>> queryMixin;

private final Client client;

private final Function<SearchHit, K> transformer;

private final ElasticsearchSerializer serializer;

public ElasticsearchQuery(Client client, Function<SearchHit, K> transformer, ElasticsearchSerializer serializer) {
this.queryMixin = new QueryMixin<ElasticsearchQuery<K>>(this, new DefaultQueryMetadata().noValidate(), false);
this.client = client;
this.transformer = transformer;
this.serializer = serializer;
}

@Override
public CloseableIterator<K> iterate() {
return new IteratorAdapter<K>(fetch().iterator());
}

public List<K> fetch(Path<?>... paths) {
queryMixin.setProjection(paths);
return fetch();
}

@Override
public List<K> fetch() {
// Test if there're limit or offset, and if not, set them to retrieve all results
// because by default elasticsearch returns only 10 results
QueryMetadata metadata = queryMixin.getMetadata();
QueryModifiers modifiers = metadata.getModifiers();
if (modifiers.getLimit() == null && modifiers.getOffset() == null) {
long count = fetchCount();
if (count > 0L) {
// Set the limit only if there's result
metadata.setModifiers(new QueryModifiers(count, 0L));
}
}

// Execute search
SearchResponse searchResponse = executeSearch();
List<K> results = new ArrayList<K>();
for (SearchHit hit : searchResponse.getHits().getHits()) {
results.add(transformer.apply(hit));
}
return results;
}

public K fetchFirst(Path<?>... paths) {
queryMixin.setProjection(paths);
return fetchFirst();
}

@Nullable
@Override
public K fetchFirst() {
// Set the size of response
queryMixin.getMetadata().setModifiers(new QueryModifiers(1L, 0L));

SearchResponse searchResponse = executeSearch();
SearchHits hits = searchResponse.getHits();
if (hits.getTotalHits() > 0) {
return transformer.apply(hits.getAt(0));
} else {
return null;
}
}

public K fetchOne(Path<?>... paths) {
queryMixin.setProjection(paths);
return fetchOne();
}

@Nullable
@Override
public K fetchOne() {
// Set the size of response
// Set 2 as limit because it has to be ony one result which match the condition
queryMixin.getMetadata().setModifiers(new QueryModifiers(2L, 0L));

SearchResponse searchResponse = executeSearch();
SearchHits hits = searchResponse.getHits();
long totalHits = hits.getTotalHits();
if (totalHits == 1L) {
return transformer.apply(hits.getAt(0));
} else if (totalHits > 1L) {
throw new NonUniqueResultException();
} else {
return null;
}
}

public QueryResults<K> fetchResults(Path<?>... paths) {
queryMixin.setProjection(paths);
return fetchResults();
}

@Override
public QueryResults<K> fetchResults() {
long total = fetchCount();
if (total > 0L) {
return new QueryResults<K>(fetch(), queryMixin.getMetadata().getModifiers(), total);
} else {
return QueryResults.emptyResults();
}
}

@Override
public long fetchCount() {
Predicate filter = createFilter(queryMixin.getMetadata());
return client.prepareCount().setQuery(createQuery(filter)).execute().actionGet().getCount();
}

@Override
public ElasticsearchQuery<K> limit(@Nonnegative long limit) {
return queryMixin.limit(limit);
}

@Override
public ElasticsearchQuery<K> offset(@Nonnegative long offset) {
return queryMixin.offset(offset);
}

@Override
public ElasticsearchQuery<K> restrict(QueryModifiers modifiers) {
return queryMixin.restrict(modifiers);
}

@Override
public ElasticsearchQuery<K> orderBy(OrderSpecifier<?>... o) {
return queryMixin.orderBy(o);
}

@Override
public <T> ElasticsearchQuery<K> set(ParamExpression<T> param, T value) {
return queryMixin.set(param, value);
}

@Override
public ElasticsearchQuery<K> distinct() {
return queryMixin.distinct();
}

@Override
public ElasticsearchQuery<K> where(Predicate... o) {
return queryMixin.where(o);
}

@Nullable
protected Predicate createFilter(QueryMetadata metadata) {
return metadata.getWhere();
}

private QueryBuilder createQuery(@Nullable Predicate predicate) {
if (predicate != null) {
return (QueryBuilder) serializer.handle(predicate);
} else {
return QueryBuilders.matchAllQuery();
}
}

private SearchResponse executeSearch() {
QueryMetadata metadata = queryMixin.getMetadata();
Predicate filter = createFilter(metadata);
return executeSearch(getIndex(), getType(), filter, metadata.getProjection(), metadata.getModifiers(),
metadata.getOrderBy());
}

private SearchResponse executeSearch(String index, String type, Predicate filter,
Expression<?> projection, QueryModifiers modifiers, List<OrderSpecifier<?>> orderBys) {
SearchRequestBuilder requestBuilder = client.prepareSearch(index).setTypes(type);

// Set query
requestBuilder.setQuery(createQuery(filter));

// Add order by
for (OrderSpecifier<?> sort : orderBys) {
requestBuilder.addSort(serializer.toSort(sort));
}

// Add projections
if (projection != null) {
List<String> sourceFields = new ArrayList<String>();
if (projection instanceof FactoryExpression) {
for (Expression<?> pr : ((FactoryExpression<?>) projection).getArgs()) {
sourceFields.add(pr.accept(serializer, null).toString());
}
} else {
sourceFields.add(projection.accept(serializer, null).toString());
}

requestBuilder.setFetchSource(sourceFields.toArray(new String[sourceFields.size()]), null);
}

// Add limit and offset
Integer limit = modifiers.getLimitAsInteger();
Integer offset = modifiers.getOffsetAsInteger();
if (limit != null) {
requestBuilder.setSize(limit);
}
if (offset != null) {
requestBuilder.setFrom(offset);
}

return requestBuilder.execute().actionGet();
}

public abstract String getIndex();

public abstract String getType();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/*
* Copyright 2014, Mysema Ltd
*
* 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 com.querydsl.elasticsearch2;

import java.util.Collection;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.querydsl.core.types.*;
import com.querydsl.core.types.dsl.Expressions;

/**
* Serializes the given Querydsl query to a String query for Elasticsearch
*
* @author Kevin Leturc
*/
public class ElasticsearchSerializer implements Visitor<Object, BoolQueryBuilder> {

/** AND and OR operands. */
private static final Set<Operator> AND_OR = Sets.<Operator>newHashSet(Ops.AND, Ops.OR);

public Object handle(Expression<?> expression) {
BoolQueryBuilder context = QueryBuilders.boolQuery();
QueryBuilder query = (QueryBuilder) expression.accept(this, context);
if (!context.hasClauses() && query != null) {
context.must(query);
}
return context;
}

public SortBuilder toSort(OrderSpecifier<?> orderBy) {
Object key = orderBy.getTarget().accept(this, null);
return SortBuilders.fieldSort(key.toString()).order(orderBy.getOrder() == Order.ASC ? SortOrder.ASC : SortOrder.DESC);
}

@Nullable
@Override
public Object visit(Constant<?> expr, @Nullable BoolQueryBuilder context) {
if (Enum.class.isAssignableFrom(expr.getType())) {
return ((Enum<?>) expr.getConstant()).name();
} else {
return expr.getConstant();
}
}

@Nullable
@Override
public Object visit(FactoryExpression<?> expr, @Nullable BoolQueryBuilder context) {
return null;
}

public String asDBKey(Operation<?> expr, int index) {
return StringUtils.toString(asDBValue(expr, index));
}

public Object asDBValue(Operation<?> expr, int index) {
return expr.getArg(index).accept(this, null);
}

@Nullable
@Override
public Object visit(Operation<?> expr, @Nullable BoolQueryBuilder context) {
Preconditions.checkNotNull(context);
Operator op = expr.getOperator();
if (op == Ops.EQ) {
Expression<?> keyArg = expr.getArg(0);
String value = StringUtils.toString(asDBValue(expr, 1));
if (keyArg instanceof Path<?> && isIdPath((Path<?>) expr.getArg(0))) {
return QueryBuilders.idsQuery().ids(value);
} else {
// Currently all queries are made with ignore case sensitive
// Because the query to get exact value have to be run on a not_analyzed field
return QueryBuilders.queryStringQuery(value).field(asDBKey(expr, 0));
}

} else if (op == Ops.EQ_IGNORE_CASE) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery(value).field(asDBKey(expr, 0));

} else if (op == Ops.NE) {
// Decompose the query as NOT and EQ query
return visit(
Expressions.predicate(
Ops.NOT,
Expressions.predicate(
Ops.EQ,
expr.getArg(0),
expr.getArg(1))),
context);

} else if (op == Ops.STRING_IS_EMPTY) {
return QueryBuilders.queryStringQuery("").field(asDBKey(expr, 0));

} else if (op == Ops.AND || op == Ops.OR) {
Operation<?> left = (Operation<?>) expr.getArg(0);
Operation<?> right = (Operation<?>) expr.getArg(1);
// Perform the left expression
QueryBuilder leftResult = visitSubAndOr(op, context, left);
// Perform the right expression
QueryBuilder rightResult = visitSubAndOr(op, context, right);

if (op == Ops.AND) {
safeMust(context, leftResult);
safeMust(context, rightResult);
} else {
safeShould(context, leftResult);
safeShould(context, rightResult);
}
return null;

} else if (op == Ops.IN) {

int constIndex = 0;
int exprIndex = 1;
if (expr.getArg(1) instanceof Constant<?>) {
constIndex = 1;
exprIndex = 0;
}
Expression<?> keyExpr = expr.getArg(exprIndex);
if (keyExpr instanceof Path<?> && isIdPath((Path<?>) keyExpr)) {
IdsQueryBuilder idsQuery = QueryBuilders.idsQuery();
// Hope this is the only case for Elasticsearch ids
Collection<?> values = (Collection<?>) ((Constant<?>) expr.getArg(constIndex)).getConstant();
for (Object value : values) {
idsQuery.addIds(StringUtils.toString(value));
}
return idsQuery;
} else {
// Currently all queries are made with ignore case sensitive
// Because the query to get exact value have to be run on a not_analyzed field
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
String key = asDBKey(expr, exprIndex);
if (Collection.class.isAssignableFrom(expr.getArg(constIndex).getType())) {
Collection<?> values = (Collection<?>) ((Constant<?>) expr.getArg(constIndex)).getConstant();
for (Object value : values) {
boolQuery.should(QueryBuilders.queryStringQuery(StringUtils.toString(value)).field(key));
}
return boolQuery;

}
}

} else if (op == Ops.NOT_IN) {
// Decompose the query as NOT and IN query
return visit(
Expressions.predicate(
Ops.NOT,
Expressions.predicate(
Ops.IN,
expr.getArg(1))),
context);

} else if (op == Ops.BETWEEN) {
Object from = asDBValue(expr, 1);
Object to = asDBValue(expr, 2);
return QueryBuilders.rangeQuery(asDBKey(expr, 0)).from(from).to(to);

} else if (op == Ops.LT) {
return QueryBuilders.rangeQuery(asDBKey(expr, 0)).lt(asDBValue(expr, 1));

} else if (op == Ops.GT) {
return QueryBuilders.rangeQuery(asDBKey(expr, 0)).gt(asDBValue(expr, 1));

} else if (op == Ops.LOE) {
return QueryBuilders.rangeQuery(asDBKey(expr, 0)).lte(asDBValue(expr, 1));

} else if (op == Ops.GOE) {
return QueryBuilders.rangeQuery(asDBKey(expr, 0)).gte(asDBValue(expr, 1));

} else if (op == Ops.STARTS_WITH) {
// Currently all queries are made with ignore case sensitive
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery(value + "*").field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.STARTS_WITH_IC) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery(value + "*").field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.ENDS_WITH) {
// Currently all queries are made with ignore case sensitive
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery("*" + value).field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.ENDS_WITH_IC) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery("*" + value).field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.STRING_CONTAINS) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery("*" + value + "*").field(asDBKey(expr, 0)).analyzeWildcard(true);

} else if (op == Ops.STRING_CONTAINS_IC) {
String value = StringUtils.toString(asDBValue(expr, 1));
return QueryBuilders.queryStringQuery("*" + value + "*").field(asDBKey(expr, 0)).analyzer("standard").analyzeWildcard(true);

} else if (op == Ops.NOT) {
// Handle the not's child
BoolQueryBuilder subContext = QueryBuilders.boolQuery();
QueryBuilder result = (QueryBuilder) expr.getArg(0).accept(this, subContext);
if (result == null) {
result = subContext;
}
return QueryBuilders.boolQuery().mustNot(result);

}

throw new UnsupportedOperationException("Illegal operation " + expr);
}

@Nullable
@Override
public Object visit(ParamExpression<?> expr, @Nullable BoolQueryBuilder context) {
return null;
}

@Nullable
@Override
public Object visit(Path<?> expr, @Nullable BoolQueryBuilder context) {
PathMetadata metadata = expr.getMetadata();
return getKeyForPath(expr, metadata);
}

@Nullable
@Override
public Object visit(SubQueryExpression<?> expr, @Nullable BoolQueryBuilder context) {
return null;
}

@Nullable
@Override
public Object visit(TemplateExpression<?> expr, @Nullable BoolQueryBuilder context) {
return null;
}

protected String getKeyForPath(Path<?> expr, PathMetadata metadata) {
if (isIdPath(expr)) {
return "_id";
} else {
return metadata.getElement().toString();
}
}

protected boolean isIdPath(Path<?> expr) {
return "id".equals(expr.getMetadata().getElement().toString());
}

private QueryBuilder visitSubAndOr(Operator op, BoolQueryBuilder context, Operation<?> subOperation) {
QueryBuilder result;
if (AND_OR.contains(subOperation.getOperator()) && subOperation.getOperator() != op) {
// Opposite case, if current operator is an AND so sub operation is a OR, so create a sub query
result = QueryBuilders.boolQuery();
subOperation.accept(this, (BoolQueryBuilder) result);
} else {
// Here let's do recursive if sub operation has the same operator than the current one (result is null)
// or it's another operator than AND/OR so add it to query
result = (QueryBuilder) subOperation.accept(this, context);
}
return result;
}

private void safeMust(BoolQueryBuilder context, QueryBuilder query) {
if (query != null) {
context.must(query);
}
}

private void safeShould(BoolQueryBuilder context, QueryBuilder query) {
if (query != null) {
context.should(query);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.querydsl.elasticsearch2.jackson;

import java.io.IOException;
import java.lang.reflect.Field;

import javax.annotation.Nullable;

import org.elasticsearch.client.Client;
import org.elasticsearch.search.SearchHit;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Function;
import com.querydsl.elasticsearch2.ElasticsearchQuery;
import com.querydsl.elasticsearch2.ElasticsearchSerializer;

/**
* JacksonElasticsearchQueries is a factory to provide ElasticsearchQuery basic implementation.
*
* @author Kevin Leturc
*/
public class JacksonElasticsearchQueries {

private final Client client;

/**
* Default constructor.
*
* @param client The elasticsearch client.
*/
public JacksonElasticsearchQueries(Client client) {
this.client = client;
}

public <K> ElasticsearchQuery<K> query(Class<K> entityClass, String index, String type) {
return query(entityClass, index, type, new ElasticsearchSerializer());
}

public <K> ElasticsearchQuery<K> query(Class<K> entityClass, String index, String type, ElasticsearchSerializer serializer) {
return query(index, type, serializer, defaultTransformer(entityClass));
}

public <K> ElasticsearchQuery<K> query(String index, String type, Function<SearchHit, K> transformer) {
return query(index, type, new ElasticsearchSerializer(), transformer);
}

public <K> ElasticsearchQuery<K> query(final String index, final String type, ElasticsearchSerializer serializer, Function<SearchHit, K> transformer) {
return new ElasticsearchQuery<K>(client, transformer, serializer) {

/**
* {@inheritDoc}
*/
@Override
public String getIndex() {
return index;
}

/**
* {@inheritDoc}
*/
@Override
public String getType() {
return type;
}

};
}

/**
* Returns the default transformer.
*
* @param entityClass The entity class.
* @param <K> The entity type.
* @return The default transformer.
*/
private <K> Function<SearchHit, K> defaultTransformer(final Class<K> entityClass) {
final ObjectMapper mapper = new ObjectMapper();
return new Function<SearchHit, K>() {

/**
* {@inheritDoc}
*/
@Nullable
@Override
public K apply(@Nullable SearchHit input) {
try {
K bean = mapper.readValue(input.getSourceAsString(), entityClass);

Field idField = null;
Class<?> target = entityClass;
while (idField == null && target != Object.class) {
for (Field field : target.getDeclaredFields()) {
if ("id".equals(field.getName())) {
idField = field;
}
}
target = target.getSuperclass();
}
if (idField != null) {
idField.setAccessible(true);
idField.set(bean, input.getId());
}

return bean;
} catch (SecurityException se) {
throw new MappingException("Unable to lookup id field, may be use a custom transformer ?", se);
} catch (IllegalAccessException e) {
throw new MappingException("Unable to set id value in id field, may be use a custom transformer ?", e);
} catch (IOException e) {
throw new MappingException("Unable to read the Elasticsearch response.", e);
}
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.querydsl.elasticsearch2.jackson;

/**
* Mapping exception for factory purposes.
*
* @author Kevin Leturc
*/
public class MappingException extends RuntimeException {

/**
* Default constructor.
*
* @param message The message.
* @param cause The cause.
*/
public MappingException(String message, Throwable cause) {
super(message, cause);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
package com.querydsl.elasticsearch2;

import com.querydsl.elasticsearch2.ElasticsearchQuery;
import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.elasticsearch.client.Requests.refreshRequest;
import static org.junit.Assert.*;

import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.querydsl.core.NonUniqueResultException;
import com.querydsl.core.QueryResults;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.elasticsearch2.domain.QUser;
import com.querydsl.elasticsearch2.domain.User;
import com.querydsl.elasticsearch2.jackson.JacksonElasticsearchQueries;

public class ElasticsearchQueryTest {

private static final ObjectMapper mapper = new ObjectMapper();

private static Client client;

private final String indexUser = "index1";
private final String typeUser = "user";

private final QUser user = QUser.user;
List<User> users = Lists.newArrayList();
User u1, u2, u3, u4;

public ElasticsearchQueryTest() {
}

@BeforeClass
public static void beforeClass() {
String path = ElasticsearchQueryTest.class.getResource("").getPath();
path = System.getProperty("os.name").contains("indow") ? path.substring(1) : path;
Settings.Builder settings = Settings.builder().put("path.home",path);
Node node = NodeBuilder.nodeBuilder().local(true).settings(settings).node();
client = node.client();

}

@Before
public void before() {
deleteType(indexUser);
createIndex(indexUser);

u1 = addUser("Jaakko", "Jantunen", 20);
u2 = addUser("Jaakki", "Jantunen", 30);
u3 = addUser("Jaana", "Aakkonen", 40);
u4 = addUser("Jaana", "BeekkoNen", 50);

refresh(indexUser, false);
}

@Test
public void Count() {
assertEquals(4, query().fetchCount());
}

@Test
public void Count_Predicate() {
assertEquals(2, where(user.lastName.eq("Jantunen")).fetchCount());
}

@Test
public void SingleResult_Keys() {
User u = where(user.firstName.eq("Jaakko")).fetchFirst(user.firstName);
assertEquals("Jaakko", u.getFirstName());
assertNull(u.getLastName());
assertEquals(0, u.getAge());
}

@Test
public void UniqueResult_Keys() {
User u = where(user.firstName.eq("Jaakko")).fetchOne(user.firstName);
assertEquals("Jaakko", u.getFirstName());
assertNull(u.getLastName());
assertEquals(0, u.getAge());
}

@Test(expected = NonUniqueResultException.class)
public void UniqueResult_Keys_Non_Unique() {
where(user.firstName.eq("Jaana")).fetchOne(user.firstName);
}

@Test
public void Contains() {
//assertQuery(user.friends.contains(u1), u3, u4, u2);
}

@Test
public void Contains2() {
//assertQuery(user.friends.contains(u4));
}

@Test
public void NotContains() {
//assertQuery(user.friends.contains(u1).not(), u1);
}

@Test
public void Contains_Ignore_Case() {
assertTrue(where(user.firstName.containsIgnoreCase("akk")).fetchCount() > 0);
}

@Test
public void Contains_Ignore_Case_2() {
assertFalse(where(user.firstName.containsIgnoreCase("xyzzz")).fetchCount() > 0);
}

@Test
public void Equals_Ignore_Case() {
assertTrue(where(user.firstName.equalsIgnoreCase("jAaKko")).fetchCount() > 0);
assertTrue(where(user.firstName.equalsIgnoreCase("AaKk")).fetchCount() == 0);
}

@Test
public void Starts_With_and_Between() {
assertQuery(user.firstName.startsWith("Jaa").and(user.age.between(20, 30)), u2, u1);
assertQuery(user.firstName.startsWith("Jaa").and(user.age.goe(20).and(user.age.loe(30))), u2, u1);
}

@Test
public void Exists() {
assertTrue(where(user.firstName.eq("Jaakko")).fetchCount() > 0);
assertTrue(where(user.firstName.eq("JaakkoX")).fetchCount() == 0);
assertTrue(where(user.id.eq(u1.getId())).fetchCount() > 0);
}

@Test
public void Find_By_Id() {
assertNotNull(where(user.id.eq(u1.getId())).fetchOne());
}

@Test
public void Find_By_Ids() {
assertQuery(user.id.in(u1.getId(), u2.getId()), u2, u1);
}

@Test
public void Order() {
List<User> users = query().orderBy(user.age.asc()).fetch();
assertEquals(asList(u1, u2, u3, u4), users);

users = query().orderBy(user.age.desc()).fetch();
assertEquals(asList(u4, u3, u2, u1), users);
}

@Test
public void ListResults() {
QueryResults<User> results = query().limit(2).orderBy(user.age.asc()).fetchResults();
assertEquals(4L, results.getTotal());
assertEquals(2, results.getResults().size());

results = query().offset(2).orderBy(user.age.asc()).fetchResults();
assertEquals(4L, results.getTotal());
assertEquals(2, results.getResults().size());
}

@Test
public void EmptyResults() {
QueryResults<User> results = query().where(user.firstName.eq("XXX")).fetchResults();
assertEquals(0L, results.getTotal());
assertEquals(Collections.<User>emptyList(), results.getResults());
}

@Test
public void EqInAndOrderByQueries() {
assertQuery(user.firstName.eq("Jaakko"), u1);
assertQuery(user.firstName.equalsIgnoreCase("jaakko"), u1);
assertQuery(user.lastName.eq("Aakkonen"), u3);

assertQuery(user.firstName.in("Jaakko","Teppo"), u1);
assertQuery(user.lastName.in("Aakkonen", "BeekkoNen"), u3, u4);

assertQuery(user.firstName.eq("Jouko"));

assertQuery(user.firstName.eq("Jaana"), user.lastName.asc(), u3, u4);
assertQuery(user.firstName.eq("Jaana"), user.lastName.desc(), u4, u3);
assertQuery(user.lastName.eq("Jantunen"), user.firstName.asc(), u2, u1);
assertQuery(user.lastName.eq("Jantunen"), user.firstName.desc(), u1, u2);

assertQuery(user.firstName.eq("Jaana").and(user.lastName.eq("Aakkonen")), u3);
//This shoud produce 'and' also
assertQuery(where(user.firstName.eq("Jaana"), user.lastName.eq("Aakkonen")), u3);

assertQuery(user.firstName.ne("Jaana"), u2, u1);
assertQuery(user.firstName.ne("Jaana").and(user.lastName.ne("Jantunen")));
assertQuery(user.firstName.eq("Jaana").and(user.lastName.eq("Aakkonen")).not(), u4, u2, u1);

}

@Test
public void Iterate() {
User a = addUser("A", "A", 10);
User b = addUser("A1", "B", 10);
User c = addUser("A2", "C", 10);

refresh(indexUser, false);

Iterator<User> i = where(user.firstName.startsWith("A"))
.orderBy(user.firstName.asc())
.iterate();

assertEquals(a, i.next());
assertEquals(b, i.next());
assertEquals(c, i.next());
assertEquals(false, i.hasNext());
}

@Test
public void Enum_Eq() {
assertQuery(user.gender.eq(User.Gender.MALE), u3, u4, u2, u1);
}

@Test
public void Enum_Ne() {
assertQuery(user.gender.ne(User.Gender.MALE));
}

private ElasticsearchQuery<User> query() {
return new JacksonElasticsearchQueries(client).query(User.class, indexUser, typeUser);
}

private ElasticsearchQuery<User> where(Predicate predicate) {
return query().where(predicate);
}

private ElasticsearchQuery<User> where(Predicate ... e) {
return query().where(e);
}

private void assertQuery(Predicate e, User ... expected) {
assertQuery(where(e).orderBy(user.lastName.asc(), user.firstName.asc()), expected);
}

private void assertQuery(Predicate e, OrderSpecifier<?> orderBy, User ... expected) {
assertQuery(where(e).orderBy(orderBy), expected);
}

private void assertQuery(ElasticsearchQuery<User> query, User ... expected) {
List<User> results = query.fetch();

assertNotNull(results);
if (expected == null) {
assertEquals("Should get empty result", 0, results.size());
return;
}
assertEquals(expected.length, results.size());
int i = 0;
for (User u : expected) {
assertEquals(u, results.get(i++));
}
}

private User addUser(String first, String last, int age) {
User user = new User(first, last, age, new Date());
user.setGender(User.Gender.MALE);
try {
IndexResponse response = client.prepareIndex(indexUser, typeUser).setSource(mapper.writeValueAsString(user)).execute().actionGet();
user.setId(response.getId());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
users.add(user);
return user;
}

public void deleteType(String index) {
if (indexExists(index)) {
client.admin().indices().delete(new DeleteIndexRequest(index)).actionGet();
}
}

public boolean indexExists(String index) {
return client.admin().indices().exists(Requests.indicesExistsRequest(index)).actionGet().isExists();
}

public boolean createIndex(String index) {
if (indexExists(index)) {
return true;
}

CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(index);
return createIndexRequestBuilder.execute().actionGet().isAcknowledged();
}

public void refresh(String indexName, boolean waitForOperation) {
client.admin().indices().refresh(refreshRequest(indexName)).actionGet();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
/*
* Copyright 2011, Mysema Ltd
*
* 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 com.querydsl.elasticsearch2;

import com.querydsl.elasticsearch2.ElasticsearchSerializer;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.junit.Assert.assertEquals;

import java.sql.Timestamp;
import java.util.Date;

import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Before;
import org.junit.Test;

import com.google.common.collect.Lists;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.dsl.*;
import com.querydsl.elasticsearch2.domain.QUser;

public class ElasticsearchSerializerTest {

private PathBuilder<Object> entityPath;
private StringPath id;
private StringPath title;
private NumberPath<Integer> year;
private NumberPath<Double> gross;

private NumberPath<Long> longField;
private NumberPath<Short> shortField;
private NumberPath<Byte> byteField;
private NumberPath<Float> floatField;

private DatePath<Date> date;
private final Date dateVal = new Date();
private DateTimePath<Timestamp> dateTime;
private final Timestamp dateTimeVal = new Timestamp(System.currentTimeMillis());

private ElasticsearchSerializer serializer;

@Before
public void before() {
serializer = new ElasticsearchSerializer();
entityPath = new PathBuilder<Object>(Object.class, "obj");
id = entityPath.getString("id");
title = entityPath.getString("title");
year = entityPath.getNumber("year", Integer.class);
gross = entityPath.getNumber("gross", Double.class);
longField = entityPath.getNumber("longField", Long.class);
shortField = entityPath.getNumber("shortField", Short.class);
byteField = entityPath.getNumber("byteField", Byte.class);
floatField = entityPath.getNumber("floatField", Float.class);
date = entityPath.getDate("date", Date.class);
dateTime = entityPath.getDateTime("dateTime", Timestamp.class);
}

@Test
public void Paths() {
QUser user = QUser.user;
assertEquals("user", serializer.visit(user, null));
//assertEquals("addresses", serializer.visit(user.addresses, null));
//assertEquals("addresses", serializer.visit(user.addresses.any(), null));
//assertEquals("addresses.street", serializer.visit(user.addresses.any().street, null));
assertEquals("firstName", serializer.visit(user.firstName, null));
}

@Test
public void PropertyAnnotation() {
//QDummyEntity entity = QDummyEntity.dummyEntity;
//assertEquals("prop", serializer.visit(entity.property, null));
}

@Test
public void IndexedAccess() {
QUser user = QUser.user;
//assertEquals("addresses.0.street", serializer.visit(user.addresses.get(0).street, null));
}

@Test
public void CollectionAny() {
QUser user = QUser.user;
//assertQuery(eq("addresses.street", "Aakatu"), user.addresses.any().street.eq("Aakatu"));
}

@Test
public void Equals() {
assertQuery(and(eq("title", "A")), title.eq("A"));
assertQuery(and(eq("year", 1)), year.eq(1));
assertQuery(and(eq("gross", 1.0D)), gross.eq(1.0D));
assertQuery(and(eq("longField", 1L)), longField.eq(1L));
assertQuery(and(eq("shortField", 1)), shortField.eq((short) 1));
assertQuery(and(eq("byteField", 1L)), byteField.eq((byte) 1));
assertQuery(and(eq("floatField", 1.0F)), floatField.eq(1.0F));

assertQuery(and(eq("date", dateVal)), date.eq(dateVal));
assertQuery(and(eq("dateTime", dateTimeVal)), dateTime.eq(dateTimeVal));

assertQuery(and(idsQuery().ids("id1")), id.eq("id1"));
}

@Test
public void EqAndEq() {
assertQuery(
and(eq("title", "A"), eq("year", 1)),
title.eq("A").and(year.eq(1))
);

assertQuery(
and(eq("year", 1), eq("gross", 1.0D), eq("title", "A")),
title.eq("A").and(year.eq(1).and(gross.eq(1.0D)))
);

assertQuery(
and(eq("title", "A"), eq("year", 1), eq("gross", 1.0D)),
title.eq("A").and(year.eq(1)).and(gross.eq(1.0D))
);
}

@Test
public void EqOrEq() {
assertQuery(
or(eq("title", "A"), eq("year", 1)),
title.eq("A").or(year.eq(1))
);

assertQuery(
or(eq("year", 1), eq("gross", 1.0D), eq("title", "A")),
title.eq("A").or(year.eq(1).or(gross.eq(1.0D)))
);

assertQuery(
or(eq("title", "A"), eq("year", 1), eq("gross", 1.0D)),
title.eq("A").or(year.eq(1)).or(gross.eq(1.0D))
);
}

@Test
public void In() {
assertQuery(
and(in("title", Lists.newArrayList("A", "B", "C"))),
title.in(Lists.newArrayList("A", "B", "C"))
);
}

@Test
public void Between() {
Date start = new Date(31L * 24L * 60L * 60L * 1000L);
Date end = new Date();
assertQuery(
and(between("date", start, end)),
date.between(start, end)
);

assertQuery(
and(between("year", 1, 2)),
year.between(1, 2)
);
}

@Test
public void InAndBetween() {
Date start = new Date(31L * 24L * 60L * 60L * 1000L);
Date end = new Date();
assertQuery(
and(in("title", Lists.newArrayList("A", "B", "C")), between("date", start, end)),
title.in(Lists.newArrayList("A", "B", "C")).and(date.between(start, end))
);
}

@Test
public void EqOrEqAndEq() {

assertQuery(
or(eq("title", "A"), and(eq("year", 1), eq("gross", 1.0D))),
title.eq("A").or(year.eq(1).and(gross.eq(1.0D)))
);

assertQuery(
and(
or(eq("title", "A"), eq("year", 1)),
eq("gross", 1.0D)),
title.eq("A").or(year.eq(1)).and(gross.eq(1.0D))
);
}

@Test
public void EqAndEqOrEq() {

assertQuery(
and(
eq("title", "A"),
or(eq("year", 1), eq("gross", 1.0D))),
title.eq("A").and(year.eq(1).or(gross.eq(1.0D)))
);

assertQuery(
or(
and(eq("title", "A"), eq("year", 1)),
eq("gross", 1.0D)),
title.eq("A").and(year.eq(1)).or(gross.eq(1.0D))
);
}

@Test
public void EqAndEqOrEqAndEq() {

assertQuery(
and(
or(
and(eq("title", "A"), eq("year", 1)),
eq("title", "B")),
eq("year", 2)
),
title.eq("A").and(year.eq(1)).or(title.eq("B")).and(year.eq(2))
);

assertQuery(
or(
and(eq("title", "A"), eq("year", 1)),
and(eq("title", "B"), eq("year", 2))
),
title.eq("A").and(year.eq(1)).or(title.eq("B").and(year.eq(2)))
);

assertQuery(
and(
or(
eq("year", 1),
eq("title", "B")),
eq("year", 2),
eq("title", "A")),
title.eq("A").and(year.eq(1).or(title.eq("B")).and(year.eq(2)))
);

assertQuery(
and(
eq("title", "A"),
or(
eq("year", 1),
and(eq("title", "B"), eq("year", 2)))),
title.eq("A").and(year.eq(1).or(title.eq("B").and(year.eq(2))))
);

}

public static QueryBuilder eq(String key, Object value) {
return QueryBuilders.queryStringQuery(StringUtils.toString(value)).field(key);
}

public static QueryBuilder in(String key, Iterable<?> values) {
BoolQueryBuilder query = boolQuery();
for (Object value : values) {
query.should(eq(key, value));
}
return query;
}

public static QueryBuilder and(QueryBuilder... builders) {
BoolQueryBuilder query = boolQuery();
must(query, builders);
return query;
}

public static QueryBuilder or(QueryBuilder... builders) {
BoolQueryBuilder query = boolQuery();
should(query, builders);
return query;
}

public static BoolQueryBuilder must(BoolQueryBuilder query, QueryBuilder... builders) {
for (QueryBuilder builder : builders) {
query.must(builder);
}
return query;
}

public static BoolQueryBuilder should(BoolQueryBuilder query, QueryBuilder... builders) {
for (QueryBuilder builder : builders) {
query.should(builder);
}
return query;
}

public static QueryBuilder between(String key, int start, int end) {
return rangeQuery(key).from(start).to(end);
}

public static QueryBuilder between(String key, double start, double end) {
return rangeQuery(key).from(start).to(end);
}

public static QueryBuilder between(String key, Date start, Date end) {
return rangeQuery(key).from(start).to(end);
}

private void assertQuery(QueryBuilder expected, Expression<?> e) {
QueryBuilder result = (QueryBuilder) serializer.handle(e);
assertEquals(expected.toString(), result.toString());
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2014, Mysema Ltd
*
* 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 com.querydsl.elasticsearch2;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

import org.junit.Test;

import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import com.mysema.codegen.CodeWriter;
import com.querydsl.apt.QuerydslAnnotationProcessor;
import com.querydsl.codegen.CodegenModule;
import com.querydsl.core.types.Expression;

public class PackageVerification {

@Test
public void Verify_Package() throws Exception {
String version = System.getProperty("version");
verify(new File("target/querydsl-elasticsearch2-" + version + "-apt-one-jar.jar"));
}

private void verify(File oneJar) throws Exception {
assertTrue(oneJar.getPath() + " doesn't exist", oneJar.exists());
// verify classLoader
URLClassLoader oneJarClassLoader = new URLClassLoader(new URL[]{oneJar.toURI().toURL()});
oneJarClassLoader.loadClass(Expression.class.getName()); // querydsl-core
oneJarClassLoader.loadClass(CodeWriter.class.getName()); // codegen
oneJarClassLoader.loadClass(CodegenModule.class.getName()).newInstance();
//oneJarClassLoader.loadClass(Entity.class.getName()); // elasticsearch
Class cl = oneJarClassLoader.loadClass(QuerydslAnnotationProcessor.class.getName()); // querydsl-apt
cl.newInstance();
String resourceKey = "META-INF/services/javax.annotation.processing.Processor";
assertEquals(QuerydslAnnotationProcessor.class.getName(), Resources.toString(oneJarClassLoader.findResource(resourceKey), Charsets.UTF_8));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.querydsl.elasticsearch2.domain;

import com.google.common.base.Objects;
import com.querydsl.core.annotations.QuerySupertype;

@QuerySupertype
public abstract class AbstractEntity {

private String id;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

@Override
public int hashCode() {
return id != null ? 0 : id.hashCode();
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
} else if (obj instanceof AbstractEntity) {
AbstractEntity other = (AbstractEntity) obj;
return Objects.equal(other.getId(), id);
} else {
return false;
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.querydsl.elasticsearch2.domain;

import java.util.Date;

import com.querydsl.core.annotations.QueryEntity;

@QueryEntity
public class User extends AbstractEntity {

public enum Gender { MALE, FEMALE }

private String firstName;

private String lastName;

private Date created;

private Gender gender;

//@QueryEmbedded
//private final List<Address> addresses = new ArrayList<Address>();

//@QueryEmbedded
//private Address mainAddress;

private int age;

public User() {
}

public User(String firstName, String lastName) {
this.firstName = firstName; this.lastName = lastName;
this.created = new Date();
}

public User(String firstName, String lastName, int age, Date created) {
this.firstName = firstName; this.lastName = lastName; this.age = age; this.created = created;
}

@Override
public String toString() {
return "TestUser [id=" + getId() + ", firstName=" + firstName + ", lastName=" + lastName
+ "]";
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Date getCreated() {
return created;
}

public void setCreated(Date created) {
this.created = created;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Gender getGender() {
return gender;
}

public void setGender(Gender gender) {
this.gender = gender;
}

}