use of com.blazebit.persistence.parser.expression.StringLiteral in project blaze-persistence by Blazebit.
the class TestLiterals method testCharacterLiteral.
@Test
public void testCharacterLiteral() {
StringLiteral result = (StringLiteral) parse("'a'");
assertEquals(new StringLiteral("a"), result);
}
use of com.blazebit.persistence.parser.expression.StringLiteral in project blaze-persistence by Blazebit.
the class TestLiterals method testStringLiteralWithBackslash.
@Test
public void testStringLiteralWithBackslash() {
StringLiteral result = (StringLiteral) parse("'a\\_'");
assertEquals(new StringLiteral("a\\_"), result);
}
use of com.blazebit.persistence.parser.expression.StringLiteral in project blaze-persistence by Blazebit.
the class SizeTransformationVisitor method getSizeExpression.
private Expression getSizeExpression(ExpressionModifier parentModifier, PathExpression sizeArg) {
JoinNode sizeArgJoin = (JoinNode) sizeArg.getBaseNode();
String property = sizeArg.getPathReference().getField();
final Type<?> nodeType = ((JoinNode) sizeArg.getBaseNode()).getNodeType();
if (!(nodeType instanceof EntityType<?>)) {
throw new IllegalArgumentException("Size on a collection owned by a non-entity type is not supported yet: " + sizeArg);
}
final EntityType<?> startType = (EntityType<?>) nodeType;
AttributeHolder result = JpaUtils.getAttributeForJoining(metamodel, sizeArg);
PluralAttribute<?, ?, ?> targetAttribute = (PluralAttribute<?, ?, ?>) result.getAttribute();
if (targetAttribute == null) {
throw new RuntimeException("Attribute [" + property + "] not found on class " + startType.getJavaType().getName());
}
final PluralAttribute.CollectionType collectionType = targetAttribute.getCollectionType();
final boolean isElementCollection = jpaProvider.getJpaMetamodelAccessor().isElementCollection(targetAttribute);
boolean subqueryRequired;
if (isElementCollection) {
subqueryRequired = false;
} else {
ManagedType<?> managedTargetType = (ManagedType<?>) result.getAttributeType();
if (managedTargetType instanceof EntityType<?>) {
// we could also generate counts for collections with embeddable id but we do not implement this for now
subqueryRequired = ((EntityType<?>) managedTargetType).getIdType().getPersistenceType() == PersistenceType.EMBEDDABLE;
} else {
throw new RuntimeException("Path [" + sizeArg.toString() + "] does not refer to a collection");
}
}
// build group by id clause
List<PathExpression> groupByExprs = new ArrayList<>();
for (SingularAttribute<?, ?> idAttribute : JpaMetamodelUtils.getIdAttributes(startType)) {
List<PathElementExpression> pathElementExpr = new ArrayList<>(2);
pathElementExpr.add(new PropertyExpression(sizeArgJoin.getAlias()));
pathElementExpr.add(new PropertyExpression(idAttribute.getName()));
PathExpression groupByExpr = new PathExpression(pathElementExpr);
groupByExprs.add(groupByExpr);
}
subqueryRequired = subqueryRequired || // we could also generate counts for collections with IdClass attributes but we do not implement this for now
!startType.hasSingleIdAttribute() || joinManager.getRoots().size() > 1 || clause == ClauseType.JOIN || !isCountTransformationEnabled() || // for now, we always generate a subquery when a bag is encountered
jpaProvider.isBag((EntityType<?>) targetAttribute.getDeclaringType(), targetAttribute.getName()) || requiresBlacklistedNode(sizeArg) || aggregateFunctionContext;
if (subqueryRequired) {
return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
} else {
if (currentJoinNode != null && (!currentJoinNode.equals(sizeArgJoin))) {
int currentJoinDepth = currentJoinNode.getJoinDepth();
int sizeArgJoinDepth = sizeArgJoin.getJoinDepth();
if (currentJoinDepth > sizeArgJoinDepth) {
return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
} else {
// we have to change all transformed expressions to subqueries
for (TransformedExpressionEntry transformedExpressionEntry : transformedExpressions) {
PathExpression originalSizeArg = transformedExpressionEntry.getOriginalSizeArg();
Expression subquery = wrapSubqueryConditionally(generateSubquery(originalSizeArg), transformedExpressionEntry.isAggregateFunctionContext());
transformedExpressionEntry.getParentModifier().set(subquery);
}
transformedExpressions.clear();
requiredGroupBys.clear();
lateJoins.clear();
distinctRequired = false;
if (currentJoinDepth == sizeArgJoinDepth) {
return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
}
}
}
for (PathExpression groupByExpr : groupByExprs) {
joinManager.implicitJoin(groupByExpr, true, true, true, null, null, new HashSet<String>(), false, false, false, false);
}
PathExpression originalSizeArg = sizeArg.copy(ExpressionCopyContext.EMPTY);
originalSizeArg.setPathReference(sizeArg.getPathReference());
sizeArg.setUsedInCollectionFunction(false);
List<Expression> countArguments = new ArrayList<>();
String joinLookupKey = getJoinLookupKey(sizeArg);
LateJoinEntry lateJoin = lateJoins.get(joinLookupKey);
if (lateJoin == null) {
lateJoin = new LateJoinEntry();
lateJoins.put(joinLookupKey, lateJoin);
}
lateJoin.getExpressionsToJoin().add(sizeArg);
lateJoin.getClauseDependencies().add(clause);
if ((isElementCollection && collectionType != PluralAttribute.CollectionType.MAP) || collectionType == PluralAttribute.CollectionType.SET) {
if (IDENTIFIABLE_PERSISTENCE_TYPES.contains(targetAttribute.getElementType().getPersistenceType()) && targetAttribute.isCollection()) {
// append id attribute name of joinable size argument
PluralAttribute<?, ?, ?> sizeArgTargetAttribute = (PluralAttribute<?, ?, ?>) JpaMetamodelUtils.getAttribute(startType, sizeArg.getPathReference().getField());
for (Attribute<?, ?> idAttribute : JpaMetamodelUtils.getIdAttributes(((IdentifiableType<?>) sizeArgTargetAttribute.getElementType()))) {
List<PathElementExpression> pathElementExpressions = new ArrayList<>(sizeArg.getExpressions().size() + 1);
pathElementExpressions.addAll(sizeArg.getExpressions());
pathElementExpressions.add(new PropertyExpression(idAttribute.getName()));
PathExpression pathExpression = new PathExpression(pathElementExpressions);
countArguments.add(pathExpression);
lateJoin.getExpressionsToJoin().add(pathExpression);
}
} else {
countArguments.add(sizeArg);
}
} else {
sizeArg.setCollectionQualifiedPath(true);
if (collectionType == PluralAttribute.CollectionType.LIST) {
countArguments.add(new ListIndexExpression(sizeArg));
} else {
countArguments.add(new MapKeyExpression(sizeArg));
}
}
AggregateExpression countExpr = createCountFunction(distinctRequired, countArguments);
transformedExpressions.add(new TransformedExpressionEntry(countExpr, originalSizeArg, parentModifier, aggregateFunctionContext));
currentJoinNode = (JoinNode) originalSizeArg.getBaseNode();
if (!distinctRequired) {
if (lateJoins.size() + joinManager.getCollectionJoins().size() > 1) {
distinctRequired = true;
/*
* As soon as we encounter another collection join, set previously
* performed transformations to distinct.
*/
for (TransformedExpressionEntry transformedExpressionEntry : transformedExpressions) {
AggregateExpression transformedExpr = transformedExpressionEntry.getTransformedExpression();
if (ExpressionUtils.isCustomFunctionInvocation(transformedExpr) && AbstractCountFunction.FUNCTION_NAME.equalsIgnoreCase(((StringLiteral) transformedExpr.getExpressions().get(0)).getValue())) {
Expression possibleDistinct = transformedExpr.getExpressions().get(1);
if (!(possibleDistinct instanceof StringLiteral) || !AbstractCountFunction.DISTINCT_QUALIFIER.equals(((StringLiteral) possibleDistinct).getValue())) {
transformedExpr.getExpressions().add(1, new StringLiteral(AbstractCountFunction.DISTINCT_QUALIFIER));
}
} else {
transformedExpr.setDistinct(true);
}
}
}
}
for (Expression groupByExpr : groupByExprs) {
String groupByExprString = groupByExpr.toString();
ResolvedExpression resolvedExpression = new ResolvedExpression(groupByExprString, groupByExpr);
Set<ClauseType> clauseTypes = requiredGroupBys.get(resolvedExpression);
if (clauseTypes == null) {
requiredGroupBys.put(resolvedExpression, EnumSet.of(clause));
} else {
clauseTypes.add(clause);
}
}
return countExpr;
}
}
use of com.blazebit.persistence.parser.expression.StringLiteral in project blaze-persistence by Blazebit.
the class AbstractCommonQueryBuilder method asExpression.
protected Expression asExpression(AbstractCommonQueryBuilder<?, ?, ?, ?, ?> queryBuilder, boolean externalRepresentation, boolean quantifiedPredicate) {
if (queryBuilder instanceof BaseFinalSetOperationBuilderImpl<?, ?, ?>) {
return queryBuilder.asExpression(externalRepresentation, quantifiedPredicate);
}
final String queryString = queryBuilder.buildBaseQueryString(externalRepresentation);
Expression expression = new SubqueryExpression(new Subquery() {
@Override
public String getQueryString() {
return queryString;
}
});
if (externalRepresentation) {
return expression;
}
if (queryBuilder.joinManager.hasEntityFunctions()) {
for (EntityFunctionNode node : queryBuilder.getEntityFunctionNodes(null)) {
List<Expression> arguments = new ArrayList<>(6);
arguments.add(new StringLiteral("ENTITY_FUNCTION"));
arguments.add(expression);
String subquery = node.getSubquery();
String aliases = node.getAliases();
String syntheticPredicate = node.getSyntheticPredicate();
// TODO: this is a hibernate specific integration detail
// Replace the subview subselect that is generated for this subselect
String entityName = node.getEntityName();
arguments.add(new StringLiteral(entityName));
arguments.add(new StringLiteral(subquery));
arguments.add(new StringLiteral(aliases == null ? "" : aliases));
arguments.add(new StringLiteral(syntheticPredicate == null ? "" : syntheticPredicate));
expression = new FunctionExpression("FUNCTION", arguments);
}
}
if (queryBuilder.hasLimit()) {
final boolean hasFirstResult = queryBuilder.getFirstResult() != 0;
final boolean hasMaxResults = queryBuilder.getMaxResults() != Integer.MAX_VALUE;
List<Expression> arguments = new ArrayList<>(2);
arguments.add(new StringLiteral(LimitFunction.FUNCTION_NAME));
arguments.add(expression);
if (!hasMaxResults) {
throw new IllegalArgumentException("First result without max results is not supported!");
} else {
arguments.add(new NumericLiteral(Integer.toString(queryBuilder.getMaxResults()), NumericType.INTEGER));
}
if (hasFirstResult) {
arguments.add(new NumericLiteral(Integer.toString(queryBuilder.getFirstResult()), NumericType.INTEGER));
}
expression = new FunctionExpression("FUNCTION", arguments);
if (quantifiedPredicate && !mainQuery.dbmsDialect.supportsLimitInQuantifiedPredicateSubquery()) {
arguments = new ArrayList<>(2);
arguments.add(new StringLiteral(QueryWrapperFunction.FUNCTION_NAME));
arguments.add(expression);
expression = new FunctionExpression("FUNCTION", arguments);
}
}
return expression;
}
use of com.blazebit.persistence.parser.expression.StringLiteral in project blaze-persistence by Blazebit.
the class AbstractFullQueryBuilder method applyPageIdQueryInto.
protected void applyPageIdQueryInto(AbstractCommonQueryBuilder<?, ?, ?, ?, ?> newBuilder, KeysetPage keysetPage, int firstResult, int maxResults, ResolvedExpression[] identifierExpressionsToUse, boolean withAlias) {
ExpressionCopyContext expressionCopyContext = newBuilder.applyFrom(this, true, false, false, false, ID_QUERY_GROUP_BY_CLAUSE_EXCLUSIONS, getIdentifierExpressionsToUseNonRootJoinNodes(identifierExpressionsToUse), new IdentityHashMap<JoinManager, JoinManager>(), ExpressionCopyContext.EMPTY);
newBuilder.setFirstResult(firstResult);
newBuilder.setMaxResults(maxResults);
// Paginated criteria builders always need the last order by expression to be unique
List<OrderByExpression> orderByExpressions = orderByManager.getOrderByExpressions(false, whereManager.rootPredicate.getPredicate(), hasGroupBy ? Arrays.asList(getIdentifierExpressions()) : Collections.<ResolvedExpression>emptyList(), null);
if (!orderByExpressions.get(orderByExpressions.size() - 1).isResultUnique()) {
throw new IllegalStateException("The order by items of the query builder are not guaranteed to produce unique tuples! Consider also ordering by the entity identifier!");
}
if (keysetPage != null) {
KeysetMode keysetMode = KeysetPaginationHelper.getKeysetMode(keysetPage, null, firstResult, maxResults);
if (keysetMode == KeysetMode.NONE) {
newBuilder.keysetManager.setKeysetLink(null);
} else if (keysetMode == KeysetMode.NEXT) {
newBuilder.keysetManager.setKeysetLink(new SimpleKeysetLink(keysetPage.getHighest(), keysetMode));
} else {
newBuilder.keysetManager.setKeysetLink(new SimpleKeysetLink(keysetPage.getLowest(), keysetMode));
}
newBuilder.keysetManager.initialize(orderByExpressions);
}
// Applying order by items needs special care for page id queries because we have to re-alias the items to avoid collisions
Map<String, Integer> identifierExpressionStringMap = new HashMap<>(identifierExpressionsToUse.length);
for (int i = 0; i < identifierExpressionsToUse.length; i++) {
identifierExpressionStringMap.put(identifierExpressionsToUse[i].getExpressionString(), i);
}
String[] identifierToUseSelectAliases = newBuilder.orderByManager.applyFrom(orderByManager, identifierExpressionStringMap);
if (withAlias) {
for (int i = 0; i < identifierExpressionsToUse.length; i++) {
List<Expression> args = new ArrayList<>(2);
args.add(identifierExpressionsToUse[i].getExpression().copy(expressionCopyContext));
args.add(new StringLiteral(ColumnTruncFunction.SYNTHETIC_COLUMN_PREFIX + i));
newBuilder.selectManager.select(new FunctionExpression(AliasFunction.FUNCTION_NAME, args), identifierToUseSelectAliases[i]);
}
} else {
for (int i = 0; i < identifierExpressionsToUse.length; i++) {
newBuilder.selectManager.select(identifierExpressionsToUse[i].getExpression().copy(expressionCopyContext), identifierToUseSelectAliases[i]);
}
}
}
Aggregations