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

net.oneandone.troilus.SingleReadQuery 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 java.util.Iterator;
import java.util.List;



import org.reactivestreams.Publisher;

import net.oneandone.troilus.java7.FetchingIterator;
import net.oneandone.troilus.java7.Record;
import net.oneandone.troilus.java7.ResultList;
import net.oneandone.troilus.java7.SingleRead;
import net.oneandone.troilus.java7.SingleReadWithUnit;
import net.oneandone.troilus.java7.interceptor.ReadQueryData;
import net.oneandone.troilus.java7.interceptor.ResultListAdapter;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;




/**
 * Read query implementation
 */
class SingleReadQuery extends AbstractQuery implements SingleReadWithUnit {

    private final ReadQueryData data;
    
    /**
     * @param ctx   the context 
     * @param data  the data
     */
    SingleReadQuery(Context ctx, ReadQueryData data) {
        super(ctx);
        this.data = data;
    }
   
    
    ////////////////////
    // factory methods
    
    @Override
    protected SingleReadQuery newQuery(Context newContext) {
        return new SingleReadQuery(newContext, data);
    }

    private SingleReadQuery newQuery(ReadQueryData data) {
        return new SingleReadQuery(getContext(), data);
    }

    //
    ////////////////////


    
    @Override
    public SingleReadQuery all() {
        return newQuery(data.columnsToFetch(ImmutableMap.of()));
    }
    
   
    @Override
    public SingleReadQuery column(String name) {
        return newQuery(data.columnsToFetch(Immutables.join(data.getColumnsToFetch(), name, false)));
    }

    @Override
    public SingleReadQuery columnWithMetadata(String name) {
        return newQuery(data.columnsToFetch(Immutables.join(data.getColumnsToFetch(), name, true)));
    }
    
    @Override
    public SingleReadQuery columns(String... names) {
        return columns(ImmutableList.copyOf(names));
    }

    
    private SingleReadQuery columns(ImmutableList names) {
        SingleReadQuery read = this;
        for (String columnName : names) {
            read = read.column(columnName);
        }
        return read;
    }

    @Override
    public SingleReadQuery column(ColumnName name) {
        return column(name.getName());
    }

    @Override
    public SingleReadQuery columnWithMetadata(ColumnName name) {
        return column(name.getName());
    }
    
    @Override
    public SingleReadQuery columns(ColumnName... names) {
        List ns = Lists.newArrayList();
        for (ColumnName name : names) {
            ns.add(name.getName());
        }
        return columns(ImmutableList.copyOf(ns));
    }
    
    @Override
    public  SingleEntityReadQuery asEntity(Class objectClass) {
        return new SingleEntityReadQuery(getContext(), this, objectClass);
    }
    
    @Override
    public Record execute() {
        return ListenableFutures.getUninterruptibly(executeAsync());
    }
    
    @Override
    public ListenableFuture executeAsync() {
        ListenableFuture> recordsFuture = new ListReadQuery(getContext(), data).executeAsync();
        recordsFuture = toSingleEntryResultList(recordsFuture);
        
        Function, Record> fetchRecordFunction = new Function, Record>() {
            
            @Override
            public Record apply(ResultList records) {
                Iterator it = records.iterator();
                if (it.hasNext()) {
                    Record record = it.next();
                    
                    if (it.hasNext()) {
                        throw new TooManyResultsException(records, "more than one record exists");
                    }
                    
                    return record;
                } else {
                    return null;
                }
            }
        };
        
        return Futures.transform(recordsFuture, fetchRecordFunction);
    }
    
    
    @Override
    public Publisher executeRx() {
        ListenableFuture> recordsFuture = new ListReadQuery(getContext(), data).executeAsync();
        recordsFuture = toSingleEntryResultList(recordsFuture);
        
        return new ResultListPublisher(recordsFuture);
    }
    
    
    /**
     * Entity read query 
     * @param  the entity type
     */
    static class SingleEntityReadQuery extends AbstractQuery> implements SingleRead {
        private final Class clazz;
        private final SingleReadQuery query;
        
        
        /**
         * @param ctx    the context
         * @param query  the underlying query  
         * @param clazz  the entity type
         */
        SingleEntityReadQuery(Context ctx, SingleReadQuery query, Class clazz) {
            super(ctx);
            this.query = query;
            this.clazz = clazz;
        }
        
        @Override
        protected SingleEntityReadQuery newQuery(Context newContext) {
            return new SingleReadQuery(newContext, query.data).asEntity(clazz); 
        }
        
        @Override
        public E execute() {
            return ListenableFutures.getUninterruptibly(executeAsync());
        }
        
        @Override
        public ListenableFuture executeAsync() {
            ListenableFuture future = query.executeAsync();
            
            Function mapEntity = new Function() {
                @Override
                public E apply(Record record) {
                    if (record == null) {
                        return null;
                    } else {
                        return getContext().getBeanMapper().fromValues(clazz, RecordImpl.toPropertiesSource(record), getContext().getDbSession().getColumnNames());
                    }
                }
            };
            
            return Futures.transform(future, mapEntity);
        }
        
        @Override
        public Publisher executeRx() {
            ListenableFuture> recordsFuture = new ListReadQuery(getContext(), query.data).asEntity(clazz).executeAsync();
            recordsFuture = toSingleEntryResultList(recordsFuture);
                
            return new ResultListPublisher(recordsFuture);
        }
    }
    
    
    
    private static  ListenableFuture> toSingleEntryResultList(ListenableFuture> list) {
        
        Function, ResultList> mapperFunction = new Function, ResultList>() {
            
            @Override
            public ResultList apply(ResultList list) {
                return new SingleEntryResultList<>(list);
            }
        };
        
        return Futures.transform(list, mapperFunction);
    }
    
    
    
    private static final class SingleEntryResultList extends ResultListAdapter {
        
        public SingleEntryResultList(ResultList list) {
           super(list);
        }
        
        @Override
        public FetchingIterator iterator() {
            return new SingleFetchingIterator<>(super.iterator());
        }

        
        private final class SingleFetchingIterator implements FetchingIterator {
            
            private final FetchingIterator iterator;
            
            public SingleFetchingIterator(FetchingIterator iterator) {
                this.iterator = iterator;
            }
            
            @Override
            public boolean hasNext() {
                return iterator.hasNext();
            }
            
            @Override
            public E next() {
                E element = iterator.next();
                    
                if (iterator.hasNext()) {
                    throw new TooManyResultsException(SingleEntryResultList.this, "more than one record exists");
                }
                    
                return element;
            }
            
            @Override
            public int getAvailableWithoutFetching() {
                return iterator.getAvailableWithoutFetching();
            }
            
            @Override
            public ListenableFuture fetchMoreResultsAsync() {
                return iterator.fetchMoreResultsAsync();
            }
            
            @Override
            public boolean isFullyFetched() {
                return iterator.isFullyFetched();
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy