Package com.jengine.orm.model.multi

Source Code of com.jengine.orm.model.multi.MultiModel$RightJoin

/*
*  This file is part of JEngine.
*  *
*  * Copyright (C) 2013-2014 Cetus (http://cs1.com.ua/). All rights reserved.
*  *
*  * JEngine 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.
*  *
*  * JEngine 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 JEngine.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.jengine.orm.model.multi;


import com.jengine.orm.DB;
import com.jengine.orm.DBFactory;
import com.jengine.orm.db.query.SQLQuery;
import com.jengine.orm.model.ModelClassBase;
import com.jengine.orm.model.field.Field;
import com.jengine.orm.model.field.ForeignField;
import com.jengine.orm.model.field.reference.BaseReference;
import com.jengine.orm.model.field.reference.ReferenceField;
import com.jengine.orm.model.multi.field.CalcMultiField;
import com.jengine.orm.model.multi.field.MultiModelField;
import com.jengine.orm.model.multi.parser.ExprLexer;
import com.jengine.orm.model.multi.parser.ExprParser;
import com.jengine.utils.commons.expression.ExpressionData;
import com.jengine.utils.commons.expression.ExpressionNode;
import com.jengine.utils.commons.expression.ExpressionOperation;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

import java.util.*;

import static com.jengine.utils.commons.CollectionUtil.list;
import static com.jengine.utils.commons.CollectionUtil.toList;

public class MultiModel {
    protected LinkedHashMap<String, MultiModelItem> items = new LinkedHashMap<String, MultiModelItem>();
    protected LinkedHashMap<String, MultiModelField> fields = new LinkedHashMap<String, MultiModelField>();
    protected ExpressionNode expression;
    protected List<Join> operations = new ArrayList<Join>();
    protected Map<String, Integer> _modelCounters = new HashMap<String, Integer>();
    protected DB db;

    public MultiModel(String expr) throws RecognitionException {
        db = DBFactory.get();
        expression = parse(expr);
    }

    public MultiModel(DB db, String expr) throws RecognitionException {
        this.expression = parse(expr);
        this.db = db;
    }

    public MultiModel(ModelClassBase model) {
        MultiModelItem item = add(new MultiModelItem(this, model, model.getName()));
        expression =  new MultiModelNode(item);
        db = model.getDb();
    }

    public MultiModel(ModelClassBase model, String name) {
        add(new MultiModelItem(this, model, name));
        db = model.getDb();
    }

    public MultiModel restriction(int operationIndex, String reference, String key) {
        operations.get(operationIndex).setReference(fields.get(reference));
        operations.get(operationIndex).setKey(fields.get(key));
        return this;
    }

    public MultiModel alias(int itemIndex, String alias) {
        return alias(getItemList().get(itemIndex), alias);
    }

    public MultiModel alias(String itemName, String alias) {
        return alias(items.get(itemName), alias);
    }

    public MultiModel alias(MultiModelItem item, String alias) {
        items.put(alias, item);
        for (MultiModelField field : item.getFields().values()) {
            fields.put(alias + "." + field.getModelField().getFieldName(), field);
        }
        return this;
    }

    public MultiModelField getField(String field) {
        return fields.get(field);
    }

    /* model operations */

    public MultiModel join(ModelClassBase model, String reference, String key) {
        return join(model, makeItemName(model), reference, key);
    }

    public MultiModel join(ModelClassBase model, String name, String reference, String key) {
        MultiModelItem item = add(new MultiModelItem(this, model, name));
        expression = new InnerJoin(expression, new MultiModelNode(item), fields.get(reference), fields.get(key));
        operations.add((Join) expression);
        return this;
    }

    public MultiModel join(ModelClassBase model) {
        MultiModelItem item = add(new MultiModelItem(this, model, makeItemName(model)));
        String[] keys = calcRestrictionKeys(toList(items.values()), item);
        expression = new InnerJoin(expression, new MultiModelNode(item), fields.get(keys[0]), fields.get(keys[1]));
        operations.add((Join) expression);
        return this;
    }

    /* left join operations */

    public MultiModel ljoin(ModelClassBase model, String reference, String key) {
        return ljoin(model, makeItemName(model), reference, key);
    }

    public MultiModel ljoin(ModelClassBase model, String name, String reference, String key) {
        MultiModelItem item = add(new MultiModelItem(this, model, name));
        expression = new LeftJoin(expression, new MultiModelNode(item), fields.get(reference), fields.get(key));
        operations.add((Join) expression);
        return this;
    }

    public MultiModel ljoin(ModelClassBase model) {
        MultiModelItem item = add(new MultiModelItem(this, model, makeItemName(model)));
        String[] keys = calcRestrictionKeys(toList(items.values()), item);
        expression = new LeftJoin(expression, new MultiModelNode(item), fields.get(keys[0]), fields.get(keys[1]));
        operations.add((Join) expression);
        return this;
    }

    /* right join operations */

    public MultiModel rjoin(ModelClassBase model, String reference, String key) {
        return rjoin(model, makeItemName(model), reference, key);
    }

    public MultiModel rjoin(ModelClassBase model, String name, String reference, String key) {
        MultiModelItem item = add(new MultiModelItem(this, model, name));
        expression = new RightJoin(expression, new MultiModelNode(item), fields.get(reference), fields.get(key));
        operations.add((Join) expression);
        return this;
    }

    public MultiModel rjoin(ModelClassBase model) {
        MultiModelItem item = add(new MultiModelItem(this, model, makeItemName(model)));
        String[] keys = calcRestrictionKeys(toList(items.values()), item);
        expression = new RightJoin(expression, new MultiModelNode(item), fields.get(keys[0]), fields.get(keys[1]));
        operations.add((Join) expression);
        return this;
    }

    /* full join operations */

    public MultiModel fjoin(ModelClassBase model, String reference, String key) {
        return rjoin(model, makeItemName(model), reference, key);
    }

    public MultiModel fjoin(ModelClassBase model, String name, String reference, String key) {
        MultiModelItem item = add(new MultiModelItem(this, model, name));
        expression = new FullJoin(expression, new MultiModelNode(item), fields.get(reference), fields.get(key));
        operations.add((Join) expression);
        return this;
    }

    public MultiModel fjoin(ModelClassBase model) {
        MultiModelItem item = add(new MultiModelItem(this, model, makeItemName(model)));
        String[] keys = calcRestrictionKeys(toList(items.values()), item);
        expression = new FullJoin(expression, new MultiModelNode(item), fields.get(keys[0]), fields.get(keys[1]));
        operations.add((Join) expression);
        return this;
    }

    /* cross join operations */

    public MultiModel and(ModelClassBase model) {
        return and(model, makeItemName(model));
    }

    public MultiModel and(ModelClassBase model, String name) {
        MultiModelItem item = add(new MultiModelItem(this, model, name));
        expression = new And(expression, new MultiModelNode(item));
        return this;
    }

    protected String[] calcRestrictionKeys(List<MultiModelItem> items, List<MultiModelItem> joinItems) {
        for (MultiModelItem joinItem : joinItems) {
            String[] result = calcRestrictionKeys(items, joinItem);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    protected String[] calcRestrictionKeys(List<MultiModelItem> items, MultiModelItem joinItem) {
        String[] result = new String[2];

        for (MultiModelItem item : items) {
            if (item.getName().equals(joinItem.getName())) {
                continue;
            }
            ModelClassBase modelClass = item.getModelClass();
            HashMap<String, ReferenceField> referenceModels = modelClass.getManager().getReferenceModels();
            if (referenceModels.containsKey(joinItem.getModelClass().getName())) {
                ReferenceField referenceField = referenceModels.get(joinItem.getModelClass().getName());
                result[0] = joinItem.getMultiModelField(referenceField.getReferenceModelKey()).getName();
                result[1] = item.getMultiModelField(referenceField).getName();
                return result;
            }
        }

        return null;
    }

    public <T extends CalcMultiField> T addCalcField(T field) {
        fields.put(field.getName(), field);
        field.config(this);
        return field;
    }

    protected MultiModelItem add(MultiModelItem item) {
        items.put(item.getName(), item);
        fields.putAll(item.getFields());
        _modelCounters.put(item.getModelClass().getName(), 0);
        item.config();
        return item;
    }

    /* Join Related Models */

    public MultiModelField getRelatedField(MultiModelItem item, String field) {
        return getRelatedField(item, item.getModelClass().getManager().getField(field));
    }

    public MultiModelField getRelatedField(MultiModelItem item, Field modelField) {
        String fullName = getRelatedFieldName(item, modelField.getFieldName());
        this.joinRelatedModels(item, getReferencePath(modelField));
        return fields.get(fullName);
    }

    public List<String> getReferencePath(Field modelField) {
        List<String> result = new ArrayList<String>();

        if (modelField instanceof ForeignField) {
            result.addAll(((ForeignField) modelField).getReferencePath());
        } else if (modelField instanceof BaseReference) {
            result.add(modelField.getFieldName());
        }

        return result;
    }

    protected String getRelatedFieldName(MultiModelItem item, String fieldName) {
        return item.getName() + "." + fieldName;
    }

    public void joinRelatedModels(MultiModelItem item, List<String> path) {
        if (path.size() > 0) {
            String fieldName = path.get(0);
            ReferenceField currentField  = (ReferenceField) item.getModelClass().getManager().getField(fieldName);
            ModelClassBase referenceClass = currentField.getReferenceClass();
            String referenceItemName = item.getName() + "." + fieldName;
            if (!this.items.containsKey(referenceItemName)) {
                this.ljoin(referenceClass, referenceItemName,
                        String.format("%s.%s", referenceItemName, currentField.getReferenceModelKey().getFieldName()),
                        String.format("%s.%s", item.getName(), fieldName));
            }
            joinRelatedModels(items.get(referenceItemName), path.subList(1, path.size()));
        }
    }

    /* SQL methods*/

    public SQLQuery.Table getMultiTable() {
        List<SQLQuery.TableItem> tableItems = getTableItems();
        ExpressionNode expressionNode  = makeSQLExpression();
        return new SQLQuery.Table(tableItems, expressionNode);
    }

    protected ExpressionNode makeSQLExpression() {
        return expression instanceof MultiModelNode ?
                ((MultiModelNode) expression).toSQL() :
                ((ModelOperation) expression).toSQL();
    }

    protected List<SQLQuery.TableItem> getTableItems() {
        List<SQLQuery.TableItem> items = new ArrayList<SQLQuery.TableItem>();

        for (MultiModelItem modelItem : this.items.values()) {
            items.add(modelItem.getTableItem());
        }

        return items;
    }

    protected String makeItemName(ModelClassBase modelClass) {
        String name = modelClass.getName();

        if (items.containsKey(name)) {
            Integer modelCounter = _modelCounters.get(name) + 1;
            name = String.format("%s%s", name, modelCounter);
            _modelCounters.put(name, modelCounter);
        }

        return name;
    }

    /* getters and setters */

    public List<MultiModelItem> getItemList() {
        return toList(items.values());
    }

    public LinkedHashMap<String, MultiModelItem> getItems() {
        return items;
    }

    public LinkedHashMap<String, MultiModelField> getFields() {
        return fields;
    }

    public List<MultiModelField> getFieldList() {
        return toList(fields.values());
    }

    public ExpressionNode getExpression() {
        return expression;
    }

    public DB getDB() {
        return db;
    }

    /* parsing methods */
    public ExpressionNode parse(String modelExpression) throws RecognitionException {
        ANTLRStringStream in = new ANTLRStringStream(modelExpression);
        ExprLexer lexer = new ExprLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExprParser parser = new ExprParser(tokens);
        CommonTree tree = (CommonTree) parser.model_expression().getTree();
        return visit(tree);
    }

    protected ExpressionNode visit(Tree tree) {
        if (tree.getType() == ExprParser.GROUP) {
            return new Group(visit(tree.getChild(0)));
        } else if (tree.getType() == ExprParser.MODEL_NAME) {
            String modelClassName = tree.getChild(0).getText();
            ModelClassBase modelClass = getDB().getModelClass(modelClassName);
            MultiModelItem item = add(new MultiModelItem(this, modelClass, makeItemName(modelClass)));
            return new MultiModelNode(item);
        } else if (tree.getType() == ExprParser.RIGHT_JOIN) {
            ExpressionNode operand1 = visit(tree.getChild(0));
            ExpressionNode operand2 = visit(tree.getChild(1));
            String[] keys = calcRestrictionKeys(getMultiModelItems(operand2), getMultiModelItems(operand1));
            keys = keys != null ?  keys : calcRestrictionKeys(getMultiModelItems(operand1), getMultiModelItems(operand2));
            RightJoin join = new RightJoin(operand1, operand2, fields.get(keys[0]), fields.get(keys[1]));
            operations.add(join);
            return join;
        } else if (tree.getType() == ExprParser.LEFT_JOIN) {
            ExpressionNode operand1 = visit(tree.getChild(0));
            ExpressionNode operand2 = visit(tree.getChild(1));
            String[] keys = calcRestrictionKeys(getMultiModelItems(operand1), getMultiModelItems(operand2));
            keys = keys != null ?  keys : calcRestrictionKeys(getMultiModelItems(operand2), getMultiModelItems(operand1));
            LeftJoin join = new LeftJoin(operand1, operand2, fields.get(keys[0]), fields.get(keys[1]));
            operations.add(join);
            return join;
        } else if (tree.getType() == ExprParser.FULL_JOIN) {
            ExpressionNode operand1 = visit(tree.getChild(0));
            ExpressionNode operand2 = visit(tree.getChild(1));
            String[] keys = calcRestrictionKeys(getMultiModelItems(operand1), getMultiModelItems(operand2));
            keys = keys != null ?  keys : calcRestrictionKeys(getMultiModelItems(operand2), getMultiModelItems(operand1));
            FullJoin join = new FullJoin(operand1, operand2, fields.get(keys[0]), fields.get(keys[1]));
            operations.add(join);
            return join;
        } else if (tree.getType() == ExprParser.INNER_JOIN) {
            ExpressionNode operand1 = visit(tree.getChild(0));
            ExpressionNode operand2 = visit(tree.getChild(1));
            String[] keys = calcRestrictionKeys(getMultiModelItems(operand1), getMultiModelItems(operand2));
            keys = keys != null ?  keys : calcRestrictionKeys(getMultiModelItems(operand2), getMultiModelItems(operand1));
            InnerJoin join = new InnerJoin(operand1, operand2, fields.get(keys[0]), fields.get(keys[1]));
            operations.add(join);
            return join;
        } else if (tree.getType() == ExprParser.AND) {
            ExpressionNode operand1 = visit(tree.getChild(0));
            ExpressionNode operand2 = visit(tree.getChild(1));
            return new And(operand1, operand2);
        }
        return null;
    }

    protected List<MultiModelItem> getMultiModelItems(ExpressionNode node) {
        return node instanceof MultiModelNode ?
                list(((MultiModelNode) node).getData()) :
                ((ModelOperation) node).getMultiModelItems();
    }

    /* inner classes */

    public static class MultiModelNode extends ExpressionData<MultiModelItem> {

        public MultiModelNode(MultiModelItem data) {
            super(data);
        }

        public SQLQuery.TableItem getTableItem() {
            return getData().getTableItem();
        }

        public ExpressionData<SQLQuery.TableItem> toSQL() {
            return new ExpressionData<SQLQuery.TableItem>(getTableItem());
        }
    }

    public static class ModelOperation extends ExpressionOperation {
        public ModelOperation(List<ExpressionNode> nodes) {
            super(nodes);
        }

        public ModelOperation(ExpressionNode... nodes) {
            super(nodes);
        }

        protected List<MultiModelItem> getMultiModelItems() {
            List<MultiModelItem> items = new ArrayList<MultiModelItem>();

            for (ExpressionNode node : nodes) {
                if (node instanceof MultiModelNode) {
                    items.add(((MultiModelNode) node).getData());
                } else {
                    items.addAll(((ModelOperation) node).getMultiModelItems());
                }
            }

            return items;
        }

        public ExpressionOperation toSQL() {
            return null;
        }

        protected ExpressionNode toSQL(ExpressionNode node) {
            return node instanceof MultiModelNode ? ((MultiModelNode) node).toSQL() : ((ModelOperation) node).toSQL();
        }
    }

    public static class Group extends ModelOperation {

        public Group(ExpressionNode expressionNode) {
            super(expressionNode);
        }

        public ExpressionNode getChild() {
            return nodes.get(0);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.Group(toSQL(getChild()));
        }
    }

    public static abstract class Join extends ModelOperation {
        private MultiModelField reference;
        private MultiModelField key;

        public Join(ExpressionNode operand1, ExpressionNode operand2, MultiModelField reference, MultiModelField key) {
            super(operand1, operand2);
            this.reference = reference;
            this.key = key;
        }

        public ExpressionNode getLeftNode() {
            return nodes.get(0);
        }

        public ExpressionNode getJoinNode() {
            return nodes.get(1);
        }

        public void setReference(MultiModelField reference) {
            this.reference = reference;
        }

        public void setKey(MultiModelField key) {
            this.key = key;
        }

        abstract public ExpressionOperation toSQL();

        protected String makeSQLRestriction() {
            return String.format("%s = %s", reference.getSQLName(), key.getSQLName());
        }
    }

    public static class InnerJoin extends Join {

        public InnerJoin(ExpressionNode operand1, ExpressionNode operand2, MultiModelField reference, MultiModelField key) {
            super(operand1, operand2, reference, key);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.Join(toSQL(getLeftNode()), toSQL(getJoinNode()), makeSQLRestriction());
        }

    }

    public static class FullJoin extends Join {

        public FullJoin(ExpressionNode operand1, ExpressionNode operand2, MultiModelField reference, MultiModelField key) {
            super(operand1, operand2, reference, key);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.FullJoin(toSQL(getLeftNode()), toSQL(getJoinNode()), makeSQLRestriction());
        }

    }

    public static class LeftJoin extends Join {
        public LeftJoin(ExpressionNode operand1, ExpressionNode operand2, MultiModelField reference, MultiModelField key) {
            super(operand1, operand2, reference, key);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.LeftJoin(toSQL(getLeftNode()), toSQL(getJoinNode()), makeSQLRestriction());
        }
    }

    public static class RightJoin extends Join {
        public RightJoin(ExpressionNode operand1, ExpressionNode operand2, MultiModelField reference, MultiModelField key) {
            super(operand1, operand2, reference, key);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.RightJoin(toSQL(getLeftNode()), toSQL(getJoinNode()), makeSQLRestriction());
        }
    }

    public static class And extends ModelOperation {
        public And(ExpressionNode operand1, ExpressionNode operand2) {
            super(operand1, operand2);
        }

        public ExpressionOperation toSQL() {
            return new SQLQuery.And(toSQL(getNodes().get(0)), toSQL(getNodes().get(1)));
        }
    }
}
TOP

Related Classes of com.jengine.orm.model.multi.MultiModel$RightJoin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.