package org.exist.xquery.modules.range;
import org.exist.dom.QName;
import org.exist.indexing.range.RangeIndexWorker;
import org.exist.util.Occurrences;
import org.exist.xquery.*;
import org.exist.xquery.value.*;
public class IndexKeys extends BasicFunction {
public final static FunctionSignature[] signatures = {
new FunctionSignature(
new QName("index-keys-for-field", RangeIndexModule.NAMESPACE_URI, RangeIndexModule.PREFIX),
"Retrieve all index keys contained in a range index which has been defined with a field name. Similar to" +
"util:index-keys, but works with fields.",
new SequenceType[] {
new FunctionParameterSequenceType("field", Type.STRING, Cardinality.EXACTLY_ONE, "The field to use"),
new FunctionParameterSequenceType("function-reference", Type.FUNCTION_REFERENCE, Cardinality.EXACTLY_ONE, "The function reference as created by the util:function function. " +
"It can be an arbitrary user-defined function, but it should take exactly 2 arguments: " +
"1) the current index key as found in the range index as an atomic value, 2) a sequence " +
"containing three int values: a) the overall frequency of the key within the node set, " +
"b) the number of distinct documents in the node set the key occurs in, " +
"c) the current position of the key in the whole list of keys returned."),
new FunctionParameterSequenceType("max-number-returned", Type.INT, Cardinality.ZERO_OR_ONE , "The maximum number of returned keys")
},
new FunctionReturnSequenceType(Type.ITEM, Cardinality.ZERO_OR_MORE, "the results of the eval of the $function-reference")),
new FunctionSignature(
new QName("index-keys-for-field", RangeIndexModule.NAMESPACE_URI, RangeIndexModule.PREFIX),
"Retrieve all index keys contained in a range index which has been defined with a field name. Similar to" +
"util:index-keys, but works with fields.",
new SequenceType[] {
new FunctionParameterSequenceType("field", Type.STRING, Cardinality.EXACTLY_ONE, "The field to use"),
new FunctionParameterSequenceType("start-value", Type.ATOMIC, Cardinality.ZERO_OR_ONE, "Only index keys of the same type but being greater than $start-value will be reported for non-string types. For string types, only keys starting with the given prefix are reported."),
new FunctionParameterSequenceType("function-reference", Type.FUNCTION_REFERENCE, Cardinality.EXACTLY_ONE, "The function reference as created by the util:function function. " +
"It can be an arbitrary user-defined function, but it should take exactly 2 arguments: " +
"1) the current index key as found in the range index as an atomic value, 2) a sequence " +
"containing three int values: a) the overall frequency of the key within the node set, " +
"b) the number of distinct documents in the node set the key occurs in, " +
"c) the current position of the key in the whole list of keys returned."),
new FunctionParameterSequenceType("max-number-returned", Type.INT, Cardinality.ZERO_OR_ONE , "The maximum number of returned keys")
},
new FunctionReturnSequenceType(Type.ITEM, Cardinality.ZERO_OR_MORE, "the results of the eval of the $function-reference"))
};
public IndexKeys(XQueryContext context, FunctionSignature signature) {
super(context, signature);
}
@Override
public Sequence eval(final Sequence[] args, final Sequence contextSequence) throws XPathException {
int arg = 0;
final String field = args[arg++].getStringValue();
String start = null;
if (args.length == 4) {
start = args[arg++].getStringValue();
}
final FunctionReference ref = (FunctionReference) args[arg++].itemAt(0);
int max = -1;
if (!args[arg].isEmpty()) {
max = ((IntegerValue)args[arg].itemAt(0)).getInt();
}
final Sequence result = new ValueSequence();
final RangeIndexWorker worker = (RangeIndexWorker) context.getBroker().getIndexController().getWorkerByIndexName("range-index");
Occurrences[] occur = worker.scanIndexByField(field, contextSequence == null ? context.getStaticallyKnownDocuments() : contextSequence.getDocumentSet(), start, max);
final int len = (max != -1 && occur.length > max ? max : occur.length);
final Sequence params[] = new Sequence[2];
ValueSequence data = new ValueSequence();
for (int j = 0; j < len; j++) {
params[0] = new StringValue(occur[j].getTerm().toString());
data.add(new IntegerValue(occur[j].getOccurrences(),
Type.UNSIGNED_INT));
data.add(new IntegerValue(occur[j].getDocuments(),
Type.UNSIGNED_INT));
data.add(new IntegerValue(j + 1, Type.UNSIGNED_INT));
params[1] = data;
result.addAll(ref.evalFunction(Sequence.EMPTY_SEQUENCE, null, params));
data.clear();
}
return result;
}
}