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

com.landawn.abacus.metadata.Association Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2015 HaiYang Li
 *
 * 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.landawn.abacus.metadata;

import static com.landawn.abacus.condition.ConditionFactory.leftJoin;
import static com.landawn.abacus.condition.ConditionFactory.on;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.landawn.abacus.condition.Join;
import com.landawn.abacus.util.WD;
import com.landawn.abacus.util.N;

// TODO: Auto-generated Javadoc
/**
 *
 * @author Haiyang Li
 * @since 0.8
 */
public class Association implements Serializable {

    private static final long serialVersionUID = -3451344350605572248L;

    private final String joinOn;

    private final Property prop;

    private final Property srcProp;

    private final Property targetProp;

    private final Property[] biEntityProps;

    private final EntityDefinition biEntityDef;

    private final JoinType joinType;

    private final List joins;

    public Association(Property prop, String joinOn) {
        this.joinOn = joinOn;
        this.prop = prop;
        this.joins = new ArrayList<>();

        String spliter = WD.SPACE + WD.AND + WD.SPACE;
        int index = joinOn.toUpperCase().indexOf(spliter);
        String[] lr = null;

        if (index > 0) {
            lr = N.asArray(joinOn.substring(0, index), joinOn.substring(index + spliter.length()));
        } else {
            lr = N.asArray(joinOn);
        }

        EntityDefinition entityDef = prop.getEntityDefinition();
        String[] left = lr[0].split(WD.EQUAL);
        Property left1 = checkProperty(entityDef, left[0].trim());
        Property left2 = checkProperty(entityDef, left[1].trim());

        if (1 == lr.length) {
            if (left1.getEntityDefinition().equals(entityDef)) {
                srcProp = left1;
                targetProp = left2;
            } else {
                srcProp = left2;
                targetProp = left1;
            }

            EntityDefinition targetEntityDef = targetProp.getEntityDefinition();

            if (targetProp.isId()) {
                throw new IllegalArgumentException("Unsupported joinOn: '" + joinOn + "'. '" + targetEntityDef.getName() + "' can joinOn '"
                        + entityDef.getName() + "'. but '" + entityDef.getName() + "' can't joinOn '" + targetEntityDef.getName() + "'.");
            }

            joins.add(leftJoin(targetProp.getEntityDefinition().getName(), on(lr[0])));
            biEntityProps = null;
            biEntityDef = null;
        } else {
            String[] right = lr[1].split(WD.EQUAL);
            Property right1 = checkProperty(entityDef, right[0].trim());
            Property right2 = checkProperty(entityDef, right[1].trim());
            biEntityProps = new Property[2];

            if (left1.getEntityDefinition().equals(entityDef)) {
                srcProp = left1;
                biEntityProps[0] = left2;

                if (right1.getEntityDefinition().equals(biEntityProps[0].getEntityDefinition())) {
                    biEntityProps[1] = right1;
                    targetProp = right2;
                } else {
                    biEntityProps[1] = right2;
                    targetProp = right1;
                }
            } else if (left2.getEntityDefinition().equals(entityDef)) {
                srcProp = left2;
                biEntityProps[0] = left1;

                if (right1.getEntityDefinition().equals(biEntityProps[0].getEntityDefinition())) {
                    biEntityProps[1] = right1;
                    targetProp = right2;
                } else {
                    biEntityProps[1] = right2;
                    targetProp = right1;
                }
            } else if (right1.getEntityDefinition().equals(entityDef)) {
                srcProp = right1;
                biEntityProps[0] = right2;

                if (left1.getEntityDefinition().equals(biEntityProps[0].getEntityDefinition())) {
                    biEntityProps[1] = left1;
                    targetProp = left2;
                } else {
                    biEntityProps[1] = left2;
                    targetProp = left1;
                }
            } else {
                srcProp = right2;
                biEntityProps[0] = right1;

                if (left1.getEntityDefinition().equals(biEntityProps[0].getEntityDefinition())) {
                    biEntityProps[1] = left1;
                    targetProp = left2;
                } else {
                    biEntityProps[1] = left2;
                    targetProp = left1;
                }
            }

            biEntityDef = biEntityProps[0].getEntityDefinition();

            if (targetProp.equals(right1) || targetProp.equals(right2)) {
                joins.add(leftJoin(biEntityDef.getName(), on(lr[0])));
                joins.add(leftJoin(targetProp.getEntityDefinition().getName(), on(lr[1])));
            } else {
                joins.add(leftJoin(biEntityDef.getName(), on(lr[1])));
                joins.add(leftJoin(targetProp.getEntityDefinition().getName(), on(lr[0])));
            }
        }

        joinType = (targetProp.isId() && (biEntityDef == null)) ? JoinType.OUTER : JoinType.INNER;

        if ((biEntityDef == null) && (srcProp.isId() && targetProp.isId())) {
            throw new RuntimeException("Not supported assocation. The foreigin and reference properties can't both be id.");
        }
    }

    /**
     *
     * @param ed
     * @param propName
     * @return
     */
    private Property checkProperty(EntityDefinition ed, String propName) {
        propName = propName.trim();

        Property prop = ed.getProperty(propName);

        if ((prop == null) && (propName.indexOf(".") < 0)) {
            propName = ed.getName() + "." + propName;
            prop = ed.getProperty(propName);
        }

        if (prop == null) {
            throw new IllegalArgumentException("Invalid joinOn property name[" + propName + "]. ");
        }

        return prop;
    }

    /**
     * Gets the property.
     *
     * @return
     */
    public Property getProperty() {
        return prop;
    }

    /**
     * Gets the src property.
     *
     * @return
     */
    public Property getSrcProperty() {
        return srcProp;
    }

    /**
     * Gets the target property.
     *
     * @return
     */
    public Property getTargetProperty() {
        return targetProp;
    }

    /**
     * Gets the bi entity properties.
     *
     * @return
     */
    public Property[] getBiEntityProperties() {
        return biEntityProps;
    }

    /**
     * Gets the bi entity def.
     *
     * @return
     */
    public EntityDefinition getBiEntityDef() {
        return biEntityDef;
    }

    /**
     * Gets the join type.
     *
     * @return
     */
    public JoinType getJoinType() {
        return joinType;
    }

    /**
     * Gets the join condition.
     *
     * @return
     */
    public Collection getJoinCondition() {
        return joins;
    }

    /**
     *
     * @param obj
     * @return true, if successful
     */
    @Override
    public boolean equals(Object obj) {
        return this == obj || (obj instanceof Association && N.equals(((Association) obj).joinOn, joinOn));
    }

    @Override
    public int hashCode() {
        return joinOn.hashCode();
    }

    @Override
    public String toString() {
        return joinOn;
    }

    /**
     * The Enum JoinType.
     */
    public enum JoinType {
        /**
         * Filed INNER.
         */
        INNER,
        /**
         * Field OUTER.
         */
        OUTER;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy