com.chadekin.jadys.syntax.from.impl.FromClauseBuilderImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.chadekin.jadys.syntax.from.impl.FromClauseBuilderImpl.java

Source

/**
 *                     GNU General Public License (GPL)
 *                        version 3.0, 29 June 2007
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 *
 * Copyright (C) 2017 Marc Mamiah.
 * License GPLv3+: GNU GPL version 3
 */
package com.chadekin.jadys.syntax.from.impl;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.chadekin.jadys.JadysSqlQueryBuilder;
import com.chadekin.jadys.commons.AbstractSqlQueryBuilder;
import com.chadekin.jadys.commons.enums.SqlCrudSyntax;
import com.chadekin.jadys.commons.enums.SqlLexical;
import com.chadekin.jadys.commons.resourcekeys.JadysKeys;
import com.chadekin.jadys.model.SqlExpressionItem;
import com.chadekin.jadys.syntax.AliasStatement;
import com.chadekin.jadys.syntax.from.FromClauseExtendedBuilder;
import com.chadekin.jadys.syntax.select.SelectClauseBuilder;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;

/**
 * FromClauseBuilder
 */
public class FromClauseBuilderImpl<X extends FromClauseExtendedBuilder<X, W, O>, W, O>
        extends AbstractSqlQueryBuilder<X> implements FromClauseExtendedBuilder<X, W, O>, AliasStatement<X> {

    private static final Set<SqlLexical> JOIN_STATEMENTS = Sets.newHashSet(SqlLexical.JOIN, SqlLexical.FULL_JOIN,
            SqlLexical.LEFT_JOIN, SqlLexical.RIGHT_JOIN);
    private static final Set<SqlLexical> ON_STATEMENTS = Sets.newHashSet(SqlLexical.ON);
    private static final Set<SqlLexical> HEADER_STATEMENTS = Sets.union(ON_STATEMENTS,
            Sets.newHashSet(SqlLexical.SELECT));
    private static final Set<SqlLexical> FILTER_STATEMENTS = Sets.newHashSet(SqlLexical.WHERE, SqlLexical.GROUP_BY,
            SqlLexical.HAVING, SqlLexical.ORDER_BY);
    private static final Set<SqlLexical> FOOTER_STATEMENTS = Sets.union(ON_STATEMENTS, FILTER_STATEMENTS);

    // Map<Alias, JoinStatement>
    private Map<String, String> joinStatements = Maps.newLinkedHashMap();
    private Map.Entry<String, String> joinStatementTemp = null;

    protected FromClauseBuilderImpl(JadysSqlQueryBuilder parent, String table_name) {
        super(parent);
        if (StringUtils.isBlank(table_name)) {
            throw new IllegalArgumentException("Table name cannot be empty");
        }
        initBuilderValue(table_name);
    }

    public static FromClauseBuilderImpl newFromStatement(JadysSqlQueryBuilder parent, String table_name) {
        return new FromClauseBuilderImpl(parent, table_name);
    }

    @Override
    public SqlLexical getType() {
        return SqlLexical.FROM;
    }

    @Override
    public void finalizeExpression() {
        String exp = getSqlExpressionItem().toString();
        if (StringUtils.isNotBlank(exp) && exp.contains(SqlLexical.JOIN.getName())) {
            int beginIndex = exp.indexOf(SqlLexical.JOIN.getName() + JadysKeys.SPACE);
            int endIndex = exp.indexOf(JadysKeys.SPACE + SqlLexical.ON.getName());
            String alias = Stream.of(exp.substring(beginIndex, endIndex).split(JadysKeys.SPACE)).reduce((a, b) -> b)
                    .orElse(StringUtils.EMPTY).concat(JadysKeys.DOT);
            withAlias(alias);
            joinStatements.put(alias, exp);
        }
    }

    @Override
    public void applyJoin(SqlLexical sqlLexical, String alias, String fullStatement) {
        if (JOIN_STATEMENTS.contains(sqlLexical)) {
            joinStatementTemp = Maps.immutableEntry(alias + JadysKeys.DOT, fullStatement);
        } else if (SqlLexical.ON == sqlLexical) {
            StringBuilder statement = new StringBuilder(joinStatementTemp.getValue()).append(JadysKeys.SPACE)
                    .append(SqlLexical.ON).append(JadysKeys.SPACE).append(fullStatement);
            SqlExpressionItem expressionItem = new SqlExpressionItem();
            expressionItem.setParam(statement.toString());
            setSqlExpressionItem(expressionItem);
        }
    }

    @Override
    public String buildNext() {
        // retrieve active aliases
        Set<String> aliases = retrieveBasicActiveAliases();

        // check linked aliases and record them
        attachRelatedActiveAliases(aliases);

        String[] statements = joinStatements.entrySet().stream().filter(entry -> aliases.contains(entry.getKey()))
                .map(entry -> entry.getValue()).toArray(String[]::new);

        this.apply(statements);
        return super.buildNext();
    }

    private Set<String> retrieveBasicActiveAliases() {
        boolean isLazy = getParent() != null && getParent() instanceof SelectClauseBuilder
                && ((SelectClauseBuilder) getParent()).isLazy();
        Set<String> parentAliases = getParent() == null ? Sets.newHashSet() : getParent().getAlias();
        Set<String> childAliases = Sets.newHashSet();
        JadysSqlQueryBuilder childBuilder = getChild();
        while (childBuilder != null) {
            childAliases.addAll(childBuilder.getAlias());
            childBuilder = childBuilder.getChild();
        }
        return joinStatements.entrySet().stream()
                .filter(entry -> isLazy || parentAliases.contains(entry.getKey())
                        || childAliases.contains(entry.getKey()))
                .map(entry -> extractAlias(entry.getValue())).flatMap(entry -> entry.stream())
                .filter(val -> joinStatements.keySet().contains(val)).collect(Collectors.toSet());
    }

    private void attachRelatedActiveAliases(Set<String> aliases) {
        Set<String> foundAliases = Sets.newHashSet(aliases);
        while (!foundAliases.isEmpty()) {
            Set<String> result = Sets.difference(findRelatedAlias(foundAliases), aliases);
            foundAliases.clear();
            foundAliases.addAll(result);
            aliases.addAll(result);
        }
    }

    private Set<String> findRelatedAlias(Collection<String> aliasToSearch) {
        return joinStatements.entrySet().stream().filter(entry -> aliasToSearch.contains(entry.getKey()))
                .map(entry -> extractAlias(entry.getValue())).flatMap(entry -> entry.stream())
                .filter(alias -> joinStatements.keySet().contains(alias) && !aliasToSearch.contains(alias))
                .collect(Collectors.toSet());
    }

    private void initBuilderValue(String table_name) {
        StringBuilder value = new StringBuilder();
        if (table_name.contains(SqlCrudSyntax.SELECT.getCode())) {
            value.append(JadysKeys.OPEN_PARENTHESIS).append(table_name).append(JadysKeys.CLOSE_PARENTHESIS);
        } else {
            value.append(table_name);
        }
        apply(value.toString());
    }

}