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

net.oneandone.troilus.ListReadQuery Maven / Gradle / Ivy

There is a newer version: 0.18
Show newest version
/*
 * 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