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}