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