use of io.micronaut.data.model.PersistentPropertyPath in project micronaut-data by micronaut-projects.
the class AbstractSqlLikeQueryBuilder method appendFunctionProjection.
private void appendFunctionProjection(PersistentEntity entity, String functionName, QueryModel.PropertyProjection propertyProjection, String tableAlias, StringBuilder queryString) {
PersistentPropertyPath propertyPath = entity.getPropertyPath(propertyProjection.getPropertyName());
if (propertyPath == null) {
throw new IllegalArgumentException("Cannot project on non-existent property: " + propertyProjection.getPropertyName());
}
String columnName;
if (computePropertyPaths()) {
columnName = entity.getNamingStrategy().mappedName(propertyPath.getAssociations(), propertyPath.getProperty());
if (shouldEscape(entity)) {
columnName = quote(columnName);
}
} else {
columnName = propertyPath.getPath();
}
queryString.append(functionName).append(OPEN_BRACKET).append(tableAlias).append(DOT).append(columnName).append(CLOSE_BRACKET);
}
use of io.micronaut.data.model.PersistentPropertyPath in project micronaut-data by micronaut-projects.
the class AbstractSqlLikeQueryBuilder method findPropertyInternal.
private QueryPropertyPath findPropertyInternal(QueryState queryState, PersistentEntity entity, String tableAlias, String name, Class criterionType) {
PersistentPropertyPath propertyPath = entity.getPropertyPath(name);
if (propertyPath != null) {
if (propertyPath.getAssociations().isEmpty()) {
return new QueryPropertyPath(propertyPath, tableAlias);
}
Association joinAssociation = null;
StringJoiner joinPathJoiner = new StringJoiner(".");
String lastJoinAlias = null;
for (Association association : propertyPath.getAssociations()) {
joinPathJoiner.add(association.getName());
if (association instanceof Embedded) {
continue;
}
if (joinAssociation == null) {
joinAssociation = association;
continue;
}
if (association != joinAssociation.getAssociatedEntity().getIdentity()) {
if (!queryState.isAllowJoins()) {
throw new IllegalArgumentException("Joins cannot be used in a DELETE or UPDATE operation");
}
String joinStringPath = joinPathJoiner.toString();
if (!queryState.isJoined(joinStringPath)) {
throw new IllegalArgumentException("Property is not joined at path: " + joinStringPath);
}
lastJoinAlias = joinInPath(queryState, joinStringPath);
// Continue to look for a joined property
joinAssociation = association;
} else {
// We don't need to join to access the id of the relation
joinAssociation = null;
}
}
PersistentProperty property = propertyPath.getProperty();
if (joinAssociation != null) {
// We don't need to join to access the id of the relation if it is not a foreign key association
if (property != joinAssociation.getAssociatedEntity().getIdentity() || joinAssociation.isForeignKey()) {
String joinStringPath = joinPathJoiner.toString();
if (!queryState.isJoined(joinStringPath)) {
throw new IllegalArgumentException("Property is not joined at path: " + joinStringPath);
}
if (lastJoinAlias == null) {
lastJoinAlias = joinInPath(queryState, joinPathJoiner.toString());
}
}
if (lastJoinAlias != null) {
// 'joinPath.prop' should be represented as a path of 'prop' with a join alias
return new QueryPropertyPath(new PersistentPropertyPath(Collections.emptyList(), property, property.getName()), lastJoinAlias);
}
}
} else if (TypeRole.ID.equals(name) && entity.getIdentity() != null) {
// special case handling for ID
return new QueryPropertyPath(new PersistentPropertyPath(Collections.emptyList(), entity.getIdentity(), entity.getIdentity().getName()), queryState.getRootAlias());
}
if (propertyPath == null) {
if (criterionType == null || criterionType == Sort.Order.class) {
throw new IllegalArgumentException("Cannot order on non-existent property path: " + name);
} else {
throw new IllegalArgumentException("Cannot use [" + criterionType.getSimpleName() + "] criterion on non-existent property path: " + name);
}
}
return new QueryPropertyPath(propertyPath, tableAlias);
}
use of io.micronaut.data.model.PersistentPropertyPath in project micronaut-data by micronaut-projects.
the class SqlQueryBuilder method buildCreateTableStatements.
/**
* Builds the create table statement. Designed for testing and not production usage. For production a
* SQL migration tool such as Flyway or Liquibase is recommended.
*
* @param entity The entity
* @return The tables for the give entity
*/
@Experimental
@NonNull
public String[] buildCreateTableStatements(@NonNull PersistentEntity entity) {
ArgumentUtils.requireNonNull("entity", entity);
final String unescapedTableName = getUnescapedTableName(entity);
String tableName = getTableName(entity);
boolean escape = shouldEscape(entity);
PersistentProperty identity = entity.getIdentity();
List<String> createStatements = new ArrayList<>();
String schema = entity.getAnnotationMetadata().stringValue(MappedEntity.class, SqlMembers.SCHEMA).orElse(null);
if (StringUtils.isNotEmpty(schema)) {
if (escape) {
schema = quote(schema);
}
createStatements.add("CREATE SCHEMA " + schema + ";");
}
Collection<Association> foreignKeyAssociations = getJoinTableAssociations(entity);
NamingStrategy namingStrategy = entity.getNamingStrategy();
if (CollectionUtils.isNotEmpty(foreignKeyAssociations)) {
for (Association association : foreignKeyAssociations) {
StringBuilder joinTableBuilder = new StringBuilder("CREATE TABLE ");
PersistentEntity associatedEntity = association.getAssociatedEntity();
Optional<Association> inverseSide = association.getInverseSide().map(Function.identity());
Association owningAssociation = inverseSide.orElse(association);
AnnotationMetadata annotationMetadata = owningAssociation.getAnnotationMetadata();
String joinTableName = annotationMetadata.stringValue(ANN_JOIN_TABLE, "name").orElseGet(() -> namingStrategy.mappedName(association));
if (escape) {
joinTableName = quote(joinTableName);
}
joinTableBuilder.append(joinTableName).append(" (");
List<PersistentPropertyPath> leftProperties = new ArrayList<>();
List<PersistentPropertyPath> rightProperties = new ArrayList<>();
boolean isAssociationOwner = !inverseSide.isPresent();
List<String> leftJoinTableColumns = resolveJoinTableJoinColumns(annotationMetadata, isAssociationOwner, entity, namingStrategy);
List<String> rightJoinTableColumns = resolveJoinTableJoinColumns(annotationMetadata, !isAssociationOwner, association.getAssociatedEntity(), namingStrategy);
traversePersistentProperties(entity.getIdentity(), (associations, property) -> {
leftProperties.add(PersistentPropertyPath.of(associations, property, ""));
});
traversePersistentProperties(associatedEntity.getIdentity(), (associations, property) -> {
rightProperties.add(PersistentPropertyPath.of(associations, property, ""));
});
if (leftJoinTableColumns.size() == leftProperties.size()) {
for (int i = 0; i < leftJoinTableColumns.size(); i++) {
PersistentPropertyPath pp = leftProperties.get(i);
String columnName = leftJoinTableColumns.get(i);
if (escape) {
columnName = quote(columnName);
}
joinTableBuilder.append(addTypeToColumn(pp.getProperty(), columnName, true)).append(',');
}
} else {
for (PersistentPropertyPath pp : leftProperties) {
String columnName = namingStrategy.mappedJoinTableColumn(entity, pp.getAssociations(), pp.getProperty());
if (escape) {
columnName = quote(columnName);
}
joinTableBuilder.append(addTypeToColumn(pp.getProperty(), columnName, true)).append(',');
}
}
if (rightJoinTableColumns.size() == rightProperties.size()) {
for (int i = 0; i < rightJoinTableColumns.size(); i++) {
PersistentPropertyPath pp = rightProperties.get(i);
String columnName = rightJoinTableColumns.get(i);
if (escape) {
columnName = quote(columnName);
}
joinTableBuilder.append(addTypeToColumn(pp.getProperty(), columnName, true)).append(',');
}
} else {
for (PersistentPropertyPath pp : rightProperties) {
String columnName = namingStrategy.mappedJoinTableColumn(entity, pp.getAssociations(), pp.getProperty());
if (escape) {
columnName = quote(columnName);
}
joinTableBuilder.append(addTypeToColumn(pp.getProperty(), columnName, true)).append(',');
}
}
joinTableBuilder.setLength(joinTableBuilder.length() - 1);
joinTableBuilder.append(")");
if (dialect != Dialect.ORACLE) {
joinTableBuilder.append(';');
}
createStatements.add(joinTableBuilder.toString());
}
}
boolean generatePkAfterColumns = false;
List<String> primaryColumnsName = new ArrayList<>();
List<String> columns = new ArrayList<>();
if (identity != null) {
List<PersistentPropertyPath> ids = new ArrayList<>();
traversePersistentProperties(identity, (associations, property) -> {
ids.add(PersistentPropertyPath.of(associations, property, ""));
});
if (ids.size() > 1) {
generatePkAfterColumns = true;
}
boolean finalGeneratePkAfterColumns = generatePkAfterColumns;
for (PersistentPropertyPath pp : ids) {
String column = namingStrategy.mappedName(pp.getAssociations(), pp.getProperty());
if (escape) {
column = quote(column);
}
primaryColumnsName.add(column);
column = addTypeToColumn(pp.getProperty(), column, isRequired(pp.getAssociations(), pp.getProperty()));
if (isNotForeign(pp.getAssociations())) {
column = addGeneratedStatementToColumn(pp.getProperty(), column, !finalGeneratePkAfterColumns);
}
columns.add(column);
}
}
PersistentProperty version = entity.getVersion();
if (version != null) {
String column = namingStrategy.mappedName(Collections.emptyList(), version);
if (escape) {
column = quote(column);
}
column = addTypeToColumn(version, column, true);
columns.add(column);
}
BiConsumer<List<Association>, PersistentProperty> addColumn = (associations, property) -> {
String column = namingStrategy.mappedName(associations, property);
if (escape) {
column = quote(column);
}
column = addTypeToColumn(property, column, isRequired(associations, property));
if (isNotForeign(associations)) {
column = addGeneratedStatementToColumn(property, column, false);
}
columns.add(column);
};
for (PersistentProperty prop : entity.getPersistentProperties()) {
traversePersistentProperties(prop, addColumn);
}
StringBuilder builder = new StringBuilder("CREATE TABLE ").append(tableName).append(" (");
builder.append(String.join(",", columns));
if (generatePkAfterColumns) {
builder.append(", PRIMARY KEY(").append(String.join(",", primaryColumnsName)).append(')');
}
if (dialect == Dialect.ORACLE) {
builder.append(")");
} else {
builder.append(");");
}
if (identity != null && identity.isGenerated()) {
GeneratedValue.Type idGeneratorType = identity.getAnnotationMetadata().enumValue(GeneratedValue.class, GeneratedValue.Type.class).orElseGet(() -> selectAutoStrategy(identity));
boolean isSequence = idGeneratorType == GeneratedValue.Type.SEQUENCE;
final String generatedDefinition = identity.getAnnotationMetadata().stringValue(GeneratedValue.class, "definition").orElse(null);
if (generatedDefinition != null) {
createStatements.add(generatedDefinition);
} else if (isSequence) {
final boolean isSqlServer = dialect == Dialect.SQL_SERVER;
final String sequenceName = quote(unescapedTableName + SEQ_SUFFIX);
String createSequenceStmt = "CREATE SEQUENCE " + sequenceName;
if (isSqlServer) {
createSequenceStmt += " AS BIGINT";
}
createSequenceStmt += " MINVALUE 1 START WITH 1";
if (dialect == Dialect.ORACLE) {
createSequenceStmt += " NOCACHE NOCYCLE";
} else {
if (isSqlServer) {
createSequenceStmt += " INCREMENT BY 1";
}
}
createStatements.add(createSequenceStmt);
}
}
createStatements.add(builder.toString());
addIndexes(entity, tableName, createStatements);
return createStatements.toArray(new String[0]);
}
use of io.micronaut.data.model.PersistentPropertyPath in project micronaut-data by micronaut-projects.
the class AbstractCriteriaBuilder method parameter.
@Override
@NonNull
public <T> ParameterExpression<T> parameter(@NonNull Class<T> paramClass, @NonNull String name) {
return new ParameterExpressionImpl<T>(paramClass, name) {
@Override
public QueryParameterBinding bind(BindingContext bindingContext) {
String name = bindingContext.getName() == null ? String.valueOf(bindingContext.getIndex()) : bindingContext.getName();
PersistentPropertyPath outgoingQueryParameterProperty = bindingContext.getOutgoingQueryParameterProperty();
return new QueryParameterBinding() {
@Override
public String getKey() {
return name;
}
@Override
public DataType getDataType() {
return outgoingQueryParameterProperty.getProperty().getDataType();
}
@Override
public String[] getPropertyPath() {
return asStringPath(outgoingQueryParameterProperty.getAssociations(), outgoingQueryParameterProperty.getProperty());
}
};
}
};
}
use of io.micronaut.data.model.PersistentPropertyPath in project micronaut-data by micronaut-projects.
the class AbstractCriteriaBuilder method parameter.
@Override
@NonNull
public <T> ParameterExpression<T> parameter(@NonNull Class<T> paramClass) {
return new ParameterExpressionImpl<T>(paramClass, null) {
@Override
public QueryParameterBinding bind(BindingContext bindingContext) {
String name = bindingContext.getName() == null ? String.valueOf(bindingContext.getIndex()) : bindingContext.getName();
PersistentPropertyPath outgoingQueryParameterProperty = bindingContext.getOutgoingQueryParameterProperty();
return new QueryParameterBinding() {
@Override
public String getKey() {
return name;
}
@Override
public DataType getDataType() {
return outgoingQueryParameterProperty.getProperty().getDataType();
}
@Override
public String[] getPropertyPath() {
return asStringPath(outgoingQueryParameterProperty.getAssociations(), outgoingQueryParameterProperty.getProperty());
}
@Override
public boolean isExpandable() {
return bindingContext.isExpandable();
}
};
}
};
}
Aggregations