<commit_before>/**
 *
 * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
 *
 * 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.speedment.runtime.core.internal.manager.sql;

import com.speedment.runtime.core.db.FieldPredicateView;
import com.speedment.runtime.core.db.SqlPredicateFragment;
import static com.speedment.runtime.core.internal.manager.sql.AbstractFieldPredicateView.of;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getFirstOperandAsRaw;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getFirstOperandAsRawSet;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getInclusionOperand;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getSecondOperand;
import com.speedment.runtime.field.predicate.FieldPredicate;
import com.speedment.runtime.field.predicate.Inclusion;
import java.util.Set;
import static java.util.stream.Collectors.joining;

/**
 *
 * @author <NAME>
 */
@SuppressWarnings("rawtypes")
public final class MySqlSpeedmentPredicateView extends AbstractFieldPredicateView implements FieldPredicateView {

    /*
    create table colltest (
      name character(20)
    ) charset latin1

    insert into colltest (name) values ('olle');
    insert into colltest (name) values ('sven');
    
    select * from colltest where name = 'olle' collate utf8_bin;
    
     */
    private enum Collation {

        UTF8_BIN, UTF8_GENERAL_CI;

        private final String collateCommand;

        private Collation() {
            this.collateCommand = "COLLATE " + name().toLowerCase();
        }

        String getCollateCommand() {
            return collateCommand;
        }
    }

