001package io.ebeaninternal.dbmigration.model;
002
003import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp;
004import io.ebeaninternal.dbmigration.migration.AddUniqueConstraint;
005import io.ebeaninternal.dbmigration.migration.UniqueConstraint;
006
007import java.util.Arrays;
008import java.util.Objects;
009
010import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
011import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.splitWithNull;
012
013/**
014 * A unique constraint for multiple columns.
015 * <p>
016 * Note that unique constraint on a single column is instead
017 * a boolean flag on the associated MColumn.
018 * </p>
019 */
020public class MCompoundUniqueConstraint {
021
022  private final String name;
023
024  /**
025   * Flag if true indicates this was specifically created for a OneToOne mapping.
026   */
027  private final boolean oneToOne;
028
029  /**
030   * The columns combined to be unique.
031   */
032  private final String[] columns;
033
034  private final String platforms;
035
036  private String[] nullableColumns;
037
038  /**
039   * Create for OneToOne.
040   */
041  public MCompoundUniqueConstraint(String[] columns, String name) {
042    this.name = name;
043    this.columns = columns;
044    this.oneToOne = true;
045    this.platforms = null;
046  }
047
048  public MCompoundUniqueConstraint(String[] columns, boolean oneToOne, String name, String platforms) {
049    this.name = name;
050    this.columns = columns;
051    this.oneToOne = oneToOne;
052    this.platforms = platforms;
053  }
054
055  public MCompoundUniqueConstraint(AddUniqueConstraint change) {
056    this.name = change.getConstraintName();
057    this.columns = split(change.getColumnNames());
058    this.oneToOne = Boolean.TRUE.equals(change.isOneToOne());
059    this.platforms = change.getPlatforms();
060    this.nullableColumns = splitWithNull(change.getNullableColumns());
061  }
062
063  public MCompoundUniqueConstraint(UniqueConstraint uq) {
064    this.name = uq.getName();
065    this.columns = split(uq.getColumnNames());
066    this.oneToOne = Boolean.TRUE.equals(uq.isOneToOne());
067    this.platforms = uq.getPlatforms();
068    this.nullableColumns = splitWithNull(uq.getNullableColumns());
069  }
070
071  /**
072   * Return the columns for this unique constraint.
073   */
074  public String[] getColumns() {
075    return columns;
076  }
077
078  /**
079   * Return true if this unique constraint is specifically for OneToOne mapping.
080   */
081  public boolean isOneToOne() {
082    return oneToOne;
083  }
084
085  /**
086   * Return the constraint name.
087   */
088  public String getName() {
089    return name;
090  }
091
092  public String getPlatforms() {
093    return platforms;
094  }
095
096  public UniqueConstraint getUniqueConstraint() {
097    UniqueConstraint uq = new UniqueConstraint();
098    uq.setName(getName());
099    uq.setColumnNames(join(columns));
100    uq.setNullableColumns(join(nullableColumns));
101    uq.setOneToOne(isOneToOne());
102    uq.setPlatforms(platforms);
103    return uq;
104  }
105
106  /**
107   * Return a AddUniqueConstraint migration for this constraint.
108   */
109  public AddUniqueConstraint addUniqueConstraint(String tableName) {
110    AddUniqueConstraint create = new AddUniqueConstraint();
111    create.setConstraintName(getName());
112    create.setTableName(tableName);
113    create.setColumnNames(join(columns));
114    create.setNullableColumns(join(nullableColumns));
115    create.setOneToOne(isOneToOne());
116    create.setPlatforms(platforms);
117    return create;
118  }
119
120  /**
121   * Create a AddUniqueConstraint migration with 'DROP CONSTRAINT' set for this index.
122   */
123  public AddUniqueConstraint dropUniqueConstraint(String tableName) {
124    AddUniqueConstraint drop = new AddUniqueConstraint();
125    drop.setConstraintName(name);
126    drop.setTableName(tableName);
127    drop.setColumnNames(DdlHelp.DROP_CONSTRAINT);
128    drop.setNullableColumns(join(nullableColumns));
129    drop.setPlatforms(platforms);
130    return drop;
131  }
132
133  public void setNullableColumns(String[] nullableColumns) {
134    if (nullableColumns != null && nullableColumns.length == 0) {
135      this.nullableColumns = null;
136    } else {
137      this.nullableColumns = nullableColumns;
138    }
139  }
140
141  private String join(String[] arr) {
142    if (arr == null) {
143      return "";
144    }
145    StringBuilder sb = new StringBuilder(50);
146    for (int i = 0; i < arr.length; i++) {
147      if (i > 0) {
148        sb.append(",");
149      }
150      sb.append(arr[i]);
151    }
152    return sb.toString();
153  }
154
155  @Override
156  public int hashCode() {
157    return Arrays.hashCode(columns) + 31 * Objects.hash(name, oneToOne);
158  }
159
160  @Override
161  public boolean equals(Object obj) {
162    if (obj == this) {
163      return true;
164    }
165    if (!(obj instanceof MCompoundUniqueConstraint)) {
166      return false;
167    }
168    MCompoundUniqueConstraint other = (MCompoundUniqueConstraint) obj;
169    // not including platforms in equals check
170    return oneToOne == other.oneToOne
171      && Objects.equals(name, other.name)
172      && Arrays.equals(columns, other.columns)
173      && Arrays.equals(nullableColumns, other.nullableColumns);
174  }
175}