use of io.micronaut.data.model.Association 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;
}
use of io.micronaut.data.model.Association 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);
}
}
}
use of io.micronaut.data.model.Association in project micronaut-data by micronaut-projects.
the class AbstractMongoCollectionsCreator method initialize.
/**
* Initialize the collections.
*
* @param runtimeEntityRegistry The entity registry
* @param mongoConfigurations The configuration
* @param databaseOperationsProvider The database provider
*/
protected void initialize(RuntimeEntityRegistry runtimeEntityRegistry, List<AbstractMongoConfiguration> mongoConfigurations, DatabaseOperationsProvider<Dtbs> databaseOperationsProvider) {
for (AbstractMongoConfiguration mongoConfiguration : mongoConfigurations) {
// TODO: different initializer per conf
Collection<BeanIntrospection<Object>> introspections = BeanIntrospector.SHARED.findIntrospections(MappedEntity.class);
PersistentEntity[] entities = introspections.stream().filter(i -> !i.getBeanType().getName().contains("$")).filter(i -> !java.lang.reflect.Modifier.isAbstract(i.getBeanType().getModifiers())).map(e -> runtimeEntityRegistry.getEntity(e.getBeanType())).toArray(PersistentEntity[]::new);
DatabaseOperations<Dtbs> databaseOperations = databaseOperationsProvider.get(mongoConfiguration);
for (PersistentEntity entity : entities) {
Dtbs database = databaseOperations.find(entity);
Set<String> collections = databaseOperations.listCollectionNames(database);
String persistedName = entity.getPersistedName();
if (collections.add(persistedName)) {
if (LOG.isInfoEnabled()) {
LOG.info("Creating collection: {} in database: {}", persistedName, databaseOperations.getDatabaseName(database));
}
databaseOperations.createCollection(database, persistedName);
}
for (PersistentProperty persistentProperty : entity.getPersistentProperties()) {
if (persistentProperty instanceof Association) {
Association association = (Association) persistentProperty;
Optional<Association> inverseSide = association.getInverseSide().map(Function.identity());
if (association.getKind() == Relation.Kind.MANY_TO_MANY || association.isForeignKey() && !inverseSide.isPresent()) {
Association owningAssociation = inverseSide.orElse(association);
NamingStrategy namingStrategy = association.getOwner().getNamingStrategy();
String joinCollectionName = namingStrategy.mappedName(owningAssociation);
if (collections.add(joinCollectionName)) {
if (LOG.isInfoEnabled()) {
LOG.info("Creating collection: {} in database: {}", persistedName, databaseOperations.getDatabaseName(database));
}
databaseOperations.createCollection(database, joinCollectionName);
}
}
}
}
}
}
}
use of io.micronaut.data.model.Association in project micronaut-data by micronaut-projects.
the class AbstractSqlLikeQueryBuilder method traversePersistentProperties.
private void traversePersistentProperties(List<Association> associations, PersistentProperty property, BiConsumer<List<Association>, PersistentProperty> consumerProperty) {
if (property instanceof Embedded) {
Embedded embedded = (Embedded) property;
PersistentEntity embeddedEntity = embedded.getAssociatedEntity();
Collection<? extends PersistentProperty> embeddedProperties = embeddedEntity.getPersistentProperties();
List<Association> newAssociations = new ArrayList<>(associations);
newAssociations.add((Association) property);
for (PersistentProperty embeddedProperty : embeddedProperties) {
traversePersistentProperties(newAssociations, embeddedProperty, consumerProperty);
}
} else if (property instanceof Association) {
Association association = (Association) property;
if (association.isForeignKey()) {
return;
}
List<Association> newAssociations = new ArrayList<>(associations);
newAssociations.add((Association) property);
PersistentEntity associatedEntity = association.getAssociatedEntity();
PersistentProperty assocIdentity = associatedEntity.getIdentity();
if (assocIdentity == null) {
throw new IllegalStateException("Identity cannot be missing for: " + associatedEntity);
}
if (assocIdentity instanceof Association) {
traversePersistentProperties(newAssociations, assocIdentity, consumerProperty);
} else {
consumerProperty.accept(newAssociations, assocIdentity);
}
} else {
consumerProperty.accept(associations, property);
}
}
use of io.micronaut.data.model.Association in project micronaut-data by micronaut-projects.
the class AbstractSqlLikeQueryBuilder method buildSelect.
private void buildSelect(QueryState queryState, StringBuilder queryString, List<QueryModel.Projection> projectionList, String tableAlias, PersistentEntity entity) {
if (projectionList.isEmpty()) {
selectAllColumns(queryState, queryString);
} else {
for (Iterator i = projectionList.iterator(); i.hasNext(); ) {
QueryModel.Projection projection = (QueryModel.Projection) i.next();
if (projection instanceof QueryModel.LiteralProjection) {
queryString.append(asLiteral(((QueryModel.LiteralProjection) projection).getValue()));
} else if (projection instanceof QueryModel.CountProjection) {
appendProjectionRowCount(queryString, tableAlias);
} else if (projection instanceof QueryModel.DistinctProjection) {
queryString.append("DISTINCT(").append(tableAlias).append(CLOSE_BRACKET);
} else if (projection instanceof QueryModel.IdProjection) {
if (entity.hasCompositeIdentity()) {
for (PersistentProperty identity : entity.getCompositeIdentity()) {
appendPropertyProjection(queryString, asQueryPropertyPath(queryState.getRootAlias(), identity));
queryString.append(COMMA);
}
queryString.setLength(queryString.length() - 1);
} else if (entity.hasIdentity()) {
PersistentProperty identity = entity.getIdentity();
if (identity == null) {
throw new IllegalArgumentException("Cannot query on ID with entity that has no ID");
}
appendPropertyProjection(queryString, asQueryPropertyPath(queryState.getRootAlias(), identity));
} else {
throw new IllegalArgumentException("Cannot query on ID with entity that has no ID");
}
} else if (projection instanceof QueryModel.PropertyProjection) {
QueryModel.PropertyProjection pp = (QueryModel.PropertyProjection) projection;
String alias = pp.getAlias().orElse(null);
if (projection instanceof QueryModel.AvgProjection) {
appendFunctionProjection(queryState.getEntity(), AVG, pp, tableAlias, queryString);
} else if (projection instanceof QueryModel.DistinctPropertyProjection) {
appendFunctionProjection(queryState.getEntity(), DISTINCT, pp, tableAlias, queryString);
} else if (projection instanceof QueryModel.SumProjection) {
appendFunctionProjection(queryState.getEntity(), SUM, pp, tableAlias, queryString);
} else if (projection instanceof QueryModel.MinProjection) {
appendFunctionProjection(queryState.getEntity(), MIN, pp, tableAlias, queryString);
} else if (projection instanceof QueryModel.MaxProjection) {
appendFunctionProjection(queryState.getEntity(), MAX, pp, tableAlias, queryString);
} else if (projection instanceof QueryModel.CountDistinctProjection) {
appendFunctionProjection(queryState.getEntity(), COUNT_DISTINCT, pp, tableAlias, queryString);
queryString.append(CLOSE_BRACKET);
} else {
String propertyName = pp.getPropertyName();
PersistentPropertyPath propertyPath = entity.getPropertyPath(propertyName);
if (propertyPath == null) {
throw new IllegalArgumentException("Cannot project on non-existent property: " + propertyName);
}
PersistentProperty property = propertyPath.getProperty();
if (property instanceof Association && !(property instanceof Embedded)) {
if (!queryState.isJoined(propertyPath.getPath())) {
queryString.setLength(queryString.length() - 1);
continue;
}
String joinAlias = queryState.computeAlias(propertyPath.getPath());
selectAllColumns(((Association) property).getAssociatedEntity(), joinAlias, queryString);
} else {
appendPropertyProjection(queryString, findProperty(queryState, propertyName, null));
}
}
if (alias != null) {
queryString.append(AS_CLAUSE).append(alias);
}
}
if (i.hasNext()) {
queryString.append(COMMA);
}
}
}
}
Aggregations