All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.kazuki.v0.internal.v2schema.SchemaDiffUtil Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2014 Sunny Gleason and original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.kazuki.v0.internal.v2schema;

import io.kazuki.v0.store.schema.model.Attribute;
import io.kazuki.v0.store.schema.model.IndexAttribute;
import io.kazuki.v0.store.schema.model.IndexDefinition;
import io.kazuki.v0.store.schema.model.Schema;
import io.kazuki.v0.store.schema.model.diff.SchemaDiff;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Objects;

/**
 * Utility class for performing "diff" operations on Schema instances.
 */
public class SchemaDiffUtil {
  /**
   * Returns a list of differences between two Schema instances.
   * 
   * @param oldSchema Schema instance for the "old" version
   * @param newSchema Schema instance for the "new" version
   * @return List list of differences
   */
  @SuppressWarnings("rawtypes")
  public static List diff(Schema oldSchema, Schema newSchema) {
    List diffs = new ArrayList();

    diffAttributes(oldSchema, newSchema, diffs);
    diffIndexes(oldSchema, newSchema, diffs);

    return diffs;
  }

  @SuppressWarnings("rawtypes")
  private static void diffAttributes(Schema oldSchema, Schema newSchema, List diffs) {
    Map oldAttrs = oldSchema.getAttributeMap();
    Map newAttrs = newSchema.getAttributeMap();

    Set oldAttrsDone = new HashSet();

    for (Map.Entry attrEntry : newAttrs.entrySet()) {
      String attrName = attrEntry.getKey();
      Attribute attr = attrEntry.getValue();

      if (attr.getRenameOf() != null && !oldAttrs.containsKey(attr.getRenameOf())) {
        throw new IllegalArgumentException("new schema contains renameOf non-existent attribute: "
            + attrName);
      }

      if (attr.getRenameOf() != null) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_RENAME, Attribute.class,
            oldAttrs.get(attr.getRenameOf()), attr));
        oldAttrsDone.add(attr.getRenameOf());
        continue;
      }

      if (!oldAttrs.containsKey(attrName)) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_ADD, Attribute.class,
            null, attr));
        oldAttrsDone.add(attrName);
        continue;
      }

      Attribute oldAttr = oldAttrs.get(attrName);

      if (!oldAttr.getType().equals(attr.getType())) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_MODIFY, Attribute.class,
            oldAttr, attr));
        oldAttrsDone.add(attrName);
        continue;
      }

      if (oldAttr.isNullable() != attr.isNullable()) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_MODIFY, Attribute.class,
            oldAttr, attr));
        oldAttrsDone.add(attrName);
        continue;
      }

      List oldVals = oldAttr.getValues();
      List newVals = attr.getValues();

      if ((oldVals != null && (newVals == null || !oldVals.equals(newVals)))
          || (newVals != null && (oldVals == null || !newVals.equals(oldVals)))) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_MODIFY, Attribute.class,
            oldAttr, attr));
        continue;
      }
    }

    for (Map.Entry attrEntry : oldAttrs.entrySet()) {
      String attrName = attrEntry.getKey();
      Attribute oldAttr = attrEntry.getValue();

      if (oldAttrsDone.contains(attrName)) {
        continue;
      }

      if (!newAttrs.containsKey(attrName)) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.ATTRIBUTE_REMOVE, Attribute.class,
            oldAttr, null));
        oldAttrsDone.add(attrName);
        continue;
      }
    }
  }

  @SuppressWarnings("rawtypes")
  private static void diffIndexes(Schema oldSchema, Schema newSchema, List diffs) {
    Map oldIndexes = oldSchema.getIndexMap();
    Map newIndexes = newSchema.getIndexMap();

    Set oldIndexDone = new HashSet();

    for (Map.Entry indexEntry : newIndexes.entrySet()) {
      String indexName = indexEntry.getKey();
      IndexDefinition index = indexEntry.getValue();

      if (index.getRenameOf() != null && !oldIndexes.containsKey(index.getRenameOf())) {
        throw new IllegalArgumentException("new schema contains renameOf non-existent index: "
            + indexName);
      }

      if (index.getRenameOf() != null) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_RENAME,
            IndexDefinition.class, oldIndexes.get(index.getRenameOf()), index));
        oldIndexDone.add(index.getRenameOf());
        continue;
      }

      if (!oldIndexes.containsKey(indexName)) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_ADD,
            IndexDefinition.class, null, index));
        oldIndexDone.add(indexName);
        continue;
      }

      IndexDefinition oldIndex = oldIndexes.get(indexName);

      if (oldIndex.isUnique() != index.isUnique()) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_MODIFY,
            IndexDefinition.class, oldIndex, index));
        oldIndexDone.add(indexName);
        continue;
      }

      int oldAttrLen = oldIndex.getIndexAttributes().size();
      int newAttrLen = index.getIndexAttributes().size();

      if (oldAttrLen != newAttrLen) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_MODIFY,
            IndexDefinition.class, oldIndex, index));
        oldIndexDone.add(indexName);
        continue;
      }

      for (int i = 0; i < oldAttrLen; i++) {
        IndexAttribute oldAttr = oldIndex.getIndexAttributes().get(i);
        IndexAttribute newAttr = index.getIndexAttributes().get(i);

        if (!oldAttr.getName().equals(newAttr.getName())
            || !Objects.equal(oldAttr.getSortDirection(), newAttr.getSortDirection())
            || !Objects.equal(oldAttr.getTransform(), newAttr.getTransform())) {
          diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_MODIFY,
              IndexDefinition.class, oldIndex, index));
          oldIndexDone.add(indexName);
          continue;
        }
      }
    }

    for (Map.Entry indexEntry : oldIndexes.entrySet()) {
      String indexName = indexEntry.getKey();
      IndexDefinition oldIndex = indexEntry.getValue();

      if (oldIndexDone.contains(indexName)) {
        continue;
      }

      if (!newIndexes.containsKey(indexName)) {
        diffs.add(new SchemaDiff(SchemaDiff.DiffType.INDEX_REMOVE,
            IndexDefinition.class, oldIndex, null));
        oldIndexDone.add(indexName);
        continue;
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy