
net.oneandone.troilus.ListReadQuery Maven / Gradle / Ivy
/*
* Copyright 1&1 Internet AG, https://github.com/1and1/
*
* 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 net.oneandone.troilus;
import static com.datastax.driver.core.querybuilder.QueryBuilder.select;
import java.util.List;
import net.oneandone.troilus.java7.FetchingIterator;
import net.oneandone.troilus.java7.ListRead;
import net.oneandone.troilus.java7.ListReadWithUnit;
import net.oneandone.troilus.java7.Record;
import net.oneandone.troilus.java7.ResultList;
import net.oneandone.troilus.java7.interceptor.ReadQueryData;
import net.oneandone.troilus.java7.interceptor.ReadQueryRequestInterceptor;
import net.oneandone.troilus.java7.interceptor.ReadQueryResponseInterceptor;
import org.reactivestreams.Publisher;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Clause;
import com.datastax.driver.core.querybuilder.Select;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
/**
* The list read query implementation
*
*/
class ListReadQuery extends AbstractQuery implements ListReadWithUnit, Record> {
private final ReadQueryData data;
/**
* @param ctx the context
* @param data the data
*/
ListReadQuery(Context ctx, ReadQueryData data) {
super(ctx);
this.data = data;
}
////////////////////
// factory methods
@Override
protected ListReadQuery newQuery(Context newContext) {
return new ListReadQuery(newContext, data);
}
private ListReadQuery newQuery(ReadQueryData data) {
return new ListReadQuery(getContext(), data);
}
//
////////////////////
@Override
public ListReadQuery all() {
return newQuery(data.columnsToFetch(ImmutableMap.of()));
}
private ListReadQuery columns(ImmutableCollection namesToRead) {
ListReadQuery read = this;
for (String columnName : namesToRead) {
read = read.column(columnName);
}
return read;
}
@Override
public ListReadQuery column(String name) {
return newQuery(data.columnsToFetch(Immutables.join(data.getColumnsToFetch(), name, false)));
}
@Override
public ListReadQuery columnWithMetadata(String name) {
return newQuery(data.columnsToFetch(Immutables.join(data.getColumnsToFetch(), name, true)));
}
@Override
public ListReadQuery columns(String... names) {
return columns(ImmutableSet.copyOf(names));
}
@Override
public ListReadQuery column(ColumnName> name) {
return column(name.getName());
}
@Override
public ListReadQuery columnWithMetadata(ColumnName> name) {
return columnWithMetadata(name.getName());
}
@Override
public ListReadQuery columns(ColumnName>... names) {
List ns = Lists.newArrayList();
for (ColumnName> name : names) {
ns.add(name.getName());
}
return columns(ImmutableList.copyOf(ns));
}
@Override
public ListReadQuery withLimit(int limit) {
return newQuery(data.limit(limit));
}
@Override
public ListReadQuery withAllowFiltering() {
return newQuery(data.allowFiltering(true));
}
@Override
public ListReadQuery withFetchSize(int fetchSize) {
return newQuery(data.fetchSize(fetchSize));
}
@Override
public ListReadQuery withDistinct() {
return newQuery(data.distinct(true));
}
@Override
public CountReadQuery count() {
return new CountReadQuery(getContext(), new CountReadQueryData().whereConditions(data.getWhereConditions())
.limit(data.getLimit())
.fetchSize(data.getFetchSize())
.allowFiltering(data.getAllowFiltering())
.distinct(data.getDistinct()));
}
@Override
public ListEntityReadQuery asEntity(Class objectClass) {
return new ListEntityReadQuery<>(getContext(), this, objectClass) ;
}
@Override
public Publisher executeRx() {
ListenableFuture> recordsFuture = executeAsync();
return new ResultListPublisher<>(recordsFuture);
}
@Override
public ResultList execute() {
return ListenableFutures.getUninterruptibly(executeAsync());
}
@Override
public ListenableFuture> executeAsync() {
// perform request executors
ListenableFuture queryDataFuture = executeRequestInterceptorsAsync(Futures.immediateFuture(data));
// execute query asnyc
Function>> queryExecutor = new Function>>() {
@Override
public ListenableFuture> apply(ReadQueryData querData) {
return executeAsync(querData);
}
};
return ListenableFutures.transform(queryDataFuture, queryExecutor);
}
private ListenableFuture> executeAsync(final ReadQueryData queryData) {
// perform query
ListenableFuture resultSetFuture = performAsync(ReadQueryDataImpl.toStatementAsync(queryData, getContext()));
// result set to record list mapper
Function> resultSetToRecordList = new Function>() {
@Override
public ResultList apply(ResultSet resultSet) {
return new RecordListImpl(getContext(), queryData, resultSet);
}
};
ListenableFuture> recordListFuture = Futures.transform(resultSetFuture, resultSetToRecordList);
// running interceptors within dedicated threads!
return executeResponseInterceptorsAsync(queryData, recordListFuture);
}
private ListenableFuture executeRequestInterceptorsAsync(ListenableFuture queryDataFuture) {
for (ReadQueryRequestInterceptor interceptor : getContext().getInterceptorRegistry().getInterceptors(ReadQueryRequestInterceptor.class).reverse()) {
final ReadQueryRequestInterceptor icptor = interceptor;
Function> mapperFunction = new Function>() {
@Override
public ListenableFuture apply(ReadQueryData queryData) {
return icptor.onReadRequestAsync(queryData);
}
};
// running interceptors within dedicated threads!
queryDataFuture = ListenableFutures.transform(queryDataFuture, mapperFunction, getContext().getTaskExecutor());
}
return queryDataFuture;
}
private ListenableFuture> executeResponseInterceptorsAsync(final ReadQueryData queryData, ListenableFuture> recordFuture) {
for (ReadQueryResponseInterceptor interceptor : getContext().getInterceptorRegistry().getInterceptors(ReadQueryResponseInterceptor.class).reverse()) {
final ReadQueryResponseInterceptor icptor = interceptor;
Function, ListenableFuture>> mapperFunction = new Function, ListenableFuture>>() {
@Override
public ListenableFuture> apply(ResultList recordList) {
return icptor.onReadResponseAsync(queryData, recordList);
}
};
// running interceptors within dedicagted threads!
recordFuture = ListenableFutures.transform(recordFuture, mapperFunction, getContext().getTaskExecutor());
}
return recordFuture;
}
/**
* The entity list read implementation
* @param the entity type
*/
static class ListEntityReadQuery extends AbstractQuery> implements ListRead, E> {
private final ListReadQuery query;
private final Class clazz;
/**
* @param ctx the context
* @param query the query
* @param clazz the entity type
*/
ListEntityReadQuery(Context ctx, ListReadQuery query, Class clazz) {
super(ctx);
this.query = query;
this.clazz = clazz;
}
@Override
protected ListEntityReadQuery newQuery(Context newContext) {
return new ListReadQuery(newContext, query.data).asEntity(clazz);
}
@Override
public ListEntityReadQuery withDistinct() {
return query.withDistinct().asEntity(clazz);
}
@Override
public ListEntityReadQuery withFetchSize(int fetchSize) {
return query.withFetchSize(fetchSize).asEntity(clazz);
}
@Override
public ListEntityReadQuery withAllowFiltering() {
return query.withAllowFiltering().asEntity(clazz);
}
@Override
public ListEntityReadQuery withLimit(int limit) {
return query.withLimit(limit).asEntity(clazz);
}
@Override
public ResultList execute() {
return ListenableFutures.getUninterruptibly(executeAsync());
}
@Override
public ListenableFuture> executeAsync() {
ListenableFuture> future = query.executeAsync();
Function, ResultList> mapEntity = new Function, ResultList>() {
@Override
public ResultList apply(ResultList recordList) {
return new EntityListImpl<>(getContext(), recordList, clazz);
}
};
return Futures.transform(future, mapEntity);
}
@Override
public Publisher executeRx() {
ListenableFuture> recordsFuture = executeAsync();
return new ResultListPublisher<>(recordsFuture);
}
}
private static class EntityListImpl extends ResultAdapter implements ResultList {
private final Context ctx;
private final ResultList recordList;
private final Class clazz;
EntityListImpl(Context ctx, ResultList recordList, Class clazz) {
super(recordList);
this.ctx = ctx;
this.recordList = recordList;
this.clazz = clazz;
}
public FetchingIterator iterator() {
return new FetchingIterator() {
private final FetchingIterator recordIt = recordList.iterator();
@Override
public boolean hasNext() {
return recordIt.hasNext();
}
@Override
public F next() {
return ctx.getBeanMapper().fromValues(clazz, RecordImpl.toPropertiesSource(recordIt.next()), ctx.getDbSession().getColumnNames());
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public int getAvailableWithoutFetching() {
return recordIt.getAvailableWithoutFetching();
}
@Override
public boolean isFullyFetched() {
return recordIt.isFullyFetched();
}
@Override
public ListenableFuture fetchMoreResultsAsync() {
return recordIt.fetchMoreResultsAsync();
}
};
}
}
private static final class CountReadQueryData {
final ImmutableSet whereClauses;
final Integer limit;
final Boolean allowFiltering;
final Integer fetchSize;
final Boolean distinct;
public CountReadQueryData() {
this(ImmutableSet.of(),
null,
null,
null,
null);
}
private CountReadQueryData(ImmutableSet whereClauses,
Integer limit,
Boolean allowFiltering,
Integer fetchSize,
Boolean distinct) {
this.whereClauses = whereClauses;
this.limit = limit;
this.allowFiltering = allowFiltering;
this.fetchSize = fetchSize;
this.distinct = distinct;
}
public CountReadQueryData whereConditions(ImmutableSet whereClauses) {
return new CountReadQueryData(whereClauses,
this.limit,
this.allowFiltering,
this.fetchSize,
this.distinct);
}
public CountReadQueryData limit(Integer limit) {
return new CountReadQueryData(this.whereClauses,
limit,
this.allowFiltering,
this.fetchSize,
this.distinct);
}
public CountReadQueryData allowFiltering(Boolean allowFiltering) {
return new CountReadQueryData(this.whereClauses,
this.limit,
allowFiltering,
this.fetchSize,
this.distinct);
}
public CountReadQueryData fetchSize(Integer fetchSize) {
return new CountReadQueryData(this.whereClauses,
this.limit,
this.allowFiltering,
fetchSize,
this.distinct);
}
public CountReadQueryData distinct(Boolean distinct) {
return new CountReadQueryData(this.whereClauses,
this.limit,
this.allowFiltering,
this.fetchSize,
distinct);
}
public ImmutableSet getWhereConditions() {
return whereClauses;
}
public Integer getLimit() {
return limit;
}
public Boolean getAllowFiltering() {
return allowFiltering;
}
public Integer getFetchSize() {
return fetchSize;
}
public Boolean getDistinct() {
return distinct;
}
}
static class CountReadQuery extends AbstractQuery implements ListRead {
private final CountReadQueryData data;
public CountReadQuery(Context ctx, CountReadQueryData data) {
super(ctx);
this.data = data;
}
@Override
protected CountReadQuery newQuery(Context newContext) {
return new CountReadQuery(newContext, data);
}
@Override
public CountReadQuery withLimit(int limit) {
return new CountReadQuery(getContext(),
data.limit(limit));
}
@Override
public CountReadQuery withAllowFiltering() {
return new CountReadQuery(getContext(),
data.allowFiltering(true));
}
@Override
public CountReadQuery withFetchSize(int fetchSize) {
return new CountReadQuery(getContext(),
data.fetchSize(fetchSize));
}
@Override
public CountReadQuery withDistinct() {
return new CountReadQuery(getContext(),
data.distinct(true));
}
private Statement toStatement(CountReadQueryData queryData) {
Select.Selection selection = select();
if (queryData.getDistinct() != null) {
if (queryData.getDistinct()) {
selection.distinct();
};
}
selection.countAll();
Select select = selection.from(getContext().getDbSession().getTablename());
for (Clause whereCondition : queryData.getWhereConditions()) {
select.where(whereCondition);
}
if (queryData.getLimit() != null) {
select.limit(queryData.getLimit());
}
if (queryData.getAllowFiltering() != null) {
if (queryData.getAllowFiltering()) {
select.allowFiltering();
}
}
if (queryData.getFetchSize() != null) {
select.setFetchSize(queryData.getFetchSize());
}
return select;
}
@Override
public Count execute() {
return ListenableFutures.getUninterruptibly(executeAsync());
}
@Override
public ListenableFuture executeAsync() {
ListenableFuture future = performAsync(toStatement(data));
Function mapEntity = new Function() {
@Override
public Count apply(ResultSet resultSet) {
return Count.newCountResult(resultSet);
}
};
return Futures.transform(future, mapEntity);
}
@Override
public Publisher executeRx() {
ListenableFuture countFuture = executeAsync();
Function> toListFunction = new Function>() {
@Override
public ResultList apply(Count count) {
return new SingleEntryResultListAdapter<>(count);
}
};
return new ResultListPublisher<>(Futures.transform(countFuture, toListFunction));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy