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}