001package io.ebeaninternal.dbmigration.model;
002
003import io.ebeaninternal.dbmigration.migration.CreateIndex;
004import io.ebeaninternal.dbmigration.migration.DropIndex;
005
006import java.util.ArrayList;
007import java.util.Collections;
008import java.util.List;
009import java.util.Objects;
010
011/**
012 * Index as part of the logical model.
013 */
014public class MIndex {
015
016  private String tableName;
017  private String indexName;
018  private String platforms;
019  private List<String> columns = new ArrayList<>();
020  private boolean unique;
021  private boolean concurrent;
022  private String definition;
023
024  /**
025   * Create a single column non unique index.
026   */
027  public MIndex(String indexName, String tableName, String columnName) {
028    this.tableName = tableName;
029    this.indexName = indexName;
030    this.columns.add(columnName);
031  }
032
033  /**
034   * Create a multi column non unique index.
035   */
036  public MIndex(String indexName, String tableName, String[] columnNames) {
037    this.tableName = tableName;
038    this.indexName = indexName;
039    Collections.addAll(this.columns, columnNames);
040  }
041
042  public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique, boolean concurrent, String definition) {
043    this(indexName, tableName, columnNames);
044    this.platforms = platforms;
045    this.unique = unique;
046    this.concurrent = concurrent;
047    this.definition = emptyToNull(definition);
048  }
049
050  public MIndex(CreateIndex createIndex) {
051    this.indexName = createIndex.getIndexName();
052    this.tableName = createIndex.getTableName();
053    this.columns = split(createIndex.getColumns());
054    this.platforms = createIndex.getPlatforms();
055    this.unique = Boolean.TRUE.equals(createIndex.isUnique());
056    this.concurrent = Boolean.TRUE.equals(createIndex.isConcurrent());
057    this.definition = emptyToNull(createIndex.getDefinition());
058  }
059
060  public String getKey() {
061    // currently indexName should be unique (not indexName + platforms)
062    return indexName;
063  }
064
065  /**
066   * Return the index name.
067   */
068  public String getIndexName() {
069    return indexName;
070  }
071
072  /**
073   * Return the table this index is on.
074   */
075  public String getTableName() {
076    return tableName;
077  }
078
079  /**
080   * Return the columns in the index (in order).
081   */
082  public List<String> getColumns() {
083    return columns;
084  }
085
086  /**
087   * Return a CreateIndex migration for this index.
088   */
089  public CreateIndex createIndex() {
090    CreateIndex create = new CreateIndex();
091    create.setIndexName(indexName);
092    create.setTableName(tableName);
093    create.setColumns(join());
094    create.setPlatforms(platforms);
095    if (Boolean.TRUE.equals(unique)) {
096      create.setUnique(Boolean.TRUE);
097    }
098    if (Boolean.TRUE.equals(concurrent)) {
099      create.setConcurrent(Boolean.TRUE);
100    }
101    create.setDefinition(emptyToNull(definition));
102    return create;
103  }
104
105  private String emptyToNull(String val) {
106    if (val == null || val.isEmpty()) {
107      return null;
108    }
109    return val;
110  }
111
112  /**
113   * Create a DropIndex migration for this index.
114   */
115  public DropIndex dropIndex() {
116    DropIndex dropIndex = new DropIndex();
117    dropIndex.setIndexName(indexName);
118    dropIndex.setTableName(tableName);
119    dropIndex.setPlatforms(platforms);
120    if (Boolean.TRUE.equals(concurrent)) {
121      dropIndex.setConcurrent(Boolean.TRUE);
122    }
123    return dropIndex;
124  }
125
126  /**
127   * Compare with an index of the same name.
128   */
129  public void compare(ModelDiff modelDiff, MIndex newIndex) {
130    if (changed(newIndex)) {
131      // drop and recreate the index
132      modelDiff.addDropIndex(dropIndex());
133      modelDiff.addCreateIndex(newIndex.createIndex());
134    }
135  }
136
137  /**
138   * Return true if the index has changed.
139   */
140  private boolean changed(MIndex newIndex) {
141    if (!tableName.equals(newIndex.getTableName())) {
142      return true;
143    }
144    if (unique != newIndex.unique) {
145      return true;
146    }
147    if (!Objects.equals(definition, newIndex.definition)) {
148      return true;
149    }
150    List<String> newColumns = newIndex.getColumns();
151    if (columns.size() != newColumns.size()) {
152      return true;
153    }
154    for (int i = 0; i < columns.size(); i++) {
155      if (!columns.get(i).equals(newColumns.get(i))) {
156        return true;
157      }
158    }
159    return false;
160  }
161
162
163  private List<String> split(String columns) {
164    if (columns.isEmpty()) {
165      return Collections.emptyList();
166    }
167    String[] cols = columns.split(",");
168    List<String> colList = new ArrayList<>(cols.length);
169    Collections.addAll(colList, cols);
170    return colList;
171  }
172
173  private String join() {
174    StringBuilder sb = new StringBuilder(50);
175    for (int i = 0; i < columns.size(); i++) {
176      if (i > 0) {
177        sb.append(",");
178      }
179      sb.append(columns.get(i));
180    }
181    return sb.toString();
182  }
183
184}