use of org.apache.sis.internal.geoapi.filter.ValueReference in project sis by apache.
the class FeatureQuery method expectedType.
/**
* Returns the type of values evaluated by this query when executed on features of the given type.
* If some expressions have no name, default names are computed as below:
*
* <ul>
* <li>If the expression is an instance of {@link ValueReference}, the name of the
* property referenced by the {@linkplain ValueReference#getXPath() x-path}.</li>
* <li>Otherwise the localized string "Unnamed #1" with increasing numbers.</li>
* </ul>
*
* @param valueType the type of features to be evaluated by the expressions in this query.
* @return type resulting from expressions evaluation (never null).
* @throws IllegalArgumentException if this method can operate only on some feature types
* and the given type is not one of them.
* @throws IllegalArgumentException if this method can not determine the result type of an expression
* in this query. It may be because that expression is backed by an unsupported implementation.
*/
final DefaultFeatureType expectedType(final DefaultFeatureType valueType) {
if (projection == null) {
// All columns included: result is of the same type.
return valueType;
}
// Sequential number for unnamed expressions.
int unnamedNumber = 0;
// Names already used, for avoiding collisions.
Set<String> names = null;
final FeatureTypeBuilder ftb = new FeatureTypeBuilder().setName(valueType.getName());
for (int column = 0; column < projection.length; column++) {
/*
* For each property, get the expected type (mandatory) and its name (optional).
* A default name will be computed if no alias were explicitly given by user.
*/
GenericName name = projection[column].alias;
final Expression<?, ?> expression = projection[column].expression;
final FeatureExpression<?, ?> fex = FeatureExpression.castOrCopy(expression);
final PropertyTypeBuilder resultType;
if (fex == null || (resultType = fex.expectedType(valueType, ftb)) == null) {
throw new IllegalArgumentException(Resources.format(Resources.Keys.InvalidExpression_2, expression.getFunctionName().toInternationalString(), column));
}
if (name == null) {
/*
* Build a list of aliases declared by the user, for making sure that we do not collide with them.
* No check for `GenericName` collision here because it was already verified by `setProjection(…)`.
* We may have collision of their `String` representations however, which is okay.
*/
if (names == null) {
names = new HashSet<>(Containers.hashMapCapacity(projection.length));
for (final NamedExpression p : projection) {
if (p.alias != null) {
names.add(p.alias.toString());
}
}
}
/*
* If the expression is a `ValueReference`, the `PropertyType` instance can be taken directly
* from the source feature (the Apache SIS implementation does just that). If the name is set,
* then we assume that it is correct. Otherwise we take the tip of the XPath.
*/
CharSequence text = null;
if (expression instanceof ValueReference<?, ?>) {
final GenericName current = resultType.getName();
if (current != null && names.add(current.toString())) {
continue;
}
String xpath = ((ValueReference<?, ?>) expression).getXPath().trim();
// Works also if '/' is not found.
xpath = xpath.substring(xpath.lastIndexOf('/') + 1);
if (!(xpath.isEmpty() || names.contains(xpath))) {
text = xpath;
}
}
/*
* If we still have no name at this point, create a name like "Unnamed #1".
* Note that despite the use of `Vocabulary` resources, the name will be unlocalized
* (for easier programmatic use) because `GenericName` implementation is designed for
* providing localized names only if explicitly requested.
*/
if (text == null)
do {
text = Vocabulary.formatInternational(Vocabulary.Keys.Unnamed_1, ++unnamedNumber);
} while (!names.add(text.toString()));
name = Names.createLocalName(null, null, text);
}
resultType.setName(name);
}
return ftb.build();
}
Aggregations