Search in sources :

Example 1 with MappingException

use of io.micronaut.data.exceptions.MappingException in project micronaut-data by micronaut-projects.

the class MongoQueryBuilder method resolveJoinTableAssociatedFields.

@NonNull
private List<String> resolveJoinTableAssociatedFields(AnnotationMetadata annotationMetadata, boolean associationOwner, PersistentEntity entity, NamingStrategy namingStrategy) {
    List<String> joinColumns = getJoinedFields(annotationMetadata, associationOwner, "referencedColumnName");
    if (!joinColumns.isEmpty()) {
        return joinColumns;
    }
    PersistentProperty identity = entity.getIdentity();
    if (identity == null) {
        throw new MappingException("Cannot have a foreign key association without an ID on entity: " + entity.getName());
    }
    List<String> fields = new ArrayList<>();
    traversePersistentProperties(identity, (associations, property) -> {
        fields.add(asPath(associations, property));
    });
    return fields;
}
Also used : ArrayList(java.util.ArrayList) PersistentProperty(io.micronaut.data.model.PersistentProperty) MappingException(io.micronaut.data.exceptions.MappingException) NonNull(io.micronaut.core.annotation.NonNull)

Example 2 with MappingException

use of io.micronaut.data.exceptions.MappingException in project micronaut-data by micronaut-projects.

the class MongoQueryBuilder method addLookups.

