All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mybatis.dynamic.sql.where.render.CriterionRenderer Maven / Gradle / Ivy

/*
 *    Copyright ${license.git.copyrightYears} the original author or authors.
 *
 *    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 org.mybatis.dynamic.sql.where.render;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import org.mybatis.dynamic.sql.ColumnAndConditionCriterion;
import org.mybatis.dynamic.sql.ExistsCriterion;
import org.mybatis.dynamic.sql.ExistsPredicate;
import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.SqlCriterionVisitor;
import org.mybatis.dynamic.sql.render.RenderingStrategy;
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
import org.mybatis.dynamic.sql.select.render.SelectRenderer;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.FragmentCollector;

/**
 * Renders a {@link SqlCriterion} to a {@link RenderedCriterion}. The process is complex because all conditions
 * may or may not be a candidate for rendering. For example, "isEqualWhenPresent" will not render when the value
 * is null. It is also complex because SqlCriterion may or may not include sub-criteria.
 *
 * 

Rendering is a recursive process. The renderer will recurse into each sub-criteria - which may also * contain further sub-criteria - until all possible sub-criteria are rendered into a single fragment. So, for example, * the fragment may end up looking like: * *

 *     col1 = ? and (col2 = ? or (col3 = ? and col4 = ?))
 * 
* *

It is also possible that the end result will be empty if all criteria and sub-criteria are not valid for * rendering. * * @author Jeff Butler */ public class CriterionRenderer implements SqlCriterionVisitor> { private final AtomicInteger sequence; private final RenderingStrategy renderingStrategy; private final TableAliasCalculator tableAliasCalculator; private final String parameterName; private CriterionRenderer(Builder builder) { sequence = Objects.requireNonNull(builder.sequence); renderingStrategy = Objects.requireNonNull(builder.renderingStrategy); tableAliasCalculator = Objects.requireNonNull(builder.tableAliasCalculator); parameterName = builder.parameterName; } @Override public Optional visit(ColumnAndConditionCriterion criterion) { if (criterion.condition().shouldRender()) { return renderWithInitialCondition(renderCondition(criterion), criterion); } else { criterion.condition().renderingSkipped(); return renderWithoutInitialCondition(criterion); } } @Override public Optional visit(ExistsCriterion criterion) { ExistsPredicate existsPredicate = criterion.existsPredicate(); SelectStatementProvider selectStatement = SelectRenderer .withSelectModel(existsPredicate.selectModelBuilder().build()) .withRenderingStrategy(renderingStrategy) .withSequence(sequence) .build() .render(); String fragment = existsPredicate.operator() + " (" //$NON-NLS-1$ + selectStatement.getSelectStatement() + ")"; //$NON-NLS-1$ FragmentAndParameters initialCondition = FragmentAndParameters .withFragment(fragment) .withParameters(selectStatement.getParameters()) .build(); return renderWithInitialCondition(initialCondition, criterion); } private FragmentAndParameters renderCondition(ColumnAndConditionCriterion criterion) { WhereConditionVisitor visitor = WhereConditionVisitor.withColumn(criterion.column()) .withRenderingStrategy(renderingStrategy) .withSequence(sequence) .withTableAliasCalculator(tableAliasCalculator) .withParameterName(parameterName) .build(); return criterion.condition().accept(visitor); } private List renderSubCriteria(SqlCriterion criterion) { return criterion.mapSubCriteria(c -> c.accept(this)) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); } private Optional renderWithoutInitialCondition(SqlCriterion criterion) { List subCriteria = renderSubCriteria(criterion); if (subCriteria.isEmpty()) { return Optional.empty(); } return calculateRenderedCriterion(subCriteria, criterion); } private Optional renderWithInitialCondition(FragmentAndParameters initialCondition, SqlCriterion criterion) { List subCriteria = renderSubCriteria(criterion); if (subCriteria.isEmpty()) { return calculateRenderedCriterion(initialCondition, criterion); } return calculateRenderedCriterion(initialCondition, criterion, subCriteria); } private Optional calculateRenderedCriterion(FragmentAndParameters initialCondition, SqlCriterion criterion) { return fromFragmentAndParameters(initialCondition, criterion); } private Optional calculateRenderedCriterion(List subCriteria, SqlCriterion criterion) { return calculateRenderedCriterion(subCriteria.get(0).fragmentAndParameters(), criterion, subCriteria.subList(1, subCriteria.size())); } private Optional calculateRenderedCriterion(FragmentAndParameters initialCondition, SqlCriterion criterion, List subCriteria) { FragmentCollector fc = subCriteria.stream() .map(RenderedCriterion::fragmentAndParametersWithConnector) .collect(FragmentCollector.collect(initialCondition)); return fromFragmentAndParameters(FragmentAndParameters.withFragment(calculateFragment(fc)) .withParameters(fc.parameters()) .build(), criterion); } private String calculateFragment(FragmentCollector collector) { if (collector.hasMultipleFragments()) { return collector.fragments() .collect(Collectors.joining(" ", "(", ")")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } else { return collector.fragments().findFirst().orElse(""); //$NON-NLS-1$ } } private Optional fromFragmentAndParameters(FragmentAndParameters fragmentAndParameters, SqlCriterion criterion) { RenderedCriterion.Builder builder = new RenderedCriterion.Builder() .withFragmentAndParameters(fragmentAndParameters); criterion.connector().ifPresent(builder::withConnector); return Optional.of(builder.build()); } public static class Builder { private AtomicInteger sequence; private RenderingStrategy renderingStrategy; private TableAliasCalculator tableAliasCalculator; private String parameterName; public Builder withSequence(AtomicInteger sequence) { this.sequence = sequence; return this; } public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) { this.renderingStrategy = renderingStrategy; return this; } public Builder withTableAliasCalculator(TableAliasCalculator tableAliasCalculator) { this.tableAliasCalculator = tableAliasCalculator; return this; } public Builder withParameterName(String parameterName) { this.parameterName = parameterName; return this; } public CriterionRenderer build() { return new CriterionRenderer(this); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy