001: /**********************************************************************
002: Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: ...
017: **********************************************************************/package org.jpox.store.expression;
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.Set;
024:
025: import org.jpox.store.DatastoreAdapter;
026: import org.jpox.store.mapping.JavaTypeMapping;
027:
028: /**
029: * An SQL expression that will test if a column of a table falls within the
030: * given Map's keys. This is used for Querys where a transient Map is passed
031: * in as a parameter.
032: *
033: * @version $Revision: 1.12 $
034: */
035: public class MapKeyLiteral extends ScalarExpression {
036: private final boolean isEmpty;
037: private final boolean containsNull;
038: private final DatastoreAdapter dba;
039: private final Map map;
040: /** ScalarExpressions for all elements in the Map **/
041: private List scalarExpressions;
042:
043: /**
044: * Constructor.
045: * @param qs The QueryStatement the MapKeyLiteral will be used in.
046: * @param mapping The mapping for the Map
047: * @param map The transient Map that is the value.
048: */
049: public MapKeyLiteral(QueryExpression qs, JavaTypeMapping mapping,
050: Map map) {
051: super (qs);
052: this .mapping = mapping;
053: containsNull = (map != null) && map.containsValue(null);
054: dba = qs.getStoreManager().getDatastoreAdapter();
055: this .map = map;
056:
057: // We'll consider the Map to be empty if it is null, is really
058: // empty, or only contains null.
059: // If it contains null we need a special case when creating the SQL.
060: isEmpty = (map == null) || (map.isEmpty())
061: || (map.size() == 1 && containsNull);
062:
063: // If the Map is empty, don't build the list of SQLExpressions.
064: if (!isEmpty) {
065: st.append("(");
066: scalarExpressions = new ArrayList();
067:
068: boolean hadPrev = false;
069:
070: Set keys = map.keySet();
071: for (Iterator it = keys.iterator(); it.hasNext();) {
072: Object current = it.next();
073: if (null != current) {
074: JavaTypeMapping m = dba.getMapping(current
075: .getClass(), qs.getStoreManager(), qs
076: .getClassLoaderResolver());
077: ScalarExpression expr = m.newLiteral(qs, current);
078:
079: // Append the SQLExpression (should be a literal) for the
080: // current element.
081: st.append(hadPrev ? "," : "");
082: st.append(expr);
083: scalarExpressions.add(expr);
084:
085: hadPrev = true;
086: }
087: }
088:
089: st.append(")");
090: }
091: }
092:
093: /**
094: * Method to check the containing of a key in the Map.
095: * Return the BooleanExpression that results from
096: * MapKeyLiteral.contains(SQLExpression).
097: * @param expr The SQLExpression that is checked for membership in the Map.
098: * @return The BooleanExpression that results from
099: * MapKeyLiteral.contains(SQLExpression).
100: */
101: public BooleanExpression containsMethod(ScalarExpression expr) {
102: if (isEmpty) {
103: return new BooleanLiteral(qs, mapping, false);
104: }
105: BooleanExpression bExpr = null;
106: for (int i = 0; i < scalarExpressions.size(); i++) {
107: if (bExpr == null) {
108: bExpr = ((ScalarExpression) scalarExpressions.get(i))
109: .eq(expr);
110: } else {
111: bExpr = bExpr.ior(((ScalarExpression) scalarExpressions
112: .get(i)).eq(expr));
113: }
114: }
115: bExpr.encloseWithInParentheses();
116: return bExpr;
117: }
118:
119: /**
120: * Method to get a value from the Map for a key
121: * @param expr The key argument expression
122: * @return The statement
123: **/
124: public ScalarExpression getMethod(ScalarExpression expr) {
125: if (map == null) {
126: return new NullLiteral(qs);
127: }
128: if (expr instanceof Literal) {
129: Object value = map.get(((Literal) expr).getValue());
130: if (value == null) {
131: return new NullLiteral(qs);
132: }
133: JavaTypeMapping m = dba.getMapping(value.getClass(), qs
134: .getStoreManager(), qs.getClassLoaderResolver());
135: return new ObjectLiteral(qs, m, value);
136: }
137: //impossible to invoke Map.get with an expression, only with literals
138: //using CASE WHEN booleanexpression THEN expression does not work, since expression can only be
139: //one single field (column), however, one could have two CASE expressions
140: throw new IllegalOperationException(this , "getMethod", expr);
141: }
142:
143: /**
144: * Method to check for emptiness of the collection.
145: * @return The BooleanExpression.
146: **/
147: public BooleanExpression isEmptyMethod() {
148: return new BooleanLiteral(qs, mapping, isEmpty);
149: }
150: }
|