/*
*
* * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
* *
* * 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.
* *
* * For more information: http://www.orientechnologies.com
*
*/
package com.orientechnologies.orient.core.sql;
import com.orientechnologies.common.util.OResettable;
import com.orientechnologies.orient.core.command.OCommandContext;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.ridbag.ORidBag;
import com.orientechnologies.orient.core.id.OClusterPositionFactory;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.record.ORecord;
import com.orientechnologies.orient.core.record.ORecordInternal;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.filter.OSQLFilterItemField;
import com.orientechnologies.orient.core.sql.filter.OSQLFilterItemVariable;
import com.orientechnologies.orient.core.sql.functions.OSQLFunctionRuntime;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Handles runtime results.
*
* @author Luca Garulli
*/
public class ORuntimeResult {
private final Object fieldValue;
private final Map<String, Object> projections;
private final ODocument value;
private OCommandContext context;
public ORuntimeResult(final Object iFieldValue, final Map<String, Object> iProjections, final int iProgressive,
final OCommandContext iContext) {
fieldValue = iFieldValue;
projections = iProjections;
context = iContext;
value = createProjectionDocument(iProgressive);
}
public void applyRecord(final OIdentifiable iRecord) {
applyRecord(value, projections, context, iRecord);
}
/**
* Set a single value. This is useful in case of query optimization like with indexes
*
* @param iName
* Field name
* @param iValue
* Field value
*/
public void applyValue(final String iName, final Object iValue) {
value.field(iName, iValue);
}
public ODocument getResult() {
return getResult(value, projections);
}
public static ODocument createProjectionDocument(final int iProgressive) {
final ODocument doc = new ODocument().setOrdered(true);
// ASSIGN A TEMPORARY RID TO ALLOW PAGINATION IF ANY
((ORecordId) doc.getIdentity()).clusterId = -2;
((ORecordId) doc.getIdentity()).clusterPosition = OClusterPositionFactory.INSTANCE.valueOf(iProgressive);
return doc;
}
public static ODocument applyRecord(final ODocument iValue, final Map<String, Object> iProjections,
final OCommandContext iContext, final OIdentifiable iRecord) {
// APPLY PROJECTIONS
final ODocument inputDocument = (ODocument) (iRecord != null ? iRecord.getRecord() : null);
if (iProjections.isEmpty())
// SELECT * CASE
inputDocument.copyTo(iValue);
else {
for (Entry<String, Object> projection : iProjections.entrySet()) {
final Object v = projection.getValue();
if (v == null)
continue;
final Object projectionValue;
if (v.equals("*")) {
// COPY ALL
inputDocument.copyTo(iValue);
projectionValue = null;
} else if (v instanceof OSQLFilterItemVariable) {
// RETURN A VARIABLE FROM THE CONTEXT
projectionValue = ((OSQLFilterItemVariable) v).getValue(inputDocument, iValue, iContext);
} else if (v instanceof OSQLFilterItemField)
projectionValue = ((OSQLFilterItemField) v).getValue(inputDocument, iValue, iContext);
else if (v instanceof OSQLFunctionRuntime) {
final OSQLFunctionRuntime f = (OSQLFunctionRuntime) v;
projectionValue = f.execute(inputDocument, inputDocument, iValue, iContext);
} else
projectionValue = v;
if (projectionValue != null)
if (projectionValue instanceof ORidBag)
iValue.field(projection.getKey(), new ORidBag((ORidBag) projectionValue));
else if (projectionValue instanceof OIdentifiable && !(projectionValue instanceof ORID)
&& !(projectionValue instanceof ORecord))
iValue.field(projection.getKey(), ((OIdentifiable) projectionValue).getRecord());
else if (projectionValue instanceof Iterator) {
// make temporary value typical case graph database elemenet's iterator edges
if (projectionValue instanceof OResettable)
((OResettable) projectionValue).reset();
final List<Object> iteratorValues = new ArrayList<Object>();
final Iterator projectionValueIterator = (Iterator) projectionValue;
while (projectionValueIterator.hasNext()) {
final Object value = projectionValueIterator.next();
if (value instanceof OIdentifiable && !(value instanceof ORID) && !(value instanceof ORecord))
iteratorValues.add(((OIdentifiable) value).getRecord());
else
iteratorValues.add(value);
}
iValue.field(projection.getKey(), iteratorValues);
} else
iValue.field(projection.getKey(), projectionValue);
}
}
return iValue;
}
public static ODocument getResult(final ODocument iValue, final Map<String, Object> iProjections) {
if (iValue != null) {
boolean canExcludeResult = false;
for (Entry<String, Object> projection : iProjections.entrySet()) {
if (!iValue.containsField(projection.getKey())) {
// ONLY IF NOT ALREADY CONTAINS A VALUE, OTHERWISE HAS BEEN SET MANUALLY (INDEX?)
final Object v = projection.getValue();
if (v instanceof OSQLFunctionRuntime) {
final OSQLFunctionRuntime f = (OSQLFunctionRuntime) v;
canExcludeResult = f.filterResult();
Object fieldValue = f.getResult();
if (fieldValue != null)
iValue.field(projection.getKey(), fieldValue);
}
}
}
if (canExcludeResult && iValue.isEmpty())
// RESULT EXCLUDED FOR EMPTY RECORD
return null;
// AVOID SAVING OF TEMP RECORD
ORecordInternal.unsetDirty(iValue);
}
return iValue;
}
public static ODocument getProjectionResult(final int iId, final Map<String, Object> iProjections,
final OCommandContext iContext, final OIdentifiable iRecord) {
return ORuntimeResult.getResult(
ORuntimeResult.applyRecord(ORuntimeResult.createProjectionDocument(iId), iProjections, iContext, iRecord), iProjections);
}
public Object getFieldValue() {
return fieldValue;
}
}