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

com.mysema.query.jdoql.sql.JDOSQLQuery Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010 Mysema Ltd.
 * All rights reserved.
 *
 */
package com.mysema.query.jdoql.sql;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.annotation.Nullable;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mysema.commons.lang.CloseableIterator;
import com.mysema.commons.lang.IteratorAdapter;
import com.mysema.query.DefaultQueryMetadata;
import com.mysema.query.QueryException;
import com.mysema.query.QueryMetadata;
import com.mysema.query.QueryModifiers;
import com.mysema.query.SearchResults;
import com.mysema.query.jdoql.JDOTuple;
import com.mysema.query.sql.SQLCommonQuery;
import com.mysema.query.sql.SQLSerializer;
import com.mysema.query.sql.SQLTemplates;
import com.mysema.query.types.EConstructor;
import com.mysema.query.types.Expr;
import com.mysema.query.types.expr.QTuple;

/**
 * JDOSQLQuery is an SQLQuery implementation that uses JDO's SQL query functionality
 * to execute queries
 *
 * @author tiwe
 *
 */
public final class JDOSQLQuery extends AbstractSQLQuery implements SQLCommonQuery{
    
    private static final Logger logger = LoggerFactory.getLogger(JDOSQLQuery.class);
    
    private final Closeable closeable = new Closeable(){
        @Override
        public void close() throws IOException {
            JDOSQLQuery.this.close();            
        }        
    };

    private final boolean detach;

    private List orderedConstants = new ArrayList();

    @Nullable
    private final PersistenceManager persistenceManager;

    private List queries = new ArrayList(2);

    private final SQLTemplates templates;

    public JDOSQLQuery(@Nullable PersistenceManager persistenceManager, SQLTemplates templates) {
        this(persistenceManager, templates, new DefaultQueryMetadata(), false);
    }

    public JDOSQLQuery(
            @Nullable PersistenceManager persistenceManager,
            SQLTemplates templates,
            QueryMetadata metadata, boolean detach) {
        super(metadata);
        this.templates = templates;
        this.persistenceManager = persistenceManager;
        this.detach = detach;
    }

    public void close() {
        for (Query query : queries){
            query.closeAll();
        }
    }

    public long count() {
        Query query = createQuery(true);
        query.setUnique(true);
        reset();
        Long rv = (Long) execute(query);
        if (rv != null){
            return rv.longValue();
        }else{
            throw new QueryException("Query returned null");
        }
    }

    private Query createQuery(boolean forCount) {
        SQLSerializer serializer = new SQLSerializer(templates);
        serializer.serialize(queryMixin.getMetadata(), forCount);

        // create Query
        if (logger.isDebugEnabled()){
            logger.debug(serializer.toString());
        }
        Query query = persistenceManager.newQuery("javax.jdo.query.SQL",serializer.toString());
        orderedConstants = serializer.getConstants();
        queries.add(query);

        if (!forCount){
            List> projection = queryMixin.getMetadata().getProjection();
            Class exprType = projection.get(0).getClass();
            if (exprType.equals(QTuple.class)){
                query.setResultClass(JDOTuple.class);
            } else if (EConstructor.class.isAssignableFrom(exprType)){
                query.setResultClass(projection.get(0).getType());
            }
        }else{
            query.setResultClass(Long.class);
        }

        return query;
    }

    @SuppressWarnings("unchecked")
    private  T detach(T results){
        if (results instanceof Collection){
            return (T) persistenceManager.detachCopyAll(results);
        }else{
            return persistenceManager.detachCopy(results);
        }
    }

    private Object execute(Query query) {
        Object rv;
        if (!orderedConstants.isEmpty()) {
            rv = query.executeWithArray(orderedConstants.toArray());
        } else {
            rv = query.execute();
        }
        if (isDetach()){
            rv = detach(rv);
        }
        return rv;
    }

    public QueryMetadata getMetadata(){
        return queryMixin.getMetadata();
    }

    public boolean isDetach() {
        return detach;
    }

    public CloseableIterator iterate(Expr[] args) {
        return new IteratorAdapter(list(args).iterator(), closeable);
    }

    public  CloseableIterator iterate(Expr projection) {
        return new IteratorAdapter(list(projection).iterator(), closeable);
    }

    @SuppressWarnings("unchecked")
    public List list(Expr[] args) {
        queryMixin.addToProjection(args);
        Object rv = execute(createQuery(false));
        reset();
        return (rv instanceof List) ? ((List)rv) : Collections.singletonList((Object[])rv);
    }

    @SuppressWarnings("unchecked")
    public  List list(Expr expr) {
        queryMixin.addToProjection(expr);
        Object rv = execute(createQuery(false));
        reset();
        return rv instanceof List ? (List)rv : Collections.singletonList((RT)rv);
    }

    @SuppressWarnings("unchecked")
    public  SearchResults listResults(Expr expr) {
        queryMixin.addToProjection(expr);
        Query countQuery = createQuery(true);
        countQuery.setUnique(true);
        long total = (Long) execute(countQuery);
        if (total > 0) {
            QueryModifiers modifiers = queryMixin.getMetadata().getModifiers();
            Query query = createQuery(false);
            reset();
            return new SearchResults((List) execute(query), modifiers, total);
        } else {
            reset();
            return SearchResults.emptyResults();
        }
    }

    private void reset(){
        queryMixin.getMetadata().reset();
    }

    @Override
    public String toString(){
        if (!queryMixin.getMetadata().getJoins().isEmpty()){
            SQLSerializer serializer = new SQLSerializer(templates);
            serializer.serialize(queryMixin.getMetadata(), false);
            return serializer.toString().trim();
        }else{
            return super.toString();
        }
    }

    @SuppressWarnings("unchecked")
    public  RT uniqueResult(Expr expr) {
        queryMixin.addToProjection(expr);
        Query query = createQuery(false);
        query.setUnique(true);
        reset();
        return (RT) execute(query);
    }


}