package io.ebean.dbmigration.model; import java.util.Arrays; /** * The version of a migration used so that migrations are processed in order. */ public class MigrationVersion implements Comparable<MigrationVersion> { private static final int[] REPEAT_ORDERING = {Integer.MAX_VALUE}; private static final boolean[] REPEAT_UNDERSCORES = {false}; /** * The raw version text. */ private final String raw; /** * The ordering parts. */ private final int[] ordering; private final boolean[] underscores; private final String comment; /** * Construct for "repeatable" version. */ private MigrationVersion(String raw, String comment) { this.raw = raw; this.comment = comment; this.ordering = REPEAT_ORDERING; this.underscores = REPEAT_UNDERSCORES; } /** * Construct for "normal" version. */ private MigrationVersion(String raw, int[] ordering, boolean[] underscores, String comment) { this.raw = raw; this.ordering = ordering; this.underscores = underscores; this.comment = comment; } /** * Return true if this is a "repeatable" version. */ public boolean isRepeatable() { return ordering == REPEAT_ORDERING; } /** * Return the full version. */ public String getFull() { return raw; } @Override public String toString() { return raw; } /** * Return the version comment. */ public String getComment() { return comment; } /** * Return the version in raw form. */ public String getRaw() { return raw; } /** * Return the trimmed version excluding version comment and un-parsable string. */ public String asString() { return formattedVersion(false, false); } /** * Return the trimmed version with any underscores replaced with '.' */ public String normalised() { return formattedVersion(true, false); } /** * Return the next version based on this version. */ public String nextVersion() { return formattedVersion(false, true); } /** * Returns the version part of the string. * <p> * Normalised means always use '.' delimiters (no underscores). * NextVersion means bump/increase the last version number by 1. */ private String formattedVersion(boolean normalised, boolean nextVersion) { if (ordering == REPEAT_ORDERING) { return "R"; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < ordering.length; i++) { if (i < ordering.length - 1) { sb.append(ordering[i]); if (normalised) { sb.append('.'); } else { sb.append(underscores[i] ? '_' : '.'); } } else { sb.append((nextVersion) ? ordering[i] + 1 : ordering[i]); } } return sb.toString(); } @Override public int compareTo(MigrationVersion other) { int otherLength = other.ordering.length; for (int i = 0; i < ordering.length; i++) { if (i >= otherLength) { // considered greater return 1; } if (ordering[i] != other.ordering[i]) { return (ordering[i] > other.ordering[i]) ? 1 : -1; } } return comment.compareTo(other.comment); } /** * Parse the raw version string and just return the leading version number; */ public static String trim(String raw) { return parse(raw).asString(); } /** * Parse the raw version string into a MigrationVersion. */ public static MigrationVersion parse(String raw) { if (raw.startsWith("V") || raw.startsWith("v")) { raw = raw.substring(1); } String comment = ""; String value = raw; int commentStart = raw.indexOf("__"); if (commentStart > -1) { // trim off the trailing comment comment = raw.substring(commentStart + 2); value = value.substring(0, commentStart); } value = value.replace('_', '.'); String[] sections = value.split("[\\.-]"); if ("r".equalsIgnoreCase(sections[0])) { // a "repeatable" version (does not have a version number) return new MigrationVersion(raw, comment); } boolean[] underscores = new boolean[sections.length]; int[] ordering = new int[sections.length]; int delimiterPos = 0; int stopIndex = 0; for (int i = 0; i < sections.length; i++) { try { ordering[i] = Integer.parseInt(sections[i]); stopIndex++; delimiterPos += sections[i].length(); underscores[i] = (delimiterPos < raw.length() - 1 && raw.charAt(delimiterPos) == '_'); delimiterPos++; } catch (NumberFormatException e) { // stop parsing break; } } int[] actualOrder = Arrays.copyOf(ordering, stopIndex); boolean[] actualUnderscores = Arrays.copyOf(underscores, stopIndex); return new MigrationVersion(raw, actualOrder, actualUnderscores, comment); } }