Arrow.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you 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 org.apache.calcite.util;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
/**
* Represents one functional dependency (Arrow) between two sets of columns,
* where each column is identified by its ordinal index.
*
* <p>{@link Arrow} models the functional dependency such that the values of the
* {@link #determinants} columns uniquely determine the values of the
* {@link #dependents} columns. In other words, if two rows have the same values
* for all determinant columns, they must also have the same values for all
* dependent columns. Both {@link #determinants} and {@link #dependents} are
* ImmutableBitSet column ordinals.
*
* <p>This structure supports arbitrary cardinality for both determinant and
* dependent column sets, allowing the representation relationships:
* <ul>
* <li>One-to-one: {@code {0} ��� {1}}
* <li>One-to-many: {@code {0} ��� {1, 2}}
* <li>Many-to-one: {@code {0, 1} ��� {2}}
* <li>Many-to-many: {@code {0, 1} ��� {2, 3}}
* </ul>
*
* <p>Example:
*
* <blockquote>
* <pre>
* Table schema: [emp_id, name, dept, salary] // ordinals: 0, 1, 2, 3
* Arrow: {0} ��� {1, 2}
* Functional dependency: emp_id ��� {name, dept}
* </pre>
* </blockquote>
*
* <p>This indicates that the employee ID uniquely determines both the name
* and department attributes.
*/
public class Arrow {
// The set of column ordinals that are the determinants in the functional dependency.
private final ImmutableBitSet determinants;
// The set of column ordinals that are determined by the determinants.
private final ImmutableBitSet dependents;
private Arrow(ImmutableBitSet determinants, ImmutableBitSet dependents) {
this.determinants = requireNonNull(determinants, "determinants must not be null");
this.dependents = requireNonNull(dependents, "dependents must not be null");
}
/**
* Create Arrow from determinant set to dependent set.
*/
public static Arrow of(ImmutableBitSet determinants, ImmutableBitSet dependents) {
return new Arrow(determinants, dependents);
}
/**
* Create Arrow from single determinant to single dependent.
*/
public static Arrow of(int determinant, int dependent) {
return Arrow.of(ImmutableBitSet.of(determinant), ImmutableBitSet.of(dependent));
}
public ImmutableBitSet getDeterminants() {
return determinants;
}
public ImmutableBitSet getDependents() {
return dependents;
}
/**
* Returns true if this Arrow is trivial (dependents ��� determinants).
*/
public boolean isTrivial() {
return determinants.contains(dependents);
}
@Override public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Arrow)) {
return false;
}
Arrow that = (Arrow) o;
return determinants.equals(that.determinants)
&& dependents.equals(that.dependents);
}
@Override public int hashCode() {
return Objects.hash(determinants, dependents);
}
@Override public String toString() {
return determinants + " -> " + dependents;
}
}