Search in sources :

Example 11 with FeatureTypeBuilder

use of org.apache.sis.feature.builder.FeatureTypeBuilder in project sis by apache.

the class ConcatenatedFeatureSetTest method testCommonSuperType.

/**
 * Tests the concatenation of two feature sets having different feature types.
 *
 * @throws DataStoreException if an error occurred while concatenating the feature sets.
 */
@Test
@DependsOnMethod("testSameType")
public void testCommonSuperType() throws DataStoreException {
    /*
         * First, we prepare two types sharing a common ancestor. We'll create two types using same properties,
         * so we can ensure that all data is exposed upon traversal, not only data defined in the super type.
         */
    final FeatureTypeBuilder builder = new FeatureTypeBuilder();
    builder.addAttribute(Integer.class).setName("value");
    builder.setName("parent");
    final DefaultFeatureType superType = builder.build();
    builder.clear();
    builder.setSuperTypes(superType);
    builder.addAttribute(String.class).setName("label");
    final DefaultFeatureType t1 = builder.setName("t1").build();
    final DefaultFeatureType t2 = builder.setName("t2").build();
    // Populate a feature set for first type.
    final AbstractFeature t1f1 = t1.newInstance();
    t1f1.setPropertyValue("value", 2);
    t1f1.setPropertyValue("label", "first-first");
    final AbstractFeature t1f2 = t1.newInstance();
    t1f2.setPropertyValue("value", 3);
    t1f2.setPropertyValue("label", "first-second");
    final FeatureSet t1fs = new MemoryFeatureSet(null, t1, Arrays.asList(t1f1, t1f2));
    // Populate a feature set for second type.
    final AbstractFeature t2f1 = t2.newInstance();
    t2f1.setPropertyValue("value", 3);
    t2f1.setPropertyValue("label", "second-first");
    final AbstractFeature t2f2 = t2.newInstance();
    t2f2.setPropertyValue("value", 4);
    t2f2.setPropertyValue("label", "second-second");
    final FeatureSet t2fs = new MemoryFeatureSet(null, t2, Arrays.asList(t2f1, t2f2));
    /*
         * First, we'll test that total sum of value property is coherent with initialized features.
         * After that, we will ensure that we can get back the right labels for each subtype.
         */
    final FeatureSet set = ConcatenatedFeatureSet.create(t1fs, t2fs);
    final int sum = set.features(true).mapToInt(f -> (int) f.getPropertyValue("value")).sum();
    assertEquals("Sum of feature `value` property", 12, sum);
    final Object[] t1labels = set.features(false).filter(f -> t1.equals(f.getType())).map(f -> f.getPropertyValue("label")).toArray();
    assertArrayEquals("First type labels", new String[] { "first-first", "first-second" }, t1labels);
    final Object[] t2labels = set.features(false).filter(f -> t2.equals(f.getType())).map(f -> f.getPropertyValue("label")).toArray();
    assertArrayEquals("First type labels", new String[] { "second-first", "second-second" }, t2labels);
}
Also used : Arrays(java.util.Arrays) MetadataAssert(org.apache.sis.test.MetadataAssert) FeatureTypeBuilder(org.apache.sis.feature.builder.FeatureTypeBuilder) DefaultMetadata(org.apache.sis.metadata.iso.DefaultMetadata) Metadata(org.opengis.metadata.Metadata) FeatureCatalogueDescription(org.opengis.metadata.content.FeatureCatalogueDescription) Lineage(org.opengis.metadata.lineage.Lineage) Test(org.junit.Test) TestUtilities.getSingleton(org.apache.sis.test.TestUtilities.getSingleton) DefaultFeatureType(org.apache.sis.feature.DefaultFeatureType) DataStoreContentException(org.apache.sis.storage.DataStoreContentException) FeatureSet(org.apache.sis.storage.FeatureSet) DependsOnMethod(org.apache.sis.test.DependsOnMethod) TestCase(org.apache.sis.test.TestCase) DataStoreException(org.apache.sis.storage.DataStoreException) AbstractFeature(org.apache.sis.feature.AbstractFeature) Collections(java.util.Collections) FeatureTypeBuilder(org.apache.sis.feature.builder.FeatureTypeBuilder) DefaultFeatureType(org.apache.sis.feature.DefaultFeatureType) AbstractFeature(org.apache.sis.feature.AbstractFeature) FeatureSet(org.apache.sis.storage.FeatureSet) Test(org.junit.Test) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Example 12 with FeatureTypeBuilder

use of org.apache.sis.feature.builder.FeatureTypeBuilder in project sis by apache.

the class ConcatenatedFeatureSetTest method noCommonType.

/**
 * Tests the concatenation of two feature sets having no common parent.
 * Creation of {@link ConcatenatedFeatureSet} is expected to fail.
 */
@Test
@DependsOnMethod("testCommonSuperType")
public void noCommonType() {
    final FeatureTypeBuilder builder = new FeatureTypeBuilder();
    builder.setName("super");
    final DefaultFeatureType mockSuperType = builder.build();
    final DefaultFeatureType firstType = builder.setSuperTypes(mockSuperType).setName("first").build();
    final DefaultFeatureType secondType = builder.clear().setName("second").build();
    final FeatureSet fs1 = new MemoryFeatureSet(null, firstType, Collections.emptyList());
    final FeatureSet fs2 = new MemoryFeatureSet(null, secondType, Collections.emptyList());
    try {
        FeatureSet concatenation = ConcatenatedFeatureSet.create(fs1, fs2);
        fail("Concatenation succeeded despite the lack of common type. Result is:\n" + concatenation);
    } catch (DataStoreContentException e) {
    // Expected behavior.
    } catch (DataStoreException e) {
        fail("Concatenation failed with an error reserved for other kind of error.");
    }
}
Also used : FeatureTypeBuilder(org.apache.sis.feature.builder.FeatureTypeBuilder) DataStoreException(org.apache.sis.storage.DataStoreException) DataStoreContentException(org.apache.sis.storage.DataStoreContentException) DefaultFeatureType(org.apache.sis.feature.DefaultFeatureType) FeatureSet(org.apache.sis.storage.FeatureSet) Test(org.junit.Test) DependsOnMethod(org.apache.sis.test.DependsOnMethod)

Example 13 with FeatureTypeBuilder

use of org.apache.sis.feature.builder.FeatureTypeBuilder 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)13 Test (org.junit.Test)10 AbstractFeature (org.apache.sis.feature.AbstractFeature)7 DefaultFeatureType (org.apache.sis.feature.DefaultFeatureType)7 FeatureSet (org.apache.sis.storage.FeatureSet)4 DefaultMetadata (org.apache.sis.metadata.iso.DefaultMetadata)2 DataStoreContentException (org.apache.sis.storage.DataStoreContentException)2 DataStoreException (org.apache.sis.storage.DataStoreException)2 DependsOnMethod (org.apache.sis.test.DependsOnMethod)2 Metadata (org.opengis.metadata.Metadata)2 Lineage (org.opengis.metadata.lineage.Lineage)2 Arrays (java.util.Arrays)1 Collections (java.util.Collections)1 PropertyTypeBuilder (org.apache.sis.feature.builder.PropertyTypeBuilder)1 Optimization (org.apache.sis.filter.Optimization)1 GeometryWrapper (org.apache.sis.internal.feature.GeometryWrapper)1 ValueReference (org.apache.sis.internal.geoapi.filter.ValueReference)1 MetadataAssert (org.apache.sis.test.MetadataAssert)1 TestCase (org.apache.sis.test.TestCase)1 TestUtilities.getSingleton (org.apache.sis.test.TestUtilities.getSingleton)1