001package io.ebeaninternal.dbmigration.model;
002
003import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
004import io.ebeaninternal.dbmigration.migration.AlterForeignKey;
005import io.ebeaninternal.dbmigration.migration.ForeignKey;
006
007import java.util.ArrayList;
008import java.util.List;
009import java.util.Objects;
010
011/**
012 * A unique constraint for multiple columns.
013 * <p>
014 * Note that unique constraint on a single column is instead
015 * a boolean flag on the associated MColumn.
016 * </p>
017 */
018public class MCompoundForeignKey {
019
020  private String name;
021  private final String referenceTable;
022  private final List<String> columns = new ArrayList<>();
023  private final List<String> referenceColumns = new ArrayList<>();
024  private String indexName;
025
026  public MCompoundForeignKey(String name, String referenceTable, String indexName) {
027    this.name = name;
028    this.referenceTable = referenceTable;
029    this.indexName = indexName;
030  }
031
032  /**
033   * Add a column pair of local and referenced column.
034   */
035  public void addColumnPair(String dbCol, String refColumn) {
036    columns.add(dbCol);
037    referenceColumns.add(refColumn);
038  }
039
040  /**
041   * Create and return an ForeignKey migration element.
042   */
043  public ForeignKey createForeignKey() {
044    ForeignKey fk = new ForeignKey();
045    fk.setName(name);
046    fk.setIndexName(indexName);
047    fk.setColumnNames(toColumnNames(columns));
048    fk.setRefColumnNames(toColumnNames(referenceColumns));
049    fk.setRefTableName(referenceTable);
050    return fk;
051  }
052  
053  /**
054   * Create and return an AlterForeignKey migration element.
055   */
056  public AlterForeignKey addForeignKey(String tableName) {
057    AlterForeignKey fk = new AlterForeignKey();
058    fk.setName(name);
059    fk.setIndexName(indexName);
060    fk.setColumnNames(toColumnNames(columns));
061    fk.setRefColumnNames(toColumnNames(referenceColumns));
062    fk.setRefTableName(referenceTable);
063    fk.setTableName(tableName);
064    return fk;
065  }
066  
067  /**
068   * Create and return an AlterForeignKey migration element.
069   */
070  public AlterForeignKey dropForeignKey(String tableName) {
071    AlterForeignKey fk = new AlterForeignKey();
072    fk.setName(name);
073    fk.setIndexName(indexName);
074    fk.setColumnNames(DdlHelp.DROP_FOREIGN_KEY);
075    fk.setTableName(tableName);
076    return fk;
077  }
078
079  /**
080   * Add a counter to the foreign key and index names to avoid duplication.
081   */
082  public void addNameSuffix(int counter) {
083    this.name = name + "_" + counter;
084    this.indexName = indexName + "_" + counter;
085  }
086
087  /**
088   * Return the foreign key name.
089   */
090  public String getName() {
091    return name;
092  }
093
094  /**
095   * Return the index name.
096   */
097  public String getIndexName() {
098    return indexName;
099  }
100
101  /**
102   * Return the columns making up the foreign key in order.
103   */
104  public List<String> getColumns() {
105    return columns;
106  }
107
108  /**
109   * Set the associated index name. Note that setting to null has the effect
110   * of indicating an associated index should not be created for this foreign key.
111   */
112  public void setIndexName(String indexName) {
113    this.indexName = indexName;
114  }
115
116  /**
117   * Return as an array of string column names.
118   */
119  private String toColumnNames(List<String> columns) {
120
121    StringBuilder sb = new StringBuilder(40);
122    for (int i = 0; i < columns.size(); i++) {
123      if (i > 0) {
124        sb.append(",");
125      }
126      sb.append(columns.get(i));
127    }
128    return sb.toString();
129  }
130
131  @Override
132  public int hashCode() {
133    return Objects.hash(columns, indexName, name, referenceColumns, referenceTable);
134  }
135
136  @Override
137  public boolean equals(Object obj) {
138    if (this == obj)
139      return true;
140    if (!(obj instanceof MCompoundForeignKey))
141      return false;
142    
143    MCompoundForeignKey other = (MCompoundForeignKey) obj;
144    return Objects.equals(columns, other.columns)
145        && Objects.equals(indexName, other.indexName)
146        && Objects.equals(name, other.name)
147        && Objects.equals(referenceColumns, other.referenceColumns)
148        && Objects.equals(referenceTable, other.referenceTable);
149  }
150
151}