Search in sources :

Example 1 with ValueReference

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();
}
Also used : FeatureTypeBuilder(org.apache.sis.feature.builder.FeatureTypeBuilder) PropertyTypeBuilder(org.apache.sis.feature.builder.PropertyTypeBuilder) GenericName(org.opengis.util.GenericName) ValueReference(org.apache.sis.internal.geoapi.filter.ValueReference)

Aggregations

FeatureTypeBuilder (org.apache.sis.feature.builder.FeatureTypeBuilder)1 PropertyTypeBuilder (org.apache.sis.feature.builder.PropertyTypeBuilder)1 ValueReference (org.apache.sis.internal.geoapi.filter.ValueReference)1 GenericName (org.opengis.util.GenericName)1