Package org.datanucleus.store.rdbms.sql.method

Source Code of org.datanucleus.store.rdbms.sql.method.MapGetMethod

/**********************************************************************
Copyright (c) 2008 Andy Jefferson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.datanucleus.store.rdbms.sql.method;

import java.util.List;

import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.MapMetaData;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.metadata.MapMetaData.MapType;
import org.datanucleus.query.compiler.CompilationComponent;
import org.datanucleus.store.mapped.DatastoreClass;
import org.datanucleus.store.mapped.DatastoreContainerObject;
import org.datanucleus.store.mapped.mapping.JavaTypeMapping;
import org.datanucleus.store.mapped.mapping.MappingConsumer;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.sql.SQLStatement;
import org.datanucleus.store.rdbms.sql.SQLTable;
import org.datanucleus.store.rdbms.sql.expression.MapExpression;
import org.datanucleus.store.rdbms.sql.expression.MapLiteral;
import org.datanucleus.store.rdbms.sql.expression.NullLiteral;
import org.datanucleus.store.rdbms.sql.expression.SQLExpression;
import org.datanucleus.store.rdbms.sql.expression.SQLLiteral;
import org.datanucleus.store.rdbms.sql.expression.SubqueryExpression;
import org.datanucleus.store.rdbms.sql.expression.UnboundExpression;
import org.datanucleus.store.rdbms.table.MapTable;

/**
* Method for evaluating {mapExpr}.get(keyExpr).
* Returns an ObjectExpression representing the value
*/
public class MapGetMethod extends AbstractSQLMethod
{
    /* (non-Javadoc)
     * @see org.datanucleus.store.rdbms.sql.method.SQLMethod#getExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression, java.util.List)
     */
    public SQLExpression getExpression(SQLExpression expr, List args)
    {
        if (args == null || args.size() == 0 || args.size() > 1)
        {
            throw new NucleusException(LOCALISER.msg("060016", "get", "MapExpression", 1));
        }

        MapExpression mapExpr = (MapExpression)expr;
        SQLExpression keyValExpr = (SQLExpression)args.get(0);
        if (keyValExpr instanceof UnboundExpression)
        {
            // TODO Add support for unbound variables (as per CollectionContains)
            throw new NucleusException("Dont currently support binding of unbound variables using Map.get");
        }

        if (mapExpr instanceof MapLiteral && keyValExpr instanceof SQLLiteral)
        {
            MapLiteral lit = (MapLiteral)expr;
            if (lit.getValue() == null)
            {
                return new NullLiteral(stmt, null, null, null);
            }

            return lit.getKeyLiteral().invoke("get", args);
        }
        else if (mapExpr instanceof MapLiteral)
        {
            // MapLiteral.get(SQLExpression)
            throw new NucleusUserException("We do not support MapLiteral.get(SQLExpression) since SQL doesnt allow such constructs");
        }
        else
        {
            if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.FILTER ||
                stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.ORDERING)
            {
                return getAsInnerJoin(mapExpr, keyValExpr);
            }
            else if (stmt.getQueryGenerator().getCompilationComponent() == CompilationComponent.RESULT)
            {
                return getAsSubquery(mapExpr, keyValExpr);
            }

            throw new NucleusException("Map.get() is not supported for " + mapExpr +
                " with argument " + keyValExpr + " for query component " + stmt.getQueryGenerator().getCompilationComponent());
        }
    }

    /**
     * Implementation of Map.get() using a subquery on the table representing the map,
     * adding a condition on the key and returning the value.
     * @param mapExpr The map expression
     * @param keyValExpr The key value expression
     * @return The value expression
     */
    protected SQLExpression getAsSubquery(MapExpression mapExpr, SQLExpression keyValExpr)
    {
        AbstractMemberMetaData mmd = mapExpr.getJavaTypeMapping().getMemberMetaData();
        MapMetaData mapmd = mmd.getMap();
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        MetaDataManager mmgr = storeMgr.getMetaDataManager();

        JavaTypeMapping ownerMapping = null;
        JavaTypeMapping keyMapping = null;
        JavaTypeMapping valMapping = null;
        DatastoreContainerObject mapTbl = null;
        if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN)
        {
            // JoinTable
            mapTbl = storeMgr.getDatastoreContainerObject(mmd);
            ownerMapping = ((MapTable)mapTbl).getOwnerMapping();
            keyMapping = ((MapTable)mapTbl).getKeyMapping();
            valMapping = ((MapTable)mapTbl).getValueMapping();
        }
        else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE)
        {
            // ForeignKey from value table to key
            AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr, mmgr);
            mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getValueType(), clr);
            if (mmd.getMappedBy() != null)
            {
                ownerMapping = mapTbl.getMemberMapping(valCmd.getMetaDataForMember(mmd.getMappedBy()));
            }
            else
            {
                ownerMapping = ((DatastoreClass)mapTbl).getExternalMapping(mmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK);
            }
            String keyFieldName = mmd.getKeyMetaData().getMappedBy();
            AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(keyFieldName);
            keyMapping = mapTbl.getMemberMapping(valKeyMmd);
            valMapping = mapTbl.getIdMapping();
        }
        else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY)
        {
            // ForeignKey from key table to value
            AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr, mmgr);
            mapTbl = storeMgr.getDatastoreClass(mmd.getMap().getKeyType(), clr);
            if (mmd.getMappedBy() != null)
            {
                ownerMapping = mapTbl.getMemberMapping(keyCmd.getMetaDataForMember(mmd.getMappedBy()));
            }
            else
            {
                ownerMapping = ((DatastoreClass)mapTbl).getExternalMapping(mmd, MappingConsumer.MAPPING_TYPE_EXTERNAL_FK);
            }
            keyMapping = mapTbl.getIdMapping();
            String valFieldName = mmd.getValueMetaData().getMappedBy();
            AbstractMemberMetaData keyValMmd = keyCmd.getMetaDataForMember(valFieldName);
            valMapping = mapTbl.getMemberMapping(keyValMmd);
        }
        else
        {
            throw new NucleusException("Invalid map for " + mapExpr + " in get() call");
        }

        SQLStatement subStmt = new SQLStatement(stmt, storeMgr, mapTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        SQLExpression valExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), valMapping);
        subStmt.select(valExpr, null);

        // Link to primary statement
        SQLExpression elementOwnerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(),
            ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, mapExpr.getSQLTable(),
            mapExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(elementOwnerExpr.eq(ownerIdExpr), true);

        // Condition on key
        SQLExpression keyExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), keyMapping);
        subStmt.whereAnd(keyExpr.eq(keyValExpr), true);

        SubqueryExpression subExpr = new SubqueryExpression(stmt, subStmt);
        subExpr.setJavaTypeMapping(valMapping);
        return subExpr;
    }

    /**
     * Implementation of Map.get() using an inner join to the table representing the map,
     * adding a condition on the key and returning the value.
     * @param mapExpr The map expression
     * @param keyValExpr The key value expression
     * @return The value expression
     */
    protected SQLExpression getAsInnerJoin(MapExpression mapExpr, SQLExpression keyValExpr)
    {
        JavaTypeMapping m = mapExpr.getJavaTypeMapping();
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        MetaDataManager mmgr = storeMgr.getMetaDataManager();
        AbstractMemberMetaData mmd = m.getMemberMetaData();
        if (mmd != null)
        {
            MapMetaData mapmd = mmd.getMap();
            if (mapmd.getMapType() == MapType.MAP_TYPE_JOIN)
            {
                MapTable joinTbl = (MapTable)stmt.getRDBMSManager().getDatastoreContainerObject(mmd);

                // Add join to join table
                SQLTable joinSqlTbl = stmt.innerJoin(mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(),
                    joinTbl, null, joinTbl.getOwnerMapping(), null, null);

                // Add condition on key
                SQLExpression keyExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getKeyMapping());
                stmt.whereAnd(keyExpr.eq(keyValExpr), true);

                // Return value expression
                if (mapmd.getValueClassMetaData(clr, mmgr) != null)
                {
                    // Persistable value so join to its table
                    DatastoreClass valTable = stmt.getRDBMSManager().getDatastoreClass(mapmd.getValueType(), clr);
                    SQLTable valueSqlTbl = stmt.innerJoin(joinSqlTbl, joinTbl.getValueMapping(),
                        valTable, null, valTable.getIdMapping(), null, null);

                    return exprFactory.newExpression(stmt, valueSqlTbl, valTable.getIdMapping());
                }
                else
                {
                    // Return mapping for the value in the join table
                    SQLExpression valueExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getValueMapping());
                    return valueExpr;
                }
            }
            else if (mapmd.getMapType() == MapType.MAP_TYPE_KEY_IN_VALUE)
            {
                // Key stored in value table, so join to value table, add condition on key, and return value
                DatastoreClass valTable = stmt.getRDBMSManager().getDatastoreClass(mapmd.getValueType(), clr);
                AbstractClassMetaData valCmd = mapmd.getValueClassMetaData(clr, mmgr);

                // Add join to value table
                SQLTable valSqlTbl = stmt.innerJoin(mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(),
                    valTable, null, valTable.getIdMapping(), null, null);

                // Add condition on key
                String keyFieldName = mmd.getKeyMetaData().getMappedBy();
                AbstractMemberMetaData valKeyMmd = valCmd.getMetaDataForMember(keyFieldName);
                JavaTypeMapping keyMapping = valTable.getMemberMapping(valKeyMmd);
                SQLExpression keyExpr = exprFactory.newExpression(stmt, valSqlTbl, keyMapping);
                stmt.whereAnd(keyExpr.eq(keyValExpr), true);

                // Return value expression
                SQLExpression valueExpr = exprFactory.newExpression(stmt, valSqlTbl, valTable.getIdMapping());
                return valueExpr;
            }
            else if (mapmd.getMapType() == MapType.MAP_TYPE_VALUE_IN_KEY)
            {
                // Value stored in key table, so join to key table, add condition on key, and return value
                DatastoreClass keyTable = stmt.getRDBMSManager().getDatastoreClass(mapmd.getKeyType(), clr);
                AbstractClassMetaData keyCmd = mapmd.getKeyClassMetaData(clr, mmgr);

                // Add join to key table
                SQLTable keySqlTbl = stmt.innerJoin(mapExpr.getSQLTable(), mapExpr.getSQLTable().getTable().getIdMapping(),
                    keyTable, null, keyTable.getIdMapping(), null, null);

                // Add condition on key
                SQLExpression keyExpr = exprFactory.newExpression(stmt, keySqlTbl, keyTable.getIdMapping());
                stmt.whereAnd(keyExpr.eq(keyValExpr), true);

                // Return value expression
                String valueFieldName = mmd.getValueMetaData().getMappedBy();
                AbstractMemberMetaData valKeyMmd = keyCmd.getMetaDataForMember(valueFieldName);
                JavaTypeMapping valueMapping = keyTable.getMemberMapping(valKeyMmd);
                SQLExpression valueExpr = exprFactory.newExpression(stmt, keySqlTbl, valueMapping);
                return valueExpr;
            }
        }
        throw new NucleusException("Map.get() for the filter is not supported for " + mapExpr +
            " with an argument of " + keyValExpr + ". Why not contribute support for it?");
    }
}
TOP

Related Classes of org.datanucleus.store.rdbms.sql.method.MapGetMethod

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.