private void addLookups(Collection<JoinPath> joins, QueryState queryState) {
    if (joins.isEmpty()) {
        return;
    }
    List<String> joined = joins.stream().map(JoinPath::getPath).sorted((o1, o2) -> Comparator.comparingInt(String::length).thenComparing(String::compareTo).compare(o1, o2)).collect(Collectors.toList());
    for (String join : joined) {
        StringJoiner rootPath = new StringJoiner(".");
        StringJoiner currentEntityPath = new StringJoiner(".");
        LookupsStage currentLookup = queryState.rootLookups;
        for (String path : StringUtils.splitOmitEmptyStrings(join, '.')) {
            rootPath.add(path);
            currentEntityPath.add(path);
            String thisPath = currentEntityPath.toString();
            if (currentLookup.subLookups.containsKey(thisPath)) {
                currentLookup = currentLookup.subLookups.get(path);
                currentEntityPath = new StringJoiner(".");
                continue;
            }
            PersistentPropertyPath propertyPath = currentLookup.persistentEntity.getPropertyPath(thisPath);
            PersistentProperty property = propertyPath.getProperty();
            if (!(property instanceof Association)) {
                continue;
            }
            Association association = (Association) property;
            if (association.getKind() == Relation.Kind.EMBEDDED) {
                continue;
            }
            LookupsStage lookupStage = new LookupsStage(association.getAssociatedEntity());
            List<Map<String, Object>> pipeline = currentLookup.pipeline;
            Optional<Association> inverseSide = association.getInverseSide().map(Function.identity());
            PersistentEntity persistentEntity = association.getOwner();
            String joinedCollectionName = association.getAssociatedEntity().getPersistedName();
            String ownerCollectionName = persistentEntity.getPersistedName();
            if (association.getKind() == Relation.Kind.MANY_TO_MANY || association.isForeignKey() && !inverseSide.isPresent()) {
                PersistentEntity associatedEntity = association.getAssociatedEntity();
                PersistentEntity associationOwner = association.getOwner();
                // JOIN TABLE
                PersistentProperty identity = associatedEntity.getIdentity();
                if (identity == null) {
                    throw new IllegalArgumentException("Associated entity [" + associatedEntity.getName() + "] defines no ID. Cannot join.");
                }
                final PersistentProperty associatedId = associationOwner.getIdentity();
                if (associatedId == null) {
                    throw new MappingException("Cannot join on entity [" + associationOwner.getName() + "] that has no declared ID");
                }
                Association owningAssociation = inverseSide.orElse(association);
                boolean isAssociationOwner = !association.getInverseSide().isPresent();
                NamingStrategy namingStrategy = associationOwner.getNamingStrategy();
                AnnotationMetadata annotationMetadata = owningAssociation.getAnnotationMetadata();
                List<String> ownerJoinFields = resolveJoinTableAssociatedFields(annotationMetadata, isAssociationOwner, associationOwner, namingStrategy);
                List<String> ownerJoinCollectionFields = resolveJoinTableJoinFields(annotationMetadata, isAssociationOwner, associationOwner, namingStrategy);
                List<String> associationJoinFields = resolveJoinTableAssociatedFields(annotationMetadata, !isAssociationOwner, associatedEntity, namingStrategy);
                List<String> associationJoinCollectionFields = resolveJoinTableJoinFields(annotationMetadata, !isAssociationOwner, associatedEntity, namingStrategy);
                String joinCollectionName = namingStrategy.mappedName(owningAssociation);
                // String joinTableName = annotationMetadata
                // .stringValue(ANN_JOIN_TABLE, "name")
                // .orElseGet(() -> namingStrategy.mappedName(association));
                List<Map<String, Object>> joinCollectionLookupPipeline = new ArrayList<>();
                pipeline.add(lookup(joinCollectionName, "_id", ownerCollectionName, joinCollectionLookupPipeline, thisPath));
                joinCollectionLookupPipeline.add(lookup(joinedCollectionName, joinedCollectionName, "_id", lookupStage.pipeline, joinedCollectionName));
                joinCollectionLookupPipeline.add(unwind("$" + joinedCollectionName, true));
                joinCollectionLookupPipeline.add(singletonMap("$replaceRoot", singletonMap("newRoot", "$" + joinedCollectionName)));
            } else {
                String currentPath = asPath(propertyPath.getAssociations(), propertyPath.getProperty());
                if (association.isForeignKey()) {
                    String mappedBy = association.getAnnotationMetadata().stringValue(Relation.class, "mappedBy").orElseThrow(IllegalStateException::new);
                    PersistentPropertyPath mappedByPath = association.getAssociatedEntity().getPropertyPath(mappedBy);
                    if (mappedByPath == null) {
                        throw new IllegalStateException("Cannot find mapped path: " + mappedBy);
                    }
                    if (!(mappedByPath.getProperty() instanceof Association)) {
                        throw new IllegalStateException("Expected association as a mapped path: " + mappedBy);
                    }
                    List<String> localMatchFields = new ArrayList<>();
                    List<String> foreignMatchFields = new ArrayList<>();
                    traversePersistentProperties(currentLookup.persistentEntity.getIdentity(), (associations, p) -> {
                        String fieldPath = asPath(associations, p);
                        localMatchFields.add(fieldPath);
                    });
                    List<Association> mappedAssociations = new ArrayList<>(mappedByPath.getAssociations());
                    mappedAssociations.add((Association) mappedByPath.getProperty());
                    traversePersistentProperties(mappedAssociations, currentLookup.persistentEntity.getIdentity(), (associations, p) -> {
                        String fieldPath = asPath(associations, p);
                        foreignMatchFields.add(fieldPath);
                    });
                    pipeline.add(lookup(joinedCollectionName, localMatchFields, foreignMatchFields, lookupStage.pipeline, currentPath));
                } else {
                    List<Association> mappedAssociations = new ArrayList<>(propertyPath.getAssociations());
                    mappedAssociations.add((Association) propertyPath.getProperty());
                    List<String> localMatchFields = new ArrayList<>();
                    List<String> foreignMatchFields = new ArrayList<>();
                    PersistentProperty identity = lookupStage.persistentEntity.getIdentity();
                    if (identity == null) {
                        throw new IllegalStateException("Null identity of persistent entity: " + lookupStage.persistentEntity);
                    }
                    traversePersistentProperties(mappedAssociations, identity, (associations, p) -> {
                        String fieldPath = asPath(associations, p);
                        localMatchFields.add(fieldPath);
                    });
                    traversePersistentProperties(identity, (associations, p) -> {
                        String fieldPath = asPath(associations, p);
                        foreignMatchFields.add(fieldPath);
                    });
                    pipeline.add(lookup(joinedCollectionName, localMatchFields, foreignMatchFields, lookupStage.pipeline, currentPath));
                }
                if (association.getKind().isSingleEnded()) {
                    pipeline.add(unwind("$" + currentPath, true));
                }
            }
            currentLookup.subLookups.put(currentEntityPath.toString(), lookupStage);
        }
        queryState.joinPaths.add(join);
    }
}
Also used : Arrays(java.util.Arrays) TypeRole(io.micronaut.data.annotation.TypeRole) Internal(io.micronaut.core.annotation.Internal) Collections.singletonList(java.util.Collections.singletonList) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Locale(java.util.Locale) Arrays.asList(java.util.Arrays.asList) Map(java.util.Map) QueryResult(io.micronaut.data.model.query.builder.QueryResult) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) PersistentProperty(io.micronaut.data.model.PersistentProperty) MappingException(io.micronaut.data.exceptions.MappingException) Sort(io.micronaut.data.model.Sort) Collection(java.util.Collection) Set(java.util.Set) NotNull(javax.validation.constraints.NotNull) Collectors(java.util.stream.Collectors) StringUtils(io.micronaut.core.util.StringUtils) List(java.util.List) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) Relation(io.micronaut.data.annotation.Relation) QueryParameterBinding(io.micronaut.data.model.query.builder.QueryParameterBinding) MongoAnnotations(io.micronaut.data.document.mongo.MongoAnnotations) QueryModel(io.micronaut.data.model.query.QueryModel) HashMap(java.util.HashMap) Function(java.util.function.Function) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Embedded(io.micronaut.data.model.Embedded) SerdeConfig(io.micronaut.serde.config.annotation.SerdeConfig) Nullable(io.micronaut.core.annotation.Nullable) Pageable(io.micronaut.data.model.Pageable) BiConsumer(java.util.function.BiConsumer) Collections.singletonMap(java.util.Collections.singletonMap) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Iterator(java.util.Iterator) NonNull(io.micronaut.core.annotation.NonNull) JoinPath(io.micronaut.data.model.query.JoinPath) BindingParameter(io.micronaut.data.model.query.BindingParameter) Association(io.micronaut.data.model.Association) PersistentEntity(io.micronaut.data.model.PersistentEntity) CollectionUtils(io.micronaut.core.util.CollectionUtils) StringJoiner(java.util.StringJoiner) QueryBuilder(io.micronaut.data.model.query.builder.QueryBuilder) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Comparator(java.util.Comparator) Collections(java.util.Collections) JoinPath(io.micronaut.data.model.query.JoinPath) PersistentEntity(io.micronaut.data.model.PersistentEntity) ArrayList(java.util.ArrayList) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) PersistentProperty(io.micronaut.data.model.PersistentProperty) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) MappingException(io.micronaut.data.exceptions.MappingException) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Relation(io.micronaut.data.annotation.Relation) Association(io.micronaut.data.model.Association) Map(java.util.Map) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Collections.singletonMap(java.util.Collections.singletonMap) StringJoiner(java.util.StringJoiner)

