Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2014 - 2020 Blazebit.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.blazebit.persistence.impl;
import com.blazebit.persistence.BaseModificationCriteriaBuilder;
import com.blazebit.persistence.CriteriaBuilder;
import com.blazebit.persistence.FullSelectCTECriteriaBuilder;
import com.blazebit.persistence.ReturningBuilder;
import com.blazebit.persistence.ReturningModificationCriteriaBuilderFactory;
import com.blazebit.persistence.ReturningObjectBuilder;
import com.blazebit.persistence.ReturningResult;
import com.blazebit.persistence.SelectRecursiveCTECriteriaBuilder;
import com.blazebit.persistence.SimpleReturningBuilder;
import com.blazebit.persistence.impl.builder.object.ReturningTupleObjectBuilder;
import com.blazebit.persistence.impl.dialect.DB2DbmsDialect;
import com.blazebit.persistence.impl.query.CTENode;
import com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery;
import com.blazebit.persistence.impl.query.CustomSQLQuery;
import com.blazebit.persistence.impl.query.ModificationQuerySpecification;
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.impl.query.ReturningModificationQuerySpecification;
import com.blazebit.persistence.parser.expression.ExpressionCopyContext;
import com.blazebit.persistence.spi.AttributePath;
import com.blazebit.persistence.parser.util.JpaMetamodelUtils;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DbmsStatementType;
import com.blazebit.persistence.spi.ExtendedAttribute;
import com.blazebit.persistence.spi.ExtendedManagedType;
import com.blazebit.persistence.spi.JoinTable;
import com.blazebit.persistence.spi.JpaMetamodelAccessor;
import javax.persistence.Query;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
*
* @param The entity type of this modification builder
* @author Christian Beikov
* @since 1.1.0
*/
public abstract class AbstractModificationCriteriaBuilder, Y> extends AbstractCommonQueryBuilder, AbstractCommonQueryBuilder, BaseFinalSetOperationBuilderImpl> implements BaseModificationCriteriaBuilder, CTEInfoBuilder, SimpleReturningBuilder {
protected final EntityType entityType;
protected final String entityAlias;
protected final EntityType cteType;
protected final CTEManager.CTEKey cteKey;
protected final Y result;
protected final CTEBuilderListener listener;
protected final boolean isReturningEntityAliasAllowed;
protected final Map>> returningAttributes;
protected final Map returningAttributeBindingMap;
protected final Map attributeEntries;
protected final Map columnBindingMap;
@SuppressWarnings("unchecked")
public AbstractModificationCriteriaBuilder(MainQuery mainQuery, QueryContext queryContext, boolean isMainQuery, DbmsStatementType statementType, Class clazz, String alias, CTEManager.CTEKey cteKey, Class cteClass, Y result, CTEBuilderListener listener) {
// NOTE: using tuple here because this class is used for the join manager and tuple is definitively not an entity
// but in case of the insert criteria, the appropriate return type which is convenient because update and delete don't have a return type
super(mainQuery, queryContext, isMainQuery, statementType, (Class) Tuple.class, null);
// set defaults
if (alias != null) {
// If the user supplies an alias, the intention is clear
fromClassExplicitlySet = true;
}
this.entityType = mainQuery.metamodel.entity(clazz);
this.entityAlias = joinManager.addRoot(entityType, alias);
this.result = result;
this.listener = listener;
if (cteClass == null) {
this.cteType = null;
this.cteKey = null;
this.isReturningEntityAliasAllowed = false;
this.returningAttributes = new LinkedHashMap<>(0);
this.returningAttributeBindingMap = new LinkedHashMap<>(0);
this.attributeEntries = null;
this.columnBindingMap = null;
} else {
this.cteType = mainQuery.metamodel.entity(cteClass);
this.cteKey = cteKey;
// Returning the "entity" is only allowed in CTEs
this.isReturningEntityAliasAllowed = true;
this.returningAttributes = null;
this.attributeEntries = mainQuery.metamodel.getManagedType(ExtendedManagedType.class, cteClass).getOwnedSingularAttributes();
this.returningAttributeBindingMap = new LinkedHashMap<>(attributeEntries.size());
this.columnBindingMap = new LinkedHashMap<>(attributeEntries.size());
}
}
public AbstractModificationCriteriaBuilder(AbstractModificationCriteriaBuilder builder, MainQuery mainQuery, QueryContext queryContext, Map joinManagerMapping, ExpressionCopyContext copyContext) {
super(builder, mainQuery, queryContext, joinManagerMapping, copyContext);
this.entityType = builder.entityType;
this.entityAlias = builder.entityAlias;
this.result = null;
this.listener = null;
this.cteType = builder.cteType;
this.cteKey = builder.cteKey;
this.isReturningEntityAliasAllowed = builder.isReturningEntityAliasAllowed;
this.returningAttributes = builder.returningAttributes == null ? null : new LinkedHashMap<>(builder.returningAttributes);
this.returningAttributeBindingMap = new LinkedHashMap<>(builder.returningAttributeBindingMap);
this.attributeEntries = builder.attributeEntries;
this.columnBindingMap = builder.columnBindingMap == null ? null : new LinkedHashMap<>(builder.columnBindingMap);
}
@Override
public FullSelectCTECriteriaBuilder with(Class cteClass) {
if (!mainQuery.dbmsDialect.supportsWithClauseInModificationQuery()) {
return super.with(cteClass, true);
}
return super.with(cteClass);
}
@Override
public FullSelectCTECriteriaBuilder with(Class cteClass, CriteriaBuilder criteriaBuilder) {
if (!mainQuery.dbmsDialect.supportsWithClauseInModificationQuery()) {
return super.with(cteClass, criteriaBuilder, true);
}
return super.with(cteClass, criteriaBuilder);
}
@Override
public SelectRecursiveCTECriteriaBuilder withRecursive(Class cteClass) {
if (!mainQuery.dbmsDialect.supportsWithClauseInModificationQuery()) {
throw new UnsupportedOperationException("The database does not support a with clause in modification queries!");
}
return super.withRecursive(cteClass);
}
@Override
public ReturningModificationCriteriaBuilderFactory withReturning(Class cteClass) {
if (!mainQuery.dbmsDialect.supportsWithClauseInModificationQuery()) {
throw new UnsupportedOperationException("The database does not support a with clause in modification queries!");
}
return super.withReturning(cteClass);
}
protected void applyJpaReturning(StringBuilder sbSelectFrom) {
sbSelectFrom.append(" RETURNING ");
boolean first = true;
for (String attribute : returningAttributeBindingMap.values()) {
if (first) {
first = false;
} else {
sbSelectFrom.append(", ");
}
sbSelectFrom.append(attribute);
}
}
@Override
public Query getQuery() {
return getQuery(null);
}
@Override
protected Query getQuery(Map includedModificationStates) {
Query query;
// TODO: Oracle requires everything except the sequence to be wrapped in a derived table
// see https://github.com/Blazebit/blaze-persistence/issues/306
// We use this to make these features only available to Hibernate as it is the only provider that supports sql replace yet
if (hasLimit() || mainQuery.cteManager.hasCtes() || returningAttributeBindingMap.size() > 0) {
// We need to change the underlying sql when doing a limit with hibernate since it does not support limiting insert ... select statements
// For CTEs we will also need to change the underlying sql
query = em.createQuery(getBaseQueryStringWithCheck(null, null));
Set parameterListNames = parameterManager.getParameterListNames(query);
boolean isEmbedded = this instanceof ReturningBuilder;
String[] returningColumns = getReturningColumns();
boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
List ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
QuerySpecification querySpecification = new ModificationQuerySpecification(
this,
query,
getCountExampleQuery(),
parameterManager.getParameters(),
parameterListNames,
mainQuery.cteManager.isRecursive(),
ctes,
shouldRenderCteNodes,
isEmbedded,
returningColumns,
includedModificationStates,
returningAttributeBindingMap
);
query = new CustomSQLQuery(
querySpecification,
query,
parameterManager.getTransformers(),
parameterManager.getValuesParameters(),
parameterManager.getValuesBinders()
);
} else {
query = em.createQuery(getBaseQueryStringWithCheck(null, null));
}
parameterManager.parameterizeQuery(query);
return query;
}
public int executeUpdate() {
return getQuery().executeUpdate();
}
@Override
protected Map getModificationStates(Map, Map> explicitVersionEntities) {
Map versionEntities = explicitVersionEntities.get(entityType.getJavaType());
if (versionEntities == null) {
return null;
}
Map includedModificationStates = new HashMap();
// TODO: this needs to include the modification states based on what the dbms uses as default
boolean defaultOld = !(mainQuery.dbmsDialect instanceof DB2DbmsDialect);
if (defaultOld) {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.NEW) {
includedModificationStates.put(DbmsModificationState.NEW, entityType.getName() + "_new");
if (getStatementType() == DbmsStatementType.DELETE) {
includedModificationStates.put(DbmsModificationState.OLD, cteKey.getName());
}
break;
}
}
} else {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.OLD) {
includedModificationStates.put(DbmsModificationState.OLD, entityType.getName() + "_old");
break;
}
}
}
return includedModificationStates;
}
protected Map getModificationStateRelatedTableNameRemappings(Map, Map> explicitVersionEntities) {
Map versionEntities = explicitVersionEntities.get(entityType.getJavaType());
if (versionEntities == null) {
return null;
}
Map tableNameRemappings = new HashMap();
// TODO: this needs to include the modification states based on what the dbms uses as default, so use a DbmsDialect method
boolean defaultOld = !(mainQuery.dbmsDialect instanceof DB2DbmsDialect);
if (defaultOld) {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.NEW) {
tableNameRemappings.put(entry.getKey(), entityType.getName() + "_new");
}
}
} else {
for (Map.Entry entry : versionEntities.entrySet()) {
if (entry.getValue() == DbmsModificationState.OLD) {
tableNameRemappings.put(entry.getKey(), entityType.getName() + "_old");
}
}
}
return tableNameRemappings;
}
public ReturningResult executeWithReturning(String... attributes) {
return getWithReturningQuery(attributes).getSingleResult();
}
public TypedQuery> getWithReturningQuery(String... attributes) {
if (attributes == null) {
throw new NullPointerException("attributes");
}
if (attributes.length == 0) {
throw new IllegalArgumentException("Invalid empty attributes");
}
Query baseQuery = em.createQuery(getBaseQueryStringWithCheck(null, null));
List>> attributeList = getAndCheckAttributes(attributes);
TypedQuery