
sparksoniq.jsoniq.runtime.iterator.operational.ComparisonOperationIterator Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
* Authors: Stefan Irimescu, Can Berker Cikis
*
*/
package sparksoniq.jsoniq.runtime.iterator.operational;
import sparksoniq.exceptions.IteratorFlowException;
import sparksoniq.exceptions.NonAtomicKeyException;
import sparksoniq.exceptions.UnexpectedTypeException;
import sparksoniq.jsoniq.compiler.translator.expr.operational.base.OperationalExpressionBase;
import sparksoniq.jsoniq.compiler.translator.expr.operational.base.OperationalExpressionBase.Operator;
import sparksoniq.jsoniq.item.ItemFactory;
import sparksoniq.jsoniq.runtime.iterator.RuntimeIterator;
import sparksoniq.jsoniq.runtime.iterator.operational.base.BinaryOperationBaseIterator;
import sparksoniq.jsoniq.runtime.metadata.IteratorMetadata;
import sparksoniq.semantics.DynamicContext;
import java.util.ArrayList;
import java.util.Arrays;
import org.rumbledb.api.Item;
public class ComparisonOperationIterator extends BinaryOperationBaseIterator {
private static final long serialVersionUID = 1L;
public static final Operator[] valueComparisonOperators = new Operator[]{
Operator.VC_GE, Operator.VC_GT, Operator.VC_EQ, Operator.VC_NE, Operator.VC_LE, Operator.VC_LT};
public static final Operator[] generalComparisonOperators = new Operator[]{
Operator.GC_GE, Operator.GC_GT, Operator.GC_EQ, Operator.GC_NE, Operator.GC_LE, Operator.GC_LT};
private boolean _isValueComparison;
private Item _left;
private Item _right;
public ComparisonOperationIterator(RuntimeIterator left, RuntimeIterator right,
OperationalExpressionBase.Operator operator, IteratorMetadata iteratorMetadata) {
super(left, right, operator, iteratorMetadata);
}
@Override
public Item next() {
if (this.hasNext()) {
this._hasNext = false;
// use stored values for value comparison
if (_isValueComparison) {
return comparePair(_left, _right);
} else {
// fetch all values and perform comparison
ArrayList- left = new ArrayList<>();
ArrayList
- right = new ArrayList<>();
while (_leftIterator.hasNext())
left.add(_leftIterator.next());
while (_rightIterator.hasNext())
right.add(_rightIterator.next());
_leftIterator.close();
_rightIterator.close();
return compareAllPairs(left, right);
}
}
throw new IteratorFlowException(RuntimeIterator.FLOW_EXCEPTION_MESSAGE, getMetadata());
}
@Override
public void open(DynamicContext context) {
super.open(context);
_leftIterator.open(_currentDynamicContext);
_rightIterator.open(_currentDynamicContext);
// value comparison may return an empty sequence
if (Arrays.asList(valueComparisonOperators).contains(this._operator)) {
// if EMPTY SEQUENCE - eg. () or ((),())
// this check is added here to provide lazy evaluation: eg. () eq (2,3) = () instead of exception
if (!(_leftIterator.hasNext() && _rightIterator.hasNext())) {
this._hasNext = false;
} else {
_left = _leftIterator.next();
_right = _rightIterator.next();
// value comparison doesn't support more than 1 items
if (_leftIterator.hasNext() || _rightIterator.hasNext()) {
throw new UnexpectedTypeException("Invalid args. Value comparison can't be performed on sequences with more than 1 items", getMetadata());
}
_isValueComparison = true;
this._hasNext = true;
}
} else if (Arrays.asList(generalComparisonOperators).contains(this._operator)) {
// general comparison always returns a boolean
this._hasNext = true;
}
_leftIterator.close();
_rightIterator.close();
}
/**
* Function to compare two lists of items one by one with each other.
*
* @param left item list of left iterator
* @param right item list of right iterator
* @return true if a single match is found, false if no matches. Given an empty sequence, false is returned.
*/
public Item compareAllPairs(ArrayList
- left, ArrayList
- right) {
for (Item l : left) {
for (Item r : right) {
Item result = comparePair(l, r);
if (result.getBooleanValue() == true)
return result;
}
}
return ItemFactory.getInstance().createBooleanItem(false);
}
public Item comparePair(Item left, Item right) {
if (left.isArray() || right.isArray()) {
throw new NonAtomicKeyException("Invalid args. Comparison can't be performed on array type", getMetadata().getExpressionMetadata());
} else if (left.isObject() || right.isObject()) {
throw new NonAtomicKeyException("Invalid args. Comparison can't be performed on object type", getMetadata().getExpressionMetadata());
}
if (left.isNull() || right.isNull()) {
return compareItems(left, right);
} else if (left.isNumeric()) {
if (!right.isNumeric())
throw new UnexpectedTypeException("Invalid args for numerics comparison " + left.serialize() +
", " + right.serialize(), getMetadata());
return compareItems(left, right);
} else if (left.isString()) {
if (!(right.isString()))
throw new UnexpectedTypeException("Invalid args for string comparison " + left.serialize() +
", " + right.serialize(), getMetadata());
return compareItems(left, right);
} else if (left.isBoolean()) {
if (!right.isBoolean())
throw new UnexpectedTypeException("Invalid args for boolean comparison " + left.serialize() +
", " + right.serialize(), getMetadata());
return compareItems(left, right);
} else {
throw new IteratorFlowException("Invalid comparison expression", getMetadata());
}
}
public Item compareItems(Item left, Item right) {
int comparison = left.compareTo(right);
switch (this._operator) {
case VC_EQ:
case GC_EQ:
return ItemFactory.getInstance().createBooleanItem(comparison == 0);
case VC_NE:
case GC_NE:
return ItemFactory.getInstance().createBooleanItem(comparison != 0);
case VC_LT:
case GC_LT:
return ItemFactory.getInstance().createBooleanItem(comparison < 0);
case VC_LE:
case GC_LE:
return ItemFactory.getInstance().createBooleanItem(comparison < 0 || comparison == 0);
case VC_GT:
case GC_GT:
return ItemFactory.getInstance().createBooleanItem(comparison > 0);
case VC_GE:
case GC_GE:
return ItemFactory.getInstance().createBooleanItem(comparison > 0 || comparison == 0);
default:
}
throw new IteratorFlowException("Unrecognized operator found", getMetadata());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy