<commit_before>/*
 *    Copyright 2016-2022 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
 *
 *       https://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.common;

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

import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.render.RenderingStrategy;
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.FragmentCollector;
import org.mybatis.dynamic.sql.where.render.CriterionRenderer;
import org.mybatis.dynamic.sql.where.render.RenderedCriterion;

public abstract class AbstractBooleanExpressionRenderer<M extends AbstractBooleanExpressionModel> {
    protected final M model;
    private final CriterionRenderer criterionRenderer;
    private final String prefix;

    protected AbstractBooleanExpressionRenderer(String prefix, AbstractBuilder<M, ?> builder) {
        model = Objects.requireNonNull(builder.model);

        criterionRenderer = new CriterionRenderer.Builder()
                .withSequence(builder.sequence)
                .withRenderingStrategy(builder.renderingStrategy)
                .withTableAliasCalculator(builder.tableAliasCalculator)
                .withParameterName(builder.parameterName)
                .build();

        this.prefix = Objects.requireNonNull(prefix);
    }

    public Optional<FragmentAndParameters> render() {
        return model.initialCriterion()
                .map(this::renderWithInitialCriterion)
                .orElseGet(this::renderWithoutInitialCriterion)
                .map(rc -> FragmentAndParameters.withFragment(rc.fragmentAndParameters().fragment())
                        .withParameters(rc.fragmentAndParameters().parameters())
                        .build()
                );
    }

    private Optional<RenderedCriterion> renderWithInitialCriterion(SqlCriterion initialCriterion) {
        return criterionRenderer.render(initialCriterion, model.subCriteria(), this::calculateClause);
    }

    private Optional<RenderedCriterion> renderWithoutInitialCriterion() {
        return criterionRenderer.render(model.subCriteria(), this::calculateClause);
    }

    private String calculateClause(FragmentCollector collector) {
        if (collector.hasMultipleFragments()) {
            return collector.fragments()
                    .collect(Collectors.joining(" ", prefix + " ", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        } else {
            return collector.firstFragment()
                    .map(this::stripEnclosingParenthesesIfPresent)
                    .map(s -> prefix + " " + s) //$NON-NLS-1$
                    .orElse(""); //$NON-NLS-1$
        }
    }

    private String stripEnclosingParenthesesIfPresent(String fragment) {
        // The fragment will have surrounding open/close parentheses if there is more than one rendered condition.
        // Since there is only a single fragment, we don't need these in the where clause
        if (fragment.startsWith("(") && fragment.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$
            return fragment.substring(1, fragment.length() - 1);
        } else {
            return fragment;
        }
    }<commit_msg>Polishing<commit_after>/*
 *    Copyright 2016-2022 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
 *
 *       https://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.common;

import static org.mybatis.dynamic.sql.util.StringUtilities.spaceAfter;

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

import org.mybatis.dynamic.sql.SqlCriterion;
import org.mybatis.dynamic.sql.render.RenderingStrategy;
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
import org.mybatis.dynamic.sql.util.FragmentAndParameters;
import org.mybatis.dynamic.sql.util.FragmentCollector;
import org.mybatis.dynamic.sql.where.render.CriterionRenderer;
import org.mybatis.dynamic.sql.where.render.RenderedCriterion;

public abstract class AbstractBooleanExpressionRenderer<M extends AbstractBooleanExpressionModel> {
    protected final M model;
    private final String prefix;
    private final CriterionRenderer criterionRenderer;

    protected AbstractBooleanExpressionRenderer(String prefix, AbstractBuilder<M, ?> builder) {
        model = Objects.requireNonNull(builder.model);
        this.prefix = Objects.requireNonNull(prefix);

        criterionRenderer = new CriterionRenderer.Builder()
                .withSequence(builder.sequence)
                .withRenderingStrategy(builder.renderingStrategy)
                .withTableAliasCalculator(builder.tableAliasCalculator)
                .withParameterName(builder.parameterName)
                .build();
    }

    public Optional<FragmentAndParameters> render() {
        return model.initialCriterion()
                .map(this::renderWithInitialCriterion)
                .orElseGet(this::renderWithoutInitialCriterion)
                .map(rc -> FragmentAndParameters.withFragment(rc.fragmentAndParameters().fragment())
                        .withParameters(rc.fragmentAndParameters().parameters())
                        .build()
                );
    }

    private Optional<RenderedCriterion> renderWithInitialCriterion(SqlCriterion initialCriterion) {
        return criterionRenderer.render(initialCriterion, model.subCriteria(), this::calculateClause);
    }

    private Optional<RenderedCriterion> renderWithoutInitialCriterion() {
        return criterionRenderer.render(model.subCriteria(), this::calculateClause);
    }

    private String calculateClause(FragmentCollector collector) {
        if (collector.hasMultipleFragments()) {
            return collector.fragments()
                    .collect(Collectors.joining(" ", spaceAfter(prefix), "")); //$NON-NLS-1$ //$NON-NLS-2$
        } else {
            return collector.firstFragment()
                    .map(this::stripEnclosingParenthesesIfPresent)
                    .map(this::addPrefix)
                    .orElse(""); //$NON-NLS-1$
        }
    }

    private String stripEnclosingParenthesesIfPresent(String fragment) {
        // The fragment will have surrounding open/close parentheses if there is more than one rendered condition.
        // Since there is only a single fragment, we don't need these in the final rendered clause
        if (fragment.startsWith("(") && fragment.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$
            return fragment.substring(1, fragment.length() - 1);
        } else {
            return fragment;
        }
    }

    private String addPrefix(String fragment) {
        return spaceAfter(prefix) + fragment;
    }

{'fraction_non_alphanumeric': 0.09541888129587446, 'fraction_numerical': 0.005062009617818274, 'mean_word_length': 2.9633901705115346, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 16, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6747509', 'n_tokens_mistral': 2064, 'n_tokens_neox': 2001, 'n_words': 485}