    @Override
    protected SqlPredicateFragment equalIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of(compare(cn, " = ?", Collation.UTF8_GENERAL_CI), negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment startsWithHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() + " LIKE CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment startsWithIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT(LOWER(?) ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_GENERAL_CI.getCollateCommand() + " LIKE BINARY CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment endsWithHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() + " LIKE CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment endsWithIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT('%', LOWER(?)))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_GENERAL_CI.getCollateCommand() +" LIKE CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment containsHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() +" LIKE CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment containsIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT('%', LOWER(?) ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        //return of("(" + cn + " "+Collation.UTF8_GENERAL_CI.getCollateCommand()+" LIKE CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));        
    }

    @Override
    protected SqlPredicateFragment equalString(String cn, FieldPredicate<?> model) {
        return of(compare(cn, " = ?", Collation.UTF8_BIN)).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment notEqualString(String cn, FieldPredicate<?> model) {
        return of("(NOT " + compare(cn, " = ?", Collation.UTF8_BIN) + ")").add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment inString(String cn, FieldPredicate<?> model) {
        return inStringHelper(cn, model, false);
    }

    @Override
    protected SqlPredicateFragment notInString(String cn, FieldPredicate<?> model) {
        return inStringHelper(cn, model, true);
    }

    private SqlPredicateFragment inStringHelper(String cn, FieldPredicate<?> model, boolean negated) {
        final Set<?> set = getFirstOperandAsRawSet(model);
        return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() + " IN (" + set.stream().map($ -> "?").collect(joining(",")) + "))", negated).addAll(set);
    }

    @Override
    protected SqlPredicateFragment betweenString(String cn, FieldPredicate<?> model) {
        return betweenStringHelper(cn, model, false);
    }

    @Override
    protected SqlPredicateFragment notBetweenString(String cn, FieldPredicate<?> model) {
        return betweenStringHelper(cn, model, true);
    }

    private SqlPredicateFragment betweenStringHelper(String cn, FieldPredicate<?> model, boolean negated) {
        final Inclusion inclusion = getInclusionOperand(model);
        switch (inclusion) {
            case START_EXCLUSIVE_END_EXCLUSIVE: {
                return of(
                    "(" + greaterThanString(cn) + " AND " + lessThanString(cn) + ")",
                    negated<commit_msg>runtime-core: Fix error in in predicate view, Fix #468<commit_after>/**
 *
 * Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
 *
 * 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.speedment.runtime.core.internal.manager.sql;

import com.speedment.runtime.core.db.FieldPredicateView;
import com.speedment.runtime.core.db.SqlPredicateFragment;
import static com.speedment.runtime.core.internal.manager.sql.AbstractFieldPredicateView.of;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getFirstOperandAsRaw;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getFirstOperandAsRawSet;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getInclusionOperand;
import static com.speedment.runtime.field.internal.predicate.PredicateUtil.getSecondOperand;
import com.speedment.runtime.field.predicate.FieldPredicate;
import com.speedment.runtime.field.predicate.Inclusion;
import java.util.Set;
import static java.util.stream.Collectors.joining;

/**
 *
 * @author <NAME>
 */
@SuppressWarnings("rawtypes")
public final class MySqlSpeedmentPredicateView extends AbstractFieldPredicateView implements FieldPredicateView {

    /*
    create table colltest (
      name character(20)
    ) charset latin1;

    insert into colltest (name) values ('olle');
    insert into colltest (name) values ('sven');
    
    select * from colltest where name = 'olle' collate utf8_bin;

    select * from colltest where name in ('Olle', 'tryggve' collate utf8_bin) ;
    
     */
    private enum Collation {

        UTF8_BIN, UTF8_GENERAL_CI;

        private final String collateCommand;

        private Collation() {
            this.collateCommand = "COLLATE " + name().toLowerCase();
        }

        String getCollateCommand() {
            return collateCommand;
        }
    }

    @Override
    protected SqlPredicateFragment equalIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of(compare(cn, " = ?", Collation.UTF8_GENERAL_CI), negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment startsWithHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() + " LIKE CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment startsWithIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT(LOWER(?) ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_GENERAL_CI.getCollateCommand() + " LIKE BINARY CONCAT(? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment endsWithHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() + " LIKE CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment endsWithIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT('%', LOWER(?)))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_GENERAL_CI.getCollateCommand() +" LIKE CONCAT('%', ?))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment containsHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(" + cn + " LIKE BINARY CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        // return of("(" + cn + " " + Collation.UTF8_BIN.getCollateCommand() +" LIKE CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment containsIgnoreCaseHelper(String cn, FieldPredicate<?> model, boolean negated) {
        return of("(LOWER(" + cn + ") LIKE BINARY CONCAT('%', LOWER(?) ,'%'))", negated).add(getFirstOperandAsRaw(model));
        // Todo: Use collation like this:
        //return of("(" + cn + " "+Collation.UTF8_GENERAL_CI.getCollateCommand()+" LIKE CONCAT('%', ? ,'%'))", negated).add(getFirstOperandAsRaw(model));        
    }

    @Override
    protected SqlPredicateFragment equalString(String cn, FieldPredicate<?> model) {
        return of(compare(cn, " = ?", Collation.UTF8_BIN)).add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment notEqualString(String cn, FieldPredicate<?> model) {
        return of("(NOT " + compare(cn, " = ?", Collation.UTF8_BIN) + ")").add(getFirstOperandAsRaw(model));
    }

    @Override
    protected SqlPredicateFragment inString(String cn, FieldPredicate<?> model) {
        return inStringHelper(cn, model, false);
    }

    @Override
    protected SqlPredicateFragment notInString(String cn, FieldPredicate<?> model) {
        return inStringHelper(cn, model, true);
    }

    private SqlPredicateFragment inStringHelper(String cn, FieldPredicate<?> model, boolean negated) {
        final Set<?> set = getFirstOperandAsRawSet(model);
        return of("(" + cn + " IN (" + set.stream().map($ -> "?").collect(joining(",")) + " "+ Collation.UTF8_BIN.getCollateCommand() +"))", negated).addAll(set);
    }

    @Override
    protected SqlPredicateFragment betweenString(String cn, FieldPredicate<?> model) {
        return betweenStringHelper(cn, model, false);
    }

    @Override
    protected SqlPredicateFragment notBetweenString(String cn, FieldPredicate<?> model) {
        return betweenStringHelper(cn, model, true);
    }

    private SqlPredicateFragment betweenStringHelper(String cn, FieldPredicate<?> model, boolean negated) {
        final Inclusion inclusion = getInclusionOperand(model);
        switch (inclusion) {
            case START_EXCLUSIVE_END_EXCLUSIVE: {
                return of(
                    "(" + greaterThanString(cn) + " AND " + lessThanString(cn) + ")",
                    negated
{'fraction_non_alphanumeric': 0.1310745818677769, 'fraction_numerical': 0.004306941353815232, 'mean_word_length': 3.8057951017592275, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 39, 'https://': 0, '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': '7065726', 'n_tokens_mistral': 4210, 'n_tokens_neox': 4153, 'n_words': 947}