Example 3 with MappingException

use of io.micronaut.data.exceptions.MappingException in project micronaut-data by micronaut-projects.

the class SqlQueryBuilder method addTypeToColumn.

private String addTypeToColumn(PersistentProperty prop, String column, boolean required) {
    if (prop instanceof Association) {
        throw new IllegalStateException("Association is not supported here");
    }
    AnnotationMetadata annotationMetadata = prop.getAnnotationMetadata();
    String definition = annotationMetadata.stringValue(MappedProperty.class, "definition").orElse(null);
    DataType dataType = prop.getDataType();
    if (definition != null) {
        return column + " " + definition;
    }
    OptionalInt precision = annotationMetadata.intValue("javax.persistence.Column", "precision");
    OptionalInt scale = annotationMetadata.intValue("javax.persistence.Column", "scale");
    switch(dataType) {
        case STRING:
            int stringLength = annotationMetadata.findAnnotation("javax.validation.constraints.Size$List").flatMap(v -> {
                Optional value = v.getValue(AnnotationValue.class);
                return (Optional<AnnotationValue<Annotation>>) value;
            }).map(v -> v.intValue("max")).orElseGet(() -> annotationMetadata.intValue("javax.persistence.Column", "length")).orElse(255);
            column += " VARCHAR(" + stringLength + ")";
            if (required) {
                column += " NOT NULL";
            }
            break;
        case UUID:
            if (dialect == Dialect.ORACLE || dialect == Dialect.MYSQL) {
                column += " VARCHAR(36)";
            } else if (dialect == Dialect.SQL_SERVER) {
                column += " UNIQUEIDENTIFIER";
            } else {
                column += " UUID";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case BOOLEAN:
            if (dialect == Dialect.ORACLE) {
                column += " NUMBER(3)";
            } else if (dialect == Dialect.SQL_SERVER) {
                column += " BIT NOT NULL";
            } else {
                column += " BOOLEAN";
                if (required) {
                    column += " NOT NULL";
                }
            }
            break;
        case TIMESTAMP:
            if (dialect == Dialect.ORACLE) {
                column += " TIMESTAMP";
                if (required) {
                    column += " NOT NULL";
                }
            } else if (dialect == Dialect.SQL_SERVER) {
                // sql server timestamp is an internal type, use datetime instead
                column += " DATETIME2";
                if (required) {
                    column += " NOT NULL";
                }
            } else if (dialect == Dialect.MYSQL) {
                // mysql doesn't allow timestamp without default
                column += " TIMESTAMP(6) DEFAULT NOW(6)";
            } else {
                column += " TIMESTAMP";
                if (required) {
                    column += " NOT NULL";
                }
            }
            break;
        case DATE:
            column += " DATE";
            if (required) {
                column += " NOT NULL";
            }
            break;
        case LONG:
            if (dialect == Dialect.ORACLE) {
                column += " NUMBER(19)";
            } else {
                column += " BIGINT";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case CHARACTER:
            column += " CHAR(1)";
            if (required) {
                column += " NOT NULL";
            }
            break;
        case INTEGER:
            if (precision.isPresent()) {
                String numericName = dialect == Dialect.ORACLE ? "NUMBER" : "NUMERIC";
                column += " " + numericName + "(" + precision.getAsInt() + ")";
            } else if (dialect == Dialect.ORACLE) {
                column += " NUMBER(10)";
            } else if (dialect == Dialect.POSTGRES) {
                column += " INTEGER";
            } else {
                column += " INT";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case BIGDECIMAL:
            if (precision.isPresent()) {
                if (scale.isPresent()) {
                    String numericName = dialect == Dialect.ORACLE ? "NUMBER" : "NUMERIC";
                    column += " " + numericName + "(" + precision.getAsInt() + "," + scale.getAsInt() + ")";
                } else {
                    column += " FLOAT(" + precision.getAsInt() + ")";
                }
            } else if (dialect == Dialect.ORACLE) {
                column += " FLOAT(126)";
            } else {
                column += " DECIMAL";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case FLOAT:
            if (precision.isPresent()) {
                if (scale.isPresent()) {
                    String numericName = dialect == Dialect.ORACLE ? "NUMBER" : "NUMERIC";
                    column += " " + numericName + "(" + precision.getAsInt() + "," + scale.getAsInt() + ")";
                } else {
                    column += " FLOAT(" + precision.getAsInt() + ")";
                }
            } else if (dialect == Dialect.ORACLE || dialect == Dialect.SQL_SERVER) {
                column += " FLOAT(53)";
            } else if (dialect == Dialect.POSTGRES) {
                column += " REAL";
            } else {
                column += " FLOAT";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case BYTE_ARRAY:
            if (dialect == Dialect.POSTGRES) {
                column += " BYTEA";
            } else if (dialect == Dialect.SQL_SERVER) {
                column += " VARBINARY(MAX)";
            } else if (dialect == Dialect.ORACLE) {
                column += " BLOB";
            } else {
                column += " BLOB";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case DOUBLE:
            if (precision.isPresent()) {
                if (scale.isPresent()) {
                    String numericName = dialect == Dialect.ORACLE ? "NUMBER" : "NUMERIC";
                    column += " " + numericName + "(" + precision.getAsInt() + "," + scale.getAsInt() + ")";
                } else {
                    column += " FLOAT(" + precision.getAsInt() + ")";
                }
            } else if (dialect == Dialect.ORACLE) {
                column += " FLOAT(23)";
            } else if (dialect == Dialect.MYSQL || dialect == Dialect.H2) {
                column += " DOUBLE";
            } else {
                column += " DOUBLE PRECISION";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case SHORT:
        case BYTE:
            if (dialect == Dialect.ORACLE) {
                column += " NUMBER(5)";
            } else if (dialect == Dialect.POSTGRES) {
                column += " SMALLINT";
            } else {
                column += " TINYINT";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case JSON:
            switch(dialect) {
                case POSTGRES:
                    column += " JSONB";
                    break;
                case SQL_SERVER:
                    column += " NVARCHAR(MAX)";
                    break;
                case ORACLE:
                    column += " CLOB";
                    break;
                default:
                    column += " JSON";
                    break;
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case STRING_ARRAY:
        case CHARACTER_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else {
                column += " VARCHAR(255) ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case SHORT_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else if (dialect == Dialect.POSTGRES) {
                column += " SMALLINT ARRAY";
            } else {
                column += " TINYINT ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case INTEGER_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else if (dialect == Dialect.POSTGRES) {
                column += " INTEGER ARRAY";
            } else {
                column += " INT ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case LONG_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else {
                column += " BIGINT ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case FLOAT_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else if (dialect == Dialect.POSTGRES) {
                column += " REAL ARRAY";
            } else {
                column += " FLOAT ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case DOUBLE_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else if (dialect == Dialect.POSTGRES) {
                column += " DOUBLE PRECISION ARRAY";
            } else {
                column += " DOUBLE ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        case BOOLEAN_ARRAY:
            if (dialect == Dialect.H2) {
                column += " ARRAY";
            } else {
                column += " BOOLEAN ARRAY";
            }
            if (required) {
                column += " NOT NULL";
            }
            break;
        default:
            if (prop.isEnum()) {
                column += " VARCHAR(255)";
                if (required) {
                    column += " NOT NULL";
                }
                break;
            } else if (prop.isAssignable(Clob.class)) {
                if (dialect == Dialect.POSTGRES) {
                    column += " TEXT";
                } else {
                    column += " CLOB";
                }
                if (required) {
                    column += " NOT NULL";
                }
                break;
            } else if (prop.isAssignable(Blob.class)) {
                if (dialect == Dialect.POSTGRES) {
                    column += " BYTEA";
                } else {
                    column += " BLOB";
                }
                if (required) {
                    column += " NOT NULL";
                }
                break;
            } else {
                throw new MappingException("Unable to create table column for property [" + prop.getName() + "] of entity [" + prop.getOwner().getName() + "] with unknown data type: " + dataType);
            }
    }
    return column;
}
Also used : DataType(io.micronaut.data.model.DataType) SqlMembers(io.micronaut.data.annotation.sql.SqlMembers) Arrays(java.util.Arrays) IDENTITY(io.micronaut.data.annotation.GeneratedValue.Type.IDENTITY) ListIterator(java.util.ListIterator) ArrayUtils(io.micronaut.core.util.ArrayUtils) SEQUENCE(io.micronaut.data.annotation.GeneratedValue.Type.SEQUENCE) MappedProperty(io.micronaut.data.annotation.MappedProperty) GeneratedValue(io.micronaut.data.annotation.GeneratedValue) Locale(java.util.Locale) Map(java.util.Map) QueryResult(io.micronaut.data.model.query.builder.QueryResult) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) PersistentProperty(io.micronaut.data.model.PersistentProperty) Index(io.micronaut.data.annotation.Index) MappingException(io.micronaut.data.exceptions.MappingException) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) AUTO(io.micronaut.data.annotation.GeneratedValue.Type.AUTO) StringUtils(io.micronaut.core.util.StringUtils) AbstractSqlLikeQueryBuilder(io.micronaut.data.model.query.builder.AbstractSqlLikeQueryBuilder) List(java.util.List) Stream(java.util.stream.Stream) UUID(io.micronaut.data.annotation.GeneratedValue.Type.UUID) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Experimental(io.micronaut.core.annotation.Experimental) Pattern(java.util.regex.Pattern) Relation(io.micronaut.data.annotation.Relation) IntStream(java.util.stream.IntStream) QueryParameterBinding(io.micronaut.data.model.query.builder.QueryParameterBinding) Join(io.micronaut.data.annotation.Join) Creator(io.micronaut.core.annotation.Creator) QueryModel(io.micronaut.data.model.query.QueryModel) MappedEntity(io.micronaut.data.annotation.MappedEntity) HashMap(java.util.HashMap) OptionalInt(java.util.OptionalInt) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Embedded(io.micronaut.data.model.Embedded) Pageable(io.micronaut.data.model.Pageable) BiConsumer(java.util.function.BiConsumer) Clob(java.sql.Clob) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Indexes(io.micronaut.data.annotation.Indexes) NonNull(io.micronaut.core.annotation.NonNull) JoinPath(io.micronaut.data.model.query.JoinPath) Association(io.micronaut.data.model.Association) PersistentEntity(io.micronaut.data.model.PersistentEntity) CollectionUtils(io.micronaut.core.util.CollectionUtils) StringJoiner(java.util.StringJoiner) QueryBuilder(io.micronaut.data.model.query.builder.QueryBuilder) Repository(io.micronaut.data.annotation.Repository) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Blob(java.sql.Blob) Collections(java.util.Collections) Optional(java.util.Optional) OptionalInt(java.util.OptionalInt) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) MappingException(io.micronaut.data.exceptions.MappingException) Association(io.micronaut.data.model.Association) MappedProperty(io.micronaut.data.annotation.MappedProperty) DataType(io.micronaut.data.model.DataType) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Clob(java.sql.Clob)

Example 4 with MappingException

use of io.micronaut.data.exceptions.MappingException in project micronaut-data by micronaut-projects.

the class SqlQueryBuilder method buildJoin.

private void buildJoin(String joinType, StringBuilder sb, QueryState queryState, List<Association> joinAssociationsPath, String joinAlias, Association association, PersistentEntity associatedEntity, PersistentEntity associationOwner, String currentJoinAlias) {
    final boolean escape = shouldEscape(associationOwner);
    String mappedBy = association.getAnnotationMetadata().stringValue(Relation.class, "mappedBy").orElse(null);
    if (association.getKind() == Relation.Kind.MANY_TO_MANY || association.isForeignKey() && StringUtils.isEmpty(mappedBy)) {
        PersistentProperty identity = associatedEntity.getIdentity();
        if (identity == null) {
            throw new IllegalArgumentException("Associated entity [" + associatedEntity.getName() + "] defines no ID. Cannot join.");
        }
        final PersistentProperty associatedId = associationOwner.getIdentity();
        if (associatedId == null) {
            throw new MappingException("Cannot join on entity [" + associationOwner.getName() + "] that has no declared ID");
        }
        Optional<Association> inverseSide = association.getInverseSide().map(Function.identity());
        Association owningAssociation = inverseSide.orElse(association);
        boolean isAssociationOwner = !association.getInverseSide().isPresent();
        NamingStrategy namingStrategy = associationOwner.getNamingStrategy();
        AnnotationMetadata annotationMetadata = owningAssociation.getAnnotationMetadata();
        List<String> ownerJoinColumns = resolveJoinTableAssociatedColumns(annotationMetadata, isAssociationOwner, associationOwner, namingStrategy);
        List<String> ownerJoinTableColumns = resolveJoinTableJoinColumns(annotationMetadata, isAssociationOwner, associationOwner, namingStrategy);
        List<String> associationJoinColumns = resolveJoinTableAssociatedColumns(annotationMetadata, !isAssociationOwner, associatedEntity, namingStrategy);
        List<String> associationJoinTableColumns = resolveJoinTableJoinColumns(annotationMetadata, !isAssociationOwner, associatedEntity, namingStrategy);
        if (escape) {
            ownerJoinColumns = ownerJoinColumns.stream().map(this::quote).collect(Collectors.toList());
            ownerJoinTableColumns = ownerJoinTableColumns.stream().map(this::quote).collect(Collectors.toList());
            associationJoinColumns = associationJoinColumns.stream().map(this::quote).collect(Collectors.toList());
            associationJoinTableColumns = associationJoinTableColumns.stream().map(this::quote).collect(Collectors.toList());
        }
        String joinTableName = annotationMetadata.stringValue(ANN_JOIN_TABLE, "name").orElseGet(() -> namingStrategy.mappedName(association));
        String joinTableAlias = annotationMetadata.stringValue(ANN_JOIN_TABLE, "alias").orElseGet(() -> currentJoinAlias + joinTableName + "_");
        join(sb, queryState.getQueryModel(), joinType, escape ? quote(joinTableName) : joinTableName, joinTableAlias, joinAlias, ownerJoinColumns, ownerJoinTableColumns);
        sb.append(SPACE);
        join(sb, queryState.getQueryModel(), joinType, getTableName(associatedEntity), currentJoinAlias, joinTableAlias, associationJoinTableColumns, associationJoinColumns);
    } else {
        if (StringUtils.isNotEmpty(mappedBy)) {
            PersistentProperty ownerIdentity = associationOwner.getIdentity();
            if (ownerIdentity == null) {
                throw new IllegalArgumentException("Associated entity [" + associationOwner + "] defines no ID. Cannot join.");
            }
            PersistentPropertyPath mappedByPropertyPath = associatedEntity.getPropertyPath(mappedBy);
            if (mappedByPropertyPath == null) {
                throw new MappingException("Foreign key association with mappedBy references a property that doesn't exist [" + mappedBy + "] of entity: " + associatedEntity.getName());
            }
            join(sb, joinType, queryState, associatedEntity, associationOwner, joinAlias, currentJoinAlias, joinAssociationsPath, ownerIdentity, mappedByPropertyPath.getAssociations(), mappedByPropertyPath.getProperty());
        } else {
            PersistentProperty associatedProperty = association.getAssociatedEntity().getIdentity();
            if (associatedProperty == null) {
                throw new IllegalArgumentException("Associated entity [" + association.getAssociatedEntity().getName() + "] defines no ID. Cannot join.");
            }
            join(sb, joinType, queryState, associatedEntity, associationOwner, joinAlias, currentJoinAlias, joinAssociationsPath, association, Collections.emptyList(), associatedProperty);
        }
    }
}
Also used : NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Relation(io.micronaut.data.annotation.Relation) Association(io.micronaut.data.model.Association) PersistentProperty(io.micronaut.data.model.PersistentProperty) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) MappingException(io.micronaut.data.exceptions.MappingException)

Example 5 with MappingException

use of io.micronaut.data.exceptions.MappingException in project micronaut-data by micronaut-projects.

the class SqlQueryBuilder method join.

private void join(StringBuilder sb, String joinType, QueryState queryState, PersistentEntity associatedEntity, PersistentEntity associationOwner, String leftTableAlias, String rightTableAlias, List<Association> leftPropertyAssociations, PersistentProperty leftProperty, List<Association> rightPropertyAssociations, PersistentProperty rightProperty) {
    final boolean escape = shouldEscape(associationOwner);
    List<String> onLeftColumns = new ArrayList<>();
    List<String> onRightColumns = new ArrayList<>();
    Association association = null;
    if (leftProperty instanceof Association) {
        association = (Association) leftProperty;
    } else if (rightProperty instanceof Association) {
        association = (Association) rightProperty;
    }
    if (association != null) {
        Optional<Association> inverse = association.getInverseSide().map(Function.identity());
        Association owner = inverse.orElse(association);
        boolean isOwner = leftProperty == owner;
        AnnotationValue<Annotation> joinColumnsHolder = owner.getAnnotationMetadata().getAnnotation(ANN_JOIN_COLUMNS);
        if (joinColumnsHolder != null) {
            onLeftColumns.addAll(joinColumnsHolder.getAnnotations("value").stream().map(ann -> ann.stringValue(isOwner ? "name" : "referencedColumnName").orElse(null)).filter(Objects::nonNull).collect(Collectors.toList()));
            onRightColumns.addAll(joinColumnsHolder.getAnnotations("value").stream().map(ann -> ann.stringValue(isOwner ? "referencedColumnName" : "name").orElse(null)).filter(Objects::nonNull).collect(Collectors.toList()));
        }
    }
    if (onLeftColumns.isEmpty()) {
        traversePersistentProperties(leftProperty, (associations, p) -> {
            String column = leftProperty.getOwner().getNamingStrategy().mappedName(merge(leftPropertyAssociations, associations), p);
            onLeftColumns.add(column);
        });
        if (onLeftColumns.isEmpty()) {
            throw new MappingException("Cannot join on entity [" + leftProperty.getOwner().getName() + "] that has no declared ID");
        }
    }
    if (onRightColumns.isEmpty()) {
        traversePersistentProperties(rightProperty, (associations, p) -> {
            String column = rightProperty.getOwner().getNamingStrategy().mappedName(merge(rightPropertyAssociations, associations), p);
            onRightColumns.add(column);
        });
    }
    join(sb, queryState.getQueryModel(), joinType, getTableName(associatedEntity), rightTableAlias, leftTableAlias, escape ? onLeftColumns.stream().map(this::quote).collect(Collectors.toList()) : onLeftColumns, escape ? onRightColumns.stream().map(this::quote).collect(Collectors.toList()) : onRightColumns);
}
Also used : DataType(io.micronaut.data.model.DataType) SqlMembers(io.micronaut.data.annotation.sql.SqlMembers) Arrays(java.util.Arrays) IDENTITY(io.micronaut.data.annotation.GeneratedValue.Type.IDENTITY) ListIterator(java.util.ListIterator) ArrayUtils(io.micronaut.core.util.ArrayUtils) SEQUENCE(io.micronaut.data.annotation.GeneratedValue.Type.SEQUENCE) MappedProperty(io.micronaut.data.annotation.MappedProperty) GeneratedValue(io.micronaut.data.annotation.GeneratedValue) Locale(java.util.Locale) Map(java.util.Map) QueryResult(io.micronaut.data.model.query.builder.QueryResult) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) PersistentPropertyPath(io.micronaut.data.model.PersistentPropertyPath) PersistentProperty(io.micronaut.data.model.PersistentProperty) Index(io.micronaut.data.annotation.Index) MappingException(io.micronaut.data.exceptions.MappingException) Collection(java.util.Collection) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) AUTO(io.micronaut.data.annotation.GeneratedValue.Type.AUTO) StringUtils(io.micronaut.core.util.StringUtils) AbstractSqlLikeQueryBuilder(io.micronaut.data.model.query.builder.AbstractSqlLikeQueryBuilder) List(java.util.List) Stream(java.util.stream.Stream) UUID(io.micronaut.data.annotation.GeneratedValue.Type.UUID) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) Experimental(io.micronaut.core.annotation.Experimental) Pattern(java.util.regex.Pattern) Relation(io.micronaut.data.annotation.Relation) IntStream(java.util.stream.IntStream) QueryParameterBinding(io.micronaut.data.model.query.builder.QueryParameterBinding) Join(io.micronaut.data.annotation.Join) Creator(io.micronaut.core.annotation.Creator) QueryModel(io.micronaut.data.model.query.QueryModel) MappedEntity(io.micronaut.data.annotation.MappedEntity) HashMap(java.util.HashMap) OptionalInt(java.util.OptionalInt) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Embedded(io.micronaut.data.model.Embedded) Pageable(io.micronaut.data.model.Pageable) BiConsumer(java.util.function.BiConsumer) Clob(java.sql.Clob) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) Indexes(io.micronaut.data.annotation.Indexes) NonNull(io.micronaut.core.annotation.NonNull) JoinPath(io.micronaut.data.model.query.JoinPath) Association(io.micronaut.data.model.Association) PersistentEntity(io.micronaut.data.model.PersistentEntity) CollectionUtils(io.micronaut.core.util.CollectionUtils) StringJoiner(java.util.StringJoiner) QueryBuilder(io.micronaut.data.model.query.builder.QueryBuilder) Repository(io.micronaut.data.annotation.Repository) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Blob(java.sql.Blob) Collections(java.util.Collections) Association(io.micronaut.data.model.Association) ArrayList(java.util.ArrayList) Objects(java.util.Objects) Annotation(java.lang.annotation.Annotation) MappingException(io.micronaut.data.exceptions.MappingException)

Aggregations

MappingException (io.micronaut.data.exceptions.MappingException)6 PersistentProperty (io.micronaut.data.model.PersistentProperty)6 NonNull (io.micronaut.core.annotation.NonNull)5 ArrayList (java.util.ArrayList)5 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)4 Relation (io.micronaut.data.annotation.Relation)4 Association (io.micronaut.data.model.Association)4 PersistentPropertyPath (io.micronaut.data.model.PersistentPropertyPath)4 NamingStrategy (io.micronaut.data.model.naming.NamingStrategy)4 ArgumentUtils (io.micronaut.core.util.ArgumentUtils)3 CollectionUtils (io.micronaut.core.util.CollectionUtils)3 StringUtils (io.micronaut.core.util.StringUtils)3 Embedded (io.micronaut.data.model.Embedded)3 Pageable (io.micronaut.data.model.Pageable)3 PersistentEntity (io.micronaut.data.model.PersistentEntity)3 JoinPath (io.micronaut.data.model.query.JoinPath)3 QueryModel (io.micronaut.data.model.query.QueryModel)3 QueryBuilder (io.micronaut.data.model.query.builder.QueryBuilder)3 QueryParameterBinding (io.micronaut.data.model.query.builder.QueryParameterBinding)3 QueryResult (io.micronaut.data.model.query.builder.QueryResult)3